diff options
Diffstat (limited to 'kernel/kexec.c')
-rw-r--r-- | kernel/kexec.c | 104 |
1 files changed, 98 insertions, 6 deletions
diff --git a/kernel/kexec.c b/kernel/kexec.c index 1c5fcacbcf33..c8a4370e2a34 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c | |||
@@ -24,6 +24,12 @@ | |||
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> | ||
29 | #include <linux/freezer.h> | ||
30 | #include <linux/pm.h> | ||
31 | #include <linux/cpu.h> | ||
32 | #include <linux/console.h> | ||
27 | 33 | ||
28 | #include <asm/page.h> | 34 | #include <asm/page.h> |
29 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
@@ -242,6 +248,12 @@ static int kimage_normal_alloc(struct kimage **rimage, unsigned long entry, | |||
242 | goto out; | 248 | goto out; |
243 | } | 249 | } |
244 | 250 | ||
251 | image->swap_page = kimage_alloc_control_pages(image, 0); | ||
252 | if (!image->swap_page) { | ||
253 | printk(KERN_ERR "Could not allocate swap buffer\n"); | ||
254 | goto out; | ||
255 | } | ||
256 | |||
245 | result = 0; | 257 | result = 0; |
246 | out: | 258 | out: |
247 | if (result == 0) | 259 | if (result == 0) |
@@ -589,14 +601,12 @@ static void kimage_free_extra_pages(struct kimage *image) | |||
589 | kimage_free_page_list(&image->unuseable_pages); | 601 | kimage_free_page_list(&image->unuseable_pages); |
590 | 602 | ||
591 | } | 603 | } |
592 | static int kimage_terminate(struct kimage *image) | 604 | static void kimage_terminate(struct kimage *image) |
593 | { | 605 | { |
594 | if (*image->entry != 0) | 606 | if (*image->entry != 0) |
595 | image->entry++; | 607 | image->entry++; |
596 | 608 | ||
597 | *image->entry = IND_DONE; | 609 | *image->entry = IND_DONE; |
598 | |||
599 | return 0; | ||
600 | } | 610 | } |
601 | 611 | ||
602 | #define for_each_kimage_entry(image, ptr, entry) \ | 612 | #define for_each_kimage_entry(image, ptr, entry) \ |
@@ -988,6 +998,8 @@ asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments, | |||
988 | if (result) | 998 | if (result) |
989 | goto out; | 999 | goto out; |
990 | 1000 | ||
1001 | if (flags & KEXEC_PRESERVE_CONTEXT) | ||
1002 | image->preserve_context = 1; | ||
991 | result = machine_kexec_prepare(image); | 1003 | result = machine_kexec_prepare(image); |
992 | if (result) | 1004 | if (result) |
993 | goto out; | 1005 | goto out; |
@@ -997,9 +1009,7 @@ asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments, | |||
997 | if (result) | 1009 | if (result) |
998 | goto out; | 1010 | goto out; |
999 | } | 1011 | } |
1000 | result = kimage_terminate(image); | 1012 | kimage_terminate(image); |
1001 | if (result) | ||
1002 | goto out; | ||
1003 | } | 1013 | } |
1004 | /* Install the new kernel, and Uninstall the old */ | 1014 | /* Install the new kernel, and Uninstall the old */ |
1005 | image = xchg(dest_image, image); | 1015 | image = xchg(dest_image, image); |
@@ -1415,3 +1425,85 @@ static int __init crash_save_vmcoreinfo_init(void) | |||
1415 | } | 1425 | } |
1416 | 1426 | ||
1417 | module_init(crash_save_vmcoreinfo_init) | 1427 | module_init(crash_save_vmcoreinfo_init) |
1428 | |||
1429 | /** | ||
1430 | * kernel_kexec - reboot the system | ||
1431 | * | ||
1432 | * Move into place and start executing a preloaded standalone | ||
1433 | * executable. If nothing was preloaded return an error. | ||
1434 | */ | ||
1435 | int kernel_kexec(void) | ||
1436 | { | ||
1437 | int error = 0; | ||
1438 | |||
1439 | if (xchg(&kexec_lock, 1)) | ||
1440 | return -EBUSY; | ||
1441 | if (!kexec_image) { | ||
1442 | error = -EINVAL; | ||
1443 | goto Unlock; | ||
1444 | } | ||
1445 | |||
1446 | if (kexec_image->preserve_context) { | ||
1447 | #ifdef CONFIG_KEXEC_JUMP | ||
1448 | mutex_lock(&pm_mutex); | ||
1449 | pm_prepare_console(); | ||
1450 | error = freeze_processes(); | ||
1451 | if (error) { | ||
1452 | error = -EBUSY; | ||
1453 | goto Restore_console; | ||
1454 | } | ||
1455 | suspend_console(); | ||
1456 | error = device_suspend(PMSG_FREEZE); | ||
1457 | if (error) | ||
1458 | goto Resume_console; | ||
1459 | error = disable_nonboot_cpus(); | ||
1460 | if (error) | ||
1461 | goto Resume_devices; | ||
1462 | local_irq_disable(); | ||
1463 | /* At this point, device_suspend() has been called, | ||
1464 | * but *not* device_power_down(). We *must* | ||
1465 | * device_power_down() now. Otherwise, drivers for | ||
1466 | * some devices (e.g. interrupt controllers) become | ||
1467 | * desynchronized with the actual state of the | ||
1468 | * hardware at resume time, and evil weirdness ensues. | ||
1469 | */ | ||
1470 | error = device_power_down(PMSG_FREEZE); | ||
1471 | if (error) | ||
1472 | goto Enable_irqs; | ||
1473 | save_processor_state(); | ||
1474 | #endif | ||
1475 | } else { | ||
1476 | blocking_notifier_call_chain(&reboot_notifier_list, | ||
1477 | SYS_RESTART, NULL); | ||
1478 | system_state = SYSTEM_RESTART; | ||
1479 | device_shutdown(); | ||
1480 | sysdev_shutdown(); | ||
1481 | printk(KERN_EMERG "Starting new kernel\n"); | ||
1482 | machine_shutdown(); | ||
1483 | } | ||
1484 | |||
1485 | machine_kexec(kexec_image); | ||
1486 | |||
1487 | if (kexec_image->preserve_context) { | ||
1488 | #ifdef CONFIG_KEXEC_JUMP | ||
1489 | restore_processor_state(); | ||
1490 | device_power_up(PMSG_RESTORE); | ||
1491 | Enable_irqs: | ||
1492 | local_irq_enable(); | ||
1493 | enable_nonboot_cpus(); | ||
1494 | Resume_devices: | ||
1495 | device_resume(PMSG_RESTORE); | ||
1496 | Resume_console: | ||
1497 | resume_console(); | ||
1498 | thaw_processes(); | ||
1499 | Restore_console: | ||
1500 | pm_restore_console(); | ||
1501 | mutex_unlock(&pm_mutex); | ||
1502 | #endif | ||
1503 | } | ||
1504 | |||
1505 | Unlock: | ||
1506 | xchg(&kexec_lock, 0); | ||
1507 | |||
1508 | return error; | ||
1509 | } | ||