diff options
author | Jeff Garzik <jgarzik@pobox.com> | 2005-08-29 16:40:27 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-08-29 16:40:27 -0400 |
commit | c1b054d03f5b31c33eaa0b267c629b118eaf3790 (patch) | |
tree | 9333907ca767be24fcb3667877242976c3e3c8dd /kernel/sys.c | |
parent | 559fb51ba7e66fe298b8355fabde1275b7def35f (diff) | |
parent | bf4e70e54cf31dcca48d279c7f7e71328eebe749 (diff) |
Merge /spare/repo/linux-2.6/
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 202 |
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 | ||
364 | void emergency_restart(void) | ||
365 | { | ||
366 | machine_emergency_restart(); | ||
367 | } | ||
368 | EXPORT_SYMBOL_GPL(emergency_restart); | ||
369 | |||
370 | void 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 | } | ||
383 | EXPORT_SYMBOL_GPL(kernel_restart); | ||
384 | |||
385 | void 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 | } | ||
401 | EXPORT_SYMBOL_GPL(kernel_kexec); | ||
402 | |||
403 | void 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 | } | ||
411 | EXPORT_SYMBOL_GPL(kernel_halt); | ||
412 | |||
413 | void 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 | } | ||
421 | EXPORT_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 | ||
456 | static void deferred_cad(void *dummy) | 505 | static 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 */ |
1228 | static int groups_search(struct group_info *group_info, gid_t grp) | 1310 | int 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 | } |