diff options
| author | Ingo Molnar <mingo@elte.hu> | 2008-08-15 12:15:17 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2008-08-15 12:15:17 -0400 |
| commit | f3efbe582b5396d134024c03a5fa253f2a85d9a6 (patch) | |
| tree | e4e15b7567b82d24cb1e7327398286a2b88df04c /kernel/kexec.c | |
| parent | 05d3ed0a1fe3ea05ab9f3b8d32576a0bc2e19660 (diff) | |
| parent | b635acec48bcaa9183fcbf4e3955616b0d4119b5 (diff) | |
Merge branch 'linus' into x86/gart
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 | } | ||
