]> err.no Git - linux-2.6/commitdiff
lguest: Reboot support
authorBalaji Rao <balajirrao@gmail.com>
Fri, 28 Dec 2007 08:56:24 +0000 (14:26 +0530)
committerRusty Russell <rusty@rustcorp.com.au>
Wed, 30 Jan 2008 11:50:04 +0000 (22:50 +1100)
Reboot Implemented

(Prevent fd leak, fix style and fix documentation --RR)

Signed-off-by: Balaji Rao <balajirrao@gmail.com>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
Documentation/lguest/lguest.c
arch/x86/lguest/boot.c
drivers/lguest/core.c
drivers/lguest/hypercalls.c
include/asm-x86/lguest_hcall.h

index 9b0e322118b5402eb83868c70266f8afdf420ed1..86cac3e622ab9a584f111da0820d205a46a8e0e4 100644 (file)
@@ -153,6 +153,9 @@ struct virtqueue
        void (*handle_output)(int fd, struct virtqueue *me);
 };
 
+/* Remember the arguments to the program so we can "reboot" */
+static char **main_args;
+
 /* Since guest is UP and we don't run at the same time, we don't need barriers.
  * But I include them in the code in case others copy it. */
 #define wmb()
@@ -1489,7 +1492,9 @@ static void setup_block_file(const char *filename)
 
        /* Create stack for thread and run it */
        stack = malloc(32768);
-       if (clone(io_thread, stack + 32768, CLONE_VM, dev) == -1)
+       /* SIGCHLD - We dont "wait" for our cloned thread, so prevent it from
+        * becoming a zombie. */
+       if (clone(io_thread, stack + 32768,  CLONE_VM | SIGCHLD, dev) == -1)
                err(1, "Creating clone");
 
        /* We don't need to keep the I/O thread's end of the pipes open. */
@@ -1499,7 +1504,21 @@ static void setup_block_file(const char *filename)
        verbose("device %u: virtblock %llu sectors\n",
                devices.device_num, cap);
 }
-/* That's the end of device setup. */
+/* That's the end of device setup. :*/
+
+/* Reboot */
+static void __attribute__((noreturn)) restart_guest(void)
+{
+       unsigned int i;
+
+       /* Closing pipes causes the waker thread and io_threads to die, and
+        * closing /dev/lguest cleans up the Guest.  Since we don't track all
+        * open fds, we simply close everything beyond stderr. */
+       for (i = 3; i < FD_SETSIZE; i++)
+               close(i);
+       execv(main_args[0], main_args);
+       err(1, "Could not exec %s", main_args[0]);
+}
 
 /*L:220 Finally we reach the core of the Launcher, which runs the Guest, serves
  * its input and output, and finally, lays it to rest. */
@@ -1523,6 +1542,9 @@ static void __attribute__((noreturn)) run_guest(int lguest_fd)
                        char reason[1024] = { 0 };
                        read(lguest_fd, reason, sizeof(reason)-1);
                        errx(1, "%s", reason);
+               /* ERESTART means that we need to reboot the guest */
+               } else if (errno == ERESTART) {
+                       restart_guest();
                /* EAGAIN means the Waker wanted us to look at some input.
                 * Anything else means a bug or incompatible change. */
                } else if (errno != EAGAIN)
@@ -1571,6 +1593,12 @@ int main(int argc, char *argv[])
        /* If they specify an initrd file to load. */
        const char *initrd_name = NULL;
 
