aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sys.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sys.c')
-rw-r--r--kernel/sys.c133
1 files changed, 95 insertions, 38 deletions
diff --git a/kernel/sys.c b/kernel/sys.c
index f006632c2ba7..9a24374c23bc 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>
@@ -405,6 +407,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
405 case LINUX_REBOOT_CMD_HALT: 407 case LINUX_REBOOT_CMD_HALT:
406 notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL); 408 notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL);
407 system_state = SYSTEM_HALT; 409 system_state = SYSTEM_HALT;
410 device_suspend(PMSG_SUSPEND);
408 device_shutdown(); 411 device_shutdown();
409 printk(KERN_EMERG "System halted.\n"); 412 printk(KERN_EMERG "System halted.\n");
410 machine_halt(); 413 machine_halt();
@@ -415,6 +418,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
415 case LINUX_REBOOT_CMD_POWER_OFF: 418 case LINUX_REBOOT_CMD_POWER_OFF:
416 notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL); 419 notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL);
417 system_state = SYSTEM_POWER_OFF; 420 system_state = SYSTEM_POWER_OFF;
421 device_suspend(PMSG_SUSPEND);
418 device_shutdown(); 422 device_shutdown();
419 printk(KERN_EMERG "Power down.\n"); 423 printk(KERN_EMERG "Power down.\n");
420 machine_power_off(); 424 machine_power_off();
@@ -431,11 +435,30 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
431 435
432 notifier_call_chain(&reboot_notifier_list, SYS_RESTART, buffer); 436 notifier_call_chain(&reboot_notifier_list, SYS_RESTART, buffer);
433 system_state = SYSTEM_RESTART; 437 system_state = SYSTEM_RESTART;
438 device_suspend(PMSG_FREEZE);
434 device_shutdown(); 439 device_shutdown();
435 printk(KERN_EMERG "Restarting system with command '%s'.\n", buffer); 440 printk(KERN_EMERG "Restarting system with command '%s'.\n", buffer);
436 machine_restart(buffer); 441 machine_restart(buffer);
437 break; 442 break;
438 443
444#ifdef CONFIG_KEXEC
445 case LINUX_REBOOT_CMD_KEXEC:
446 {
447 struct kimage *image;
448 image = xchg(&kexec_image, 0);
449 if (!image) {
450 unlock_kernel();
451 return -EINVAL;
452 }
453 notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
454 system_state = SYSTEM_RESTART;
455 device_shutdown();
456 printk(KERN_EMERG "Starting new kernel\n");
457 machine_shutdown();
458 machine_kexec(image);
459 break;
460 }
461#endif
439#ifdef CONFIG_SOFTWARE_SUSPEND 462#ifdef CONFIG_SOFTWARE_SUSPEND
440 case LINUX_REBOOT_CMD_SW_SUSPEND: 463 case LINUX_REBOOT_CMD_SW_SUSPEND:
441 { 464 {
@@ -525,7 +548,7 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
525 } 548 }
526 if (new_egid != old_egid) 549 if (new_egid != old_egid)
527 { 550 {
528 current->mm->dumpable = 0; 551 current->mm->dumpable = suid_dumpable;
529 smp_wmb(); 552 smp_wmb();
530 } 553 }
531 if (rgid != (gid_t) -1 || 554 if (rgid != (gid_t) -1 ||
@@ -556,7 +579,7 @@ asmlinkage long sys_setgid(gid_t gid)
556 { 579 {
557 if(old_egid != gid) 580 if(old_egid != gid)
558 { 581 {
559 current->mm->dumpable=0; 582 current->mm->dumpable = suid_dumpable;
560 smp_wmb(); 583 smp_wmb();
561 } 584 }
562 current->gid = current->egid = current->sgid = current->fsgid = gid; 585 current->gid = current->egid = current->sgid = current->fsgid = gid;
@@ -565,7 +588,7 @@ asmlinkage long sys_setgid(gid_t gid)
565 { 588 {
566 if(old_egid != gid) 589 if(old_egid != gid)
567 { 590 {
568 current->mm->dumpable=0; 591 current->mm->dumpable = suid_dumpable;
569 smp_wmb(); 592 smp_wmb();
570 } 593 }
571 current->egid = current->fsgid = gid; 594 current->egid = current->fsgid = gid;
@@ -596,7 +619,7 @@ static int set_user(uid_t new_ruid, int dumpclear)
596 619
597 if(dumpclear) 620 if(dumpclear)
598 { 621 {
599 current->mm->dumpable = 0; 622 current->mm->dumpable = suid_dumpable;
600 smp_wmb(); 623 smp_wmb();
601 } 624 }
602 current->uid = new_ruid; 625 current->uid = new_ruid;
@@ -653,7 +676,7 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
653 676
654 if (new_euid != old_euid) 677 if (new_euid != old_euid)
655 { 678 {
656 current->mm->dumpable=0; 679 current->mm->dumpable = suid_dumpable;
657 smp_wmb(); 680 smp_wmb();
658 } 681 }
659 current->fsuid = current->euid = new_euid; 682 current->fsuid = current->euid = new_euid;
@@ -703,7 +726,7 @@ asmlinkage long sys_setuid(uid_t uid)
703 726
704 if (old_euid != uid) 727 if (old_euid != uid)
705 { 728 {
706 current->mm->dumpable = 0; 729 current->mm->dumpable = suid_dumpable;
707 smp_wmb(); 730 smp_wmb();
708 } 731 }
709 current->fsuid = current->euid = uid; 732 current->fsuid = current->euid = uid;
@@ -748,7 +771,7 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
748 if (euid != (uid_t) -1) { 771 if (euid != (uid_t) -1) {
749 if (euid != current->euid) 772 if (euid != current->euid)
750 { 773 {
751 current->mm->dumpable = 0; 774 current->mm->dumpable = suid_dumpable;
752 smp_wmb(); 775 smp_wmb();
753 } 776 }
754 current->euid = euid; 777 current->euid = euid;
@@ -798,7 +821,7 @@ asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
798 if (egid != (gid_t) -1) { 821 if (egid != (gid_t) -1) {
799 if (egid != current->egid) 822 if (egid != current->egid)
800 { 823 {
801 current->mm->dumpable = 0; 824 current->mm->dumpable = suid_dumpable;
802 smp_wmb(); 825 smp_wmb();
803 } 826 }
804 current->egid = egid; 827 current->egid = egid;
@@ -845,7 +868,7 @@ asmlinkage long sys_setfsuid(uid_t uid)
845 { 868 {
846 if (uid != old_fsuid) 869 if (uid != old_fsuid)
847 { 870 {
848 current->mm->dumpable = 0; 871 current->mm->dumpable = suid_dumpable;
849 smp_wmb(); 872 smp_wmb();
850 } 873 }
851 current->fsuid = uid; 874 current->fsuid = uid;
@@ -875,7 +898,7 @@ asmlinkage long sys_setfsgid(gid_t gid)
875 { 898 {
876 if (gid != old_fsgid) 899 if (gid != old_fsgid)
877 { 900 {
878 current->mm->dumpable = 0; 901 current->mm->dumpable = suid_dumpable;
879 smp_wmb(); 902 smp_wmb();
880 } 903 }
881 current->fsgid = gid; 904 current->fsgid = gid;
@@ -894,35 +917,69 @@ asmlinkage long sys_times(struct tms __user * tbuf)
894 */ 917 */
895 if (tbuf) { 918 if (tbuf) {
896 struct tms tmp; 919 struct tms tmp;
897 struct task_struct *tsk = current;
898 struct task_struct *t;
899 cputime_t utime, stime, cutime, cstime; 920 cputime_t utime, stime, cutime, cstime;
900 921
901 read_lock(&tasklist_lock); 922#ifdef CONFIG_SMP
902 utime = tsk->signal->utime; 923 if (thread_group_empty(current)) {
903 stime = tsk->signal->stime; 924 /*
904 t = tsk; 925 * Single thread case without the use of any locks.
905 do { 926 *
906 utime = cputime_add(utime, t->utime); 927 * We may race with release_task if two threads are
907 stime = cputime_add(stime, t->stime); 928 * executing. However, release task first adds up the
908 t = next_thread(t); 929 * counters (__exit_signal) before removing the task
909 } while (t != tsk); 930 * from the process tasklist (__unhash_process).
910 931 * __exit_signal also acquires and releases the
911 /* 932 * siglock which results in the proper memory ordering
912 * While we have tasklist_lock read-locked, no dying thread 933 * so that the list modifications are always visible
913 * can be updating current->signal->[us]time. Instead, 934 * after the counters have been updated.
914 * we got their counts included in the live thread loop. 935 *
915 * However, another thread can come in right now and 936 * If the counters have been updated by the second thread
916 * do a wait call that updates current->signal->c[us]time. 937 * but the thread has not yet been removed from the list
917 * To make sure we always see that pair updated atomically, 938 * then the other branch will be executing which will
918 * we take the siglock around fetching them. 939 * block on tasklist_lock until the exit handling of the
919 */ 940 * other task is finished.
920 spin_lock_irq(&tsk->sighand->siglock); 941 *
921 cutime = tsk->signal->cutime; 942 * This also implies that the sighand->siglock cannot
922 cstime = tsk->signal->cstime; 943 * be held by another processor. So we can also
923 spin_unlock_irq(&tsk->sighand->siglock); 944 * skip acquiring that lock.
924 read_unlock(&tasklist_lock); 945 */
946 utime = cputime_add(current->signal->utime, current->utime);
947 stime = cputime_add(current->signal->utime, current->stime);
948 cutime = current->signal->cutime;
949 cstime = current->signal->cstime;
950 } else
951#endif
952 {
925 953
954 /* Process with multiple threads */
955 struct task_struct *tsk = current;
956 struct task_struct *t;
957
958 read_lock(&tasklist_lock);
959 utime = tsk->signal->utime;
960 stime = tsk->signal->stime;
961 t = tsk;
962 do {
963 utime = cputime_add(utime, t->utime);
964 stime = cputime_add(stime, t->stime);
965 t = next_thread(t);
966 } while (t != tsk);
967
968 /*
969 * While we have tasklist_lock read-locked, no dying thread
970 * can be updating current->signal->[us]time. Instead,
971 * we got their counts included in the live thread loop.
972 * However, another thread can come in right now and
973 * do a wait call that updates current->signal->c[us]time.
974 * To make sure we always see that pair updated atomically,
975 * we take the siglock around fetching them.
976 */
977 spin_lock_irq(&tsk->sighand->siglock);
978 cutime = tsk->signal->cutime;
979 cstime = tsk->signal->cstime;
980 spin_unlock_irq(&tsk->sighand->siglock);
981 read_unlock(&tasklist_lock);
982 }
926 tmp.tms_utime = cputime_to_clock_t(utime); 983 tmp.tms_utime = cputime_to_clock_t(utime);
927 tmp.tms_stime = cputime_to_clock_t(stime); 984 tmp.tms_stime = cputime_to_clock_t(stime);
928 tmp.tms_cutime = cputime_to_clock_t(cutime); 985 tmp.tms_cutime = cputime_to_clock_t(cutime);
@@ -1225,7 +1282,7 @@ static void groups_sort(struct group_info *group_info)
1225} 1282}
1226 1283
1227/* a simple bsearch */ 1284/* a simple bsearch */
1228static int groups_search(struct group_info *group_info, gid_t grp) 1285int groups_search(struct group_info *group_info, gid_t grp)
1229{ 1286{
1230 int left, right; 1287 int left, right;
1231 1288
@@ -1652,7 +1709,7 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
1652 error = 1; 1709 error = 1;
1653 break; 1710 break;
1654 case PR_SET_DUMPABLE: 1711 case PR_SET_DUMPABLE:
1655 if (arg2 != 0 && arg2 != 1) { 1712 if (arg2 < 0 || arg2 > 2) {
1656 error = -EINVAL; 1713 error = -EINVAL;
1657 break; 1714 break;
1658 } 1715 }