KVM: Avoid useless memory write when possible
[sfrench/cifs-2.6.git] / kernel / sys.c
index 123b165080e658034a09be1ea2478c6d0093daea..872271ccc3843989ad493ae4dc219b38bf30b15e 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/prctl.h>
 #include <linux/highuid.h>
 #include <linux/fs.h>
+#include <linux/resource.h>
 #include <linux/kernel.h>
 #include <linux/kexec.h>
 #include <linux/workqueue.h>
@@ -29,6 +30,7 @@
 #include <linux/signal.h>
 #include <linux/cn_proc.h>
 #include <linux/getcpu.h>
+#include <linux/task_io_accounting_ops.h>
 
 #include <linux/compat.h>
 #include <linux/syscalls.h>
@@ -134,19 +136,39 @@ static int notifier_chain_unregister(struct notifier_block **nl,
        return -ENOENT;
 }
 
+/**
+ * notifier_call_chain - Informs the registered notifiers about an event.
+ *     @nl:            Pointer to head of the blocking notifier chain
+ *     @val:           Value passed unmodified to notifier function
+ *     @v:             Pointer passed unmodified to notifier function
+ *     @nr_to_call:    Number of notifier functions to be called. Don't care
+ *                     value of this parameter is -1.
+ *     @nr_calls:      Records the number of notifications sent. Don't care
+ *                     value of this field is NULL.
+ *     @returns:       notifier_call_chain returns the value returned by the
+ *                     last notifier function called.
+ */
+
 static int __kprobes notifier_call_chain(struct notifier_block **nl,
-               unsigned long val, void *v)
+                                       unsigned long val, void *v,
+                                       int nr_to_call, int *nr_calls)
 {
        int ret = NOTIFY_DONE;
        struct notifier_block *nb, *next_nb;
 
        nb = rcu_dereference(*nl);
-       while (nb) {
+
+       while (nb && nr_to_call) {
                next_nb = rcu_dereference(nb->next);
                ret = nb->notifier_call(nb, val, v);
+
+               if (nr_calls)
+                       (*nr_calls)++;
+
                if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK)
                        break;
                nb = next_nb;
+               nr_to_call--;
        }
        return ret;
 }
@@ -205,10 +227,12 @@ int atomic_notifier_chain_unregister(struct atomic_notifier_head *nh,
 EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
 
 /**
- *     atomic_notifier_call_chain - Call functions in an atomic notifier chain
+ *     __atomic_notifier_call_chain - Call functions in an atomic notifier chain
  *     @nh: Pointer to head of the atomic notifier chain
  *     @val: Value passed unmodified to notifier function
  *     @v: Pointer passed unmodified to notifier function
+ *     @nr_to_call: See the comment for notifier_call_chain.
+ *     @nr_calls: See the comment for notifier_call_chain.
  *
  *     Calls each function in a notifier chain in turn.  The functions
  *     run in an atomic context, so they must not block.
@@ -222,19 +246,27 @@ EXPORT_SYMBOL_GPL(atomic_notifier_chain_unregister);
  *     of the last notifier function called.
  */
  
-int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh,
-               unsigned long val, void *v)
+int __kprobes __atomic_notifier_call_chain(struct atomic_notifier_head *nh,
+                                       unsigned long val, void *v,
+                                       int nr_to_call, int *nr_calls)
 {
        int ret;
 
        rcu_read_lock();
-       ret = notifier_call_chain(&nh->head, val, v);
+       ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
        rcu_read_unlock();
        return ret;
 }
 
-EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
+EXPORT_SYMBOL_GPL(__atomic_notifier_call_chain);
 
+int __kprobes atomic_notifier_call_chain(struct atomic_notifier_head *nh,
+               unsigned long val, void *v)
+{
+       return __atomic_notifier_call_chain(nh, val, v, -1, NULL);
+}
+
+EXPORT_SYMBOL_GPL(atomic_notifier_call_chain);
 /*
  *     Blocking notifier chain routines.  All access to the chain is
  *     synchronized by an rwsem.
@@ -304,10 +336,12 @@ int blocking_notifier_chain_unregister(struct blocking_notifier_head *nh,
 EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
 
 /**
- *     blocking_notifier_call_chain - Call functions in a blocking notifier chain
+ *     __blocking_notifier_call_chain - Call functions in a blocking notifier chain
  *     @nh: Pointer to head of the blocking notifier chain
  *     @val: Value passed unmodified to notifier function
  *     @v: Pointer passed unmodified to notifier function
+ *     @nr_to_call: See comment for notifier_call_chain.
+ *     @nr_calls: See comment for notifier_call_chain.
  *
  *     Calls each function in a notifier chain in turn.  The functions
  *     run in a process context, so they are allowed to block.
@@ -320,8 +354,9 @@ EXPORT_SYMBOL_GPL(blocking_notifier_chain_unregister);
  *     of the last notifier function called.
  */
  
