Commit 8457b98c authored by Dariusz Stojaczyk's avatar Dariusz Stojaczyk Committed by Jim Harris
Browse files

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: default avatarJim Harris <james.r.harris@intel.com>
Signed-off-by: default avatarDariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
parent fab374a7
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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;


+33 −2
Original line number Diff line number Diff line
@@ -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;