]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - kernel/sysctl.c
Pidns: make full use of xxx_vnr() calls
[linux-2.6.git] / kernel / sysctl.c
index 8e96558cb8f395394e92676349fefcc887feca50..89d963ffbb01780cb1741dbbea1b56a4687c5481 100644 (file)
@@ -53,6 +53,7 @@
 #ifdef CONFIG_X86
 #include <asm/nmi.h>
 #include <asm/stacktrace.h>
+#include <asm/io.h>
 #endif
 
 static int deprecated_sysctl_warning(struct __sysctl_args *args);
@@ -66,6 +67,7 @@ extern int sysctl_overcommit_memory;
 extern int sysctl_overcommit_ratio;
 extern int sysctl_panic_on_oom;
 extern int sysctl_oom_kill_allocating_task;
+extern int sysctl_oom_dump_tasks;
 extern int max_threads;
 extern int core_uses_pid;
 extern int suid_dumpable;
@@ -80,12 +82,14 @@ extern int percpu_pagelist_fraction;
 extern int compat_log;
 extern int maps_protect;
 extern int sysctl_stat_interval;
-extern int audit_argv_kb;
 extern int latencytop_enabled;
 
 /* Constants used for minimum and  maximum */
-#ifdef CONFIG_DETECT_SOFTLOCKUP
+#if defined(CONFIG_DETECT_SOFTLOCKUP) || defined(CONFIG_HIGHMEM)
 static int one = 1;
+#endif
+
+#ifdef CONFIG_DETECT_SOFTLOCKUP
 static int sixty = 60;
 #endif
 
@@ -157,8 +161,16 @@ static int proc_dointvec_taint(struct ctl_table *table, int write, struct file *
 #endif
 
 static struct ctl_table root_table[];
-static struct ctl_table_header root_table_header =
-       { root_table, LIST_HEAD_INIT(root_table_header.ctl_entry) };
+static struct ctl_table_root sysctl_table_root;
+static struct ctl_table_header root_table_header = {
+       .ctl_table = root_table,
+       .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.header_list),
+       .root = &sysctl_table_root,
+};
+static struct ctl_table_root sysctl_table_root = {
+       .root_list = LIST_HEAD_INIT(sysctl_table_root.root_list),
+       .header_list = LIST_HEAD_INIT(root_table_header.ctl_entry),
+};
 
 static struct ctl_table kern_table[];
 static struct ctl_table vm_table[];
@@ -192,14 +204,6 @@ static struct ctl_table root_table[] = {
                .mode           = 0555,
                .child          = vm_table,
        },
