diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/kexec.c | 57 | ||||
-rw-r--r-- | kernel/sys.c | 31 |
2 files changed, 65 insertions, 23 deletions
diff --git a/kernel/kexec.c b/kernel/kexec.c index 6db42ff8d520..a0d920915b38 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c | |||
@@ -24,6 +24,8 @@ | |||
24 | #include <linux/utsrelease.h> | 24 | #include <linux/utsrelease.h> |
25 | #include <linux/utsname.h> | 25 | #include <linux/utsname.h> |
26 | #include <linux/numa.h> | 26 | #include <linux/numa.h> |
27 | #include <linux/suspend.h> | ||
28 | #include <linux/device.h> | ||
27 | 29 | ||
28 | #include <asm/page.h> | 30 | #include <asm/page.h> |
29 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
@@ -242,6 +244,12 @@ static int kimage_normal_alloc(struct kimage **rimage, unsigned long entry, | |||
242 | goto out; | 244 | goto out; |
243 | } | 245 | } |
244 | 246 | ||
247 | image->swap_page = kimage_alloc_control_pages(image, 0); | ||
248 | if (!image->swap_page) { | ||
249 | printk(KERN_ERR "Could not allocate swap buffer\n"); | ||
250 | goto out; | ||
251 | } | ||
252 | |||
245 | result = 0; | 253 | result = 0; |
246 | out: | 254 | out: |
247 | if (result == 0) | 255 | if (result == 0) |
@@ -986,6 +994,8 @@ asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments, | |||
986 | if (result) | 994 | if (result) |
987 | goto out; | 995 | goto out; |
988 | 996 | ||
997 | if (flags & KEXEC_PRESERVE_CONTEXT) | ||
998 | image->preserve_context = 1; | ||
989 | result = machine_kexec_prepare(image); | 999 | result = machine_kexec_prepare(image); |
990 | if (result) | 1000 | if (result) |
991 | goto out; | 1001 | goto out; |
@@ -1411,3 +1421,50 @@ static int __init crash_save_vmcoreinfo_init(void) | |||
1411 | } | 1421 | } |
1412 | 1422 | ||
1413 | module_init(crash_save_vmcoreinfo_init) | 1423 | module_init(crash_save_vmcoreinfo_init) |
1424 | |||
1425 | /** | ||
1426 | * kernel_kexec - reboot the system | ||
1427 | * | ||
1428 | * Move into place and start executing a preloaded standalone | ||
1429 | * executable. If nothing was preloaded return an error. | ||
1430 | */ | ||
1431 | int kernel_kexec(void) | ||
1432 | { | ||
1433 | int error = 0; | ||
1434 | |||
1435 | if (xchg(&kexec_lock, 1)) | ||
1436 | return -EBUSY; | ||
1437 | if (!kexec_image) { | ||
1438 | error = -EINVAL; | ||
1439 | goto Unlock; | ||
1440 | } | ||
1441 | |||
1442 | if (kexec_image->preserve_context) { | ||
1443 | #ifdef CONFIG_KEXEC_JUMP | ||
1444 | local_irq_disable(); | ||
1445 | save_processor_state(); | ||
1446 | #endif | ||
1447 | } else { | ||
1448 | blocking_notifier_call_chain(&reboot_notifier_list, | ||
1449 | SYS_RESTART, NULL); | ||
1450 | system_state = SYSTEM_RESTART; | ||
1451 | device_shutdown(); | ||
1452 | sysdev_shutdown(); | ||
1453 | printk(KERN_EMERG "Starting new kernel\n"); | ||
1454 | machine_shutdown(); | ||
1455 | } | ||
1456 | |||
1457 | machine_kexec(kexec_image); | ||
1458 | |||
1459 | if (kexec_image->preserve_context) { | ||
1460 | #ifdef CONFIG_KEXEC_JUMP | ||
1461 | restore_processor_state(); | ||
1462 | local_irq_enable(); | ||
1463 | #endif | ||
1464 | } | ||
1465 | |||
1466 | Unlock: | ||
1467 | xchg(&kexec_lock, 0); | ||
1468 | |||
1469 | return error; | ||
1470 | } | ||
diff --git a/kernel/sys.c b/kernel/sys.c index 0c9d3fa1f5ff..c01858090a98 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -301,26 +301,6 @@ void kernel_restart(char *cmd) | |||
301 | } | 301 | } |
302 | EXPORT_SYMBOL_GPL(kernel_restart); | 302 | EXPORT_SYMBOL_GPL(kernel_restart); |
303 | 303 | ||
304 | /** | ||
305 | * kernel_kexec - reboot the system | ||
306 | * | ||
307 | * Move into place and start executing a preloaded standalone | ||
308 | * executable. If nothing was preloaded return an error. | ||
309 | */ | ||
310 | static void kernel_kexec(void) | ||
311 | { | ||
312 | #ifdef CONFIG_KEXEC | ||
313 | struct kimage *image; | ||
314 | image = xchg(&kexec_image, NULL); | ||
315 | if (!image) | ||
316 | return; | ||
317 | kernel_restart_prepare(NULL); | ||
318 | printk(KERN_EMERG "Starting new kernel\n"); | ||
319 | machine_shutdown(); | ||
320 | machine_kexec(image); | ||
321 | #endif | ||
322 | } | ||
323 | |||
324 | static void kernel_shutdown_prepare(enum system_states state) | 304 | static void kernel_shutdown_prepare(enum system_states state) |
325 | { | 305 | { |
326 | blocking_notifier_call_chain(&reboot_notifier_list, | 306 | blocking_notifier_call_chain(&reboot_notifier_list, |
@@ -425,10 +405,15 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user | |||
425 | kernel_restart(buffer); | 405 | kernel_restart(buffer); |
426 | break; | 406 | break; |
427 | 407 | ||
408 | #ifdef CONFIG_KEXEC | ||
428 | case LINUX_REBOOT_CMD_KEXEC: | 409 | case LINUX_REBOOT_CMD_KEXEC: |
429 | kernel_kexec(); | 410 | { |
430 | unlock_kernel(); | 411 | int ret; |
431 | return -EINVAL; | 412 | ret = kernel_kexec(); |
413 | unlock_kernel(); | ||
414 | return ret; | ||
415 | } | ||
416 | #endif | ||
432 | 417 | ||
433 | #ifdef CONFIG_HIBERNATION | 418 | #ifdef CONFIG_HIBERNATION |
434 | case LINUX_REBOOT_CMD_SW_SUSPEND: | 419 | case LINUX_REBOOT_CMD_SW_SUSPEND: |