Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[safe/jmp/linux-2.6] / kernel / sys.c
index 22ea955..7cb426a 100644 (file)
 #include <linux/task_io_accounting_ops.h>
 #include <linux/seccomp.h>
 #include <linux/cpu.h>
+#include <linux/personality.h>
 #include <linux/ptrace.h>
 #include <linux/fs_struct.h>
+#include <linux/gfp.h>
 
 #include <linux/compat.h>
 #include <linux/syscalls.h>
@@ -162,6 +164,7 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
        if (niceval > 19)
                niceval = 19;
 
+       rcu_read_lock();
        read_lock(&tasklist_lock);
        switch (which) {
                case PRIO_PROCESS:
@@ -189,16 +192,17 @@ SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
                                 !(user = find_user(who)))
                                goto out_unlock;        /* No processes for this user */
 
-                       do_each_thread(g, p)
+                       do_each_thread(g, p) {
                                if (__task_cred(p)->uid == who)
                                        error = set_one_prio(p, niceval, error);
-                       while_each_thread(g, p);
+                       while_each_thread(g, p);
                        if (who != cred->uid)
                                free_uid(user);         /* For find_user() */
                        break;
        }
 out_unlock:
        read_unlock(&tasklist_lock);
+       rcu_read_unlock();
 out:
        return error;
 }
@@ -220,6 +224,7 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
        if (which > PRIO_USER || which < PRIO_PROCESS)
                return -EINVAL;
 
+       rcu_read_lock();
        read_lock(&tasklist_lock);
        switch (which) {
                case PRIO_PROCESS:
@@ -252,19 +257,20 @@ SYSCALL_DEFINE2(getpriority, int, which, int, who)
                                 !(user = find_user(who)))
                                goto out_unlock;        /* No processes for this user */
 
-                       do_each_thread(g, p)
+                       do_each_thread(g, p) {
                                if (__task_cred(p)->uid == who) {
                                        niceval = 20 - task_nice(p);
                                        if (niceval > retval)
                                                retval = niceval;
                                }
-                       while_each_thread(g, p);
+                       while_each_thread(g, p);
                        if (who != cred->uid)
                                free_uid(user);         /* for find_user() */
                        break;
        }
 out_unlock:
        read_unlock(&tasklist_lock);
+       rcu_read_unlock();
 
        return retval;
 }
@@ -567,13 +573,7 @@ static int set_user(struct cred *new)
        if (!new_user)
                return -EAGAIN;
 
