Commit ec04b13f authored by Balaji Rao's avatar Balaji Rao Committed by Rusty Russell

lguest: Reboot support

Reboot Implemented

(Prevent fd leak, fix style and fix documentation --RR)
Signed-off-by: default avatarBalaji Rao <balajirrao@gmail.com>
Signed-off-by: default avatarRusty Russell <rusty@rustcorp.com.au>
parent 5c55841d
...@@ -153,6 +153,9 @@ struct virtqueue ...@@ -153,6 +153,9 @@ struct virtqueue
void (*handle_output)(int fd, struct virtqueue *me); 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. /* 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. */ * But I include them in the code in case others copy it. */
#define wmb() #define wmb()
...@@ -1489,7 +1492,9 @@ static void setup_block_file(const char *filename) ...@@ -1489,7 +1492,9 @@ static void setup_block_file(const char *filename)
/* Create stack for thread and run it */ /* Create stack for thread and run it */
stack = malloc(32768); 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"); err(1, "Creating clone");
/* We don't need to keep the I/O thread's end of the pipes open. */ /* 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) ...@@ -1499,7 +1504,21 @@ static void setup_block_file(const char *filename)
verbose("device %u: virtblock %llu sectors\n", verbose("device %u: virtblock %llu sectors\n",
devices.device_num, cap); 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 /*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. */ * its input and output, and finally, lays it to rest. */
...@@ -1523,6 +1542,9 @@ static void __attribute__((noreturn)) run_guest(int lguest_fd) ...@@ -1523,6 +1542,9 @@ static void __attribute__((noreturn)) run_guest(int lguest_fd)
char reason[1024] = { 0 }; char reason[1024] = { 0 };
read(lguest_fd, reason, sizeof(reason)-1); read(lguest_fd, reason, sizeof(reason)-1);
errx(1, "%s", reason); 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. /* EAGAIN means the Waker wanted us to look at some input.
* Anything else means a bug or incompatible change. */ * Anything else means a bug or incompatible change. */
} else if (errno != EAGAIN) } else if (errno != EAGAIN)
...@@ -1571,6 +1593,12 @@ int main(int argc, char *argv[]) ...@@ -1571,6 +1593,12 @@ int main(int argc, char *argv[])
/* If they specify an initrd file to load. */ /* If they specify an initrd file to load. */
const char *initrd_name = NULL; 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 /* First we initialize the device list. Since console and network
* device receive input from a file descriptor, we keep an fdset * device receive input from a file descriptor, we keep an fdset
* (infds) and the maximum fd number (max_infd) with the head of the * (infds) and the maximum fd number (max_infd) with the head of the
......
...@@ -67,6 +67,7 @@ ...@@ -67,6 +67,7 @@
#include <asm/mce.h> #include <asm/mce.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/i387.h> #include <asm/i387.h>
#include <asm/reboot.h> /* for struct machine_ops */
/*G:010 Welcome to the Guest! /*G:010 Welcome to the Guest!
* *
...@@ -812,7 +813,7 @@ static void lguest_safe_halt(void) ...@@ -812,7 +813,7 @@ static void lguest_safe_halt(void)
* rather than virtual addresses, so we use __pa() here. */ * rather than virtual addresses, so we use __pa() here. */
static void lguest_power_off(void) 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) ...@@ -822,7 +823,7 @@ static void lguest_power_off(void)
*/ */
static int lguest_panic(struct notifier_block *nb, unsigned long l, void *p) 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". */ /* The hcall won't return, but to keep gcc happy, we're "done". */
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -926,6 +927,11 @@ static unsigned lguest_patch(u8 type, u16 clobber, void *ibuf, ...@@ -926,6 +927,11 @@ static unsigned lguest_patch(u8 type, u16 clobber, void *ibuf,
return insn_len; 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 /*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 * structures in the kernel provide points for (almost) every routine we have
* to override to avoid privileged instructions. */ * to override to avoid privileged instructions. */
...@@ -1059,6 +1065,7 @@ __init void lguest_init(void) ...@@ -1059,6 +1065,7 @@ __init void lguest_init(void)
* the Guest routine to power off. */ * the Guest routine to power off. */
pm_power_off = lguest_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 /* Now we're set up, call start_kernel() in init/main.c and we proceed
* to boot as normal. It never returns. */ * to boot as normal. It never returns. */
start_kernel(); start_kernel();
......
...@@ -235,6 +235,8 @@ int run_guest(struct lguest *lg, unsigned long __user *user) ...@@ -235,6 +235,8 @@ int run_guest(struct lguest *lg, unsigned long __user *user)
lguest_arch_handle_trap(lg); lguest_arch_handle_trap(lg);
} }
if (lg->dead == ERR_PTR(-ERESTART))
return -ERESTART;
/* The Guest is dead => "No such file or directory" */ /* The Guest is dead => "No such file or directory" */
return -ENOENT; return -ENOENT;
} }
......
...@@ -41,8 +41,8 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args) ...@@ -41,8 +41,8 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args)
* do that. */ * do that. */
kill_guest(lg, "already have lguest_data"); kill_guest(lg, "already have lguest_data");
break; break;
case LHCALL_CRASH: { case LHCALL_SHUTDOWN: {
/* Crash is such a trivial hypercall that we do it in four /* Shutdown is such a trivial hypercall that we do it in four
* lines right here. */ * lines right here. */
char msg[128]; char msg[128];
/* If the lgread fails, it will call kill_guest() itself; the /* 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) ...@@ -50,6 +50,8 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args)
__lgread(lg, msg, args->arg1, sizeof(msg)); __lgread(lg, msg, args->arg1, sizeof(msg));
msg[sizeof(msg)-1] = '\0'; msg[sizeof(msg)-1] = '\0';
kill_guest(lg, "CRASH: %s", msg); kill_guest(lg, "CRASH: %s", msg);
if (args->arg2 == LGUEST_SHUTDOWN_RESTART)
lg->dead = ERR_PTR(-ERESTART);
break; break;
} }
case LHCALL_FLUSH_TLB: case LHCALL_FLUSH_TLB:
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
#define LHCALL_FLUSH_ASYNC 0 #define LHCALL_FLUSH_ASYNC 0
#define LHCALL_LGUEST_INIT 1 #define LHCALL_LGUEST_INIT 1
#define LHCALL_CRASH 2 #define LHCALL_SHUTDOWN 2
#define LHCALL_LOAD_GDT 3 #define LHCALL_LOAD_GDT 3
#define LHCALL_NEW_PGTABLE 4 #define LHCALL_NEW_PGTABLE 4
#define LHCALL_FLUSH_TLB 5 #define LHCALL_FLUSH_TLB 5
...@@ -20,6 +20,10 @@ ...@@ -20,6 +20,10 @@
#define LGUEST_TRAP_ENTRY 0x1F #define LGUEST_TRAP_ENTRY 0x1F
/* Argument number 3 to LHCALL_LGUEST_SHUTDOWN */
#define LGUEST_SHUTDOWN_POWEROFF 1
#define LGUEST_SHUTDOWN_RESTART 2
#ifndef __ASSEMBLY__ #ifndef __ASSEMBLY__
#include <asm/hw_irq.h> #include <asm/hw_irq.h>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment