aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRusty Russell <rusty@rustcorp.com.au>2007-10-21 21:24:23 -0400
committerRusty Russell <rusty@rustcorp.com.au>2007-10-23 01:49:56 -0400
commit56ae43dfe233323683248a5c553bad7160db2fa5 (patch)
tree27260aff3586bd0373ee6cf4a468dd5962209e88
parent17cbca2ba3de990258943d9e5a1788430ca3ad0d (diff)
Example launcher handle guests not being ready for input
We currently discard console and network input when the guest has no input buffers. This patch changes that, so that we simply stop listening to that fd until the guest refills its input buffers. This is particularly important because hvc_console without interrupts does backoff polling and so often lose characters if we discard. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
-rw-r--r--Documentation/lguest/lguest.c107
1 files changed, 57 insertions, 50 deletions
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c
index 7418f852e40c..cbf4becd2667 100644
--- a/Documentation/lguest/lguest.c
+++ b/Documentation/lguest/lguest.c
@@ -598,15 +598,17 @@ static void wake_parent(int pipefd, int lguest_fd)
598 select(devices.max_infd+1, &rfds, NULL, NULL, NULL); 598 select(devices.max_infd+1, &rfds, NULL, NULL, NULL);
599 /* Is it a message from the Launcher? */ 599 /* Is it a message from the Launcher? */
600 if (FD_ISSET(pipefd, &rfds)) { 600 if (FD_ISSET(pipefd, &rfds)) {
601 int ignorefd; 601 int fd;
602 /* If read() returns 0, it means the Launcher has 602 /* If read() returns 0, it means the Launcher has
603 * exited. We silently follow. */ 603 * exited. We silently follow. */
604 if (read(pipefd, &ignorefd, sizeof(ignorefd)) == 0) 604 if (read(pipefd, &fd, sizeof(fd)) == 0)
605 exit(0); 605 exit(0);
606 /* Otherwise it's telling us there's a problem with one 606 /* Otherwise it's telling us to change what file
607 * of the devices, and we should ignore that file 607 * descriptors we're to listen to. */
608 * descriptor from now on. */ 608 if (fd >= 0)
609 FD_CLR(ignorefd, &devices.infds); 609 FD_SET(fd, &devices.infds);
610 else
611 FD_CLR(-fd - 1, &devices.infds);
610 } else /* Send LHREQ_BREAK command. */ 612 } else /* Send LHREQ_BREAK command. */
611 write(lguest_fd, args, sizeof(args)); 613 write(lguest_fd, args, sizeof(args));
612 } 614 }
@@ -658,18 +660,6 @@ static void *_check_pointer(unsigned long addr, unsigned int size,
658/* A macro which transparently hands the line number to the real function. */ 660/* A macro which transparently hands the line number to the real function. */
659#define check_pointer(addr,size) _check_pointer(addr, size, __LINE__) 661#define check_pointer(addr,size) _check_pointer(addr, size, __LINE__)
660 662
661/* This simply sets up an iovec array where we can put data to be discarded.
662 * This happens when the Guest doesn't want or can't handle the input: we have
663 * to get rid of it somewhere, and if we bury it in the ceiling space it will
664 * start to smell after a week. */
665static void discard_iovec(struct iovec *iov, unsigned int *num)
666{
667 static char discard_buf[1024];
668 *num = 1;
669 iov->iov_base = discard_buf;
670 iov->iov_len = sizeof(discard_buf);
671}
672
673/* This function returns the next descriptor in the chain, or vq->vring.num. */ 663/* This function returns the next descriptor in the chain, or vq->vring.num. */
674static unsigned next_desc(struct virtqueue *vq, unsigned int i) 664static unsigned next_desc(struct virtqueue *vq, unsigned int i)
675{ 665{
@@ -812,12 +802,13 @@ static bool handle_console_input(int fd, struct device *dev)
812 802
813 /* First we need a console buffer from the Guests's input virtqueue. */ 803 /* First we need a console buffer from the Guests's input virtqueue. */
814 head = get_vq_desc(dev->vq, iov, &out_num, &in_num); 804 head = get_vq_desc(dev->vq, iov, &out_num, &in_num);
815 if (head == dev->vq->vring.num) { 805
816 /* If they're not ready for input, we warn and set up to 806 /* If they're not ready for input, stop listening to this file
817 * discard. */ 807 * descriptor. We'll start again once they add an input buffer. */
818 warnx("console: no dma buffer!"); 808 if (head == dev->vq->vring.num)
819 discard_iovec(iov, &in_num); 809 return false;
820 } else if (out_num) 810
811 if (out_num)
821 errx(1, "Output buffers in console in queue?"); 812 errx(1, "Output buffers in console in queue?");
822 813
823 /* This is why we convert to iovecs: the readv() call uses them, and so 814 /* This is why we convert to iovecs: the readv() call uses them, and so
@@ -827,15 +818,16 @@ static bool handle_console_input(int fd, struct device *dev)
827 /* This implies that the console is closed, is /dev/null, or 818 /* This implies that the console is closed, is /dev/null, or
828 * something went terribly wrong. */ 819 * something went terribly wrong. */
829 warnx("Failed to get console input, ignoring console."); 820 warnx("Failed to get console input, ignoring console.");
830 /* Put the input terminal back and return failure (meaning, 821 /* Put the input terminal back. */
831 * don't call us again). */
832 restore_term(); 822 restore_term();
823 /* Remove callback from input vq, so it doesn't restart us. */
824 dev->vq->handle_output = NULL;
825 /* Stop listening to this fd: don't call us again. */
833 return false; 826 return false;
834 } 827 }
835 828
836 /* If we actually read the data into the Guest, tell them about it. */ 829 /* Tell the Guest about the new input. */
837 if (head != dev->vq->vring.num) 830 add_used_and_trigger(fd, dev->vq, head, len);
838 add_used_and_trigger(fd, dev->vq, head, len);
839 831
840 /* Three ^C within one second? Exit. 832 /* Three ^C within one second? Exit.
841 * 833 *
@@ -924,7 +916,8 @@ static bool handle_tun_input(int fd, struct device *dev)
924 /* FIXME: Actually want DRIVER_ACTIVE here. */ 916 /* FIXME: Actually want DRIVER_ACTIVE here. */
925 if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) 917 if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK)
926 warn("network: no dma buffer!"); 918 warn("network: no dma buffer!");
927 discard_iovec(iov, &in_num); 919 /* We'll turn this back on if input buffers are registered. */
920 return false;
928 } else if (out_num) 921 } else if (out_num)
929 errx(1, "Output buffers in network recv queue?"); 922 errx(1, "Output buffers in network recv queue?");
930 923
@@ -938,9 +931,8 @@ static bool handle_tun_input(int fd, struct device *dev)
938 if (len <= 0) 931 if (len <= 0)
939 err(1, "reading network"); 932 err(1, "reading network");
940 933
941 /* If we actually read the data into the Guest, tell them about it. */ 934 /* Tell the Guest about the new packet. */
942 if (head != dev->vq->vring.num) 935 add_used_and_trigger(fd, dev->vq, head, sizeof(*hdr) + len);
943 add_used_and_trigger(fd, dev->vq, head, sizeof(*hdr) + len);
944 936
945 verbose("tun input packet len %i [%02x %02x] (%s)\n", len, 937 verbose("tun input packet len %i [%02x %02x] (%s)\n", len,
946 ((u8 *)iov[1].iov_base)[0], ((u8 *)iov[1].iov_base)[1], 938 ((u8 *)iov[1].iov_base)[0], ((u8 *)iov[1].iov_base)[1],
@@ -950,6 +942,15 @@ static bool handle_tun_input(int fd, struct device *dev)
950 return true; 942 return true;
951} 943}
952 944
945/* This callback ensures we try again, in case we stopped console or net
946 * delivery because Guest didn't have any buffers. */
947static void enable_fd(int fd, struct virtqueue *vq)
948{
949 add_device_fd(vq->dev->fd);
950 /* Tell waker to listen to it again */
951 write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd));
952}
953
953/* This is the generic routine we call when the Guest uses LHCALL_NOTIFY. */ 954/* This is the generic routine we call when the Guest uses LHCALL_NOTIFY. */
954static void handle_output(int fd, unsigned long addr) 955static void handle_output(int fd, unsigned long addr)
955{ 956{
@@ -996,17 +997,22 @@ static void handle_input(int fd)
996 * file descriptors and a method of handling them. */ 997 * file descriptors and a method of handling them. */
997 for (i = devices.dev; i; i = i->next) { 998 for (i = devices.dev; i; i = i->next) {
998 if (i->handle_input && FD_ISSET(i->fd, &fds)) { 999 if (i->handle_input && FD_ISSET(i->fd, &fds)) {
1000 int dev_fd;
1001 if (i->handle_input(fd, i))
1002 continue;
1003
999 /* If handle_input() returns false, it means we 1004 /* If handle_input() returns false, it means we
1000 * should no longer service it. 1005 * should no longer service it. Networking and
1001 * handle_console_input() does this. */ 1006 * console do this when there's no input
1002 if (!i->handle_input(fd, i)) { 1007 * buffers to deliver into. Console also uses
1003 /* Clear it from the set of input file 1008 * it when it discovers that stdin is
1004 * descriptors kept at the head of the 1009 * closed. */
1005 * device list. */ 1010 FD_CLR(i->fd, &devices.infds);
1006 FD_CLR(i->fd, &devices.infds); 1011 /* Tell waker to ignore it too, by sending a
1007 /* Tell waker to ignore it too... */ 1012 * negative fd number (-1, since 0 is a valid
1008 write(waker_fd, &i->fd, sizeof(i->fd)); 1013 * FD number). */
1009 } 1014 dev_fd = -i->fd - 1;
1015 write(waker_fd, &dev_fd, sizeof(dev_fd));
1010 } 1016 }
1011 } 1017 }
1012 } 1018 }
@@ -1154,11 +1160,11 @@ static void setup_console(void)
1154 dev->priv = malloc(sizeof(struct console_abort)); 1160 dev->priv = malloc(sizeof(struct console_abort));
1155 ((struct console_abort *)dev->priv)->count = 0; 1161 ((struct console_abort *)dev->priv)->count = 0;
1156 1162
1157 /* The console needs two virtqueues: the input then the output. We 1163 /* The console needs two virtqueues: the input then the output. When
1158 * don't care when they refill the input queue, since we don't hold 1164 * they put something the input queue, we make sure we're listening to
1159 * data waiting for them. That's why the input queue's callback is 1165 * stdin. When they put something in the output queue, we write it to
1160 * NULL. */ 1166 * stdout. */
1161 add_virtqueue(dev, VIRTQUEUE_NUM, NULL); 1167 add_virtqueue(dev, VIRTQUEUE_NUM, enable_fd);
1162 add_virtqueue(dev, VIRTQUEUE_NUM, handle_console_output); 1168 add_virtqueue(dev, VIRTQUEUE_NUM, handle_console_output);
1163 1169
1164 verbose("device %u: console\n", devices.device_num++); 1170 verbose("device %u: console\n", devices.device_num++);
@@ -1270,8 +1276,9 @@ static void setup_tun_net(const char *arg)
1270 /* First we create a new network device. */ 1276 /* First we create a new network device. */
1271 dev = new_device("net", VIRTIO_ID_NET, netfd, handle_tun_input); 1277 dev = new_device("net", VIRTIO_ID_NET, netfd, handle_tun_input);
1272 1278
1273 /* Network devices need a receive and a send queue. */ 1279 /* Network devices need a receive and a send queue, just like
1274 add_virtqueue(dev, VIRTQUEUE_NUM, NULL); 1280 * console. */
1281 add_virtqueue(dev, VIRTQUEUE_NUM, enable_fd);
1275 add_virtqueue(dev, VIRTQUEUE_NUM, handle_net_output); 1282 add_virtqueue(dev, VIRTQUEUE_NUM, handle_net_output);
1276 1283
1277 /* We need a socket to perform the magic network ioctls to bring up the 1284 /* We need a socket to perform the magic network ioctls to bring up the