-#ifdef CONFIG_NET
-       {
-               .ctl_name       = CTL_NET,
-               .procname       = "net",
-               .mode           = 0555,
-               .child          = net_table,
-       },
-#endif
        {
                .ctl_name       = CTL_FS,
                .procname       = "fs",
@@ -389,16 +393,6 @@ static struct ctl_table kern_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
-#ifdef CONFIG_AUDITSYSCALL
-       {
-               .ctl_name       = CTL_UNNUMBERED,
-               .procname       = "audit_argv_kb",
-               .data           = &audit_argv_kb,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = &proc_dointvec,
-       },
-#endif
        {
                .ctl_name       = KERN_CORE_PATTERN,
                .procname       = "core_pattern",
@@ -426,15 +420,6 @@ static struct ctl_table kern_table[] = {
                .proc_handler   = &proc_dointvec,
        },
 #endif
-#ifdef CONFIG_SECURITY_CAPABILITIES
-       {
-               .procname       = "cap-bound",
-               .data           = &cap_bset,
-               .maxlen         = sizeof(kernel_cap_t),
-               .mode           = 0600,
-               .proc_handler   = &proc_dointvec_bset,
-       },
-#endif /* def CONFIG_SECURITY_CAPABILITIES */
 #ifdef CONFIG_BLK_DEV_INITRD
        {
                .ctl_name       = KERN_REALROOTDEV,
@@ -727,6 +712,14 @@ static struct ctl_table kern_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "io_delay_type",
+               .data           = &io_delay_type,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
 #endif
 #if defined(CONFIG_MMU)
        {
@@ -878,6 +871,14 @@ static struct ctl_table vm_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "oom_dump_tasks",
+               .data           = &sysctl_oom_dump_tasks,
+               .maxlen         = sizeof(sysctl_oom_dump_tasks),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
        {
                .ctl_name       = VM_OVERCOMMIT_RATIO,
                .procname       = "overcommit_ratio",
@@ -981,7 +982,7 @@ static struct ctl_table vm_table[] = {
                .data           = &nr_overcommit_huge_pages,
                .maxlen         = sizeof(nr_overcommit_huge_pages),
                .mode           = 0644,
-               .proc_handler   = &proc_doulongvec_minmax,
+               .proc_handler   = &hugetlb_overcommit_handler,
        },
 #endif
        {
@@ -1152,6 +1153,19 @@ static struct ctl_table vm_table[] = {
                .extra1         = &zero,
        },
 #endif
+#ifdef CONFIG_HIGHMEM
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "highmem_is_dirtyable",
+               .data           = &vm_highmem_is_dirtyable,
+               .maxlen         = sizeof(vm_highmem_is_dirtyable),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec_minmax,
+               .strategy       = &sysctl_intvec,
+               .extra1         = &zero,
+               .extra2         = &one,
+       },
+#endif
 /*
  * NOTE: do not add new entries to this table unless you have read
  * Documentation/sysctl/ctl_unnumbered.txt
@@ -1197,6 +1211,14 @@ static struct ctl_table fs_table[] = {
                .mode           = 0644,
                .proc_handler   = &proc_dointvec,
        },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "nr_open",
+               .data           = &sysctl_nr_open,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
        {
                .ctl_name       = FS_DENTRY,
                .procname       = "dentry-state",
@@ -1371,12 +1393,27 @@ void sysctl_head_finish(struct ctl_table_header *head)
        spin_unlock(&sysctl_lock);
 }
 
-struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev)
+static struct list_head *
+lookup_header_list(struct ctl_table_root *root, struct nsproxy *namespaces)
 {
+       struct list_head *header_list;
+       header_list = &root->header_list;
+       if (root->lookup)
+               header_list = root->lookup(root, namespaces);
+       return header_list;
+}
+
+struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces,
+                                           struct ctl_table_header *prev)
+{
+       struct ctl_table_root *root;
+       struct list_head *header_list;
        struct ctl_table_header *head;
        struct list_head *tmp;
+
        spin_lock(&sysctl_lock);
        if (prev) {
+               head = prev;
                tmp = &prev->ctl_entry;
                unuse_table(prev);
                goto next;
@@ -1390,14 +1427,38 @@ struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev)
                spin_unlock(&sysctl_lock);
                return head;
        next:
+               root = head->root;
                tmp = tmp->next;
-               if (tmp == &root_table_header.ctl_entry)
-                       break;
+               header_list = lookup_header_list(root, namespaces);
+               if (tmp != header_list)
+                       continue;
+
+               do {
+                       root = list_entry(root->root_list.next,
+                                       struct ctl_table_root, root_list);
+                       if (root == &sysctl_table_root)
+                               goto out;
+                       header_list = lookup_header_list(root, namespaces);
+               } while (list_empty(header_list));
+               tmp = header_list->next;
        }
+out:
        spin_unlock(&sysctl_lock);
        return NULL;
 }
 
+struct ctl_table_header *sysctl_head_next(struct ctl_table_header *prev)
+{
+       return __sysctl_head_next(current->nsproxy, prev);
+}
+
+void register_sysctl_root(struct ctl_table_root *root)
+{
+       spin_lock(&sysctl_lock);
+       list_add_tail(&root->root_list, &sysctl_table_root.root_list);
+       spin_unlock(&sysctl_lock);
+}
+
 #ifdef CONFIG_SYSCTL_SYSCALL
 int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp,
               void __user *newval, size_t newlen)
@@ -1554,18 +1615,21 @@ static __init int sysctl_init(void)
 {
        int err;
        sysctl_set_parent(NULL, root_table);
-       err = sysctl_check_table(root_table);
+       err = sysctl_check_table(current->nsproxy, root_table);
        return 0;
 }
 
 core_initcall(sysctl_init);
 
 /**
- * register_sysctl_table - register a sysctl hierarchy
+ * __register_sysctl_paths - register a sysctl hierarchy
+ * @root: List of sysctl headers to register on
+ * @namespaces: Data to compute which lists of sysctl entries are visible
+ * @path: The path to the directory the sysctl table is in.
  * @table: the top-level table structure
  *
  * Register a sysctl table hierarchy. @table should be a filled in ctl_table
- * array. An entry with a ctl_name of 0 terminates the table. 
+ * array. A completely 0 filled entry terminates the table.
  *
  * The members of the &struct ctl_table structure are used as follows:
  *
@@ -1628,25 +1692,99 @@ core_initcall(sysctl_init);
  * This routine returns %NULL on a failure to register, and a pointer
  * to the table header on success.
  */
-struct ctl_table_header *register_sysctl_table(struct ctl_table * table)
+struct ctl_table_header *__register_sysctl_paths(
+       struct ctl_table_root *root,
+       struct nsproxy *namespaces,
+       const struct ctl_path *path, struct ctl_table *table)
 {
-       struct ctl_table_header *tmp;
-       tmp = kmalloc(sizeof(struct ctl_table_header), GFP_KERNEL);
-       if (!tmp)
+       struct list_head *header_list;
+       struct ctl_table_header *header;
+       struct ctl_table *new, **prevp;
+       unsigned int n, npath;
+
+       /* Count the path components */
+       for (npath = 0; path[npath].ctl_name || path[npath].procname; ++npath)
+               ;
+
+       /*
+        * For each path component, allocate a 2-element ctl_table array.
+        * The first array element will be filled with the sysctl entry
+        * for this, the second will be the sentinel (ctl_name == 0).
+        *
+        * We allocate everything in one go so that we don't have to
+        * worry about freeing additional memory in unregister_sysctl_table.
+        */
+       header = kzalloc(sizeof(struct ctl_table_header) +
+                        (2 * npath * sizeof(struct ctl_table)), GFP_KERNEL);
+       if (!header)
                return NULL;
-       tmp->ctl_table = table;
-       INIT_LIST_HEAD(&tmp->ctl_entry);
-       tmp->used = 0;
-       tmp->unregistering = NULL;
-       sysctl_set_parent(NULL, table);
-       if (sysctl_check_table(tmp->ctl_table)) {
-               kfree(tmp);
+
+       new = (struct ctl_table *) (header + 1);
+
+       /* Now connect the dots */
+       prevp = &header->ctl_table;
+       for (n = 0; n < npath; ++n, ++path) {
+               /* Copy the procname */
+               new->procname = path->procname;
+               new->ctl_name = path->ctl_name;
+               new->mode     = 0555;
+
+               *prevp = new;
+               prevp = &new->child;
+
+               new += 2;
+       }
+       *prevp = table;
+       header->ctl_table_arg = table;
+
+       INIT_LIST_HEAD(&header->ctl_entry);
+       header->used = 0;
+       header->unregistering = NULL;
+       header->root = root;
+       sysctl_set_parent(NULL, header->ctl_table);
+       if (sysctl_check_table(namespaces, header->ctl_table)) {
+               kfree(header);
                return NULL;
        }
        spin_lock(&sysctl_lock);
-       list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry);
+       header_list = lookup_header_list(root, namespaces);
+       list_add_tail(&header->ctl_entry, header_list);
        spin_unlock(&sysctl_lock);
-       return tmp;
+
+       return header;
+}
+
+/**
+ * register_sysctl_table_path - register a sysctl table hierarchy
+ * @path: The path to the directory the sysctl table is in.
+ * @table: the top-level table structure
+ *
+ * Register a sysctl table hierarchy. @table should be a filled in ctl_table
+ * array. A completely 0 filled entry terminates the table.
+ *
+ * See __register_sysctl_paths for more details.
+ */
+struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,
+                                               struct ctl_table *table)
+{
+       return __register_sysctl_paths(&sysctl_table_root, current->nsproxy,
+                                       path, table);
+}
+
+/**
+ * register_sysctl_table - register a sysctl table hierarchy
+ * @table: the top-level table structure
+ *
+ * Register a sysctl table hierarchy. @table should be a filled in ctl_table
+ * array. A completely 0 filled entry terminates the table.
+ *
+ * See register_sysctl_paths for more details.
+ */
+struct ctl_table_header *register_sysctl_table(struct ctl_table *table)
+{
+       static const struct ctl_path null_path[] = { {} };
+
+       return register_sysctl_paths(null_path, table);
 }
 
 /**
@@ -1675,6 +1813,12 @@ struct ctl_table_header *register_sysctl_table(struct ctl_table * table)
        return NULL;
 }
 
+struct ctl_table_header *register_sysctl_paths(const struct ctl_path *path,
+                                                   struct ctl_table *table)
+{
+       return NULL;
+}
+
 void unregister_sysctl_table(struct ctl_table_header * table)
 {
 }
@@ -1960,26 +2104,6 @@ static int do_proc_dointvec_bset_conv(int *negp, unsigned long *lvalp,
        return 0;
 }
 
-#ifdef CONFIG_SECURITY_CAPABILITIES
-/*
- *     init may raise the set.
- */
-
-int proc_dointvec_bset(struct ctl_table *table, int write, struct file *filp,
-                       void __user *buffer, size_t *lenp, loff_t *ppos)
-{
-       int op;
-
-       if (write && !capable(CAP_SYS_MODULE)) {
-               return -EPERM;
-       }
-
-       op = is_global_init(current) ? OP_SET : OP_AND;
-       return do_proc_dointvec(table,write,filp,buffer,lenp,ppos,
-                               do_proc_dointvec_bset_conv,&op);
-}
-#endif /* def CONFIG_SECURITY_CAPABILITIES */
-
 /*
  *     Taint values can only be increased
  */
@@ -2364,7 +2488,7 @@ static int proc_do_cad_pid(struct ctl_table *table, int write, struct file *filp
        pid_t tmp;
        int r;
 
-       tmp = pid_nr_ns(cad_pid, current->nsproxy->pid_ns);
+       tmp = pid_vnr(cad_pid);
 
        r = __do_proc_dointvec(&tmp, table, write, filp, buffer,
                               lenp, ppos, NULL, NULL);
@@ -2393,12 +2517,6 @@ int proc_dointvec(struct ctl_table *table, int write, struct file *filp,
        return -ENOSYS;
 }
 
-int proc_dointvec_bset(struct ctl_table *table, int write, struct file *filp,
-                       void __user *buffer, size_t *lenp, loff_t *ppos)
-{
-       return -ENOSYS;
-}
-
 int proc_dointvec_minmax(struct ctl_table *table, int write, struct file *filp,
                    void __user *buffer, size_t *lenp, loff_t *ppos)
 {
@@ -2733,6 +2851,7 @@ EXPORT_SYMBOL(proc_dostring);
 EXPORT_SYMBOL(proc_doulongvec_minmax);
 EXPORT_SYMBOL(proc_doulongvec_ms_jiffies_minmax);
 EXPORT_SYMBOL(register_sysctl_table);
+EXPORT_SYMBOL(register_sysctl_paths);
 EXPORT_SYMBOL(sysctl_intvec);
 EXPORT_SYMBOL(sysctl_jiffies);
 EXPORT_SYMBOL(sysctl_ms_jiffies);