On error, virtio blk dirties guest memory but doesn't want to tell guest about it. Add virtqueue_fill_partial to cover this use case. This gets two parameters: host_len is >= the amount of guest memory actually written, guest_len is how much we guarantee to guest.
Cc: Paolo Bonzini <pbonz...@redhat.com> Signed-off-by: Michael S. Tsirkin <m...@redhat.com> --- include/hw/virtio/virtio.h | 3 +++ hw/virtio/virtio.c | 25 ++++++++++++++++++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index e3adb1d..9957aae 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -135,6 +135,9 @@ void virtio_del_queue(VirtIODevice *vdev, int n); void virtqueue_push(VirtQueue *vq, const VirtQueueElement *elem, unsigned int len); void virtqueue_flush(VirtQueue *vq, unsigned int count); +void virtqueue_fill_partial(VirtQueue *vq, const VirtQueueElement *elem, + unsigned int host_len, unsigned int guest_len, + unsigned int idx); void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, unsigned int len, unsigned int idx); diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 159e5c6..111b0db 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -241,17 +241,26 @@ int virtio_queue_empty(VirtQueue *vq) return vring_avail_idx(vq) == vq->last_avail_idx; } -void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, - unsigned int len, unsigned int idx) +/* + * Some devices dirty guest memory but don't want to tell guest about it. In + * that case, use virtqueue_fill_partial: host_len is >= the amount of guest + * memory actually written, guest_len is how much we guarantee to guest. + * If you know exactly how much was written, use virtqueue_fill instead. + */ +void virtqueue_fill_partial(VirtQueue *vq, const VirtQueueElement *elem, + unsigned int host_len, unsigned int guest_len, + unsigned int idx) { unsigned int offset; int i; - trace_virtqueue_fill(vq, elem, len, idx); + assert(host_len >= guest_len); + + trace_virtqueue_fill(vq, elem, guest_len, idx); offset = 0; for (i = 0; i < elem->in_num; i++) { - size_t size = MIN(len - offset, elem->in_sg[i].iov_len); + size_t size = MIN(host_len - offset, elem->in_sg[i].iov_len); cpu_physical_memory_unmap(elem->in_sg[i].iov_base, elem->in_sg[i].iov_len, @@ -269,7 +278,13 @@ void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, /* Get a pointer to the next entry in the used ring. */ vring_used_ring_id(vq, idx, elem->index); - vring_used_ring_len(vq, idx, len); + vring_used_ring_len(vq, idx, guest_len); +} + +void virtqueue_fill(VirtQueue *vq, const VirtQueueElement *elem, + unsigned int len, unsigned int idx) +{ + virtqueue_fill_partial(vq, elem, len, len, idx); } void virtqueue_flush(VirtQueue *vq, unsigned int count) -- MST