aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sys.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sys.c')
-rw-r--r--kernel/sys.c202
1 files changed, 142 insertions, 60 deletions
diff --git a/kernel/sys.c b/kernel/sys.c
index f006632c2ba7..0bcaed6560ac 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -16,6 +16,8 @@
16#include <linux/init.h> 16#include <linux/init.h>
17#include <linux/highuid.h> 17#include <linux/highuid.h>
18#include <linux/fs.h> 18#include <linux/fs.h>
19#include <linux/kernel.h>
20#include <linux/kexec.h>
19#include <linux/workqueue.h> 21#include <linux/workqueue.h>
20#include <linux/device.h> 22#include <linux/device.h>
21#include <linux/key.h> 23#include <linux/key.h>
@@ -359,6 +361,64 @@ out_unlock:
359 return retval; 361 return retval;
360} 362}
361 363
364void emergency_restart(void)
365{
366 machine_emergency_restart();
367}
368EXPORT_SYMBOL_GPL(emergency_restart);
369
370void kernel_restart(char *cmd)
371{
372 notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
373 system_state = SYSTEM_RESTART;
374 device_shutdown();
375 if (!cmd) {
376 printk(KERN_EMERG "Restarting system.\n");
377 } else {
378 printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd);
379 }
380 printk(".\n");
381 machine_restart(cmd);
382}
383EXPORT_SYMBOL_GPL(kernel_restart);
384
385void kernel_kexec(void)
386{
387#ifdef CONFIG_KEXEC
388 struct kimage *image;
389 image = xchg(&kexec_image, 0);
390 if (!image) {
391 return;
392 }
393 notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
394 system_state = SYSTEM_RESTART;
395 device_shutdown();
396 printk(KERN_EMERG "Starting new kernel\n");
397 machine_shutdown();
398 machine_kexec(image);
399#endif
400}
401EXPORT_SYMBOL_GPL(kernel_kexec);
402
403void kernel_halt(void)
404{
405 notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL);
406 system_state = SYSTEM_HALT;
407 device_shutdown();
408 printk(KERN_EMERG "System halted.\n");
409 machine_halt();
410}
411EXPORT_SYMBOL_GPL(kernel_halt);
412
413void kernel_power_off(void)
414{
415 notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL);
416 system_state = SYSTEM_POWER_OFF;
417 device_shutdown();
418 printk(KERN_EMERG "Power down.\n");
419 machine_power_off();
420}
421EXPORT_SYMBOL_GPL(kernel_power_off);
362 422
363/* 423/*
364 * Reboot system call: for obvious reasons only root may call it, 424 * Reboot system call: for obvious reasons only root may call it,
@@ -387,11 +447,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
387 lock_kernel(); 447 lock_kernel();
388 switch (cmd) { 448 switch (cmd) {
389 case LINUX_REBOOT_CMD_RESTART: 449 case LINUX_REBOOT_CMD_RESTART:
390 notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL); 450 kernel_restart(NULL);
391 system_state = SYSTEM_RESTART;
392 device_shutdown();
393 printk(KERN_EMERG "Restarting system.\n");
394 machine_restart(NULL);
395 break; 451 break;
396 452
397 case LINUX_REBOOT_CMD_CAD_ON: 453 case LINUX_REBOOT_CMD_CAD_ON:
@@ -403,21 +459,13 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
403 break; 459 break;
404 460
405 case LINUX_REBOOT_CMD_HALT: 461 case LINUX_REBOOT_CMD_HALT:
406 notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL); 462 kernel_halt();
407 system_state = SYSTEM_HALT;
408 device_shutdown();
409 printk(KERN_EMERG "System halted.\n");
410 machine_halt();
411 unlock_kernel(); 463 unlock_kernel();
412 do_exit(0); 464 do_exit(0);
413 break; 465 break;
414 466
415 case LINUX_REBOOT_CMD_POWER_OFF: 467 case LINUX_REBOOT_CMD_POWER_OFF:
416 notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL); 468 kernel_power_off();
417 system_state = SYSTEM_POWER_OFF;
418 device_shutdown();
419 printk(KERN_EMERG "Power down.\n");
420 machine_power_off();
421 unlock_kernel(); 469 unlock_kernel();
422 do_exit(0); 470 do_exit(0);
423 break; 471 break;
@@ -429,13 +477,14 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
429 } 477 }
430 buffer[sizeof(buffer) - 1] = '\0'; 478 buffer[sizeof(buffer) - 1] = '\0';
431 479
432 notifier_call_chain(&reboot_notifier_list, SYS_RESTART, buffer); 480 kernel_restart(buffer);
433 system_state = SYSTEM_RESTART;
434 device_shutdown();
435 printk(KERN_EMERG "Restarting system with command '%s'.\n", buffer);
436 machine_restart(buffer);
437 break; 481 break;
438 482
483 case LINUX_REBOOT_CMD_KEXEC:
484 kernel_kexec();
485 unlock_kernel();
486 return -EINVAL;
487
439#ifdef CONFIG_SOFTWARE_SUSPEND 488#ifdef CONFIG_SOFTWARE_SUSPEND
440 case LINUX_REBOOT_CMD_SW_SUSPEND: 489 case LINUX_REBOOT_CMD_SW_SUSPEND:
441 { 490 {
@@ -455,8 +504,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
455 504
456static void deferred_cad(void *dummy) 505static void deferred_cad(void *dummy)
457{ 506{
458 notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL); 507 kernel_restart(NULL);
459 machine_restart(NULL);
460} 508}
461 509
462/* 510/*
@@ -525,7 +573,7 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
525 } 573 }
526 if (new_egid != old_egid) 574 if (new_egid != old_egid)
527 { 575 {
528 current->mm->dumpable = 0; 576 current->mm->dumpable = suid_dumpable;
529 smp_wmb(); 577 smp_wmb();
530 } 578 }
531 if (rgid != (gid_t) -1 || 579 if (rgid != (gid_t) -1 ||
@@ -556,7 +604,7 @@ asmlinkage long sys_setgid(gid_t gid)
556 { 604 {
557 if(old_egid != gid) 605 if(old_egid != gid)
558 { 606 {
559 current->mm->dumpable=0; 607 current->mm->dumpable = suid_dumpable;
560 smp_wmb(); 608 smp_wmb();
561 } 609 }
562 current->gid = current->egid = current->sgid = current->fsgid = gid; 610 current->gid = current->egid = current->sgid = current->fsgid = gid;
@@ -565,7 +613,7 @@ asmlinkage long sys_setgid(gid_t gid)
565 { 613 {
566 if(old_egid != gid) 614 if(old_egid != gid)
567 { 615 {
568 current->mm->dumpable=0; 616 current->mm->dumpable = suid_dumpable;
569 smp_wmb(); 617 smp_wmb();
570 } 618 }
571 current->egid = current->fsgid = gid; 619 current->egid = current->fsgid = gid;
@@ -596,7 +644,7 @@ static int set_user(uid_t new_ruid, int dumpclear)
596 644
597 if(dumpclear) 645 if(dumpclear)
598 { 646 {
599 current->mm->dumpable = 0; 647 current->mm->dumpable = suid_dumpable;
600 smp_wmb(); 648 smp_wmb();
601 } 649 }
602 current->uid = new_ruid; 650 current->uid = new_ruid;
@@ -653,7 +701,7 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
653 701
654 if (new_euid != old_euid) 702 if (new_euid != old_euid)
655 { 703 {
656 current->mm->dumpable=0; 704 current->mm->dumpable = suid_dumpable;
657 smp_wmb(); 705 smp_wmb();
658 } 706 }
659 current->fsuid = current->euid = new_euid; 707 current->fsuid = current->euid = new_euid;
@@ -703,7 +751,7 @@ asmlinkage long sys_setuid(uid_t uid)
703 751
704 if (old_euid != uid) 752 if (old_euid != uid)
705 { 753 {
706 current->mm->dumpable = 0; 754 current->mm->dumpable = suid_dumpable;
707 smp_wmb(); 755 smp_wmb();
708 } 756 }
709 current->fsuid = current->euid = uid; 757 current->fsuid = current->euid = uid;
@@ -748,7 +796,7 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
748 if (euid != (uid_t) -1) { 796 if (euid != (uid_t) -1) {
749 if (euid != current->euid) 797 if (euid != current->euid)
750 { 798 {
751 current->mm->dumpable = 0; 799 current->mm->dumpable = suid_dumpable;
752 smp_wmb(); 800 smp_wmb();
753 } 801 }
754 current->euid = euid; 802 current->euid = euid;
@@ -798,7 +846,7 @@ asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
798 if (egid != (gid_t) -1) { 846 if (egid != (gid_t) -1) {
799 if (egid != current->egid) 847 if (egid != current->egid)
800 { 848 {
801 current->mm->dumpable = 0; 849 current->mm->dumpable = suid_dumpable;
802 smp_wmb(); 850 smp_wmb();
803 } 851 }
804 current->egid = egid; 852 current->egid = egid;
@@ -845,7 +893,7 @@ asmlinkage long sys_setfsuid(uid_t uid)
845 { 893 {
846 if (uid != old_fsuid) 894 if (uid != old_fsuid)
847 { 895 {
848 current->mm->dumpable = 0; 896 current->mm->dumpable = suid_dumpable;
849 smp_wmb(); 897 smp_wmb();
850 } 898 }
851 current->fsuid = uid; 899 current->fsuid = uid;
@@ -875,7 +923,7 @@ asmlinkage long sys_setfsgid(gid_t gid)
875 { 923 {
876 if (gid != old_fsgid) 924 if (gid != old_fsgid)
877 { 925 {
878 current->mm->dumpable = 0; 926 current->mm->dumpable = suid_dumpable;
879 smp_wmb(); 927 smp_wmb();
880 } 928 }
881 current->fsgid = gid; 929 current->fsgid = gid;
@@ -894,35 +942,69 @@ asmlinkage long sys_times(struct tms __user * tbuf)
894 */ 942 */
895 if (tbuf) { 943 if (tbuf) {
896 struct tms tmp; 944 struct tms tmp;
897 struct task_struct *tsk = current;
898 struct task_struct *t;
899 cputime_t utime, stime, cutime, cstime; 945 cputime_t utime, stime, cutime, cstime;
900 946
901 read_lock(&tasklist_lock); 947#ifdef CONFIG_SMP
902 utime = tsk->signal->utime; 948 if (thread_group_empty(current)) {
903 stime = tsk->signal->stime; 949 /*
904 t = tsk; 950 * Single thread case without the use of any locks.
905 do { 951 *
906 utime = cputime_add(utime, t->utime); 952 * We may race with release_task if two threads are
907 stime = cputime_add(stime, t->stime); 953 * executing. However, release task first adds up the
908 t = next_thread(t); 954 * counters (__exit_signal) before removing the task
909 } while (t != tsk); 955 * from the process tasklist (__unhash_process).
910 956 * __exit_signal also acquires and releases the
911 /* 957 * siglock which results in the proper memory ordering
912 * While we have tasklist_lock read-locked, no dying thread 958 * so that the list modifications are always visible
913 * can be updating current->signal->[us]time. Instead, 959 * after the counters have been updated.
914 * we got their counts included in the live thread loop. 960 *
915 * However, another thread can come in right now and 961 * If the counters have been updated by the second thread
916 * do a wait call that updates current->signal->c[us]time. 962 * but the thread has not yet been removed from the list
917 * To make sure we always see that pair updated atomically, 963 * then the other branch will be executing which will
918 * we take the siglock around fetching them. 964 * block on tasklist_lock until the exit handling of the
919 */ 965 * other task is finished.
920 spin_lock_irq(&tsk->sighand->siglock); 966 *
921 cutime = tsk->signal->cutime; 967 * This also implies that the sighand->siglock cannot
922 cstime = tsk->signal->cstime; 968 * be held by another processor. So we can also
923 spin_unlock_irq(&tsk->sighand->siglock); 969 * skip acquiring that lock.
924 read_unlock(&tasklist_lock); 970 */
971 utime = cputime_add(current->signal->utime, current->utime);
972 stime = cputime_add(current->signal->utime, current->stime);
973 cutime = current->signal->cutime;
974 cstime = current->signal->cstime;
975 } else
976#endif
977 {
978
979 /* Process with multiple threads */
980 struct task_struct *tsk = current;
981 struct task_struct *t;
925 982
983 read_lock(&tasklist_lock);
984 utime = tsk->signal->utime;
985 stime = tsk->signal->stime;
986 t = tsk;
987 do {
988 utime = cputime_add(utime, t->utime);
989 stime = cputime_add(stime, t->stime);
990 t = next_thread(t);
991 } while (t != tsk);
992
993 /*
994 * While we have tasklist_lock read-locked, no dying thread
995 * can be updating current->signal->[us]time. Instead,
996 * we got their counts included in the live thread loop.
997 * However, another thread can come in right now and
998 * do a wait call that updates current->signal->c[us]time.
999 * To make sure we always see that pair updated atomically,
1000 * we take the siglock around fetching them.
1001 */
1002 spin_lock_irq(&tsk->sighand->siglock);
1003 cutime = tsk->signal->cutime;
1004 cstime = tsk->signal->cstime;
1005 spin_unlock_irq(&tsk->sighand->siglock);
1006 read_unlock(&tasklist_lock);
1007 }
926 tmp.tms_utime = cputime_to_clock_t(utime); 1008 tmp.tms_utime = cputime_to_clock_t(utime);
927 tmp.tms_stime = cputime_to_clock_t(stime); 1009 tmp.tms_stime = cputime_to_clock_t(stime);
928 tmp.tms_cutime = cputime_to_clock_t(cutime); 1010 tmp.tms_cutime = cputime_to_clock_t(cutime);
@@ -1225,7 +1307,7 @@ static void groups_sort(struct group_info *group_info)
1225} 1307}
1226 1308
1227/* a simple bsearch */ 1309/* a simple bsearch */
1228static int groups_search(struct group_info *group_info, gid_t grp) 1310int groups_search(struct group_info *group_info, gid_t grp)
1229{ 1311{
1230 int left, right; 1312 int left, right;
1231 1313
@@ -1652,7 +1734,7 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
1652 error = 1; 1734 error = 1;
1653 break; 1735 break;
1654 case PR_SET_DUMPABLE: 1736 case PR_SET_DUMPABLE:
1655 if (arg2 != 0 && arg2 != 1) { 1737 if (arg2 < 0 || arg2 > 2) {
1656 error = -EINVAL; 1738 error = -EINVAL;
1657 break; 1739 break;
1658 } 1740 }