diff options
author | Balaji Rao <balajirrao@gmail.com> | 2007-12-28 03:56:24 -0500 |
---|---|---|
committer | Rusty Russell <rusty@rustcorp.com.au> | 2008-01-30 06:50:04 -0500 |
commit | ec04b13f67be3c90b38c625f4b8bdfea54c1ff60 (patch) | |
tree | 7819de21361fdd65487ef75ea9f2b774e4203f83 | |
parent | 5c55841d16dbf7c759fa6fb2ecc5e615b86d17db (diff) |
lguest: Reboot support
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>
-rw-r--r-- | Documentation/lguest/lguest.c | 32 | ||||
-rw-r--r-- | arch/x86/lguest/boot.c | 11 | ||||
-rw-r--r-- | drivers/lguest/core.c | 2 | ||||
-rw-r--r-- | drivers/lguest/hypercalls.c | 6 | ||||
-rw-r--r-- | include/asm-x86/lguest_hcall.h | 6 |
5 files changed, 50 insertions, 7 deletions
diff --git a/Documentation/lguest/lguest.c b/Documentation/lguest/lguest.c index 9b0e322118b5..86cac3e622ab 100644 --- a/Documentation/lguest/lguest.c +++ b/Documentation/lguest/lguest.c | |||
@@ -153,6 +153,9 @@ struct virtqueue | |||
153 | void (*handle_output)(int fd, struct virtqueue *me); | 153 | void (*handle_output)(int fd, struct virtqueue *me); |
154 | }; | 154 | }; |
155 | 155 | ||
156 | /* Remember the arguments to the program so we can "reboot" */ | ||
157 | static char **main_args; | ||
158 | |||
156 | /* Since guest is UP and we don't run at the same time, we don't need barriers. | 159 | /* Since guest is UP and we don't run at the same time, we don't need barriers. |
157 | * But I include them in the code in case others copy it. */ | 160 | * But I include them in the code in case others copy it. */ |
158 | #define wmb() | 161 | #define wmb() |
@@ -1489,7 +1492,9 @@ static void setup_block_file(const char *filename) | |||
1489 | 1492 | ||
1490 | /* Create stack for thread and run it */ | 1493 | /* Create stack for thread and run it */ |
1491 | stack = malloc(32768); | 1494 | stack = malloc(32768); |
1492 | if (clone(io_thread, stack + 32768, CLONE_VM, dev) == -1) | 1495 | /* SIGCHLD - We dont "wait" for our cloned thread, so prevent it from |
1496 | * becoming a zombie. */ | ||
1497 | if (clone(io_thread, stack + 32768, CLONE_VM | SIGCHLD, dev) == -1) | ||
1493 | err(1, "Creating clone"); | 1498 | err(1, "Creating clone"); |
1494 | 1499 | ||
1495 | /* We don't need to keep the I/O thread's end of the pipes open. */ | 1500 | /* 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 | verbose("device %u: virtblock %llu sectors\n", | 1504 | verbose("device %u: virtblock %llu sectors\n", |
1500 | devices.device_num, cap); | 1505 | devices.device_num, cap); |
1501 | } | 1506 | } |
1502 | /* That's the end of device setup. */ | 1507 | /* That's the end of device setup. :*/ |
1508 | |||
1509 | /* Reboot */ | ||
1510 | static void __attribute__((noreturn)) restart_guest(void) | ||
1511 | { | ||
1512 | unsigned int i; | ||
1513 | |||
1514 | /* Closing pipes causes the waker thread and io_threads to die, and | ||
1515 | * closing /dev/lguest cleans up the Guest. Since we don't track all | ||
1516 | * open fds, we simply close everything beyond stderr. */ | ||
1517 | for (i = 3; i < FD_SETSIZE; i++) | ||
1518 | close(i); | ||
1519 | execv(main_args[0], main_args); | ||
1520 | err(1, "Could not exec %s", main_args[0]); | ||
1521 | } | ||
1503 | 1522 | ||
1504 | /*L:220 Finally we reach the core of the Launcher, which runs the Guest, serves | 1523 | /*L:220 Finally we reach the core of the Launcher, which runs the Guest, serves |
1505 | * its input and output, and finally, lays it to rest. */ | 1524 | * its input and output, and finally, lays it to rest. */ |
@@ -1523,6 +1542,9 @@ static void __attribute__((noreturn)) run_guest(int lguest_fd) | |||
1523 | char reason[1024] = { 0 }; | 1542 | char reason[1024] = { 0 }; |
1524 | read(lguest_fd, reason, sizeof(reason)-1); | 1543 | read(lguest_fd, reason, sizeof(reason)-1); |
1525 | errx(1, "%s", reason); | 1544 | errx(1, "%s", reason); |
1545 | /* ERESTART means that we need to reboot the guest */ | ||
1546 | } else if (errno == ERESTART) { | ||
1547 | restart_guest(); | ||
1526 | /* EAGAIN means the Waker wanted us to look at some input. | 1548 | /* EAGAIN means the Waker wanted us to look at some input. |
1527 | * Anything else means a bug or incompatible change. */ | 1549 | * Anything else means a bug or incompatible change. */ |
1528 | } else if (errno != EAGAIN) | 1550 | } else if (errno != EAGAIN) |
@@ -1571,6 +1593,12 @@ int main(int argc, char *argv[]) | |||
1571 | /* If they specify an initrd file to load. */ | 1593 | /* If they specify an initrd file to load. */ |
1572 | const char *initrd_name = NULL; | 1594 | const char *initrd_name = NULL; |
1573 | 1595 | ||
1596 | /* Save the args: we "reboot" by execing ourselves again. */ | ||
1597 | main_args = argv; | ||
1598 | /* We don't "wait" for the children, so prevent them from becoming | ||
1599 | * zombies. */ | ||
1600 | signal(SIGCHLD, SIG_IGN); | ||
1601 | |||
1574 | /* First we initialize the device list. Since console and network | 1602 | /* First we initialize the device list. Since console and network |
1575 | * device receive input from a file descriptor, we keep an fdset | 1603 | * device receive input from a file descriptor, we keep an fdset |
1576 | * (infds) and the maximum fd number (max_infd) with the head of the | 1604 | * (infds) and the maximum fd number (max_infd) with the head of the |
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c index 92c56117eae5..d6b18e2e5431 100644 --- a/arch/x86/lguest/boot.c +++ b/arch/x86/lguest/boot.c | |||
@@ -67,6 +67,7 @@ | |||
67 | #include <asm/mce.h> | 67 | #include <asm/mce.h> |
68 | #include <asm/io.h> | 68 | #include <asm/io.h> |
69 | #include <asm/i387.h> | 69 | #include <asm/i387.h> |
70 | #include <asm/reboot.h> /* for struct machine_ops */ | ||
70 | 71 | ||
71 | /*G:010 Welcome to the Guest! | 72 | /*G:010 Welcome to the Guest! |
72 | * | 73 | * |
@@ -812,7 +813,7 @@ static void lguest_safe_halt(void) | |||
812 | * rather than virtual addresses, so we use __pa() here. */ | 813 | * rather than virtual addresses, so we use __pa() here. */ |
813 | static void lguest_power_off(void) | 814 | static void lguest_power_off(void) |
814 | { | 815 | { |
815 | hcall(LHCALL_CRASH, __pa("Power down"), 0, 0); | 816 | hcall(LHCALL_SHUTDOWN, __pa("Power down"), LGUEST_SHUTDOWN_POWEROFF, 0); |
816 | } | 817 | } |
817 | 818 | ||
818 | /* | 819 | /* |
@@ -822,7 +823,7 @@ static void lguest_power_off(void) | |||
822 | */ | 823 | */ |
823 | static int lguest_panic(struct notifier_block *nb, unsigned long l, void *p) | 824 | static int lguest_panic(struct notifier_block *nb, unsigned long l, void *p) |
824 | { | 825 | { |
825 | hcall(LHCALL_CRASH, __pa(p), 0, 0); | 826 | hcall(LHCALL_SHUTDOWN, __pa(p), LGUEST_SHUTDOWN_POWEROFF, 0); |
826 | /* The hcall won't return, but to keep gcc happy, we're "done". */ | 827 | /* The hcall won't return, but to keep gcc happy, we're "done". */ |
827 | return NOTIFY_DONE; | 828 | return NOTIFY_DONE; |
828 | } | 829 | } |
@@ -926,6 +927,11 @@ static unsigned lguest_patch(u8 type, u16 clobber, void *ibuf, | |||
926 | return insn_len; | 927 | return insn_len; |
927 | } | 928 | } |
928 | 929 | ||
930 | static void lguest_restart(char *reason) | ||
931 | { | ||
932 | hcall(LHCALL_SHUTDOWN, __pa(reason), LGUEST_SHUTDOWN_RESTART, 0); | ||
933 | } | ||
934 | |||
929 | /*G:030 Once we get to lguest_init(), we know we're a Guest. The pv_ops | 935 | /*G:030 Once we get to lguest_init(), we know we're a Guest. The pv_ops |
930 | * structures in the kernel provide points for (almost) every routine we have | 936 | * structures in the kernel provide points for (almost) every routine we have |
931 | * to override to avoid privileged instructions. */ | 937 | * to override to avoid privileged instructions. */ |
@@ -1059,6 +1065,7 @@ __init void lguest_init(void) | |||
1059 | * the Guest routine to power off. */ | 1065 | * the Guest routine to power off. */ |
1060 | pm_power_off = lguest_power_off; | 1066 | pm_power_off = lguest_power_off; |
1061 | 1067 | ||
1068 | machine_ops.restart = lguest_restart; | ||
1062 | /* Now we're set up, call start_kernel() in init/main.c and we proceed | 1069 | /* Now we're set up, call start_kernel() in init/main.c and we proceed |
1063 | * to boot as normal. It never returns. */ | 1070 | * to boot as normal. It never returns. */ |
1064 | start_kernel(); | 1071 | start_kernel(); |
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c index f10abc8d7635..c1069bceba11 100644 --- a/drivers/lguest/core.c +++ b/drivers/lguest/core.c | |||
@@ -235,6 +235,8 @@ int run_guest(struct lguest *lg, unsigned long __user *user) | |||
235 | lguest_arch_handle_trap(lg); | 235 | lguest_arch_handle_trap(lg); |
236 | } | 236 | } |
237 | 237 | ||
238 | if (lg->dead == ERR_PTR(-ERESTART)) | ||
239 | return -ERESTART; | ||
238 | /* The Guest is dead => "No such file or directory" */ | 240 | /* The Guest is dead => "No such file or directory" */ |
239 | return -ENOENT; | 241 | return -ENOENT; |
240 | } | 242 | } |
diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c index b478affe8f91..05fad6fa8049 100644 --- a/drivers/lguest/hypercalls.c +++ b/drivers/lguest/hypercalls.c | |||
@@ -41,8 +41,8 @@ static void do_hcall(struct lguest *lg, struct hcall_args *args) | |||
41 | * do that. */ | 41 | * do that. */ |
42 | kill_guest(lg, "already have lguest_data"); | 42 | kill_guest(lg, "already have lguest_data"); |
43 | break; | 43 | break; |
44 | case LHCALL_CRASH: { | 44 | case LHCALL_SHUTDOWN: { |
45 | /* Crash is such a trivial hypercall that we do it in four | 45 | /* Shutdown is such a trivial hypercall that we do it in four |
46 | * lines right here. */ | 46 | * lines right here. */ |
47 | char msg[128]; | 47 | char msg[128]; |
48 | /* If the lgread fails, it will call kill_guest() itself; the | 48 | /* 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 | __lgread(lg, msg, args->arg1, sizeof(msg)); | 50 | __lgread(lg, msg, args->arg1, sizeof(msg)); |
51 | msg[sizeof(msg)-1] = '\0'; | 51 | msg[sizeof(msg)-1] = '\0'; |
52 | kill_guest(lg, "CRASH: %s", msg); | 52 | kill_guest(lg, "CRASH: %s", msg); |
53 | if (args->arg2 == LGUEST_SHUTDOWN_RESTART) | ||
54 | lg->dead = ERR_PTR(-ERESTART); | ||
53 | break; | 55 | break; |
54 | } | 56 | } |
55 | case LHCALL_FLUSH_TLB: | 57 | case LHCALL_FLUSH_TLB: |
diff --git a/include/asm-x86/lguest_hcall.h b/include/asm-x86/lguest_hcall.h index 2091779e91fb..758b9a5d4539 100644 --- a/include/asm-x86/lguest_hcall.h +++ b/include/asm-x86/lguest_hcall.h | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | #define LHCALL_FLUSH_ASYNC 0 | 5 | #define LHCALL_FLUSH_ASYNC 0 |
6 | #define LHCALL_LGUEST_INIT 1 | 6 | #define LHCALL_LGUEST_INIT 1 |
7 | #define LHCALL_CRASH 2 | 7 | #define LHCALL_SHUTDOWN 2 |
8 | #define LHCALL_LOAD_GDT 3 | 8 | #define LHCALL_LOAD_GDT 3 |
9 | #define LHCALL_NEW_PGTABLE 4 | 9 | #define LHCALL_NEW_PGTABLE 4 |
10 | #define LHCALL_FLUSH_TLB 5 | 10 | #define LHCALL_FLUSH_TLB 5 |
@@ -20,6 +20,10 @@ | |||
20 | 20 | ||
21 | #define LGUEST_TRAP_ENTRY 0x1F | 21 | #define LGUEST_TRAP_ENTRY 0x1F |
22 | 22 | ||
23 | /* Argument number 3 to LHCALL_LGUEST_SHUTDOWN */ | ||
24 | #define LGUEST_SHUTDOWN_POWEROFF 1 | ||
25 | #define LGUEST_SHUTDOWN_RESTART 2 | ||
26 | |||
23 | #ifndef __ASSEMBLY__ | 27 | #ifndef __ASSEMBLY__ |
24 | #include <asm/hw_irq.h> | 28 | #include <asm/hw_irq.h> |
25 | 29 | ||