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 <james.r.harris@intel.com> Signed-off-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
This commit is contained in:
parent
fab374a7c6
commit
8457b98cf2
@ -47,6 +47,7 @@
|
||||
#include <rte_ether.h>
|
||||
|
||||
#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;
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user