lguest: separate out virtqueue info from device info.

To deal with other Guest's virtqueue, we need to separate out the
parts of the structure which deal with the actual virtqueue from
configuration information and the device.  Then we can change the
virtqueue descriptor handling functions to take that smaller
structure.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
 Documentation/lguest/lguest.c |  175 ++++++++++++++++++++++--------------------
 1 file changed, 92 insertions(+), 83 deletions(-)

diff -r 1ab981c8c18d Documentation/lguest/lguest.c
--- a/Documentation/lguest/lguest.c	Wed Aug 13 11:49:31 2008 +1000
+++ b/Documentation/lguest/lguest.c	Wed Aug 13 11:58:38 2008 +1000
@@ -161,6 +161,17 @@ struct device
 };
 
 /* The virtqueue structure describes a queue attached to a device. */
+struct virtqueue_info {
+	/* The memory this virtqueue sits in (usually gmem, our Guest). */
+	struct guest_memory *mem;
+
+	/* The actual ring of buffers. */
+	struct vring vring;
+
+	/* Outstanding buffers */
+	unsigned int inflight;
+};
+
 struct virtqueue
 {
 	struct virtqueue *next;
@@ -171,14 +182,11 @@ struct virtqueue
 	/* The configuration for this queue. */
 	struct lguest_vqconfig config;
 
-	/* The actual ring of buffers. */
-	struct vring vring;
+	/* Information about the Guest's virtqueue. */
+	struct virtqueue_info vqi;
 
 	/* The routine to call when the Guest pings us, or timeout. */
 	void (*handle_output)(int fd, struct virtqueue *me, bool timeout);
-
-	/* Outstanding buffers */
-	unsigned int inflight;
 
 	/* Is this blocked awaiting a timer? */
 	bool blocked;
@@ -216,7 +224,7 @@ static void *_convert(struct iovec *iov,
 }
 
 /* Wrapper for the last available index.  Makes it easier to change. */
-#define lg_last_avail(vq)	vring_last_avail(&(vq)->vring)
+#define lg_last_avail(vqi)	vring_last_avail(&(vqi)->vring)
 
 /* The virtio configuration space is defined to be little-endian.  x86 is
  * little-endian too, but it's nice to be explicit so we have these helpers. */
@@ -680,20 +688,20 @@ static void *_check_pointer(unsigned lon
 /* Each buffer in the virtqueues is actually a chain of descriptors.  This
  * function returns the next descriptor in the chain, or vq->vring.num if we're
  * at the end. */
-static unsigned next_desc(struct virtqueue *vq, unsigned int i)
+static unsigned next_desc(struct virtqueue_info *vqi, unsigned int i)
 {
 	unsigned int next;
 
 	/* If this descriptor says it doesn't chain, we're done. */
-	if (!(vq->vring.desc[i].flags & VRING_DESC_F_NEXT))
-		return vq->vring.num;
+	if (!(vqi->vring.desc[i].flags & VRING_DESC_F_NEXT))
+		return vqi->vring.num;
 
 	/* Check they're not leading us off end of descriptors. */
-	next = vq->vring.desc[i].next;
+	next = vqi->vring.desc[i].next;
 	/* Make sure compiler knows to grab that: we don't want it changing! */
 	wmb();
 
-	if (next >= vq->vring.num)
+	if (next >= vqi->vring.num)
 		errx(1, "Desc next is %u", next);
 
 	return next;
@@ -704,9 +712,9 @@ static unsigned next_desc(struct virtque
  * number of output then some number of input descriptors, it's actually two
  * iovecs, but we pack them into one and note how many of each there were.
  *
- * This function returns the descriptor number found, or vq->vring.num (which
- * is never a valid descriptor number) if none was found. */
-static unsigned get_vq_desc(struct virtqueue *vq,
+ * This function returns the descriptor number found, or -1 if none was
+ * found. */
+static unsigned get_vq_desc(struct virtqueue_info *vqi,
 			    struct iovec iov[],
 			    unsigned int *out_num, unsigned int *in_num)
 {
@@ -714,22 +722,22 @@ static unsigned get_vq_desc(struct virtq
 	u16 last_avail;
 
 	/* Check it isn't doing very strange things with descriptor numbers. */
-	last_avail = lg_last_avail(vq);
-	if ((u16)(vq->vring.avail->idx - last_avail) > vq->vring.num)
+	last_avail = lg_last_avail(vqi);
+	if ((u16)(vqi->vring.avail->idx - last_avail) > vqi->vring.num)
 		errx(1, "Guest moved used index from %u to %u",
-		     last_avail, vq->vring.avail->idx);
+		     last_avail, vqi->vring.avail->idx);
 
 	/* If there's nothing new since last we looked, return invalid. */
-	if (vq->vring.avail->idx == last_avail)
-		return vq->vring.num;
+	if (vqi->vring.avail->idx == last_avail)
+		return -1;
 
 	/* Grab the next descriptor number they're advertising, and increment
 	 * the index we've seen. */
-	head = vq->vring.avail->ring[last_avail % vq->vring.num];
-	lg_last_avail(vq)++;
+	head = vqi->vring.avail->ring[last_avail % vqi->vring.num];
+	lg_last_avail(vqi)++;
 
 	/* If their number is silly, that's a fatal mistake. */
-	if (head >= vq->vring.num)
+	if (head >= vqi->vring.num)
 		errx(1, "Guest says index %u is available", head);
 
 	/* When we start there are none of either input nor output. */
@@ -738,12 +746,12 @@ static unsigned get_vq_desc(struct virtq
 	i = head;
 	do {
 		/* Grab the first descriptor, and check it's OK. */
-		iov[*out_num + *in_num].iov_len = vq->vring.desc[i].len;
+		iov[*out_num + *in_num].iov_len = vqi->vring.desc[i].len;
 		iov[*out_num + *in_num].iov_base
-			= check_pointer(&gmem, vq->vring.desc[i].addr,
-					vq->vring.desc[i].len);
+			= check_pointer(vqi->mem, vqi->vring.desc[i].addr,
+					vqi->vring.desc[i].len);
 		/* If this is an input descriptor, increment that count. */
-		if (vq->vring.desc[i].flags & VRING_DESC_F_WRITE)
+		if (vqi->vring.desc[i].flags & VRING_DESC_F_WRITE)
 			(*in_num)++;
 		else {
 			/* If it's an output descriptor, they're all supposed
@@ -754,29 +762,29 @@ static unsigned get_vq_desc(struct virtq
 		}
 
 		/* If we've got too many, that implies a descriptor loop. */
-		if (*out_num + *in_num > vq->vring.num)
+		if (*out_num + *in_num > vqi->vring.num)
 			errx(1, "Looped descriptor");
-	} while ((i = next_desc(vq, i)) != vq->vring.num);
+	} while ((i = next_desc(vqi, i)) != vqi->vring.num);
 
-	vq->inflight++;
+	vqi->inflight++;
 	return head;
 }
 
 /* After we've used one of their buffers, we tell them about it.  We'll then
  * want to send them an interrupt, using trigger_irq(). */
-static void add_used(struct virtqueue *vq, unsigned int head, int len)
+static void add_used(struct virtqueue_info *vqi, unsigned int head, int len)
 {
 	struct vring_used_elem *used;
 
 	/* The virtqueue contains a ring of used buffers.  Get a pointer to the
 	 * next entry in that used ring. */
-	used = &vq->vring.used->ring[vq->vring.used->idx % vq->vring.num];
+	used = &vqi->vring.used->ring[vqi->vring.used->idx % vqi->vring.num];
 	used->id = head;
 	used->len = len;
 	/* Make sure buffer is written before we update index. */
 	wmb();
-	vq->vring.used->idx++;
-	vq->inflight--;
+	vqi->vring.used->idx++;
+	vqi->inflight--;
 }
 
 /* This actually sends the interrupt for this virtqueue */
@@ -785,8 +793,8 @@ static void trigger_irq(int fd, struct v
 	unsigned long buf[] = { LHREQ_IRQ, vq->config.irq };
 
 	/* If they don't want an interrupt, don't send one, unless empty. */
-	if ((vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)
-	    && vq->inflight)
+	if ((vq->vqi.vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)
+	    && vq->vqi.inflight)
 		return;
 
 	/* Send the Guest an interrupt tell them we used something up. */
@@ -798,7 +806,7 @@ static void add_used_and_trigger(int fd,
 static void add_used_and_trigger(int fd, struct virtqueue *vq,
 				 unsigned int head, int len)
 {
-	add_used(vq, head, len);
+	add_used(&vq->vqi, head, len);
 	trigger_irq(fd, vq);
 }
 
@@ -832,15 +840,15 @@ static void dump_devices(void)
 		printf("Device %s:\n", i->name);
 		for (vq = i->vq; vq; vq = vq->next) {
 			printf("  Virtqueue %p:\n", vq);
-			printf("   num = %u\n", vq->vring.num);
+			printf("   num = %u\n", vq->vqi.vring.num);
 			printf("   avail: flags=%u idx=%u (last=%u)\n",
-			       vq->vring.avail->flags,
-			       vq->vring.avail->idx,
-			       vring_last_avail(&vq->vring));
+			       vq->vqi.vring.avail->flags,
+			       vq->vqi.vring.avail->idx,
+			       vring_last_avail(&vq->vqi.vring));
 			printf("   used: flags=%u idx=%u (last=%u)\n",
-			       vq->vring.used->flags,
-			       vq->vring.used->idx,
-			       vring_last_used(&vq->vring));
+			       vq->vqi.vring.used->flags,
+			       vq->vqi.vring.used->idx,
+			       vring_last_used(&vq->vqi.vring));
 		}
 	}
 }
@@ -848,17 +856,17 @@ static void dump_devices(void)
 /* This is the routine which handles console input (ie. stdin). */
 static bool handle_console_input(int fd, struct device *dev)
 {
-	int len;
-	unsigned int head, in_num, out_num;
-	struct iovec iov[dev->vq->vring.num];
+	int len, head;
+	unsigned int in_num, out_num;
+	struct iovec iov[dev->vq->vqi.vring.num];
 	struct console_abort *abort = dev->priv;
 
 	/* First we need a console buffer from the Guests's input virtqueue. */
-	head = get_vq_desc(dev->vq, iov, &out_num, &in_num);
+	head = get_vq_desc(&dev->vq->vqi, iov, &out_num, &in_num);
 
 	/* If they're not ready for input, stop listening to this file
 	 * descriptor.  We'll start again once they add an input buffer. */
-	if (head == dev->vq->vring.num)
+	if (head < 0)
 		return false;
 
 	if (out_num)
@@ -928,14 +936,14 @@ static bool handle_console_input(int fd,
  * and write them to stdout. */
 static void handle_console_output(int fd, struct virtqueue *vq, bool timeout)
 {
-	unsigned int head, out, in;
-	int len;
-	struct iovec iov[vq->vring.num];
+	unsigned int out, in;
+	int head, len;
+	struct iovec iov[vq->vqi.vring.num];
 
 	net_xmit_notify++;
 
 	/* Keep getting output buffers from the Guest until we run out. */
-	while ((head = get_vq_desc(vq, iov, &out, &in)) != vq->vring.num) {
+	while ((head = get_vq_desc(&vq->vqi, iov, &out, &in)) >= 0) {
 		if (in)
 			errx(1, "Input buffers in output queue?");
 		len = writev(STDOUT_FILENO, iov, out);
@@ -947,7 +955,7 @@ static void block_vq(struct virtqueue *v
 {
 	struct itimerval itm;
 
-	vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
+	vq->vqi.vring.used->flags |= VRING_USED_F_NO_NOTIFY;
 	vq->blocked = true;
 
 	itm.it_interval.tv_sec = 0;
@@ -972,13 +980,13 @@ struct virtio_net_info {
 
 static void handle_net_output(int fd, struct virtqueue *vq, bool timeout)
 {
-	unsigned int head, out, in, num = 0;
-	int len;
-	struct iovec iov[vq->vring.num];
+	unsigned int out, in, num = 0;
+	int head, len;
+	struct iovec iov[vq->vqi.vring.num];
 	static int last_timeout_num;
 
 	/* Keep getting output buffers from the Guest until we run out. */
-	while ((head = get_vq_desc(vq, iov, &out, &in)) != vq->vring.num) {
+	while ((head = get_vq_desc(&vq->vqi, iov, &out, &in)) >= 0) {
 		if (in)
 			errx(1, "Input buffers in output queue?");
 		len = writev(vq->dev->fd, iov, out);
@@ -1004,7 +1012,7 @@ static void handle_netring_output(int fd
 static void handle_netring_output(int fd, struct virtqueue *vq, bool timeout)
 {
 	struct virtio_net_info *ni = vq->dev->priv;
-	u16 num = vq->vring.avail->idx - vring_last_avail(&vq->vring);
+	u16 num = vq->vqi.vring.avail->idx - lg_last_avail(&vq->vqi);
 	static int last_timeout_num;
 
 	if (!timeout)
@@ -1032,20 +1040,20 @@ static void handle_netring_output(int fd
  * Guest. */
 static bool handle_tun_input(int fd, struct device *dev)
 {
-	unsigned int head, in_num, out_num;
-	int len;
-	struct iovec iov[dev->vq->vring.num];
+	unsigned int in_num, out_num;
+	int head, len;
+	struct iovec iov[dev->vq->vqi.vring.num];
 
 	/* First we need a network buffer from the Guests's recv virtqueue. */
-	head = get_vq_desc(dev->vq, iov, &out_num, &in_num);
-	if (head == dev->vq->vring.num) {
+	head = get_vq_desc(&dev->vq->vqi, iov, &out_num, &in_num);
+	if (head < 0) {
 		/* Now, it's expected that if we try to send a packet too
 		 * early, the Guest won't be ready yet.  Wait until the device
 		 * status says it's ready. */
 		/* FIXME: Actually want DRIVER_ACTIVE here. */
 
 		/* Now tell it we want to know if new things appear. */
-		dev->vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
+		dev->vq->vqi.vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
 		wmb();
 
 		/* We'll turn this back on if input buffers are registered. */
@@ -1063,7 +1071,7 @@ static bool handle_tun_input(int fd, str
 
 	verbose("tun input packet len %i [%02x %02x] (%s)\n", len,
 		((u8 *)iov[1].iov_base)[0], ((u8 *)iov[1].iov_base)[1],
-		head != dev->vq->vring.num ? "sent" : "discarded");
+		head >= 0 ? "sent" : "discarded");
 
 	/* All good. */
 	return true;
@@ -1083,7 +1091,7 @@ static void net_enable_fd(int fd, struct
 {
 	net_recv_notify++;
 	/* We don't need to know again when Guest refills receive buffer. */
-	vq->vring.used->flags |= VRING_USED_F_NO_NOTIFY;
+	vq->vqi.vring.used->flags |= VRING_USED_F_NO_NOTIFY;
 	enable_fd(fd, vq, timeout);
 }
 
@@ -1102,9 +1110,9 @@ static void update_device_status(struct 
 
 		/* Zero out the virtqueues. */
 		for (vq = dev->vq; vq; vq = vq->next) {
-			memset(vq->vring.desc, 0,
+			memset(vq->vqi.vring.desc, 0,
 			       vring_size(vq->config.num, getpagesize()));
-			lg_last_avail(vq) = 0;
+			lg_last_avail(&vq->vqi) = 0;
 		}
 	} else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) {
 		warnx("Device %s configuration FAILED", dev->name);
@@ -1182,7 +1190,7 @@ static void handle_timeout(int fd)
 			if (!vq->blocked)
 				continue;
 
-			vq->vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
+			vq->vqi.vring.used->flags &= ~VRING_USED_F_NO_NOTIFY;
 			vq->blocked = false;
 			if (vq->handle_output)
 				vq->handle_output(fd, vq, true);
@@ -1286,7 +1294,8 @@ static void add_virtqueue(struct device 
 	/* Initialize the virtqueue */
 	vq->next = NULL;
 	vq->dev = dev;
-	vq->inflight = 0;
+	vq->vqi.inflight = 0;
+	vq->vqi.mem = &gmem;
 	vq->blocked = false;
 
 	/* Initialize the configuration. */
@@ -1295,7 +1304,7 @@ static void add_virtqueue(struct device 
 	vq->config.pfn = to_guest_phys(&gmem, p) / getpagesize();
 
 	/* Initialize the vring. */
-	vring_init(&vq->vring, num_descs, p, getpagesize());
+	vring_init(&vq->vqi.vring, num_descs, p, getpagesize());
 
 	/* Append virtqueue to this device's descriptor.  We use
 	 * device_config() to get the end of the device's current virtqueues;
@@ -1320,7 +1329,7 @@ static void add_virtqueue(struct device 
 	/* As an optimization, set the advisory "Don't Notify Me" flag if we
 	 * don't have a handler */
 	if (!handle_output)
-		vq->vring.used->flags = VRING_USED_F_NO_NOTIFY;
+		vq->vqi.vring.used->flags = VRING_USED_F_NO_NOTIFY;
 }
 
 /* The first half of the feature bitmask is for us to advertise features.  The
@@ -1651,8 +1660,8 @@ static void setup_tun_net(char *arg, boo
 
 	if (rings) {
 		/* Now we create the receive and xmit ringfds. */
-		ni->recvfd = map_vring(&dev->vq->vring);
-		ni->xmitfd = map_vring(&dev->vq->next->vring);
+		ni->recvfd = map_vring(&dev->vq->vqi.vring);
+		ni->xmitfd = map_vring(&dev->vq->next->vqi.vring);
 
 		/* Tell the tunnet to use them. */
 		if (ioctl(netfd, TUNSETRECVVRING, ni->recvfd) != 0)
@@ -1755,16 +1764,16 @@ static bool service_io(struct device *de
 static bool service_io(struct device *dev)
 {
 	struct vblk_info *vblk = dev->priv;
-	unsigned int head, out_num, in_num, wlen;
-	int ret;
+	unsigned int out_num, in_num, wlen;
+	int head, ret;
 	u8 *in;
 	struct virtio_blk_outhdr *out;
-	struct iovec iov[dev->vq->vring.num];
+	struct iovec iov[dev->vq->vqi.vring.num];
 	off64_t off;
 
 	/* See if there's a request waiting.  If not, nothing to do. */
-	head = get_vq_desc(dev->vq, iov, &out_num, &in_num);
-	if (head == dev->vq->vring.num)
+	head = get_vq_desc(&dev->vq->vqi, iov, &out_num, &in_num);
+	if (head < 0)
 		return false;
 
 	/* Every block request should contain at least one output buffer
@@ -1834,7 +1843,7 @@ static bool service_io(struct device *de
 
 	/* We can't trigger an IRQ, because we're not the Launcher.  It does
 	 * that when we tell it we're done. */
-	add_used(dev->vq, head, wlen);
+	add_used(&dev->vq->vqi, head, wlen);
 	return true;
 }
 
@@ -1963,14 +1972,14 @@ static bool handle_rng_input(int fd, str
 {
 	int len;
 	unsigned int head, in_num, out_num, totlen = 0;
-	struct iovec iov[dev->vq->vring.num];
+	struct iovec iov[dev->vq->vqi.vring.num];
 
 	/* First we need a buffer from the Guests's virtqueue. */
-	head = get_vq_desc(dev->vq, iov, &out_num, &in_num);
+	head = get_vq_desc(&dev->vq->vqi, iov, &out_num, &in_num);
 
 	/* If they're not ready for input, stop listening to this file
 	 * descriptor.  We'll start again once they add an input buffer. */
-	if (head == dev->vq->vring.num)
+	if (head < 0)
 		return false;
 
 	if (out_num)
