From 8457b98cf214149b947898235e5d6a7b3ca3d1ea Mon Sep 17 00:00:00 2001 From: Dariusz Stojaczyk Date: Mon, 8 May 2017 09:42:51 -0700 Subject: [PATCH] vhost: defer setting up new mem table There is an issue when QEMU sets new memory table just after guest OS starts booting. Then, if guest OS tries to issue any I/O to device (e.g. using BIOS INT13h - EDD) it will get stuck because previous addresses of mmaped memory might change. To fix this issue, defer using the new mem table until after we receive the first SET_VRING_ADDR message. SET_VRING_ADDR will be sent by QEMU when guest OS virtio (e.g. virtio-scsi) driver starts initialization. At this point it is safe to invalidate the old mem tables because there will be no more outstanding IO at this point. Change-Id: I24772be87a8b6c8781868b9b7773317761499748 Signed-off-by: Jim Harris Signed-off-by: Dariusz Stojaczyk --- lib/vhost/rte_vhost_17_05/vhost.h | 4 +++ lib/vhost/rte_vhost_17_05/vhost_user.c | 35 ++++++++++++++++++++++++-- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/lib/vhost/rte_vhost_17_05/vhost.h b/lib/vhost/rte_vhost_17_05/vhost.h index ddd8a9c43..fd37f4340 100644 --- a/lib/vhost/rte_vhost_17_05/vhost.h +++ b/lib/vhost/rte_vhost_17_05/vhost.h @@ -47,6 +47,7 @@ #include #include "rte_vhost.h" +#include "vhost_user.h" /* Used to indicate that the device is running on a data core */ #define VIRTIO_DEV_RUNNING 1 @@ -196,6 +197,9 @@ struct virtio_net { uint32_t nr_guest_pages; uint32_t max_guest_pages; struct guest_page *guest_pages; + int has_new_mem_table; + struct VhostUserMemory mem_table; + int mem_table_fds[VHOST_MEMORY_MAX_NREGIONS]; } __rte_cache_aligned; diff --git a/lib/vhost/rte_vhost_17_05/vhost_user.c b/lib/vhost/rte_vhost_17_05/vhost_user.c index f6bee6ebc..81b9fd90c 100644 --- a/lib/vhost/rte_vhost_17_05/vhost_user.c +++ b/lib/vhost/rte_vhost_17_05/vhost_user.c @@ -323,6 +323,8 @@ qva_to_vva(struct virtio_net *dev, uint64_t qva) return 0; } +static int vhost_setup_mem_table(struct virtio_net *dev); + /* * The virtio device sends us the desc, used and avail ring addresses. * This function then converts these to our address space. @@ -332,6 +334,12 @@ vhost_user_set_vring_addr(struct virtio_net *dev, struct vhost_vring_addr *addr) { struct vhost_virtqueue *vq; + if (dev->has_new_mem_table) { + vhost_setup_mem_table(dev); + dev->has_new_mem_table = 0; + } + + if (dev->mem == NULL) return -1; @@ -499,7 +507,30 @@ dump_guest_pages(struct virtio_net *dev) static int vhost_user_set_mem_table(struct virtio_net *dev, struct VhostUserMsg *pmsg) { - struct VhostUserMemory memory = pmsg->payload.memory; + uint32_t i; + + if (dev->has_new_mem_table) { + /* + * The previous mem table was not consumed, so close the + * file descriptors from that mem table before copying + * the new one. + */ + for (i = 0; i < dev->mem_table.nregions; i++) { + close(dev->mem_table_fds[i]); + } + } + + memcpy(&dev->mem_table, &pmsg->payload.memory, sizeof(dev->mem_table)); + memcpy(dev->mem_table_fds, pmsg->fds, sizeof(dev->mem_table_fds)); + dev->has_new_mem_table = 1; + + return 0; +} + + static int +vhost_setup_mem_table(struct virtio_net *dev) +{ + struct VhostUserMemory memory = dev->mem_table; struct rte_vhost_mem_region *reg; void *mmap_addr; uint64_t mmap_size; @@ -532,7 +563,7 @@ vhost_user_set_mem_table(struct virtio_net *dev, struct VhostUserMsg *pmsg) dev->mem->nregions = memory.nregions; for (i = 0; i < memory.nregions; i++) { - fd = pmsg->fds[i]; + fd = dev->mem_table_fds[i]; reg = &dev->mem->regions[i]; reg->guest_phys_addr = memory.regions[i].guest_phys_addr;