qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

virtio-rng: stop virtqueue while the CPU is stopped

If we modify the virtio-rng virqueue while the
vmstate is already migrated we can have some
inconsistencies between the virtqueue state and
the memory content.

To avoid this, stop the virtqueue while the CPU
is stopped.

Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Amit Shah <amit@kernel.org>
Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: Juan Quintela <quintela@redhat.com>
Signed-off-by: Juan Quintela <quintela@redhat.com>

authored by

Laurent Vivier and committed by
Juan Quintela
a23a6d18 e8199e48

+28 -6
+3
hw/virtio/trace-events
··· 11 11 12 12 # hw/virtio/virtio-rng.c 13 13 virtio_rng_guest_not_ready(void *rng) "rng %p: guest not ready" 14 + virtio_rng_cpu_is_stopped(void *rng, int size) "rng %p: cpu is stopped, dropping %d bytes" 15 + virtio_rng_popped(void *rng) "rng %p: elem popped" 14 16 virtio_rng_pushed(void *rng, size_t len) "rng %p: %zd bytes pushed" 15 17 virtio_rng_request(void *rng, size_t size, unsigned quota) "rng %p: %zd bytes requested, %u bytes quota left" 18 + virtio_rng_vm_state_change(void *rng, int running, int state) "rng %p: state change to running %d state %d" 16 19 17 20 # hw/virtio/virtio-balloon.c 18 21 #
+23 -6
hw/virtio/virtio-rng.c
··· 53 53 return; 54 54 } 55 55 56 + /* we can't modify the virtqueue until 57 + * our state is fully synced 58 + */ 59 + 60 + if (!runstate_check(RUN_STATE_RUNNING)) { 61 + trace_virtio_rng_cpu_is_stopped(vrng, size); 62 + return; 63 + } 64 + 56 65 vrng->quota_remaining -= size; 57 66 58 67 offset = 0; ··· 61 70 if (!elem) { 62 71 break; 63 72 } 73 + trace_virtio_rng_popped(vrng); 64 74 len = iov_from_buf(elem->in_sg, elem->in_num, 65 75 0, buf + offset, size - offset); 66 76 offset += len; ··· 120 130 return f; 121 131 } 122 132 123 - static int virtio_rng_post_load(void *opaque, int version_id) 133 + static void virtio_rng_vm_state_change(void *opaque, int running, 134 + RunState state) 124 135 { 125 136 VirtIORNG *vrng = opaque; 137 + 138 + trace_virtio_rng_vm_state_change(vrng, running, state); 126 139 127 140 /* We may have an element ready but couldn't process it due to a quota 128 - * limit. Make sure to try again after live migration when the quota may 129 - * have been reset. 141 + * limit or because CPU was stopped. Make sure to try again when the 142 + * CPU restart. 130 143 */ 131 - virtio_rng_process(vrng); 132 144 133 - return 0; 145 + if (running && is_guest_ready(vrng)) { 146 + virtio_rng_process(vrng); 147 + } 134 148 } 135 149 136 150 static void check_rate_limit(void *opaque) ··· 198 212 vrng->rate_limit_timer = timer_new_ms(QEMU_CLOCK_VIRTUAL, 199 213 check_rate_limit, vrng); 200 214 vrng->activate_timer = true; 215 + 216 + vrng->vmstate = qemu_add_vm_change_state_handler(virtio_rng_vm_state_change, 217 + vrng); 201 218 } 202 219 203 220 static void virtio_rng_device_unrealize(DeviceState *dev, Error **errp) ··· 205 222 VirtIODevice *vdev = VIRTIO_DEVICE(dev); 206 223 VirtIORNG *vrng = VIRTIO_RNG(dev); 207 224 225 + qemu_del_vm_change_state_handler(vrng->vmstate); 208 226 timer_del(vrng->rate_limit_timer); 209 227 timer_free(vrng->rate_limit_timer); 210 228 virtio_cleanup(vdev); ··· 218 236 VMSTATE_VIRTIO_DEVICE, 219 237 VMSTATE_END_OF_LIST() 220 238 }, 221 - .post_load = virtio_rng_post_load, 222 239 }; 223 240 224 241 static Property virtio_rng_properties[] = {
+2
include/hw/virtio/virtio-rng.h
··· 45 45 QEMUTimer *rate_limit_timer; 46 46 int64_t quota_remaining; 47 47 bool activate_timer; 48 + 49 + VMChangeStateEntry *vmstate; 48 50 } VirtIORNG; 49 51 50 52 #endif