nfsd: track last inode only in use_wgather case
[safe/jmp/linux-2.6] / kernel / sys.c
index 4c33555..e7998cf 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/seccomp.h>
 #include <linux/cpu.h>
 #include <linux/ptrace.h>
+#include <linux/fs_struct.h>
 
 #include <linux/compat.h>
 #include <linux/syscalls.h>
@@ -143,7 +144,7 @@ out:
        return error;
 }
 
-asmlinkage long sys_setpriority(int which, int who, int niceval)
+SYSCALL_DEFINE3(setpriority, int, which, int, who, int, niceval)
 {
        struct task_struct *g, *p;
        struct user_struct *user;
@@ -208,7 +209,7 @@ out:
  * has been offset by 20 (ie it returns 40..1 instead of -20..19)
  * to stay compatible.
  */
-asmlinkage long sys_getpriority(int which, int who)
+SYSCALL_DEFINE2(getpriority, int, which, int, who)
 {
        struct task_struct *g, *p;
        struct user_struct *user;
@@ -355,9 +356,11 @@ EXPORT_SYMBOL_GPL(kernel_power_off);
  *
  * reboot doesn't sync: do that yourself before calling this.
  */
-asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user * arg)
+SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
+               void __user *, arg)
 {
        char buffer[256];
+       int ret = 0;
 
        /* We only trust the superuser with rebooting the system. */
        if (!capable(CAP_SYS_BOOT))
@@ -395,7 +398,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
                kernel_halt();
                unlock_kernel();
                do_exit(0);
-               break;
+               panic("cannot halt");
 
        case LINUX_REBOOT_CMD_POWER_OFF:
                kernel_power_off();
@@ -415,29 +418,22 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
 
 #ifdef CONFIG_KEXEC
        case LINUX_REBOOT_CMD_KEXEC:
-               {
-                       int ret;
-                       ret = kernel_kexec();
-                       unlock_kernel();
-                       return ret;
-               }
+               ret = kernel_kexec();
+               break;
 #endif
 
 #ifdef CONFIG_HIBERNATION
        case LINUX_REBOOT_CMD_SW_SUSPEND:
-               {
-                       int ret = hibernate();
-                       unlock_kernel();
-                       return ret;
-               }
+               ret = hibernate();
+               break;
 #endif
 
        default:
-               unlock_kernel();
-               return -EINVAL;
+               ret = -EINVAL;
+               break;
        }
        unlock_kernel();
-       return 0;
+       return ret;
 }
 
 static void deferred_cad(struct work_struct *dummy)
@@ -478,7 +474,7 @@ void ctrl_alt_del(void)
  * SMP: There are not races, the GIDs are checked only by filesystem
  *      operations (as far as semantic preservation is concerned).
  */
