X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=kernel%2Fsys.c;h=14e97282eb6c941605913dc68c2d4e2778cbe3b6;hb=4a79acdc784c315d9c436ba2315d08f8f53b8adf;hp=304b5410d746ec724afcb4e3ce50bfe65f1bf2ff;hpb=1212663fba7c5e003e05d24f043d5ed57eb18b24;p=~andy%2Flinux diff --git a/kernel/sys.c b/kernel/sys.c index 304b5410d74..14e97282eb6 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -67,6 +67,12 @@ #ifndef SET_ENDIAN # define SET_ENDIAN(a,b) (-EINVAL) #endif +#ifndef GET_TSC_CTL +# define GET_TSC_CTL(a) (-EINVAL) +#endif +#ifndef SET_TSC_CTL +# define SET_TSC_CTL(a) (-EINVAL) +#endif /* * this is where the system-wide overflow UID and GID are defined, for @@ -315,7 +321,7 @@ static void kernel_kexec(void) #endif } -void kernel_shutdown_prepare(enum system_states state) +static void kernel_shutdown_prepare(enum system_states state) { blocking_notifier_call_chain(&reboot_notifier_list, (state == SYSTEM_HALT)?SYS_HALT:SYS_POWER_OFF, NULL); @@ -916,8 +922,8 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) { struct task_struct *p; struct task_struct *group_leader = current->group_leader; - int err = -EINVAL; - struct pid_namespace *ns; + struct pid *pgrp; + int err; if (!pid) pid = task_pid_vnr(group_leader); @@ -929,12 +935,10 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) /* From this point forward we keep holding onto the tasklist lock * so that our parent does not change from under us. -DaveM */ - ns = current->nsproxy->pid_ns; - write_lock_irq(&tasklist_lock); err = -ESRCH; - p = find_task_by_pid_ns(pid, ns); + p = find_task_by_vpid(pid); if (!p) goto out; @@ -942,7 +946,7 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) if (!thread_group_leader(p)) goto out; - if (p->real_parent->tgid == group_leader->tgid) { + if (same_thread_group(p->real_parent, group_leader)) { err = -EPERM; if (task_session(p) != task_session(group_leader)) goto out; @@ -959,10 +963,12 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) if (p->signal->leader) goto out; + pgrp = task_pid(p); if (pgid != pid) { struct task_struct *g; - g = find_task_by_pid_type_ns(PIDTYPE_PGID, pgid, ns); + pgrp = find_vpid(pgid); + g = pid_task(pgrp, PIDTYPE_PGID); if (!g || task_session(g) != task_session(group_leader)) goto out; } @@ -971,13 +977,9 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid) if (err) goto out; - if (task_pgrp_nr_ns(p, ns) != pgid) { - struct pid *pid; - - detach_pid(p, PIDTYPE_PGID); - pid = find_vpid(pgid); - attach_pid(p, PIDTYPE_PGID, pid); - set_task_pgrp(p, pid_nr(pid)); + if (task_pgrp(p) != pgrp) { + change_pid(p, PIDTYPE_PGID, pgrp); + set_task_pgrp(p, pid_nr(pgrp)); } err = 0; @@ -989,94 +991,95 @@ out: asmlinkage long sys_getpgid(pid_t pid) { + struct task_struct *p; + struct pid *grp; + int retval; + + rcu_read_lock(); if (!pid) - return task_pgrp_vnr(current); + grp = task_pgrp(current); else { - int retval; - struct task_struct *p; - struct pid_namespace *ns; - - ns = current->nsproxy->pid_ns; - - read_lock(&tasklist_lock); - p = find_task_by_pid_ns(pid, ns); retval = -ESRCH; - if (p) { - retval = security_task_getpgid(p); - if (!retval) - retval = task_pgrp_nr_ns(p, ns); - } - read_unlock(&tasklist_lock); - return retval; + p = find_task_by_vpid(pid); + if (!p) + goto out; + grp = task_pgrp(p); + if (!grp) + goto out; + + retval = security_task_getpgid(p); + if (retval) + goto out; } + retval = pid_vnr(grp); +out: + rcu_read_unlock(); + return retval; } #ifdef __ARCH_WANT_SYS_GETPGRP asmlinkage long sys_getpgrp(void) { - /* SMP - assuming writes are word atomic this is fine */ - return task_pgrp_vnr(current); + return sys_getpgid(0); } #endif asmlinkage long sys_getsid(pid_t pid) { + struct task_struct *p; + struct pid *sid; + int retval; + + rcu_read_lock(); if (!pid) - return task_session_vnr(current); + sid = task_session(current); else { - int retval; - struct task_struct *p; - struct pid_namespace *ns; - - ns = current->nsproxy->pid_ns; - - read_lock(&tasklist_lock); - p = find_task_by_pid_ns(pid, ns); retval = -ESRCH; - if (p) { - retval = security_task_getsid(p); - if (!retval) - retval = task_session_nr_ns(p, ns); - } - read_unlock(&tasklist_lock); - return retval; + p = find_task_by_vpid(pid); + if (!p) + goto out; + sid = task_session(p); + if (!sid) + goto out; + + retval = security_task_getsid(p); + if (retval) + goto out; } + retval = pid_vnr(sid); +out: + rcu_read_unlock(); + return retval; } asmlinkage long sys_setsid(void) { struct task_struct *group_leader = current->group_leader; - pid_t session; + struct pid *sid = task_pid(group_leader); + pid_t session = pid_vnr(sid); int err = -EPERM; write_lock_irq(&tasklist_lock); - /* Fail if I am already a session leader */ if (group_leader->signal->leader) goto out; - session = group_leader->pid; /* Fail if a process group id already exists that equals the * proposed session id. - * - * Don't check if session id == 1 because kernel threads use this - * session id and so the check will always fail and make it so - * init cannot successfully call setsid. */ - if (session > 1 && find_task_by_pid_type_ns(PIDTYPE_PGID, - session, &init_pid_ns)) + if (pid_task(sid, PIDTYPE_PGID)) goto out; group_leader->signal->leader = 1; - __set_special_pids(session, session); + __set_special_pids(sid); spin_lock(&group_leader->sighand->siglock); group_leader->signal->tty = NULL; spin_unlock(&group_leader->sighand->siglock); - err = task_pgrp_vnr(group_leader); + err = session; out: write_unlock_irq(&tasklist_lock); return err; @@ -1145,16 +1148,16 @@ static int groups_to_user(gid_t __user *grouplist, struct group_info *group_info) { int i; - int count = group_info->ngroups; + unsigned int count = group_info->ngroups; for (i = 0; i < group_info->nblocks; i++) { - int cp_count = min(NGROUPS_PER_BLOCK, count); - int off = i * NGROUPS_PER_BLOCK; - int len = cp_count * sizeof(*grouplist); + unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); + unsigned int len = cp_count * sizeof(*grouplist); - if (copy_to_user(grouplist+off, group_info->blocks[i], len)) + if (copy_to_user(grouplist, group_info->blocks[i], len)) return -EFAULT; + grouplist += NGROUPS_PER_BLOCK; count -= cp_count; } return 0; @@ -1165,16 +1168,16 @@ static int groups_from_user(struct group_info *group_info, gid_t __user *grouplist) { int i; - int count = group_info->ngroups; + unsigned int count = group_info->ngroups; for (i = 0; i < group_info->nblocks; i++) { - int cp_count = min(NGROUPS_PER_BLOCK, count); - int off = i * NGROUPS_PER_BLOCK; - int len = cp_count * sizeof(*grouplist); + unsigned int cp_count = min(NGROUPS_PER_BLOCK, count); + unsigned int len = cp_count * sizeof(*grouplist); - if (copy_from_user(group_info->blocks[i], grouplist+off, len)) + if (copy_from_user(group_info->blocks[i], grouplist, len)) return -EFAULT; + grouplist += NGROUPS_PER_BLOCK; count -= cp_count; } return 0; @@ -1472,7 +1475,7 @@ asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim) if ((new_rlim.rlim_max > old_rlim->rlim_max) && !capable(CAP_SYS_RESOURCE)) return -EPERM; - if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > NR_OPEN) + if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > sysctl_nr_open) return -EPERM; retval = security_task_setrlimit(resource, &new_rlim); @@ -1554,6 +1557,19 @@ out: * */ +static void accumulate_thread_rusage(struct task_struct *t, struct rusage *r, + cputime_t *utimep, cputime_t *stimep) +{ + *utimep = cputime_add(*utimep, t->utime); + *stimep = cputime_add(*stimep, t->stime); + r->ru_nvcsw += t->nvcsw; + r->ru_nivcsw += t->nivcsw; + r->ru_minflt += t->min_flt; + r->ru_majflt += t->maj_flt; + r->ru_inblock += task_io_get_inblock(t); + r->ru_oublock += task_io_get_oublock(t); +} + static void k_getrusage(struct task_struct *p, int who, struct rusage *r) { struct task_struct *t; @@ -1563,12 +1579,14 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) memset((char *) r, 0, sizeof *r); utime = stime = cputime_zero; - rcu_read_lock(); - if (!lock_task_sighand(p, &flags)) { - rcu_read_unlock(); - return; + if (who == RUSAGE_THREAD) { + accumulate_thread_rusage(p, r, &utime, &stime); + goto out; } + if (!lock_task_sighand(p, &flags)) + return; + switch (who) { case RUSAGE_BOTH: case RUSAGE_CHILDREN: @@ -1595,14 +1613,7 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) r->ru_oublock += p->signal->oublock; t = p; do { - utime = cputime_add(utime, t->utime); - stime = cputime_add(stime, t->stime); - r->ru_nvcsw += t->nvcsw; - r->ru_nivcsw += t->nivcsw; - r->ru_minflt += t->min_flt; - r->ru_majflt += t->maj_flt; - r->ru_inblock += task_io_get_inblock(t); - r->ru_oublock += task_io_get_oublock(t); + accumulate_thread_rusage(t, r, &utime, &stime); t = next_thread(t); } while (t != p); break; @@ -1610,10 +1621,9 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) default: BUG(); } - unlock_task_sighand(p, &flags); - rcu_read_unlock(); +out: cputime_to_timeval(utime, &r->ru_utime); cputime_to_timeval(stime, &r->ru_stime); } @@ -1627,7 +1637,8 @@ int getrusage(struct task_struct *p, int who, struct rusage __user *ru) asmlinkage long sys_getrusage(int who, struct rusage __user *ru) { - if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN) + if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN && + who != RUSAGE_THREAD) return -EINVAL; return getrusage(current, who, ru); } @@ -1637,14 +1648,13 @@ asmlinkage long sys_umask(int mask) mask = xchg(¤t->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) { - long error; + long error = 0; - error = security_task_prctl(option, arg2, arg3, arg4, arg5); - if (error) + if (security_task_prctl(option, arg2, arg3, arg4, arg5, &error)) return error; switch (option) { @@ -1691,23 +1701,10 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, error = PR_TIMING_STATISTICAL; break; case PR_SET_TIMING: - if (arg2 == PR_TIMING_STATISTICAL) - error = 0; - else + if (arg2 != PR_TIMING_STATISTICAL) error = -EINVAL; break; - case PR_GET_KEEPCAPS: - if (current->keep_capabilities) - error = 1; - break; - case PR_SET_KEEPCAPS: - if (arg2 != 0 && arg2 != 1) { - error = -EINVAL; - break; - } - current->keep_capabilities = arg2; - break; case PR_SET_NAME: { struct task_struct *me = current; unsigned char ncomm[sizeof(me->comm)]; @@ -1741,7 +1738,12 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, case PR_SET_SECCOMP: error = prctl_set_seccomp(arg2); break; - + case PR_GET_TSC: + error = GET_TSC_CTL(arg2); + break; + case PR_SET_TSC: + error = SET_TSC_CTL(arg2); + break; default: error = -EINVAL; break; @@ -1750,7 +1752,7 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, } asmlinkage long sys_getcpu(unsigned __user *cpup, unsigned __user *nodep, - struct getcpu_cache __user *cache) + struct getcpu_cache __user *unused) { int err = 0; int cpu = raw_smp_processor_id(); @@ -1758,24 +1760,6 @@ asmlinkage long sys_getcpu(unsigned __user *cpup, unsigned __user *nodep, err |= put_user(cpu, cpup); if (nodep) err |= put_user(cpu_to_node(cpu), nodep); - if (cache) { - /* - * The cache is not needed for this implementation, - * but make sure user programs pass something - * valid. vsyscall implementations can instead make - * good use of the cache. Only use t0 and t1 because - * these are available in both 32bit and 64bit ABI (no - * need for a compat_getcpu). 32bit has enough - * padding - */ - unsigned long t0, t1; - get_user(t0, &cache->blob[0]); - get_user(t1, &cache->blob[1]); - t0++; - t1++; - put_user(t0, &cache->blob[0]); - put_user(t1, &cache->blob[1]); - } return err ? -EFAULT : 0; }