* Copyright (C) 1991, 1992 Linus Torvalds
*/
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/utsname.h>
#include <linux/kmod.h>
#include <linux/reboot.h>
#include <linux/prctl.h>
+#include <linux/init.h>
#include <linux/highuid.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/tty.h>
#include <linux/signal.h>
#include <linux/cn_proc.h>
+#include <linux/vs_base.h>
#include <linux/vs_cvirt.h>
#include <linux/compat.h>
#ifndef GET_FPEXC_CTL
# define GET_FPEXC_CTL(a,b) (-EINVAL)
#endif
-#ifndef GET_ENDIAN
-# define GET_ENDIAN(a,b) (-EINVAL)
-#endif
-#ifndef SET_ENDIAN
-# define SET_ENDIAN(a,b) (-EINVAL)
-#endif
/*
* this is where the system-wide overflow UID and GID are defined, for
unsigned long val, void *v)
{
int ret = NOTIFY_DONE;
- struct notifier_block *nb, *next_nb;
+ struct notifier_block *nb;
nb = rcu_dereference(*nl);
while (nb) {
- next_nb = rcu_dereference(nb->next);
ret = nb->notifier_call(nb, val, v);
if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
break;
- nb = next_nb;
+ nb = rcu_dereference(nb->next);
}
return ret;
}
}
EXPORT_SYMBOL_GPL(emergency_restart);
-static void kernel_restart_prepare(char *cmd)
+void kernel_restart_prepare(char *cmd)
{
blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);
system_state = SYSTEM_RESTART;
* Move into place and start executing a preloaded standalone
* executable. If nothing was preloaded return an error.
*/
-static void kernel_kexec(void)
+void kernel_kexec(void)
{
#ifdef CONFIG_KEXEC
struct kimage *image;
machine_kexec(image);
#endif
}
+EXPORT_SYMBOL_GPL(kernel_kexec);
void kernel_shutdown_prepare(enum system_states state)
{
if (!thread_group_leader(p))
goto out;
- if (p->parent == group_leader) {
+ if (p->real_parent == group_leader) {
err = -EPERM;
if (p->signal->session != group_leader->signal->session)
goto out;
pid_t session;
int err = -EPERM;
+ mutex_lock(&tty_mutex);
write_lock_irq(&tasklist_lock);
/* Fail if I am already a session leader */
group_leader->signal->leader = 1;
__set_special_pids(session, session);
-
- spin_lock(&group_leader->sighand->siglock);
group_leader->signal->tty = NULL;
group_leader->signal->tty_old_pgrp = 0;
- spin_unlock(&group_leader->sighand->siglock);
-
err = process_group(group_leader);
out:
write_unlock_irq(&tasklist_lock);
+ mutex_unlock(&tty_mutex);
return err;
}
* fields when reaping, so a sample either gets all the additions of a
* given child after it's reaped, or none so this sample is before reaping.
*
- * Locking:
- * We need to take the siglock for CHILDEREN, SELF and BOTH
- * for the cases current multithreaded, non-current single threaded
- * non-current multithreaded. Thread traversal is now safe with
- * the siglock held.
- * Strictly speaking, we donot need to take the siglock if we are current and
- * single threaded, as no one else can take our signal_struct away, no one
- * else can reap the children to update signal->c* counters, and no one else
- * can race with the signal-> fields. If we do not take any lock, the
- * signal-> fields could be read out of order while another thread was just
- * exiting. So we should place a read memory barrier when we avoid the lock.
- * On the writer side, write memory barrier is implied in __exit_signal
- * as __exit_signal releases the siglock spinlock after updating the signal->
- * fields. But we don't do this yet to keep things simple.
+ * tasklist_lock locking optimisation:
+ * If we are current and single threaded, we do not need to take the tasklist
+ * lock or the siglock. No one else can take our signal_struct away,
+ * no one else can reap the children to update signal->c* counters, and
+ * no one else can race with the signal-> fields.
+ * If we do not take the tasklist_lock, the signal-> fields could be read
+ * out of order while another thread was just exiting. So we place a
+ * read memory barrier when we avoid the lock. On the writer side,
+ * write memory barrier is implied in __exit_signal as __exit_signal releases
+ * the siglock spinlock after updating the signal-> fields.
+ *
+ * We don't really need the siglock when we access the non c* fields
+ * of the signal_struct (for RUSAGE_SELF) even in multithreaded
+ * case, since we take the tasklist lock for read and the non c* signal->
+ * fields are updated only in __exit_signal, which is called with
+ * tasklist_lock taken for write, hence these two threads cannot execute
+ * concurrently.
*
*/
struct task_struct *t;
unsigned long flags;
cputime_t utime, stime;
+ int need_lock = 0;
memset((char *) r, 0, sizeof *r);
utime = stime = cputime_zero;
- rcu_read_lock();
- if (!lock_task_sighand(p, &flags)) {
- rcu_read_unlock();
- return;
- }
+ if (p != current || !thread_group_empty(p))
+ need_lock = 1;
+
+ if (need_lock) {
+ read_lock(&tasklist_lock);
+ if (unlikely(!p->signal)) {
+ read_unlock(&tasklist_lock);
+ return;
+ }
+ } else
+ /* See locking comments above */
+ smp_rmb();
switch (who) {
case RUSAGE_BOTH:
case RUSAGE_CHILDREN:
+ spin_lock_irqsave(&p->sighand->siglock, flags);
utime = p->signal->cutime;
stime = p->signal->cstime;
r->ru_nvcsw = p->signal->cnvcsw;
r->ru_nivcsw = p->signal->cnivcsw;
r->ru_minflt = p->signal->cmin_flt;
r->ru_majflt = p->signal->cmaj_flt;
+ spin_unlock_irqrestore(&p->sighand->siglock, flags);
if (who == RUSAGE_CHILDREN)
break;
BUG();
}
- unlock_task_sighand(p, &flags);
- rcu_read_unlock();
-
+ if (need_lock)
+ read_unlock(&tasklist_lock);
cputime_to_timeval(utime, &r->ru_utime);
cputime_to_timeval(stime, &r->ru_stime);
}
return -EFAULT;
return 0;
}
- case PR_GET_ENDIAN:
- error = GET_ENDIAN(current, arg2);
- break;
- case PR_SET_ENDIAN:
- error = SET_ENDIAN(current, arg2);
- break;
-
default:
error = -EINVAL;
break;