diff options
Diffstat (limited to 'kernel/sys.c')
-rw-r--r-- | kernel/sys.c | 83 |
1 files changed, 41 insertions, 42 deletions
diff --git a/kernel/sys.c b/kernel/sys.c index 0b6ec0e7936f..e236f98f7ec5 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -4,7 +4,6 @@ | |||
4 | * Copyright (C) 1991, 1992 Linus Torvalds | 4 | * Copyright (C) 1991, 1992 Linus Torvalds |
5 | */ | 5 | */ |
6 | 6 | ||
7 | #include <linux/config.h> | ||
8 | #include <linux/module.h> | 7 | #include <linux/module.h> |
9 | #include <linux/mm.h> | 8 | #include <linux/mm.h> |
10 | #include <linux/utsname.h> | 9 | #include <linux/utsname.h> |
@@ -13,7 +12,6 @@ | |||
13 | #include <linux/notifier.h> | 12 | #include <linux/notifier.h> |
14 | #include <linux/reboot.h> | 13 | #include <linux/reboot.h> |
15 | #include <linux/prctl.h> | 14 | #include <linux/prctl.h> |
16 | #include <linux/init.h> | ||
17 | #include <linux/highuid.h> | 15 | #include <linux/highuid.h> |
18 | #include <linux/fs.h> | 16 | #include <linux/fs.h> |
19 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
@@ -57,6 +55,12 @@ | |||
57 | #ifndef GET_FPEXC_CTL | 55 | #ifndef GET_FPEXC_CTL |
58 | # define GET_FPEXC_CTL(a,b) (-EINVAL) | 56 | # define GET_FPEXC_CTL(a,b) (-EINVAL) |
59 | #endif | 57 | #endif |
58 | #ifndef GET_ENDIAN | ||
59 | # define GET_ENDIAN(a,b) (-EINVAL) | ||
60 | #endif | ||
61 | #ifndef SET_ENDIAN | ||
62 | # define SET_ENDIAN(a,b) (-EINVAL) | ||
63 | #endif | ||
60 | 64 | ||
61 | /* | 65 | /* |
62 | * this is where the system-wide overflow UID and GID are defined, for | 66 | * this is where the system-wide overflow UID and GID are defined, for |
@@ -132,14 +136,15 @@ static int __kprobes notifier_call_chain(struct notifier_block **nl, | |||
132 | unsigned long val, void *v) | 136 | unsigned long val, void *v) |
133 | { | 137 | { |
134 | int ret = NOTIFY_DONE; | 138 | int ret = NOTIFY_DONE; |
135 | struct notifier_block *nb; | 139 | struct notifier_block *nb, *next_nb; |
136 | 140 | ||
137 | nb = rcu_dereference(*nl); | 141 | nb = rcu_dereference(*nl); |
138 | while (nb) { | 142 | while (nb) { |
143 | next_nb = rcu_dereference(nb->next); | ||
139 | ret = nb->notifier_call(nb, val, v); | 144 | ret = nb->notifier_call(nb, val, v); |
140 | if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK) | 145 | if ((ret & NOTIFY_STOP_MASK) == NOTIFY_STOP_MASK) |
141 | break; | 146 | break; |
142 | nb = rcu_dereference(nb->next); | 147 | nb = next_nb; |
143 | } | 148 | } |
144 | return ret; | 149 | return ret; |
145 | } | 150 | } |
@@ -583,7 +588,7 @@ void emergency_restart(void) | |||
583 | } | 588 | } |
584 | EXPORT_SYMBOL_GPL(emergency_restart); | 589 | EXPORT_SYMBOL_GPL(emergency_restart); |
585 | 590 | ||
586 | void kernel_restart_prepare(char *cmd) | 591 | static void kernel_restart_prepare(char *cmd) |
587 | { | 592 | { |
588 | blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); | 593 | blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); |
589 | system_state = SYSTEM_RESTART; | 594 | system_state = SYSTEM_RESTART; |
@@ -617,7 +622,7 @@ EXPORT_SYMBOL_GPL(kernel_restart); | |||
617 | * Move into place and start executing a preloaded standalone | 622 | * Move into place and start executing a preloaded standalone |
618 | * executable. If nothing was preloaded return an error. | 623 | * executable. If nothing was preloaded return an error. |
619 | */ | 624 | */ |
620 | void kernel_kexec(void) | 625 | static void kernel_kexec(void) |
621 | { | 626 | { |
622 | #ifdef CONFIG_KEXEC | 627 | #ifdef CONFIG_KEXEC |
623 | struct kimage *image; | 628 | struct kimage *image; |
@@ -631,7 +636,6 @@ void kernel_kexec(void) | |||
631 | machine_kexec(image); | 636 | machine_kexec(image); |
632 | #endif | 637 | #endif |
633 | } | 638 | } |
634 | EXPORT_SYMBOL_GPL(kernel_kexec); | ||
635 | 639 | ||
636 | void kernel_shutdown_prepare(enum system_states state) | 640 | void kernel_shutdown_prepare(enum system_states state) |
637 | { | 641 | { |
@@ -1860,23 +1864,20 @@ out: | |||
1860 | * fields when reaping, so a sample either gets all the additions of a | 1864 | * fields when reaping, so a sample either gets all the additions of a |
1861 | * given child after it's reaped, or none so this sample is before reaping. | 1865 | * given child after it's reaped, or none so this sample is before reaping. |
1862 | * | 1866 | * |
1863 | * tasklist_lock locking optimisation: | 1867 | * Locking: |
1864 | * If we are current and single threaded, we do not need to take the tasklist | 1868 | * We need to take the siglock for CHILDEREN, SELF and BOTH |
1865 | * lock or the siglock. No one else can take our signal_struct away, | 1869 | * for the cases current multithreaded, non-current single threaded |
1866 | * no one else can reap the children to update signal->c* counters, and | 1870 | * non-current multithreaded. Thread traversal is now safe with |
1867 | * no one else can race with the signal-> fields. | 1871 | * the siglock held. |
1868 | * If we do not take the tasklist_lock, the signal-> fields could be read | 1872 | * Strictly speaking, we donot need to take the siglock if we are current and |
1869 | * out of order while another thread was just exiting. So we place a | 1873 | * single threaded, as no one else can take our signal_struct away, no one |
1870 | * read memory barrier when we avoid the lock. On the writer side, | 1874 | * else can reap the children to update signal->c* counters, and no one else |
1871 | * write memory barrier is implied in __exit_signal as __exit_signal releases | 1875 | * can race with the signal-> fields. If we do not take any lock, the |
1872 | * the siglock spinlock after updating the signal-> fields. | 1876 | * signal-> fields could be read out of order while another thread was just |
1873 | * | 1877 | * exiting. So we should place a read memory barrier when we avoid the lock. |
1874 | * We don't really need the siglock when we access the non c* fields | 1878 | * On the writer side, write memory barrier is implied in __exit_signal |
1875 | * of the signal_struct (for RUSAGE_SELF) even in multithreaded | 1879 | * as __exit_signal releases the siglock spinlock after updating the signal-> |
1876 | * case, since we take the tasklist lock for read and the non c* signal-> | 1880 | * fields. But we don't do this yet to keep things simple. |
1877 | * fields are updated only in __exit_signal, which is called with | ||
1878 | * tasklist_lock taken for write, hence these two threads cannot execute | ||
1879 | * concurrently. | ||
1880 | * | 1881 | * |
1881 | */ | 1882 | */ |
1882 | 1883 | ||
@@ -1885,35 +1886,25 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) | |||
1885 | struct task_struct *t; | 1886 | struct task_struct *t; |
1886 | unsigned long flags; | 1887 | unsigned long flags; |
1887 | cputime_t utime, stime; | 1888 | cputime_t utime, stime; |
1888 | int need_lock = 0; | ||
1889 | 1889 | ||
1890 | memset((char *) r, 0, sizeof *r); | 1890 | memset((char *) r, 0, sizeof *r); |
1891 | utime = stime = cputime_zero; | 1891 | utime = stime = cputime_zero; |
1892 | 1892 | ||
1893 | if (p != current || !thread_group_empty(p)) | 1893 | rcu_read_lock(); |
1894 | need_lock = 1; | 1894 | if (!lock_task_sighand(p, &flags)) { |
1895 | 1895 | rcu_read_unlock(); | |
1896 | if (need_lock) { | 1896 | return; |
1897 | read_lock(&tasklist_lock); | 1897 | } |
1898 | if (unlikely(!p->signal)) { | ||
1899 | read_unlock(&tasklist_lock); | ||
1900 | return; | ||
1901 | } | ||
1902 | } else | ||
1903 | /* See locking comments above */ | ||
1904 | smp_rmb(); | ||
1905 | 1898 | ||
1906 | switch (who) { | 1899 | switch (who) { |
1907 | case RUSAGE_BOTH: | 1900 | case RUSAGE_BOTH: |
1908 | case RUSAGE_CHILDREN: | 1901 | case RUSAGE_CHILDREN: |
1909 | spin_lock_irqsave(&p->sighand->siglock, flags); | ||
1910 | utime = p->signal->cutime; | 1902 | utime = p->signal->cutime; |
1911 | stime = p->signal->cstime; | 1903 | stime = p->signal->cstime; |
1912 | r->ru_nvcsw = p->signal->cnvcsw; | 1904 | r->ru_nvcsw = p->signal->cnvcsw; |
1913 | r->ru_nivcsw = p->signal->cnivcsw; | 1905 | r->ru_nivcsw = p->signal->cnivcsw; |
1914 | r->ru_minflt = p->signal->cmin_flt; | 1906 | r->ru_minflt = p->signal->cmin_flt; |
1915 | r->ru_majflt = p->signal->cmaj_flt; | 1907 | r->ru_majflt = p->signal->cmaj_flt; |
1916 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | ||
1917 | 1908 | ||
1918 | if (who == RUSAGE_CHILDREN) | 1909 | if (who == RUSAGE_CHILDREN) |
1919 | break; | 1910 | break; |
@@ -1941,8 +1932,9 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) | |||
1941 | BUG(); | 1932 | BUG(); |
1942 | } | 1933 | } |
1943 | 1934 | ||
1944 | if (need_lock) | 1935 | unlock_task_sighand(p, &flags); |
1945 | read_unlock(&tasklist_lock); | 1936 | rcu_read_unlock(); |
1937 | |||
1946 | cputime_to_timeval(utime, &r->ru_utime); | 1938 | cputime_to_timeval(utime, &r->ru_utime); |
1947 | cputime_to_timeval(stime, &r->ru_stime); | 1939 | cputime_to_timeval(stime, &r->ru_stime); |
1948 | } | 1940 | } |
@@ -1991,7 +1983,7 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
1991 | error = current->mm->dumpable; | 1983 | error = current->mm->dumpable; |
1992 | break; | 1984 | break; |
1993 | case PR_SET_DUMPABLE: | 1985 | case PR_SET_DUMPABLE: |
1994 | if (arg2 < 0 || arg2 > 2) { | 1986 | if (arg2 < 0 || arg2 > 1) { |
1995 | error = -EINVAL; | 1987 | error = -EINVAL; |
1996 | break; | 1988 | break; |
1997 | } | 1989 | } |
@@ -2057,6 +2049,13 @@ asmlinkage long sys_prctl(int option, unsigned long arg2, unsigned long arg3, | |||
2057 | return -EFAULT; | 2049 | return -EFAULT; |
2058 | return 0; | 2050 | return 0; |
2059 | } | 2051 | } |
2052 | case PR_GET_ENDIAN: | ||
2053 | error = GET_ENDIAN(current, arg2); | ||
2054 | break; | ||
2055 | case PR_SET_ENDIAN: | ||
2056 | error = SET_ENDIAN(current, arg2); | ||
2057 | break; | ||
2058 | |||
2060 | default: | 2059 | default: |
2061 | error = -EINVAL; | 2060 | error = -EINVAL; |
2062 | break; | 2061 | break; |