-int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
-               unsigned long val, void *v)
+int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
+                                  unsigned long val, void *v,
+                                  int nr_to_call, int *nr_calls)
 {
        int ret = NOTIFY_DONE;
 
@@ -332,12 +367,19 @@ int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
         */
        if (rcu_dereference(nh->head)) {
                down_read(&nh->rwsem);
-               ret = notifier_call_chain(&nh->head, val, v);
+               ret = notifier_call_chain(&nh->head, val, v, nr_to_call,
+                                       nr_calls);
                up_read(&nh->rwsem);
        }
        return ret;
 }
+EXPORT_SYMBOL_GPL(__blocking_notifier_call_chain);
 
+int blocking_notifier_call_chain(struct blocking_notifier_head *nh,
+               unsigned long val, void *v)
+{
+       return __blocking_notifier_call_chain(nh, val, v, -1, NULL);
+}
 EXPORT_SYMBOL_GPL(blocking_notifier_call_chain);
 
 /*
@@ -383,10 +425,12 @@ int raw_notifier_chain_unregister(struct raw_notifier_head *nh,
 EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister);
 
 /**
- *     raw_notifier_call_chain - Call functions in a raw notifier chain
+ *     __raw_notifier_call_chain - Call functions in a raw notifier chain
  *     @nh: Pointer to head of the raw notifier chain
  *     @val: Value passed unmodified to notifier function
  *     @v: Pointer passed unmodified to notifier function
+ *     @nr_to_call: See comment for notifier_call_chain.
+ *     @nr_calls: See comment for notifier_call_chain
  *
  *     Calls each function in a notifier chain in turn.  The functions
  *     run in an undefined context.
@@ -400,10 +444,19 @@ EXPORT_SYMBOL_GPL(raw_notifier_chain_unregister);
  *     of the last notifier function called.
  */
 
+int __raw_notifier_call_chain(struct raw_notifier_head *nh,
+                             unsigned long val, void *v,
+                             int nr_to_call, int *nr_calls)
+{
+       return notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
+}
+
+EXPORT_SYMBOL_GPL(__raw_notifier_call_chain);
+
 int raw_notifier_call_chain(struct raw_notifier_head *nh,
                unsigned long val, void *v)
 {
-       return notifier_call_chain(&nh->head, val, v);
+       return __raw_notifier_call_chain(nh, val, v, -1, NULL);
 }
 
 EXPORT_SYMBOL_GPL(raw_notifier_call_chain);
@@ -478,10 +531,12 @@ int srcu_notifier_chain_unregister(struct srcu_notifier_head *nh,
 EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
 
 /**
- *     srcu_notifier_call_chain - Call functions in an SRCU notifier chain
+ *     __srcu_notifier_call_chain - Call functions in an SRCU notifier chain
  *     @nh: Pointer to head of the SRCU notifier chain
  *     @val: Value passed unmodified to notifier function
  *     @v: Pointer passed unmodified to notifier function
+ *     @nr_to_call: See comment for notifier_call_chain.
+ *     @nr_calls: See comment for notifier_call_chain
  *
  *     Calls each function in a notifier chain in turn.  The functions
  *     run in a process context, so they are allowed to block.
@@ -494,18 +549,25 @@ EXPORT_SYMBOL_GPL(srcu_notifier_chain_unregister);
  *     of the last notifier function called.
  */
 
-int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
-               unsigned long val, void *v)
+int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
+                              unsigned long val, void *v,
+                              int nr_to_call, int *nr_calls)
 {
        int ret;
        int idx;
 
        idx = srcu_read_lock(&nh->srcu);
-       ret = notifier_call_chain(&nh->head, val, v);
+       ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
        srcu_read_unlock(&nh->srcu, idx);
        return ret;
 }
