virtio-rng: use virtqueue_get_avail_bytes, fix migration

Popping an elem from the vq just to find out its length causes problems
with save/load later on.  Use the new virtqueue_get_avail_bytes()
function instead, saves us the complexity in the migration code, as well
as makes the migration endian-safe.

Signed-off-by: Amit Shah <amit.shah@redhat.com>
Reviewed-by: Anthony Liguori <aliguori@us.ibm.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
This commit is contained in:
Amit Shah 2012-11-21 11:21:18 +05:30 committed by Anthony Liguori
parent 25d87288b1
commit 1441703965

View File

@ -22,14 +22,10 @@ typedef struct VirtIORNG {
/* Only one vq - guest puts buffer(s) on it when it needs entropy */ /* Only one vq - guest puts buffer(s) on it when it needs entropy */
VirtQueue *vq; VirtQueue *vq;
VirtQueueElement elem;
/* Config data for the device -- currently only chardev */ /* Config data for the device -- currently only chardev */
VirtIORNGConf *conf; VirtIORNGConf *conf;
/* Whether we've popped a vq element into 'elem' above */
bool popped;
RngBackend *rng; RngBackend *rng;
/* We purposefully don't migrate this state. The quota will reset on the /* We purposefully don't migrate this state. The quota will reset on the
@ -48,17 +44,12 @@ static bool is_guest_ready(VirtIORNG *vrng)
return false; return false;
} }
static size_t pop_an_elem(VirtIORNG *vrng) static size_t get_request_size(VirtQueue *vq)
{ {
size_t size; unsigned int in, out;
if (!vrng->popped && !virtqueue_pop(vrng->vq, &vrng->elem)) { virtqueue_get_avail_bytes(vq, &in, &out);
return 0; return in;
}
vrng->popped = true;
size = iov_size(vrng->elem.in_sg, vrng->elem.in_num);
return size;
} }
static void virtio_rng_process(VirtIORNG *vrng); static void virtio_rng_process(VirtIORNG *vrng);
@ -67,6 +58,7 @@ static void virtio_rng_process(VirtIORNG *vrng);
static void chr_read(void *opaque, const void *buf, size_t size) static void chr_read(void *opaque, const void *buf, size_t size)
{ {
VirtIORNG *vrng = opaque; VirtIORNG *vrng = opaque;
VirtQueueElement elem;
size_t len; size_t len;
int offset; int offset;
@ -78,15 +70,14 @@ static void chr_read(void *opaque, const void *buf, size_t size)
offset = 0; offset = 0;
while (offset < size) { while (offset < size) {
if (!pop_an_elem(vrng)) { if (!virtqueue_pop(vrng->vq, &elem)) {
break; break;
} }
len = iov_from_buf(vrng->elem.in_sg, vrng->elem.in_num, len = iov_from_buf(elem.in_sg, elem.in_num,
0, buf + offset, size - offset); 0, buf + offset, size - offset);
offset += len; offset += len;
virtqueue_push(vrng->vq, &vrng->elem, len); virtqueue_push(vrng->vq, &elem, len);
vrng->popped = false;
} }
virtio_notify(&vrng->vdev, vrng->vq); virtio_notify(&vrng->vdev, vrng->vq);
@ -100,21 +91,19 @@ static void chr_read(void *opaque, const void *buf, size_t size)
static void virtio_rng_process(VirtIORNG *vrng) static void virtio_rng_process(VirtIORNG *vrng)
{ {
ssize_t size; size_t size;
if (!is_guest_ready(vrng)) { if (!is_guest_ready(vrng)) {
return; return;
} }
size = pop_an_elem(vrng); size = get_request_size(vrng->vq);
size = MIN(vrng->quota_remaining, size); size = MIN(vrng->quota_remaining, size);
if (size) {
if (size > 0) {
rng_backend_request_entropy(vrng->rng, size, chr_read, vrng); rng_backend_request_entropy(vrng->rng, size, chr_read, vrng);
} }
} }
static void handle_input(VirtIODevice *vdev, VirtQueue *vq) static void handle_input(VirtIODevice *vdev, VirtQueue *vq)
{ {
VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev); VirtIORNG *vrng = DO_UPCAST(VirtIORNG, vdev, vdev);
@ -131,23 +120,6 @@ static void virtio_rng_save(QEMUFile *f, void *opaque)
VirtIORNG *vrng = opaque; VirtIORNG *vrng = opaque;
virtio_save(&vrng->vdev, f); virtio_save(&vrng->vdev, f);
qemu_put_byte(f, vrng->popped);
if (vrng->popped) {
int i;
qemu_put_be32(f, vrng->elem.index);
qemu_put_be32(f, vrng->elem.in_num);
for (i = 0; i < vrng->elem.in_num; i++) {
qemu_put_be64(f, vrng->elem.in_addr[i]);
}
qemu_put_be32(f, vrng->elem.out_num);
for (i = 0; i < vrng->elem.out_num; i++) {
qemu_put_be64(f, vrng->elem.out_addr[i]);
}
}
} }
static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id) static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id)
@ -159,30 +131,6 @@ static int virtio_rng_load(QEMUFile *f, void *opaque, int version_id)
} }
virtio_load(&vrng->vdev, f); virtio_load(&vrng->vdev, f);
vrng->popped = qemu_get_byte(f);
if (vrng->popped) {
int i;
vrng->elem.index = qemu_get_be32(f);
vrng->elem.in_num = qemu_get_be32(f);
g_assert(vrng->elem.in_num < VIRTQUEUE_MAX_SIZE);
for (i = 0; i < vrng->elem.in_num; i++) {
vrng->elem.in_addr[i] = qemu_get_be64(f);
}
vrng->elem.out_num = qemu_get_be32(f);
g_assert(vrng->elem.out_num < VIRTQUEUE_MAX_SIZE);
for (i = 0; i < vrng->elem.out_num; i++) {
vrng->elem.out_addr[i] = qemu_get_be64(f);
}
virtqueue_map_sg(vrng->elem.in_sg, vrng->elem.in_addr,
vrng->elem.in_num, 1);
virtqueue_map_sg(vrng->elem.out_sg, vrng->elem.out_addr,
vrng->elem.out_num, 0);
}
/* We may have an element ready but couldn't process it due to a quota /* We may have an element ready but couldn't process it due to a quota
limit. Make sure to try again after live migration when the quota may limit. Make sure to try again after live migration when the quota may
have been reset. have been reset.
@ -232,7 +180,7 @@ VirtIODevice *virtio_rng_init(DeviceState *dev, VirtIORNGConf *conf)
vrng->qdev = dev; vrng->qdev = dev;
vrng->conf = conf; vrng->conf = conf;
vrng->popped = false;
vrng->quota_remaining = vrng->conf->max_bytes; vrng->quota_remaining = vrng->conf->max_bytes;
g_assert_cmpint(vrng->conf->max_bytes, <=, INT64_MAX); g_assert_cmpint(vrng->conf->max_bytes, <=, INT64_MAX);