summaryrefslogtreecommitdiffstats
path: root/kernel/sys.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-04-29 21:13:14 +0000
committer <ralf@linux-mips.org>1997-04-29 21:13:14 +0000
commit19c9bba94152148523ba0f7ef7cffe3d45656b11 (patch)
tree40b1cb534496a7f1ca0f5c314a523c69f1fee464 /kernel/sys.c
parent7206675c40394c78a90e74812bbdbf8cf3cca1be (diff)
Import of Linux/MIPS 2.1.36
Diffstat (limited to 'kernel/sys.c')
-rw-r--r--kernel/sys.c491
1 files changed, 314 insertions, 177 deletions
diff --git a/kernel/sys.c b/kernel/sys.c
index 8fcaba2de..934108fa8 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -4,7 +4,6 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -21,9 +20,10 @@
#include <linux/fcntl.h>
#include <linux/acct.h>
#include <linux/tty.h>
-#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
-#include <linux/apm_bios.h>
-#endif
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -31,8 +31,30 @@
/*
* this indicates whether you can reboot with ctrl-alt-del: the default is yes
*/
+
int C_A_D = 1;
+
+/*
+ * Notifier list for kernel code which wants to be called
+ * at shutdown. This is used to stop any idling DMA operations
+ * and the like.
+ */
+
+struct notifier_block *reboot_notifier_list = NULL;
+
+int register_reboot_notifier(struct notifier_block * nb)
+{
+ return notifier_chain_register(&reboot_notifier_list, nb);
+}
+
+int unregister_reboot_notifier(struct notifier_block * nb)
+{
+ return notifier_chain_unregister(&reboot_notifier_list, nb);
+}
+
+
+
extern void adjust_clock(void);
asmlinkage int sys_ni_syscall(void)
@@ -65,13 +87,14 @@ static int proc_sel(struct task_struct *p, int which, int who)
asmlinkage int sys_setpriority(int which, int who, int niceval)
{
struct task_struct *p;
- int error = ESRCH;
unsigned int priority;
+ int error;
if (which > 2 || which < 0)
return -EINVAL;
/* normalize: avoid signed division (rounding problems) */
+ error = ESRCH;
priority = niceval;
if (niceval < 0)
priority = -niceval;
@@ -85,6 +108,7 @@ asmlinkage int sys_setpriority(int which, int who, int niceval)
priority = 1;
}
+ read_lock(&tasklist_lock);
for_each_task(p) {
if (!proc_sel(p, which, who))
continue;
@@ -100,6 +124,8 @@ asmlinkage int sys_setpriority(int which, int who, int niceval)
else
p->priority = priority;
}
+ read_unlock(&tasklist_lock);
+
return -error;
}
@@ -116,12 +142,14 @@ asmlinkage int sys_getpriority(int which, int who)
if (which > 2 || which < 0)
return -EINVAL;
+ read_lock(&tasklist_lock);
for_each_task (p) {
if (!proc_sel(p, which, who))
continue;
if (p->priority > max_prio)
max_prio = p->priority;
}
+ read_unlock(&tasklist_lock);
/* scale the priority from timeslice to 0..40 */
if (max_prio > 0)
@@ -169,7 +197,7 @@ asmlinkage int sys_prof(void)
#endif
-extern asmlinkage sys_kill(int, int);
+extern asmlinkage int sys_kill(int, int);
/*
* Reboot system call: for obvious reasons only root may call it,
@@ -178,29 +206,70 @@ extern asmlinkage sys_kill(int, int);
* You can also set the meaning of the ctrl-alt-del-key here.
*
* reboot doesn't sync: do that yourself before calling this.
+ *
*/
-asmlinkage int sys_reboot(int magic, int magic_too, int flag)
+asmlinkage int sys_reboot(int magic1, int magic2, int cmd, void * arg)
{
+ char buffer[256];
+
+ /* We only trust the superuser with rebooting the system. */
if (!suser())
return -EPERM;
- if (magic != 0xfee1dead || magic_too != 672274793)
+
+ /* For safety, we require "magic" arguments. */
+ if (magic1 != LINUX_REBOOT_MAGIC1 ||
+ (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A))
return -EINVAL;
- if (flag == 0x01234567)
- hard_reset_now();
- else if (flag == 0x89ABCDEF)
+
+ lock_kernel();
+ switch (cmd) {
+ case LINUX_REBOOT_CMD_RESTART:
+ notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
+ printk(KERN_EMERG "Restarting system.\n");
+ machine_restart(NULL);
+ break;
+
+ case LINUX_REBOOT_CMD_CAD_ON:
C_A_D = 1;
- else if (!flag)
+ break;
+
+ case LINUX_REBOOT_CMD_CAD_OFF:
C_A_D = 0;
- else if (flag == 0xCDEF0123) {
- printk(KERN_EMERG "System halted\n");
- sys_kill(-1, SIGKILL);
-#if defined(CONFIG_APM) && defined(CONFIG_APM_POWER_OFF)
- apm_set_power_state(APM_STATE_OFF);
-#endif
+ break;
+
+ case LINUX_REBOOT_CMD_HALT:
+ notifier_call_chain(&reboot_notifier_list, SYS_HALT, NULL);
+ printk(KERN_EMERG "System halted.\n");
+ machine_halt();
do_exit(0);
- } else
+ break;
+
+ case LINUX_REBOOT_CMD_POWER_OFF:
+ notifier_call_chain(&reboot_notifier_list, SYS_POWER_OFF, NULL);
+ printk(KERN_EMERG "Power down.\n");
+ machine_power_off();
+ do_exit(0);
+ break;
+
+ case LINUX_REBOOT_CMD_RESTART2:
+ if (strncpy_from_user(&buffer[0], (char *)arg, sizeof(buffer) - 1) < 0) {
+ unlock_kernel();
+ return -EFAULT;
+ }
+ buffer[sizeof(buffer) - 1] = '\0';
+
+ notifier_call_chain(&reboot_notifier_list, SYS_RESTART, buffer);
+ printk(KERN_EMERG "Restarting system with command '%s'.\n", buffer);
+ machine_restart(buffer);
+ break;
+
+ default:
+ unlock_kernel();
return -EINVAL;
- return (0);
+ break;
+ };
+ unlock_kernel();
+ return 0;
}
/*
@@ -210,9 +279,10 @@ asmlinkage int sys_reboot(int magic, int magic_too, int flag)
*/
void ctrl_alt_del(void)
{
- if (C_A_D)
- hard_reset_now();
- else
+ if (C_A_D) {
+ notifier_call_chain(&reboot_notifier_list, SYS_RESTART, NULL);
+ machine_restart(NULL);
+ } else
kill_proc(1, SIGINT, 1);
}
@@ -231,6 +301,9 @@ void ctrl_alt_del(void)
* The general idea is that a program which uses just setregid() will be
* 100% compatible with BSD. A program which uses just setgid() will be
* 100% compatible with POSIX w/ Saved ID's.
+ *
+ * SMP: There are not races, the gid's are checked only by filesystem
+ * operations (as far as semantic preservation is concerned).
*/
asmlinkage int sys_setregid(gid_t rgid, gid_t egid)
{
@@ -243,7 +316,7 @@ asmlinkage int sys_setregid(gid_t rgid, gid_t egid)
suser())
current->gid = rgid;
else
- return(-EPERM);
+ return -EPERM;
}
if (egid != (gid_t) -1) {
if ((old_rgid == egid) ||
@@ -253,7 +326,7 @@ asmlinkage int sys_setregid(gid_t rgid, gid_t egid)
current->fsgid = current->egid = egid;
else {
current->gid = old_rgid;
- return(-EPERM);
+ return -EPERM;
}
}
if (rgid != (gid_t) -1 ||
@@ -267,6 +340,8 @@ asmlinkage int sys_setregid(gid_t rgid, gid_t egid)
/*
* setgid() is implemented like SysV w/ SAVED_IDS
+ *
+ * SMP: Same implicit races as above.
*/
asmlinkage int sys_setgid(gid_t gid)
{
@@ -278,6 +353,7 @@ asmlinkage int sys_setgid(gid_t gid)
current->egid = current->fsgid = gid;
else
return -EPERM;
+
if (current->egid != old_egid)
current->dumpable = 0;
return 0;
@@ -329,66 +405,70 @@ int acct_process(long exitcode)
asmlinkage int sys_acct(const char *name)
{
- struct inode *inode = (struct inode *)0;
- char *tmp;
- int error;
-
- if (!suser())
- return -EPERM;
-
- if (name == (char *)0) {
- if (acct_active) {
- if (acct_file.f_op->release)
- acct_file.f_op->release(acct_file.f_inode, &acct_file);
-
- if (acct_file.f_inode != (struct inode *) 0)
- iput(acct_file.f_inode);
-
- acct_active = 0;
- }
- return 0;
- } else {
- if (!acct_active) {
-
- if ((error = getname(name, &tmp)) != 0)
- return (error);
-
- error = open_namei(tmp, O_RDWR, 0600, &inode, 0);
- putname(tmp);
-
- if (error)
- return (error);
-
- if (!S_ISREG(inode->i_mode)) {
- iput(inode);
- return -EACCES;
- }
-
- if (!inode->i_op || !inode->i_op->default_file_ops ||
- !inode->i_op->default_file_ops->write) {
- iput(inode);
- return -EIO;
- }
-
- acct_file.f_mode = 3;
- acct_file.f_flags = 0;
- acct_file.f_count = 1;
- acct_file.f_inode = inode;
- acct_file.f_pos = inode->i_size;
- acct_file.f_reada = 0;
- acct_file.f_op = inode->i_op->default_file_ops;
-
- if (acct_file.f_op->open)
- if (acct_file.f_op->open(acct_file.f_inode, &acct_file)) {
- iput(inode);
- return -EIO;
- }
-
- acct_active = 1;
- return 0;
- } else
- return -EBUSY;
- }
+ struct inode *inode = (struct inode *)0;
+ char *tmp;
+ int error = -EPERM;
+
+ lock_kernel();
+ if (!suser())
+ goto out;
+
+ if (name == (char *)0) {
+ if (acct_active) {
+ if (acct_file.f_op->release)
+ acct_file.f_op->release(acct_file.f_inode, &acct_file);
+
+ if (acct_file.f_inode != (struct inode *) 0)
+ iput(acct_file.f_inode);
+
+ acct_active = 0;
+ }
+ error = 0;
+ } else {
+ error = -EBUSY;
+ if (!acct_active) {
+ if ((error = getname(name, &tmp)) != 0)
+ goto out;
+
+ error = open_namei(tmp, O_RDWR, 0600, &inode, 0);
+ putname(tmp);
+ if (error)
+ goto out;
+
+ error = -EACCES;
+ if (!S_ISREG(inode->i_mode)) {
+ iput(inode);
+ goto out;
+ }
+
+ error = -EIO;
+ if (!inode->i_op || !inode->i_op->default_file_ops ||
+ !inode->i_op->default_file_ops->write) {
+ iput(inode);
+ goto out;
+ }
+
+ acct_file.f_mode = 3;
+ acct_file.f_flags = 0;
+ acct_file.f_count = 1;
+ acct_file.f_inode = inode;
+ acct_file.f_pos = inode->i_size;
+ acct_file.f_reada = 0;
+ acct_file.f_op = inode->i_op->default_file_ops;
+
+ if(acct_file.f_op->open)
+ if(acct_file.f_op->open(acct_file.f_inode, &acct_file)) {
+ iput(inode);
+ goto out;
+ }
+
+ acct_active = 1;
+ error = 0;
+ }
+ }
+out:
+ unlock_kernel();
+ return error;
}
#ifndef __alpha__
@@ -443,16 +523,18 @@ asmlinkage int sys_old_syscall(void)
*/
asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
{
- int old_ruid = current->uid;
- int old_euid = current->euid;
+ int old_ruid;
+ int old_euid;
+ old_ruid = current->uid;
+ old_euid = current->euid;
if (ruid != (uid_t) -1) {
if ((old_ruid == ruid) ||
(current->euid==ruid) ||
suser())
current->uid = ruid;
else
- return(-EPERM);
+ return -EPERM;
}
if (euid != (uid_t) -1) {
if ((old_ruid == euid) ||
@@ -462,7 +544,7 @@ asmlinkage int sys_setreuid(uid_t ruid, uid_t euid)
current->fsuid = current->euid = euid;
else {
current->uid = old_ruid;
- return(-EPERM);
+ return -EPERM;
}
}
if (ruid != (uid_t) -1 ||
@@ -495,9 +577,10 @@ asmlinkage int sys_setuid(uid_t uid)
current->fsuid = current->euid = uid;
else
return -EPERM;
+
if (current->euid != old_euid)
current->dumpable = 0;
- return(0);
+ return 0;
}
@@ -538,6 +621,7 @@ asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
if (!(retval = put_user(current->uid, ruid)) &&
!(retval = put_user(current->euid, euid)))
retval = put_user(current->suid, suid);
+
return retval;
}
@@ -550,13 +634,15 @@ asmlinkage int sys_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid)
*/
asmlinkage int sys_setfsuid(uid_t uid)
{
- int old_fsuid = current->fsuid;
+ int old_fsuid;
+ old_fsuid = current->fsuid;
if (uid == current->uid || uid == current->euid ||
uid == current->suid || uid == current->fsuid || suser())
current->fsuid = uid;
if (current->fsuid != old_fsuid)
current->dumpable = 0;
+
return old_fsuid;
}
@@ -565,29 +651,35 @@ asmlinkage int sys_setfsuid(uid_t uid)
*/
asmlinkage int sys_setfsgid(gid_t gid)
{
- int old_fsgid = current->fsgid;
+ int old_fsgid;
+ old_fsgid = current->fsgid;
if (gid == current->gid || gid == current->egid ||
gid == current->sgid || gid == current->fsgid || suser())
current->fsgid = gid;
if (current->fsgid != old_fsgid)
current->dumpable = 0;
+
return old_fsgid;
}
asmlinkage long sys_times(struct tms * tbuf)
{
- int error;
- if (tbuf) {
- error = put_user(current->utime,&tbuf->tms_utime);
- if (!error)
- error = put_user(current->stime,&tbuf->tms_stime);
- if (!error)
- error = put_user(current->cutime,&tbuf->tms_cutime);
- if (!error)
- error = put_user(current->cstime,&tbuf->tms_cstime);
- if (error)
- return error;
+ /*
+ * In the SMP world we might just be unlucky and have one of
+ * the times increment as we use it. Since the value is an
+ * atomically safe type this is just fine. Conceptually its
+ * as if the syscall took an instant longer to occur.
+ */
+ if (tbuf)
+ {
+ /* ?? use copy_to_user() */
+ if(!access_ok(VERIFY_READ, tbuf, sizeof(struct tms)) ||
+ __put_user(current->utime,&tbuf->tms_utime)||
+ __put_user(current->stime,&tbuf->tms_stime) ||
+ __put_user(current->cutime,&tbuf->tms_cutime) ||
+ __put_user(current->cstime,&tbuf->tms_cstime))
+ return -EFAULT;
}
return jiffies;
}
@@ -604,9 +696,11 @@ asmlinkage long sys_times(struct tms * tbuf)
* Auch. Had to add the 'did_exec' flag to conform completely to POSIX.
* LBT 04.03.94
*/
+
asmlinkage int sys_setpgid(pid_t pid, pid_t pgid)
{
struct task_struct * p;
+ int err = -EINVAL;
if (!pid)
pid = current->pid;
@@ -614,82 +708,123 @@ asmlinkage int sys_setpgid(pid_t pid, pid_t pgid)
pgid = pid;
if (pgid < 0)
return -EINVAL;
+
+ read_lock(&tasklist_lock);
for_each_task(p) {
- if (p->pid == pid)
+ if (p->pid == pid) {
+ /* NOTE: I haven't dropped tasklist_lock, this is
+ * on purpose. -DaveM
+ */
goto found_task;
+ }
}
+ read_unlock(&tasklist_lock);
return -ESRCH;
found_task:
+ /* From this point forward we keep holding onto the tasklist lock
+ * so that our parent does not change from under us. -DaveM
+ */
+ err = -ESRCH;
if (p->p_pptr == current || p->p_opptr == current) {
+ err = -EPERM;
if (p->session != current->session)
- return -EPERM;
+ goto out;
+ err = -EACCES;
if (p->did_exec)
- return -EACCES;
+ goto out;
} else if (p != current)
- return -ESRCH;
+ goto out;
+ err = -EPERM;
if (p->leader)
- return -EPERM;
+ goto out;
if (pgid != pid) {
struct task_struct * tmp;
for_each_task (tmp) {
if (tmp->pgrp == pgid &&
- tmp->session == current->session)
+ tmp->session == current->session)
goto ok_pgid;
}
- return -EPERM;
+ goto out;
}
ok_pgid:
p->pgrp = pgid;
- return 0;
+ err = 0;
+out:
+ /* All paths lead to here, thus we are safe. -DaveM */
+ read_unlock(&tasklist_lock);
+ return err;
}
asmlinkage int sys_getpgid(pid_t pid)
{
- struct task_struct * p;
-
- if (!pid)
+ if (!pid) {
return current->pgrp;
- for_each_task(p) {
- if (p->pid == pid)
- return p->pgrp;
+ } else {
+ struct task_struct *p;
+ int ret = -ESRCH;
+
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ if (p->pid == pid) {
+ ret = p->pgrp;
+ break;
+ }
+ }
+ read_unlock(&tasklist_lock);
+ return ret;
}
- return -ESRCH;
}
asmlinkage int sys_getpgrp(void)
{
+ /* SMP - assuming writes are word atomic this is fine */
return current->pgrp;
}
asmlinkage int sys_getsid(pid_t pid)
{
struct task_struct * p;
-
- if (!pid)
- return current->session;
- for_each_task(p) {
- if (p->pid == pid)
- return p->session;
+ int ret;
+
+ /* SMP: The 'self' case requires no lock */
+ if (!pid) {
+ ret = current->session;
+ } else {
+ ret = -ESRCH;
+
+ read_lock(&tasklist_lock);
+ for_each_task(p) {
+ if (p->pid == pid) {
+ ret = p->session;
+ break;
+ }
+ }
+ read_unlock(&tasklist_lock);
}
- return -ESRCH;
+ return ret;
}
asmlinkage int sys_setsid(void)
{
struct task_struct * p;
+ int err = -EPERM;
+ read_lock(&tasklist_lock);
for_each_task(p) {
if (p->pgrp == current->pid)
- return -EPERM;
+ goto out;
}
current->leader = 1;
current->session = current->pgrp = current->pid;
current->tty = NULL;
current->tty_old_pgrp = 0;
- return current->pgrp;
+ err = current->pgrp;
+out:
+ read_unlock(&tasklist_lock);
+ return err;
}
/*
@@ -698,6 +833,11 @@ asmlinkage int sys_setsid(void)
asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist)
{
int i;
+
+ /*
+ * SMP: Nobody else can change our grouplist. Thus we are
+ * safe.
+ */
if (gidsetsize < 0)
return -EINVAL;
@@ -711,21 +851,21 @@ asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist)
return i;
}
+/*
+ * SMP: Our groups are not shared. We can copy to/from them safely
+ * without another task interfering.
+ */
+
asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist)
{
- int err;
-
if (!suser())
return -EPERM;
if ((unsigned) gidsetsize > NGROUPS)
return -EINVAL;
- err = copy_from_user(current->groups, grouplist, gidsetsize * sizeof(gid_t));
- if (err) {
- gidsetsize = 0;
- err = -EFAULT;
- }
+ if(copy_from_user(current->groups, grouplist, gidsetsize * sizeof(gid_t)))
+ return -EFAULT;
current->ngroups = gidsetsize;
- return err;
+ return 0;
}
int in_group_p(gid_t grp)
@@ -762,53 +902,49 @@ asmlinkage int sys_newuname(struct new_utsname * name)
* Move these to arch dependent dir since they are for
* backward compatibility only?
*/
+
+#ifndef __sparc__
asmlinkage int sys_uname(struct old_utsname * name)
{
- int error = -EFAULT;;
if (name && !copy_to_user(name, &system_utsname, sizeof (*name)))
- error = 0;
- return error;
+ return 0;
+ return -EFAULT;
}
+#endif
asmlinkage int sys_olduname(struct oldold_utsname * name)
{
int error;
+
if (!name)
return -EFAULT;
- error = copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
- if (!error)
- error = put_user(0,name->sysname+__OLD_UTS_LEN);
- if (!error)
- error = copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
- if (!error)
- error = put_user(0,name->nodename+__OLD_UTS_LEN);
- if (!error)
- error = copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
- if (!error)
- error = put_user(0,name->release+__OLD_UTS_LEN);
- if (!error)
- error = copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
- if (!error)
- error = put_user(0,name->version+__OLD_UTS_LEN);
- if (!error)
- error = copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
- if (!error)
- error = put_user(0,name->machine+__OLD_UTS_LEN);
- return error ? -EFAULT : 0;
+ if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname)))
+ return -EFAULT;
+
+ error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN);
+ error -= __put_user(0,name->sysname+__OLD_UTS_LEN);
+ error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN);
+ error -= __put_user(0,name->nodename+__OLD_UTS_LEN);
+ error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN);
+ error -= __put_user(0,name->release+__OLD_UTS_LEN);
+ error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN);
+ error -= __put_user(0,name->version+__OLD_UTS_LEN);
+ error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN);
+ error = __put_user(0,name->machine+__OLD_UTS_LEN);
+ error = error ? -EFAULT : 0;
+
+ return error;
}
#endif
asmlinkage int sys_sethostname(char *name, int len)
{
- int error;
-
if (!suser())
return -EPERM;
if (len < 0 || len > __NEW_UTS_LEN)
return -EINVAL;
- error = copy_from_user(system_utsname.nodename, name, len);
- if (error)
+ if(copy_from_user(system_utsname.nodename, name, len))
return -EFAULT;
system_utsname.nodename[len] = 0;
return 0;
@@ -820,7 +956,7 @@ asmlinkage int sys_gethostname(char *name, int len)
if (len < 0)
return -EINVAL;
- i = 1+strlen(system_utsname.nodename);
+ i = 1 + strlen(system_utsname.nodename);
if (i > len)
i = len;
return copy_to_user(name, system_utsname.nodename, i) ? -EFAULT : 0;
@@ -832,14 +968,11 @@ asmlinkage int sys_gethostname(char *name, int len)
*/
asmlinkage int sys_setdomainname(char *name, int len)
{
- int error;
-
if (!suser())
return -EPERM;
if (len < 0 || len > __NEW_UTS_LEN)
return -EINVAL;
- error = copy_from_user(system_utsname.domainname, name, len);
- if (error)
+ if(copy_from_user(system_utsname.domainname, name, len))
return -EFAULT;
system_utsname.domainname[len] = 0;
return 0;
@@ -849,20 +982,19 @@ asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim)
{
if (resource >= RLIM_NLIMITS)
return -EINVAL;
- return copy_to_user(rlim, current->rlim + resource, sizeof(*rlim))
- ? -EFAULT : 0 ;
+ else
+ return copy_to_user(rlim, current->rlim + resource, sizeof(*rlim))
+ ? -EFAULT : 0;
}
asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
{
struct rlimit new_rlim, *old_rlim;
- int err;
if (resource >= RLIM_NLIMITS)
return -EINVAL;
- err = copy_from_user(&new_rlim, rlim, sizeof(*rlim));
- if (err)
- return -EFAULT;
+ if(copy_from_user(&new_rlim, rlim, sizeof(*rlim)))
+ return -EFAULT;
old_rlim = current->rlim + resource;
if (((new_rlim.rlim_cur > old_rlim->rlim_max) ||
(new_rlim.rlim_max > old_rlim->rlim_max)) &&
@@ -883,6 +1015,13 @@ asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim)
* make sense to do this. It will make moving the rest of the information
* a lot simpler! (Which we're not doing right now because we're not
* measuring them yet).
+ *
+ * This is SMP safe. Either we are called from sys_getrusage on ourselves
+ * below (we know we aren't going to exit/disappear and only we change our
+ * rusage counters), or we are called from wait4() on a process which is
+ * either stopped or zombied. In the zombied case the task won't get
+ * reaped till shortly after the call to getrusage(), in both cases the
+ * task being examined is in a frozen state so the counters won't change.
*/
int getrusage(struct task_struct *p, int who, struct rusage *ru)
{
@@ -930,8 +1069,6 @@ asmlinkage int sys_getrusage(int who, struct rusage *ru)
asmlinkage int sys_umask(int mask)
{
- int old = current->fs->umask;
-
- current->fs->umask = mask & S_IRWXUGO;
- return (old);
+ mask = xchg(&current->fs->umask, mask & S_IRWXUGO);
+ return mask;
}