+EXPORT_SYMBOL_GPL(__srcu_notifier_call_chain);
 
+int srcu_notifier_call_chain(struct srcu_notifier_head *nh,
+               unsigned long val, void *v)
+{
+       return __srcu_notifier_call_chain(nh, val, v, -1, NULL);
+}
 EXPORT_SYMBOL_GPL(srcu_notifier_call_chain);
 
 /**
@@ -598,7 +660,7 @@ asmlinkage long sys_setpriority(int which, int who, int niceval)
        int error = -EINVAL;
        struct pid *pgrp;
 
-       if (which > 2 || which < 0)
+       if (which > PRIO_USER || which < PRIO_PROCESS)
                goto out;
 
        /* normalize: avoid signed division (rounding problems) */
@@ -662,7 +724,7 @@ asmlinkage long sys_getpriority(int which, int who)
        long niceval, retval = -ESRCH;
        struct pid *pgrp;
 
-       if (which > 2 || which < 0)
+       if (which > PRIO_USER || which < PRIO_PROCESS)
                return -EINVAL;
 
        read_lock(&tasklist_lock);
@@ -881,7 +943,7 @@ asmlinkage long sys_reboot(int magic1, int magic2, unsigned int cmd, void __user
 #ifdef CONFIG_SOFTWARE_SUSPEND
        case LINUX_REBOOT_CMD_SW_SUSPEND:
                {
-                       int ret = software_suspend();
+                       int ret = hibernate();
                        unlock_kernel();
                        return ret;
                }
@@ -1292,7 +1354,7 @@ asmlinkage long sys_setfsuid(uid_t uid)
 }
 
 /*
- * Samma på svenska..
+ * Samma på svenska..
  */
 asmlinkage long sys_setfsgid(gid_t gid)
 {
@@ -1426,7 +1488,7 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid)
        if (process_group(p) != pgid) {
                detach_pid(p, PIDTYPE_PGID);
                p->signal->pgrp = pgid;
-               attach_pid(p, PIDTYPE_PGID, pgid);
+               attach_pid(p, PIDTYPE_PGID, find_pid(pgid));
        }
 
        err = 0;
@@ -1923,6 +1985,16 @@ asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim)
        if (retval)
                return retval;
 
+       if (resource == RLIMIT_CPU && new_rlim.rlim_cur == 0) {
+               /*
+                * The caller is asking for an immediate RLIMIT_CPU
+                * expiry.  But we use the zero value to mean "it was
+                * never set".  So let's cheat and make it one second
+                * instead
+                */
+               new_rlim.rlim_cur = 1;
+       }
+
        task_lock(current->group_leader);
        *old_rlim = new_rlim;
        task_unlock(current->group_leader);
@@ -1944,15 +2016,6 @@ asmlinkage long sys_setrlimit(unsigned int resource, struct rlimit __user *rlim)
                unsigned long rlim_cur = new_rlim.rlim_cur;
                cputime_t cputime;
 
-               if (rlim_cur == 0) {
-                       /*
-                        * The caller is asking for an immediate RLIMIT_CPU
-                        * expiry.  But we use the zero value to mean "it was
-                        * never set".  So let's cheat and make it one second
-                        * instead
-                        */
-                       rlim_cur = 1;
-               }
                cputime = secs_to_cputime(rlim_cur);
                read_lock(&tasklist_lock);
                spin_lock_irq(&current->sighand->siglock);
@@ -2021,6 +2084,8 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
                        r->ru_nivcsw = p->signal->cnivcsw;
                        r->ru_minflt = p->signal->cmin_flt;
                        r->ru_majflt = p->signal->cmaj_flt;
+                       r->ru_inblock = p->signal->cinblock;
+                       r->ru_oublock = p->signal->coublock;
 
                        if (who == RUSAGE_CHILDREN)
                                break;
@@ -2032,6 +2097,8 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
                        r->ru_nivcsw += p->signal->nivcsw;
                        r->ru_minflt += p->signal->min_flt;
                        r->ru_majflt += p->signal->maj_flt;
+                       r->ru_inblock += p->signal->inblock;
+                       r->ru_oublock += p->signal->oublock;
                        t = p;
                        do {
                                utime = cputime_add(utime, t->utime);
@@ -2040,6 +2107,8 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)
                                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);
                                t = next_thread(t);
                        } while (t != p);
                        break;