sysctl: Initial support for auto-unregistering sysctl tables.
authorEric W. Biederman <ebiederm@xmission.com>
Tue, 10 Jan 2012 01:24:30 +0000 (17:24 -0800)
committerEric W. Biederman <ebiederm@xmission.com>
Wed, 25 Jan 2012 00:40:28 +0000 (16:40 -0800)
Add nreg to ctl_table_header.  When nreg drops to 0 the ctl_table_header
will be unregistered.

Factor out drop_sysctl_table from unregister_sysctl_table, and add
the logic for decrementing nreg.

Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
fs/proc/proc_sysctl.c
include/linux/sysctl.h

index 15444850b3e8e839ff77334e0c36d55e40a9b877..13faa48c467e91cc7159145ac491c908d64472ea 100644 (file)
@@ -29,8 +29,9 @@ static struct ctl_table root_table[1];
 static struct ctl_table_root sysctl_table_root;
 static struct ctl_table_header root_table_header = {
        {{.count = 1,
-       .ctl_table = root_table,
-       .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.list),}},
+         .nreg = 1,
+         .ctl_table = root_table,
+         .ctl_entry = LIST_HEAD_INIT(sysctl_table_root.default_set.list),}},
        .root = &sysctl_table_root,
        .set = &sysctl_table_root.default_set,
 };
@@ -938,6 +939,7 @@ struct ctl_table_header *__register_sysctl_table(
        header->unregistering = NULL;
        header->root = root;
        header->count = 1;
+       header->nreg = 1;
        if (sysctl_check_table(path, table))
                goto fail;
 
@@ -1192,6 +1194,20 @@ struct ctl_table_header *register_sysctl_table(struct ctl_table *table)
 }
 EXPORT_SYMBOL(register_sysctl_table);
 
+static void drop_sysctl_table(struct ctl_table_header *header)
+{
+       if (--header->nreg)
+               return;
+
+       start_unregistering(header);
+       if (!--header->parent->count) {
+               WARN_ON(1);
+               kfree_rcu(header->parent, rcu);
+       }
+       if (!--header->count)
+               kfree_rcu(header, rcu);
+}
+
 /**
  * unregister_sysctl_table - unregister a sysctl table hierarchy
  * @header: the header returned from register_sysctl_table
@@ -1224,13 +1240,7 @@ void unregister_sysctl_table(struct ctl_table_header * header)
        }
 
        spin_lock(&sysctl_lock);
-       start_unregistering(header);
-       if (!--header->parent->count) {
-               WARN_ON(1);
-               kfree_rcu(header->parent, rcu);
-       }
-       if (!--header->count)
-               kfree_rcu(header, rcu);
+       drop_sysctl_table(header);
        spin_unlock(&sysctl_lock);
 }
 EXPORT_SYMBOL(unregister_sysctl_table);
index 094bc5ccf1e2e63f4e8b2df64f586152a79f42c7..e40b8f6e5d0ea244deb81fbfdd7a63b96903de6e 100644 (file)
@@ -1032,6 +1032,7 @@ struct ctl_table_header
                        struct list_head ctl_entry;
                        int used;
                        int count;
+                       int nreg;
                };
                struct rcu_head rcu;
        };