[PATCH] ipmi: watchdog parms in sysfs
[safe/jmp/linux-2.6] / kernel / sys.c
index 7f43d6e..1e1f41b 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/init.h>
 #include <linux/highuid.h>
 #include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/kexec.h>
 #include <linux/workqueue.h>
 #include <linux/device.h>
 #include <linux/key.h>
@@ -25,6 +27,8 @@
 #include <linux/dcookies.h>
 #include <linux/suspend.h>
 #include <linux/tty.h>
+#include <linux/signal.h>
+#include <linux/cn_proc.h>
 
 #include <linux/compat.h>
 #include <linux/syscalls.h>
@@ -358,6 +362,104 @@ out_unlock:
        return retval;
 }
 
+/**
+ *     emergency_restart - reboot the system
+ *
+ *     Without shutting down any hardware or taking any locks
+ *     reboot the system.  This is called when we know we are in
+ *     trouble so this is our best effort to reboot.  This is
+ *     safe to call in interrupt context.
+ */
+void emergency_restart(void)
+{
+       machine_emergency_restart();
+}
+EXPORT_SYMBOL_GPL(emergency_restart);
+
+/**
+ *     kernel_restart - reboot the system
+ *
+ *     Shutdown everything and perform a clean reboot.
+ *     This is not safe to call in interrupt context.
+ */
+void kernel_restart_prepare(char *cmd)
+{
+       notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
+       system_state = SYSTEM_RESTART;
+       device_shutdown();
+}
+void kernel_restart(char *cmd)
+{
+       kernel_restart_prepare(cmd);
+       if (!cmd) {
+               printk(KERN_EMERG "Restarting system.\n");
+       } else {
+               printk(KERN_EMERG "Restarting system with command '%s'.\n", cmd);
+       }
+       printk(".\n");
+       machine_restart(cmd);
+}
+EXPORT_SYMBOL_GPL(kernel_restart);
+
+/**
+ *     kernel_kexec - reboot the system
+ *
+ *     Move into place and start executing a preloaded standalone
+ *     executable.  If nothing was preloaded return an error.
+ */
+void kernel_kexec(void)
+{
+#ifdef CONFIG_KEXEC
+       struct kimage *image;
+       image = xchg(&kexec_image, 0);
+       if (!image) {
+               return;
+       }
+       kernel_restart_prepare(NULL);
+       printk(KERN_EMERG "Starting new kernel\n");
+       machine_shutdown();
+       machine_kexec(image);
+#endif
+}
+EXPORT_SYMBOL_GPL(kernel_kexec);
+
+/**
+ *     kernel_halt - halt the system
+ *
+ *     Shutdown everything and perform a clean system halt.
+ */
+void kernel_halt_prepare(void)
+{
+       notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL);
+       system_state = SYSTEM_HALT;
+       device_shutdown();
+}
+void kernel_halt(void)
+{
+       kernel_halt_prepare();
+       printk(KERN_EMERG "System halted.\n");
+       machine_halt();
+}
+EXPORT_SYMBOL_GPL(kernel_halt);
+
+/**
+ *     kernel_power_off - power_off the system
+ *
+ *     Shutdown everything and perform a clean system power_off.
+ */
+void kernel_power_off_prepare(void)
+{
+       notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL);
+       system_state = SYSTEM_POWER_OFF;
+       device_shutdown();
+}
+void kernel_power_off(void)
+{
+       kernel_power_off_prepare();
+       printk(KERN_EMERG "Power down.\n");
+       machine_power_off();
+}
+EXPORT_SYMBOL_GPL(kernel_power_off);
 
 /*
  * Reboot system call: for obvious reasons only root may call it,
@@ -386,11 +488,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
        lock_kernel();
        switch (cmd) {
        case LINUX_REBOOT_CMD_RESTART:
-               notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
-               system_state = SYSTEM_RESTART;
-               device_shutdown();
-               printk(KERN_EMERG "Restarting system.\n");
-               machine_restart(NULL);
+               kernel_restart(NULL);
                break;
 
        case LINUX_REBOOT_CMD_CAD_ON:
@@ -402,21 +500,13 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
                break;
 
        case LINUX_REBOOT_CMD_HALT:
-               notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL);
-               system_state = SYSTEM_HALT;
-               device_shutdown();
-               printk(KERN_EMERG "System halted.\n");
-               machine_halt();
+               kernel_halt();
                unlock_kernel();
                do_exit(0);
                break;
 
        case LINUX_REBOOT_CMD_POWER_OFF:
-               notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL);
-               system_state = SYSTEM_POWER_OFF;
-               device_shutdown();
-               printk(KERN_EMERG "Power down.\n");
-               machine_power_off();
+               kernel_power_off();
                unlock_kernel();
                do_exit(0);
                break;
@@ -428,13 +518,14 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
                }
                buffer[sizeof(buffer) - 1] = '\0';
 
-               notifier_call_chain(&reboot_notifier_list, SYS_RESTART, buffer);
-               system_state = SYSTEM_RESTART;
-               device_shutdown();
-               printk(KERN_EMERG "Restarting system with command '%s'.\n", buffer);
-               machine_restart(buffer);
+               kernel_restart(buffer);
                break;
 
+       case LINUX_REBOOT_CMD_KEXEC:
+               kernel_kexec();
+               unlock_kernel();
+               return -EINVAL;
+
 #ifdef CONFIG_SOFTWARE_SUSPEND
        case LINUX_REBOOT_CMD_SW_SUSPEND:
                {
@@ -454,8 +545,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
 
 static void deferred_cad(void *dummy)
 {
-       notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
-       machine_restart(NULL);
+       kernel_restart(NULL);
 }
 
 /*
@@ -524,7 +614,7 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
        }
        if (new_egid != old_egid)
        {
-               current->mm->dumpable = 0;
+               current->mm->dumpable = suid_dumpable;
                smp_wmb();
        }
        if (rgid != (gid_t) -1 ||
@@ -534,6 +624,7 @@ asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
        current->egid = new_egid;
        current->gid = new_rgid;
        key_fsgid_changed(current);
+       proc_id_connector(current, PROC_EVENT_GID);
        return 0;
 }
 
@@ -555,7 +646,7 @@ asmlinkage long sys_setgid(gid_t gid)
        {
                if(old_egid != gid)
                {
-                       current->mm->dumpable=0;
+                       current->mm->dumpable = suid_dumpable;
                        smp_wmb();
                }
                current->gid = current->egid = current->sgid = current->fsgid = gid;
@@ -564,7 +655,7 @@ asmlinkage long sys_setgid(gid_t gid)
        {
                if(old_egid != gid)
                {
-                       current->mm->dumpable=0;
+                       current->mm->dumpable = suid_dumpable;
                        smp_wmb();
                }
                current->egid = current->fsgid = gid;
@@ -573,6 +664,7 @@ asmlinkage long sys_setgid(gid_t gid)
                return -EPERM;
 
        key_fsgid_changed(current);
+       proc_id_connector(current, PROC_EVENT_GID);
        return 0;
 }
   
@@ -595,7 +687,7 @@ static int set_user(uid_t new_ruid, int dumpclear)
 
        if(dumpclear)
        {
-               current->mm->dumpable = 0;
+               current->mm->dumpable = suid_dumpable;
                smp_wmb();
        }
        current->uid = new_ruid;
@@ -652,7 +744,7 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
 
        if (new_euid != old_euid)
        {
-               current->mm->dumpable=0;
+               current->mm->dumpable = suid_dumpable;
                smp_wmb();
        }
        current->fsuid = current->euid = new_euid;
@@ -662,6 +754,7 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
        current->fsuid = current->euid;
 
        key_fsuid_changed(current);
+       proc_id_connector(current, PROC_EVENT_UID);
 
        return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RE);
 }
@@ -702,13 +795,14 @@ asmlinkage long sys_setuid(uid_t uid)
 
        if (old_euid != uid)
        {
-               current->mm->dumpable = 0;
+               current->mm->dumpable = suid_dumpable;
                smp_wmb();
        }
        current->fsuid = current->euid = uid;
        current->suid = new_suid;
 
        key_fsuid_changed(current);
+       proc_id_connector(current, PROC_EVENT_UID);
 
        return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_ID);
 }
@@ -747,7 +841,7 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
        if (euid != (uid_t) -1) {
                if (euid != current->euid)
                {
-                       current->mm->dumpable = 0;
+                       current->mm->dumpable = suid_dumpable;
                        smp_wmb();
                }
                current->euid = euid;
@@ -757,6 +851,7 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
                current->suid = suid;
 
        key_fsuid_changed(current);
+       proc_id_connector(current, PROC_EVENT_UID);
 
        return security_task_post_setuid(old_ruid, old_euid, old_suid, LSM_SETID_RES);
 }
@@ -797,7 +892,7 @@ asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
        if (egid != (gid_t) -1) {
                if (egid != current->egid)
                {
-                       current->mm->dumpable = 0;
+                       current->mm->dumpable = suid_dumpable;
                        smp_wmb();
                }
                current->egid = egid;
@@ -809,6 +904,7 @@ asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
                current->sgid = sgid;
 
        key_fsgid_changed(current);
+       proc_id_connector(current, PROC_EVENT_GID);
        return 0;
 }
 
@@ -844,13 +940,14 @@ asmlinkage long sys_setfsuid(uid_t uid)
        {
                if (uid != old_fsuid)
                {
-                       current->mm->dumpable = 0;
+                       current->mm->dumpable = suid_dumpable;
                        smp_wmb();
                }
                current->fsuid = uid;
        }
 
        key_fsuid_changed(current);
+       proc_id_connector(current, PROC_EVENT_UID);
 
        security_task_post_setuid(old_fsuid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS);
 
@@ -874,11 +971,12 @@ asmlinkage long sys_setfsgid(gid_t gid)
        {
                if (gid != old_fsgid)
                {
-                       current->mm->dumpable = 0;
+                       current->mm->dumpable = suid_dumpable;
                        smp_wmb();
                }
                current->fsgid = gid;
                key_fsgid_changed(current);
+               proc_id_connector(current, PROC_EVENT_GID);
        }
        return old_fsgid;
 }
@@ -893,35 +991,69 @@ asmlinkage long sys_times(struct tms __user * tbuf)
         */
        if (tbuf) {
                struct tms tmp;
-               struct task_struct *tsk = current;
-               struct task_struct *t;
                cputime_t utime, stime, cutime, cstime;
 
-               read_lock(&tasklist_lock);
-               utime = tsk->signal->utime;
-               stime = tsk->signal->stime;
-               t = tsk;
-               do {
-                       utime = cputime_add(utime, t->utime);
-                       stime = cputime_add(stime, t->stime);
-                       t = next_thread(t);
-               } while (t != tsk);
-
-               /*
-                * While we have tasklist_lock read-locked, no dying thread
-                * can be updating current->signal->[us]time.  Instead,
-                * we got their counts included in the live thread loop.
-                * However, another thread can come in right now and
-                * do a wait call that updates current->signal->c[us]time.
-                * To make sure we always see that pair updated atomically,
-                * we take the siglock around fetching them.
-                */
-               spin_lock_irq(&tsk->sighand->siglock);
-               cutime = tsk->signal->cutime;
-               cstime = tsk->signal->cstime;
-               spin_unlock_irq(&tsk->sighand->siglock);
-               read_unlock(&tasklist_lock);
+#ifdef CONFIG_SMP
+               if (thread_group_empty(current)) {
+                       /*
+                        * Single thread case without the use of any locks.
+                        *
+                        * We may race with release_task if two threads are
+                        * executing. However, release task first adds up the
+                        * counters (__exit_signal) before  removing the task
+                        * from the process tasklist (__unhash_process).
+                        * __exit_signal also acquires and releases the
+                        * siglock which results in the proper memory ordering
+                        * so that the list modifications are always visible
+                        * after the counters have been updated.
+                        *
+                        * If the counters have been updated by the second thread
+                        * but the thread has not yet been removed from the list
+                        * then the other branch will be executing which will
+                        * block on tasklist_lock until the exit handling of the
+                        * other task is finished.
+                        *
+                        * This also implies that the sighand->siglock cannot
+                        * be held by another processor. So we can also
+                        * skip acquiring that lock.
+                        */
+                       utime = cputime_add(current->signal->utime, current->utime);
+                       stime = cputime_add(current->signal->utime, current->stime);
+                       cutime = current->signal->cutime;
+                       cstime = current->signal->cstime;
+               } else
+#endif
+               {
+
+                       /* Process with multiple threads */
+                       struct task_struct *tsk = current;
+                       struct task_struct *t;
 
+                       read_lock(&tasklist_lock);
+                       utime = tsk->signal->utime;
+                       stime = tsk->signal->stime;
+                       t = tsk;
+                       do {
+                               utime = cputime_add(utime, t->utime);
+                               stime = cputime_add(stime, t->stime);
+                               t = next_thread(t);
+                       } while (t != tsk);
+
+                       /*
+                        * While we have tasklist_lock read-locked, no dying thread
+                        * can be updating current->signal->[us]time.  Instead,
+                        * we got their counts included in the live thread loop.
+                        * However, another thread can come in right now and
+                        * do a wait call that updates current->signal->c[us]time.
+                        * To make sure we always see that pair updated atomically,
+                        * we take the siglock around fetching them.
+                        */
+                       spin_lock_irq(&tsk->sighand->siglock);
+                       cutime = tsk->signal->cutime;
+                       cstime = tsk->signal->cstime;
+                       spin_unlock_irq(&tsk->sighand->siglock);
+                       read_unlock(&tasklist_lock);
+               }
                tmp.tms_utime = cputime_to_clock_t(utime);
                tmp.tms_stime = cputime_to_clock_t(stime);
                tmp.tms_cutime = cputime_to_clock_t(cutime);
@@ -1194,7 +1326,7 @@ static int groups_from_user(struct group_info *group_info,
        return 0;
 }
 
-/* a simple shell-metzner sort */
+/* a simple Shell sort */
 static void groups_sort(struct group_info *group_info)
 {
        int base, max, stride;
@@ -1224,7 +1356,7 @@ static void groups_sort(struct group_info *group_info)
 }
 
 /* a simple bsearch */
-static int groups_search(struct group_info *group_info, gid_t grp)
+int groups_search(struct group_info *group_info, gid_t grp)
 {
        int left, right;
 
@@ -1628,7 +1760,6 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
                          unsigned long arg4, unsigned long arg5)
 {
        long error;
-       int sig;
 
        error = security_task_prctl(option, arg2, arg3, arg4, arg5);
        if (error)
@@ -1636,22 +1767,20 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
 
        switch (option) {
                case PR_SET_PDEATHSIG:
-                       sig = arg2;
-                       if (sig < 0 || sig > _NSIG) {
+                       if (!valid_signal(arg2)) {
                                error = -EINVAL;
                                break;
                        }
-                       current->pdeath_signal = sig;
+                       current->pdeath_signal = arg2;
                        break;
                case PR_GET_PDEATHSIG:
                        error = put_user(current->pdeath_signal, (int __user *)arg2);
                        break;
                case PR_GET_DUMPABLE:
-                       if (current->mm->dumpable)
-                               error = 1;
+                       error = current->mm->dumpable;
                        break;
                case PR_SET_DUMPABLE:
-                       if (arg2 != 0 && arg2 != 1) {
+                       if (arg2 < 0 || arg2 > 2) {
                                error = -EINVAL;
                                break;
                        }