Merge tag 'v3.16' into p/abusse/merge_upgrade
[projects/modsched/linux.git] / kernel / sysctl.c
index 9d57d50..53da8e5 100644 (file)
@@ -136,7 +136,6 @@ static unsigned long dirty_bytes_min = 2 * PAGE_SIZE;
 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
 static int maxolduid = 65535;
 static int minolduid;
-static int min_percpu_pagelist_fract = 8;
 
 static int ngroups_max = NGROUPS_MAX;
 static const int cap_last_cap = CAP_LAST_CAP;
@@ -152,10 +151,6 @@ static unsigned long hung_task_timeout_max = (LONG_MAX/HZ);
 #ifdef CONFIG_SPARC
 #endif
 
-#ifdef CONFIG_SPARC64
-extern int sysctl_tsb_ratio;
-#endif
-
 #ifdef __hppa__
 extern int pwrsw_enabled;
 #endif
@@ -173,6 +168,13 @@ extern int no_unaligned_warning;
 #endif
 
 #ifdef CONFIG_PROC_SYSCTL
+
+#define SYSCTL_WRITES_LEGACY   -1
+#define SYSCTL_WRITES_WARN      0
+#define SYSCTL_WRITES_STRICT    1
+
+static int sysctl_writes_strict = SYSCTL_WRITES_WARN;
+
 static int proc_do_cad_pid(struct ctl_table *table, int write,
                  void __user *buffer, size_t *lenp, loff_t *ppos);
 static int proc_taint(struct ctl_table *table, int write,
@@ -195,7 +197,7 @@ static int proc_dostring_coredump(struct ctl_table *table, int write,
 /* Note: sysrq code uses it's own private copy */
 static int __sysrq_enabled = CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE;
 
-static int sysrq_sysctl_handler(ctl_table *table, int write,
+static int sysrq_sysctl_handler(struct ctl_table *table, int write,
                                void __user *buffer, size_t *lenp,
                                loff_t *ppos)
 {
@@ -504,6 +506,15 @@ static struct ctl_table kern_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_taint,
        },
+       {
+               .procname       = "sysctl_writes_strict",
+               .data           = &sysctl_writes_strict,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &neg_one,
+               .extra2         = &one,
+       },
 #endif
 #ifdef CONFIG_LATENCYTOP
        {
@@ -652,7 +663,7 @@ static struct ctl_table kern_table[] = {
                .extra2         = &one,
        },
 #endif
-
+#ifdef CONFIG_UEVENT_HELPER
        {
                .procname       = "hotplug",
                .data           = &uevent_helper,
@@ -660,7 +671,7 @@ static struct ctl_table kern_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dostring,
        },
-
+#endif
 #ifdef CONFIG_CHR_DEV_SG
        {
                .procname       = "sg-big-buff",
@@ -858,6 +869,17 @@ static struct ctl_table kern_table[] = {
                .extra1         = &zero,
                .extra2         = &one,
        },
+#ifdef CONFIG_SMP
+       {
+               .procname       = "softlockup_all_cpu_backtrace",
+               .data           = &sysctl_softlockup_all_cpu_backtrace,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &zero,
+               .extra2         = &one,
+       },
+#endif /* CONFIG_SMP */
        {
                .procname       = "nmi_watchdog",
                .data           = &watchdog_user_enabled,
@@ -1314,7 +1336,7 @@ static struct ctl_table vm_table[] = {
                .maxlen         = sizeof(percpu_pagelist_fraction),
                .mode           = 0644,
                .proc_handler   = percpu_pagelist_fraction_sysctl_handler,
-               .extra1         = &min_percpu_pagelist_fract,
+               .extra1         = &zero,
        },
 #ifdef CONFIG_MMU
        {
@@ -1427,8 +1449,13 @@ static struct ctl_table vm_table[] = {
    (defined(CONFIG_SUPERH) && defined(CONFIG_VSYSCALL))
        {
                .procname       = "vdso_enabled",
+#ifdef CONFIG_X86_32
+               .data           = &vdso32_enabled,
+               .maxlen         = sizeof(vdso32_enabled),
+#else
                .data           = &vdso_enabled,
                .maxlen         = sizeof(vdso_enabled),
+#endif
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
                .extra1         = &zero,
@@ -1707,8 +1734,8 @@ int __init sysctl_init(void)
 
 #ifdef CONFIG_PROC_SYSCTL
 
-static int _proc_do_string(void* data, int maxlen, int write,
-                          void __user *buffer,
+static int _proc_do_string(char *data, int maxlen, int write,
+                          char __user *buffer,
                           size_t *lenp, loff_t *ppos)
 {
        size_t len;
@@ -1721,21 +1748,30 @@ static int _proc_do_string(void* data, int maxlen, int write,
        }
 
        if (write) {
-               len = 0;
+               if (sysctl_writes_strict == SYSCTL_WRITES_STRICT) {
+                       /* Only continue writes not past the end of buffer. */
+                       len = strlen(data);
+                       if (len > maxlen - 1)
+                               len = maxlen - 1;
+
+                       if (*ppos > len)
+                               return 0;
+                       len = *ppos;
+               } else {
+                       /* Start writing from beginning of buffer. */
+                       len = 0;
+               }
+
+               *ppos += *lenp;
                p = buffer;
-               while (len < *lenp) {
+               while ((p - buffer) < *lenp && len < maxlen - 1) {
                        if (get_user(c, p++))
                                return -EFAULT;
                        if (c == 0 || c == '\n')
                                break;
-                       len++;
+                       data[len++] = c;
                }
-               if (len >= maxlen)
-                       len = maxlen-1;
-               if(copy_from_user(data, buffer, len))
-                       return -EFAULT;
-               ((char *) data)[len] = 0;
-               *ppos += *lenp;
+               data[len] = 0;
        } else {
                len = strlen(data);
                if (len > maxlen)
@@ -1752,10 +1788,10 @@ static int _proc_do_string(void* data, int maxlen, int write,
                if (len > *lenp)
                        len = *lenp;
                if (len)
-                       if(copy_to_user(buffer, data, len))
+                       if (copy_to_user(buffer, data, len))
                                return -EFAULT;
                if (len < *lenp) {
-                       if(put_user('\n', ((char __user *) buffer) + len))
+                       if (put_user('\n', buffer + len))
                                return -EFAULT;
                        len++;
                }
@@ -1765,6 +1801,14 @@ static int _proc_do_string(void* data, int maxlen, int write,
        return 0;
 }
 
+static void warn_sysctl_write(struct ctl_table *table)
+{
+       pr_warn_once("%s wrote to %s when file position was not 0!\n"
+               "This will not be supported in the future. To silence this\n"
+               "warning, set kernel.sysctl_writes_strict = -1\n",
+               current->comm, table->procname);
+}
+
 /**
  * proc_dostring - read a string sysctl
  * @table: the sysctl table
@@ -1785,8 +1829,11 @@ static int _proc_do_string(void* data, int maxlen, int write,
 int proc_dostring(struct ctl_table *table, int write,
                  void __user *buffer, size_t *lenp, loff_t *ppos)
 {
-       return _proc_do_string(table->data, table->maxlen, write,
-                              buffer, lenp, ppos);
+       if (write && *ppos && sysctl_writes_strict == SYSCTL_WRITES_WARN)
+               warn_sysctl_write(table);
+
+       return _proc_do_string((char *)(table->data), table->maxlen, write,
+                              (char __user *)buffer, lenp, ppos);
 }
 
 static size_t proc_skip_spaces(char **buf)
@@ -1960,6 +2007,18 @@ static int __do_proc_dointvec(void *tbl_data, struct ctl_table *table,
                conv = do_proc_dointvec_conv;
 
        if (write) {
+               if (*ppos) {
+                       switch (sysctl_writes_strict) {
+                       case SYSCTL_WRITES_STRICT:
+                               goto out;
+                       case SYSCTL_WRITES_WARN:
+                               warn_sysctl_write(table);
+                               break;
+                       default:
+                               break;
+                       }
+               }
+
                if (left > PAGE_SIZE - 1)
                        left = PAGE_SIZE - 1;
                page = __get_free_page(GFP_TEMPORARY);
@@ -2017,6 +2076,7 @@ free:
                        return err ? : -EINVAL;
        }
        *lenp -= left;
+out:
        *ppos += *lenp;
        return err;
 }
@@ -2209,6 +2269,18 @@ static int __do_proc_doulongvec_minmax(void *data, struct ctl_table *table, int
        left = *lenp;
 
        if (write) {
+               if (*ppos) {
+                       switch (sysctl_writes_strict) {
+                       case SYSCTL_WRITES_STRICT:
+                               goto out;
+                       case SYSCTL_WRITES_WARN:
+                               warn_sysctl_write(table);
+                               break;
+                       default:
+                               break;
+                       }
+               }
+
                if (left > PAGE_SIZE - 1)
                        left = PAGE_SIZE - 1;
                page = __get_free_page(GFP_TEMPORARY);
@@ -2264,6 +2336,7 @@ free:
                        return err ? : -EINVAL;
        }
        *lenp -= left;
+out:
        *ppos += *lenp;
        return err;
 }
@@ -2510,11 +2583,11 @@ int proc_do_large_bitmap(struct ctl_table *table, int write,
        bool first = 1;
        size_t left = *lenp;
        unsigned long bitmap_len = table->maxlen;
-       unsigned long *bitmap = (unsigned long *) table->data;
+       unsigned long *bitmap = *(unsigned long **) table->data;
        unsigned long *tmp_bitmap = NULL;
        char tr_a[] = { '-', ',', '\n' }, tr_b[] = { ',', '\n', 0 }, c;
 
-       if (!bitmap_len || !left || (*ppos && !write)) {
+       if (!bitmap || !bitmap_len || !left || (*ppos && !write)) {
                *lenp = 0;
                return 0;
        }