-       if (!task_can_switch_user(new_user, current)) {
-               free_uid(new_user);
-               return -EINVAL;
-       }
-
-       if (atomic_read(&new_user->processes) >=
-                               current->signal->rlim[RLIMIT_NPROC].rlim_cur &&
+       if (atomic_read(&new_user->processes) >= rlimit(RLIMIT_NPROC) &&
                        new_user != INIT_USER) {
                free_uid(new_user);
                return -EAGAIN;
@@ -911,16 +911,15 @@ change_okay:
 
 void do_sys_times(struct tms *tms)
 {
-       struct task_cputime cputime;
-       cputime_t cutime, cstime;
+       cputime_t tgutime, tgstime, cutime, cstime;
 
-       thread_group_cputime(current, &cputime);
        spin_lock_irq(&current->sighand->siglock);
+       thread_group_times(current, &tgutime, &tgstime);
        cutime = current->signal->cutime;
        cstime = current->signal->cstime;
        spin_unlock_irq(&current->sighand->siglock);
-       tms->tms_utime = cputime_to_clock_t(cputime.utime);
-       tms->tms_stime = cputime_to_clock_t(cputime.stime);
+       tms->tms_utime = cputime_to_clock_t(tgutime);
+       tms->tms_stime = cputime_to_clock_t(tgstime);
        tms->tms_cutime = cputime_to_clock_t(cutime);
        tms->tms_cstime = cputime_to_clock_t(cstime);
 }
@@ -1110,11 +1109,22 @@ SYSCALL_DEFINE0(setsid)
        err = session;
 out:
        write_unlock_irq(&tasklist_lock);
+       if (err > 0)
+               proc_sid_connector(group_leader);
        return err;
 }
 
 DECLARE_RWSEM(uts_sem);
 
+#ifdef COMPAT_UTS_MACHINE
+#define override_architecture(name) \
+       (personality(current->personality) == PER_LINUX32 && \
+        copy_to_user(name->machine, COMPAT_UTS_MACHINE, \
+                     sizeof(COMPAT_UTS_MACHINE)))
+#else
+#define override_architecture(name)    0
+#endif
+
 SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
 {
        int errno = 0;
@@ -1123,9 +1133,66 @@ SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
        if (copy_to_user(name, utsname(), sizeof *name))
                errno = -EFAULT;
        up_read(&uts_sem);
+
+       if (!errno && override_architecture(name))
+               errno = -EFAULT;
        return errno;
 }
 
+#ifdef __ARCH_WANT_SYS_OLD_UNAME
+/*
+ * Old cruft
+ */
+SYSCALL_DEFINE1(uname, struct old_utsname __user *, name)
+{
+       int error = 0;
+
+       if (!name)
+               return -EFAULT;
+
+       down_read(&uts_sem);
+       if (copy_to_user(name, utsname(), sizeof(*name)))
+               error = -EFAULT;
+       up_read(&uts_sem);
+
+       if (!error && override_architecture(name))
+               error = -EFAULT;
+       return error;
+}
+
+SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name)
+{
+       int error;
+
+       if (!name)
+               return -EFAULT;
+       if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname)))
+               return -EFAULT;
+
+       down_read(&uts_sem);
+       error = __copy_to_user(&name->sysname, &utsname()->sysname,
+                              __OLD_UTS_LEN);
+       error |= __put_user(0, name->sysname + __OLD_UTS_LEN);
+       error |= __copy_to_user(&name->nodename, &utsname()->nodename,
+                               __OLD_UTS_LEN);
+       error |= __put_user(0, name->nodename + __OLD_UTS_LEN);
+       error |= __copy_to_user(&name->release, &utsname()->release,
+                               __OLD_UTS_LEN);
+       error |= __put_user(0, name->release + __OLD_UTS_LEN);
+       error |= __copy_to_user(&name->version, &utsname()->version,
+                               __OLD_UTS_LEN);
+       error |= __put_user(0, name->version + __OLD_UTS_LEN);
+       error |= __copy_to_user(&name->machine, &utsname()->machine,
+                               __OLD_UTS_LEN);
+       error |= __put_user(0, name->machine + __OLD_UTS_LEN);
+       up_read(&uts_sem);
+
+       if (!error && override_architecture(name))
+               error = -EFAULT;
+       return error ? -EFAULT : 0;
+}
+#endif
+
 SYSCALL_DEFINE2(sethostname, char __user *, name, int, len)
 {
        int errno;
@@ -1336,16 +1403,14 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
 {
        struct task_struct *t;
        unsigned long flags;
-       cputime_t utime, stime;
-       struct task_cputime cputime;
+       cputime_t tgutime, tgstime, utime, stime;
        unsigned long maxrss = 0;
 
        memset((char *) r, 0, sizeof *r);
        utime = stime = cputime_zero;
 
        if (who == RUSAGE_THREAD) {
-               utime = task_utime(current);
-               stime = task_stime(current);
+               task_times(current, &utime, &stime);
                accumulate_thread_rusage(p, r);
                maxrss = p->signal->maxrss;
                goto out;
@@ -1371,9 +1436,9 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
                                break;
 
                case RUSAGE_SELF:
-                       thread_group_cputime(p, &cputime);
-                       utime = cputime_add(utime, cputime.utime);
-                       stime = cputime_add(stime, cputime.stime);
+                       thread_group_times(p, &tgutime, &tgstime);
+                       utime = cputime_add(utime, tgutime);
+                       stime = cputime_add(stime, tgstime);
                        r->ru_nvcsw += p->signal->nvcsw;
                        r->ru_nivcsw += p->signal->nivcsw;
                        r->ru_minflt += p->signal->min_flt;
@@ -1546,24 +1611,37 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
                        if (arg4 | arg5)
                                return -EINVAL;
                        switch (arg2) {
-                       case 0:
+                       case PR_MCE_KILL_CLEAR:
                                if (arg3 != 0)
                                        return -EINVAL;
                                current->flags &= ~PF_MCE_PROCESS;
                                break;
-                       case 1:
+                       case PR_MCE_KILL_SET:
                                current->flags |= PF_MCE_PROCESS;
-                               if (arg3 != 0)
+                               if (arg3 == PR_MCE_KILL_EARLY)
                                        current->flags |= PF_MCE_EARLY;
-                               else
+                               else if (arg3 == PR_MCE_KILL_LATE)
                                        current->flags &= ~PF_MCE_EARLY;
+                               else if (arg3 == PR_MCE_KILL_DEFAULT)
+                                       current->flags &=
+                                               ~(PF_MCE_EARLY|PF_MCE_PROCESS);
+                               else
+                                       return -EINVAL;
                                break;
                        default:
                                return -EINVAL;
                        }
                        error = 0;
                        break;
-
+               case PR_MCE_KILL_GET:
+                       if (arg2 | arg3 | arg4 | arg5)
+                               return -EINVAL;
+                       if (current->flags & PF_MCE_PROCESS)
+                               error = (current->flags & PF_MCE_EARLY) ?
+                                       PR_MCE_KILL_EARLY : PR_MCE_KILL_LATE;
+                       else
+                               error = PR_MCE_KILL_DEFAULT;
+                       break;
                default:
                        error = -EINVAL;
                        break;