+       /* Save the args: we "reboot" by execing ourselves again. */
+       main_args = argv;
+       /* We don't "wait" for the children, so prevent them from becoming
+        * zombies. */
+       signal(SIGCHLD, SIG_IGN);
+
        /* First we initialize the device list.  Since console and network
         * device receive input from a file descriptor, we keep an fdset
         * (infds) and the maximum fd number (max_infd) with the head of the
index 92c56117eae5ed2af3cbdc37c6086d7a7dd25120..d6b18e2e54315d27cb851a1f405b098dcc8d1b75 100644 (file)
@@ -67,6 +67,7 @@
 #include <asm/mce.h>
 #include <asm/io.h>
 #include <asm/i387.h>
+#include <asm/reboot.h>                /* for struct machine_ops */
 
 /*G:010 Welcome to the Guest!
  *
@@ -812,7 +813,7 @@ static void lguest_safe_halt(void)
  * rather than virtual addresses, so we use __pa() here. */
 static void lguest_power_off(void)
 {
-       hcall(LHCALL_CRASH, __pa("Power down"), 0, 0);
+       hcall(LHCALL_SHUTDOWN, __pa("Power down"), LGUEST_SHUTDOWN_POWEROFF, 0);
 }
 
 /*
@@ -822,7 +823,7 @@ static void lguest_power_off(void)
  */
 static int lguest_panic(struct notifier_block *nb, unsigned long l, void *p)
 {
-       hcall(LHCALL_CRASH, __pa(p), 0, 0);
+       hcall(LHCALL_SHUTDOWN, __pa(p), LGUEST_SHUTDOWN_POWEROFF, 0);
        /* The hcall won't return, but to keep gcc happy, we're "done". */
        return NOTIFY_DONE;
 }
@@ -926,6 +927,11 @@ static unsigned lguest_patch(u8 type, u16 clobber, void *ibuf,
        return insn_len;
 }
 
+static void lguest_restart(char *reason)
+{
+       hcall(LHCALL_SHUTDOWN, __pa(reason), LGUEST_SHUTDOWN_RESTART, 0);
+}
+
 /*G:030 Once we get to lguest_init(), we know we're a Guest.  The pv_ops
  * structures in the kernel provide points for (almost) every routine we have
  * to override to avoid privileged instructions. */
@@ -1059,6 +1065,7 @@ __init void lguest_init(void)
         * the Guest routine to power off. */
        pm_power_off = lguest_power_off;
 
+       machine_ops.restart = lguest_restart;
        /* Now we're set up, call start_kernel() in init/main.c and we proceed
         * to boot as normal.  It never returns. */
        start_kernel();
index f10abc8d7635eb24c68e5d424fb2edf7943a91b5..c1069bceba11dde196f02e75f691e3ed873565ba 100644 (file)
@@ -235,6 +235,8 @@ int run_guest(struct lguest *lg, unsigned long __user *user)
                lguest_arch_handle_trap(lg);
        }
 
+       if (lg->dead == ERR_PTR(-ERESTART))
+               return -ERESTART;
        /* The Guest is dead => "No such file or directory" */
        return -ENOENT;
 }
index b478affe8f91331733a288fa039fce50012e8409..05fad6fa804923eed6688e381adbe9c12c012f20 100644 (file)
@@ -41,8 +41,8 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args)
                 * do that. */
                kill_guest(lg, "already have lguest_data");
                break;
-       case LHCALL_CRASH: {
-               /* Crash is such a trivial hypercall that we do it in four
+       case LHCALL_SHUTDOWN: {
+               /* Shutdown is such a trivial hypercall that we do it in four
                 * lines right here. */
                char msg[128];
                /* If the lgread fails, it will call kill_guest() itself; the
@@ -50,6 +50,8 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args)
                __lgread(lg, msg, args->arg1, sizeof(msg));
                msg[sizeof(msg)-1] = '\0';
                kill_guest(lg, "CRASH: %s", msg);
+               if (args->arg2 == LGUEST_SHUTDOWN_RESTART)
+                       lg->dead = ERR_PTR(-ERESTART);
                break;
        }
        case LHCALL_FLUSH_TLB:
index 2091779e91fbe4f06b659235dc9e8abe2c09922c..758b9a5d4539e583dd29efced39701e7ae1b64d0 100644 (file)
@@ -4,7 +4,7 @@
 
 #define LHCALL_FLUSH_ASYNC     0
 #define LHCALL_LGUEST_INIT     1
-#define LHCALL_CRASH           2
+#define LHCALL_SHUTDOWN                2
 #define LHCALL_LOAD_GDT                3
 #define LHCALL_NEW_PGTABLE     4
 #define LHCALL_FLUSH_TLB       5
 
 #define LGUEST_TRAP_ENTRY 0x1F
 
+/* Argument number 3 to LHCALL_LGUEST_SHUTDOWN */
+#define LGUEST_SHUTDOWN_POWEROFF       1
+#define LGUEST_SHUTDOWN_RESTART                2
+
 #ifndef __ASSEMBLY__
 #include <asm/hw_irq.h>