-asmlinkage long sys_setregid(gid_t rgid, gid_t egid)
+SYSCALL_DEFINE2(setregid, gid_t, rgid, gid_t, egid)
 {
        const struct cred *old;
        struct cred *new;
@@ -529,7 +525,7 @@ error:
  *
  * SMP: Same implicit races as above.
  */
-asmlinkage long sys_setgid(gid_t gid)
+SYSCALL_DEFINE1(setgid, gid_t, gid)
 {
        const struct cred *old;
        struct cred *new;
@@ -558,7 +554,7 @@ error:
        abort_creds(new);
        return retval;
 }
-  
+
 /*
  * change the user struct in a credentials set to match the new UID
  */
@@ -570,6 +566,11 @@ 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 &&
                        new_user != INIT_USER) {
@@ -597,7 +598,7 @@ static int set_user(struct cred *new)
  * 100% compatible with BSD.  A program which uses just setuid() will be
  * 100% compatible with POSIX with saved IDs. 
  */
-asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
+SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
 {
        const struct cred *old;
        struct cred *new;
@@ -630,10 +631,11 @@ asmlinkage long sys_setreuid(uid_t ruid, uid_t euid)
                        goto error;
        }
 
-       retval = -EAGAIN;
-       if (new->uid != old->uid && set_user(new) < 0)
-               goto error;
-
+       if (new->uid != old->uid) {
+               retval = set_user(new);
+               if (retval < 0)
+                       goto error;
+       }
        if (ruid != (uid_t) -1 ||
            (euid != (uid_t) -1 && euid != old->uid))
                new->suid = new->euid;
@@ -661,7 +663,7 @@ error:
  * will allow a root program to temporarily drop privileges and be able to
  * regain them by swapping the real and effective uid.  
  */
-asmlinkage long sys_setuid(uid_t uid)
+SYSCALL_DEFINE1(setuid, uid_t, uid)
 {
        const struct cred *old;
        struct cred *new;
@@ -679,9 +681,10 @@ asmlinkage long sys_setuid(uid_t uid)
        retval = -EPERM;
        if (capable(CAP_SETUID)) {
                new->suid = new->uid = uid;
-               if (uid != old->uid && set_user(new) < 0) {
-                       retval = -EAGAIN;
-                       goto error;
+               if (uid != old->uid) {
+                       retval = set_user(new);
+                       if (retval < 0)
+                               goto error;
                }
        } else if (uid != old->uid && uid != new->suid) {
                goto error;
@@ -705,7 +708,7 @@ error:
  * This function implements a generic ability to update ruid, euid,
  * and suid.  This allows you to implement the 4.4 compatible seteuid().
  */
-asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
+SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
 {
        const struct cred *old;
        struct cred *new;
@@ -733,11 +736,13 @@ asmlinkage long sys_setresuid(uid_t ruid, uid_t euid, uid_t suid)
                        goto error;
        }
 
-       retval = -EAGAIN;
        if (ruid != (uid_t) -1) {
                new->uid = ruid;
-               if (ruid != old->uid && set_user(new) < 0)
-                       goto error;
+               if (ruid != old->uid) {
+                       retval = set_user(new);
+                       if (retval < 0)
+                               goto error;
+               }
        }
        if (euid != (uid_t) -1)
                new->euid = euid;
@@ -771,7 +776,7 @@ SYSCALL_DEFINE3(getresuid, uid_t __user *, ruid, uid_t __user *, euid, uid_t __u
 /*
  * Same as above, but for rgid, egid, sgid.
  */
-asmlinkage long sys_setresgid(gid_t rgid, gid_t egid, gid_t sgid)
+SYSCALL_DEFINE3(setresgid, gid_t, rgid, gid_t, egid, gid_t, sgid)
 {
        const struct cred *old;
        struct cred *new;
@@ -833,7 +838,7 @@ SYSCALL_DEFINE3(getresgid, gid_t __user *, rgid, gid_t __user *, egid, gid_t __u
  * whatever uid it wants to). It normally shadows "euid", except when
  * explicitly set by setfsuid() or for access..
  */
-asmlinkage long sys_setfsuid(uid_t uid)
+SYSCALL_DEFINE1(setfsuid, uid_t, uid)
 {
        const struct cred *old;
        struct cred *new;
@@ -870,7 +875,7 @@ change_okay:
 /*
  * Samma på svenska..
  */
-asmlinkage long sys_setfsgid(gid_t gid)
+SYSCALL_DEFINE1(setfsgid, gid_t, gid)
 {
        const struct cred *old;
        struct cred *new;
@@ -944,7 +949,7 @@ SYSCALL_DEFINE1(times, struct tms __user *, tbuf)
  * Auch. Had to add the 'did_exec' flag to conform completely to POSIX.
  * LBT 04.03.94
  */
-asmlinkage long sys_setpgid(pid_t pid, pid_t pgid)
+SYSCALL_DEFINE2(setpgid, pid_t, pid, pid_t, pgid)
 {
        struct task_struct *p;
        struct task_struct *group_leader = current->group_leader;
@@ -1003,10 +1008,8 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid)
        if (err)
                goto out;
 
-       if (task_pgrp(p) != pgrp) {
+       if (task_pgrp(p) != pgrp)
                change_pid(p, PIDTYPE_PGID, pgrp);
-               set_task_pgrp(p, pid_nr(pgrp));
-       }
 
        err = 0;
 out:
@@ -1080,7 +1083,7 @@ out:
        return retval;
 }
 
-asmlinkage long sys_setsid(void)
+SYSCALL_DEFINE0(setsid)
 {
        struct task_struct *group_leader = current->group_leader;
        struct pid *sid = task_pid(group_leader);
@@ -1311,7 +1314,7 @@ int set_current_groups(struct group_info *group_info)
 
 EXPORT_SYMBOL(set_current_groups);
 
-asmlinkage long sys_getgroups(int gidsetsize, gid_t __user *grouplist)
+SYSCALL_DEFINE2(getgroups, int, gidsetsize, gid_t __user *, grouplist)
 {
        const struct cred *cred = current_cred();
        int i;
@@ -1340,7 +1343,7 @@ out:
  *     without another task interfering.
  */
  
-asmlinkage long sys_setgroups(int gidsetsize, gid_t __user *grouplist)
+SYSCALL_DEFINE2(setgroups, int, gidsetsize, gid_t __user *, grouplist)
 {
        struct group_info *group_info;
        int retval;
@@ -1394,7 +1397,7 @@ EXPORT_SYMBOL(in_egroup_p);
 
 DECLARE_RWSEM(uts_sem);
 
-asmlinkage long sys_newuname(struct new_utsname __user * name)
+SYSCALL_DEFINE1(newuname, struct new_utsname __user *, name)
 {
        int errno = 0;
 
@@ -1405,7 +1408,7 @@ asmlinkage long sys_newuname(struct new_utsname __user * name)
        return errno;
 }
 
-asmlinkage long sys_sethostname(char __user *name, int len)
+SYSCALL_DEFINE2(sethostname, char __user *, name, int, len)
 {
        int errno;
        char tmp[__NEW_UTS_LEN];
@@ -1429,7 +1432,7 @@ asmlinkage long sys_sethostname(char __user *name, int len)
 
 #ifdef __ARCH_WANT_SYS_GETHOSTNAME
 
-asmlinkage long sys_gethostname(char __user *name, int len)
+SYSCALL_DEFINE2(gethostname, char __user *, name, int, len)
 {
        int i, errno;
        struct new_utsname *u;
@@ -1454,7 +1457,7 @@ asmlinkage long sys_gethostname(char __user *name, int len)
  * Only setdomainname; getdomainname can be implemented by calling
  * uname()
  */
-asmlinkage long sys_setdomainname(char __user *name, int len)
+SYSCALL_DEFINE2(setdomainname, char __user *, name, int, len)
 {
        int errno;
        char tmp[__NEW_UTS_LEN];
@@ -1477,7 +1480,7 @@ asmlinkage long sys_setdomainname(char __user *name, int len)
        return errno;
 }
 
-asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit __user *rlim)
+SYSCALL_DEFINE2(getrlimit, unsigned int, resource, struct rlimit __user *, rlim)
 {
        if (resource >= RLIM_NLIMITS)
                return -EINVAL;
@@ -1496,7 +1499,8 @@ asmlinkage long sys_getrlimit(unsigned int resource, struct rlimit __user *rlim)
  *     Back compatibility for getrlimit. Needed for some apps.
  */
  
-asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit __user *rlim)
+SYSCALL_DEFINE2(old_getrlimit, unsigned int, resource,
+               struct rlimit __user *, rlim)
 {
        struct rlimit x;
        if (resource >= RLIM_NLIMITS)
@@ -1514,7 +1518,7 @@ asmlinkage long sys_old_getrlimit(unsigned int resource, struct rlimit __user *r
 
 #endif
 
-asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim)
+SYSCALL_DEFINE2(setrlimit, unsigned int, resource, struct rlimit __user *, rlim)
 {
        struct rlimit new_rlim, *old_rlim;
        int retval;
@@ -1523,22 +1527,14 @@ asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim)
                return -EINVAL;
        if (copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
                return -EFAULT;
+       if (new_rlim.rlim_cur > new_rlim.rlim_max)
+               return -EINVAL;
        old_rlim = current->signal->rlim + resource;
        if ((new_rlim.rlim_max > old_rlim->rlim_max) &&
            !capable(CAP_SYS_RESOURCE))
                return -EPERM;
-
-       if (resource == RLIMIT_NOFILE) {
-               if (new_rlim.rlim_max == RLIM_INFINITY)
-                       new_rlim.rlim_max = sysctl_nr_open;
-               if (new_rlim.rlim_cur == RLIM_INFINITY)
-                       new_rlim.rlim_cur = sysctl_nr_open;
-               if (new_rlim.rlim_max > sysctl_nr_open)
-                       return -EPERM;
-       }
-
-       if (new_rlim.rlim_cur > new_rlim.rlim_max)
-               return -EINVAL;
+       if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > sysctl_nr_open)
+               return -EPERM;
 
        retval = security_task_setrlimit(resource, &new_rlim);
        if (retval)
@@ -1687,7 +1683,7 @@ int getrusage(struct task_struct *p, int who, struct rusage __user *ru)
        return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0;
 }
 
-asmlinkage long sys_getrusage(int who, struct rusage __user *ru)
+SYSCALL_DEFINE2(getrusage, int, who, struct rusage __user *, ru)
 {
        if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN &&
            who != RUSAGE_THREAD)
@@ -1695,14 +1691,14 @@ asmlinkage long sys_getrusage(int who, struct rusage __user *ru)
        return getrusage(current, who, ru);
 }
 
-asmlinkage long sys_umask(int mask)
+SYSCALL_DEFINE1(umask, int, mask)
 {
        mask = xchg(&current->fs->umask, mask & S_IRWXUGO);
        return mask;
 }
 
-asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
-                         unsigned long arg4, unsigned long arg5)
+SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
+               unsigned long, arg4, unsigned long, arg5)
 {
        struct task_struct *me = current;
        unsigned char comm[sizeof(me->comm)];
@@ -1815,8 +1811,8 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3,
        return error;
 }
 
-asmlinkage long sys_getcpu(unsigned __user *cpup, unsigned __user *nodep,
-                          struct getcpu_cache __user *unused)
+SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep,
+               struct getcpu_cache __user *, unused)
 {
        int err = 0;
        int cpu = raw_smp_processor_id();