mirror of https://github.com/xemu-project/xemu.git
virtio-blk: correctly dirty guest memory
After qemu_iovec_destroy, the QEMUIOVector's size is zeroed and the zero size ultimately is used to compute virtqueue_push's len argument. Therefore, reads from virtio-blk devices did not migrate their results correctly. (Writes were okay). Save the size in virtio_blk_handle_request, and use it when the request is completed. Based on a patch by Wen Congyang. Signed-off-by: Wen Congyang <wency@cn.fujitsu.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Tested-by: Li Zhijian <lizhijian@cn.fujitsu.com> Message-id: 1427997044-392-1-git-send-email-pbonzini@redhat.com Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
parent
e4603fe139
commit
2a6cdd6d35
|
@ -77,8 +77,7 @@ static void complete_request_vring(VirtIOBlockReq *req, unsigned char status)
|
||||||
VirtIOBlockDataPlane *s = req->dev->dataplane;
|
VirtIOBlockDataPlane *s = req->dev->dataplane;
|
||||||
stb_p(&req->in->status, status);
|
stb_p(&req->in->status, status);
|
||||||
|
|
||||||
vring_push(s->vdev, &req->dev->dataplane->vring, &req->elem,
|
vring_push(s->vdev, &req->dev->dataplane->vring, &req->elem, req->in_len);
|
||||||
req->qiov.size + sizeof(*req->in));
|
|
||||||
|
|
||||||
/* Suppress notification to guest by BH and its scheduled
|
/* Suppress notification to guest by BH and its scheduled
|
||||||
* flag because requests are completed as a batch after io
|
* flag because requests are completed as a batch after io
|
||||||
|
|
|
@ -33,6 +33,7 @@ VirtIOBlockReq *virtio_blk_alloc_request(VirtIOBlock *s)
|
||||||
VirtIOBlockReq *req = g_slice_new(VirtIOBlockReq);
|
VirtIOBlockReq *req = g_slice_new(VirtIOBlockReq);
|
||||||
req->dev = s;
|
req->dev = s;
|
||||||
req->qiov.size = 0;
|
req->qiov.size = 0;
|
||||||
|
req->in_len = 0;
|
||||||
req->next = NULL;
|
req->next = NULL;
|
||||||
req->mr_next = NULL;
|
req->mr_next = NULL;
|
||||||
return req;
|
return req;
|
||||||
|
@ -54,7 +55,7 @@ static void virtio_blk_complete_request(VirtIOBlockReq *req,
|
||||||
trace_virtio_blk_req_complete(req, status);
|
trace_virtio_blk_req_complete(req, status);
|
||||||
|
|
||||||
stb_p(&req->in->status, status);
|
stb_p(&req->in->status, status);
|
||||||
virtqueue_push(s->vq, &req->elem, req->qiov.size + sizeof(*req->in));
|
virtqueue_push(s->vq, &req->elem, req->in_len);
|
||||||
virtio_notify(vdev, s->vq);
|
virtio_notify(vdev, s->vq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,6 +103,14 @@ static void virtio_blk_rw_complete(void *opaque, int ret)
|
||||||
if (ret) {
|
if (ret) {
|
||||||
int p = virtio_ldl_p(VIRTIO_DEVICE(req->dev), &req->out.type);
|
int p = virtio_ldl_p(VIRTIO_DEVICE(req->dev), &req->out.type);
|
||||||
bool is_read = !(p & VIRTIO_BLK_T_OUT);
|
bool is_read = !(p & VIRTIO_BLK_T_OUT);
|
||||||
|
/* Note that memory may be dirtied on read failure. If the
|
||||||
|
* virtio request is not completed here, as is the case for
|
||||||
|
* BLOCK_ERROR_ACTION_STOP, the memory may not be copied
|
||||||
|
* correctly during live migration. While this is ugly,
|
||||||
|
* it is acceptable because the device is free to write to
|
||||||
|
* the memory until the request is completed (which will
|
||||||
|
* happen on the other side of the migration).
|
||||||
|
*/
|
||||||
if (virtio_blk_handle_rw_error(req, -ret, is_read)) {
|
if (virtio_blk_handle_rw_error(req, -ret, is_read)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -496,6 +505,8 @@ void virtio_blk_handle_request(VirtIOBlockReq *req, MultiReqBuffer *mrb)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We always touch the last byte, so just see how big in_iov is. */
|
||||||
|
req->in_len = iov_size(in_iov, in_num);
|
||||||
req->in = (void *)in_iov[in_num - 1].iov_base
|
req->in = (void *)in_iov[in_num - 1].iov_base
|
||||||
+ in_iov[in_num - 1].iov_len
|
+ in_iov[in_num - 1].iov_len
|
||||||
- sizeof(struct virtio_blk_inhdr);
|
- sizeof(struct virtio_blk_inhdr);
|
||||||
|
|
|
@ -67,6 +67,7 @@ typedef struct VirtIOBlockReq {
|
||||||
struct virtio_blk_inhdr *in;
|
struct virtio_blk_inhdr *in;
|
||||||
struct virtio_blk_outhdr out;
|
struct virtio_blk_outhdr out;
|
||||||
QEMUIOVector qiov;
|
QEMUIOVector qiov;
|
||||||
|
size_t in_len;
|
||||||
struct VirtIOBlockReq *next;
|
struct VirtIOBlockReq *next;
|
||||||
struct VirtIOBlockReq *mr_next;
|
struct VirtIOBlockReq *mr_next;
|
||||||
BlockAcctCookie acct;
|
BlockAcctCookie acct;
|
||||||
|
|
Loading…
Reference in New Issue