Commit d99f160a authored by Eric W. Biederman's avatar Eric W. Biederman Committed by Linus Torvalds

[PATCH] sysctl: allow a zero ctl_name in the middle of a sysctl table

Since it is becoming clear that there are just enough users of the binary
sysctl interface that completely removing the binary interface from the kernel
will not be an option for foreseeable future, we need to find a way to address
the sysctl maintenance issues.

The basic problem is that sysctl requires one central authority to allocate
sysctl numbers, or else conflicts and ABI breakage occur.  The proc interface
to sysctl does not have that problem, as names are not densely allocated.

By not terminating a sysctl table until I have neither a ctl_name nor a
procname, it becomes simple to add sysctl entries that don't show up in the
binary sysctl interface.  Which allows people to avoid allocating a binary
sysctl value when not needed.

I have audited the kernel code and in my reading I have not found a single
sysctl table that wasn't terminated by a completely zero filled entry.  So
this change in behavior should not affect anything.

I think this mechanism eases the pain enough that combined with a little
disciple we can solve the reoccurring sysctl ABI breakage.
Signed-off-by: default avatarEric W. Biederman <ebiederm@xmission.com>
Acked-by: default avatarAlan Cox <alan@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 0e009be8
...@@ -961,8 +961,8 @@ extern ctl_handler sysctl_ms_jiffies; ...@@ -961,8 +961,8 @@ extern ctl_handler sysctl_ms_jiffies;
/* /*
* Register a set of sysctl names by calling register_sysctl_table * Register a set of sysctl names by calling register_sysctl_table
* with an initialised array of ctl_table's. An entry with zero * with an initialised array of ctl_table's. An entry with zero
* ctl_name terminates the table. table->de will be set up by the * ctl_name and NULL procname terminates the table. table->de will be
* registration and need not be initialised in advance. * set up by the registration and need not be initialised in advance.
* *
* sysctl names can be mirrored automatically under /proc/sys. The * sysctl names can be mirrored automatically under /proc/sys. The
* procname supplied controls /proc naming. * procname supplied controls /proc naming.
...@@ -973,7 +973,10 @@ extern ctl_handler sysctl_ms_jiffies; ...@@ -973,7 +973,10 @@ extern ctl_handler sysctl_ms_jiffies;
* Leaf nodes in the sysctl tree will be represented by a single file * Leaf nodes in the sysctl tree will be represented by a single file
* under /proc; non-leaf nodes will be represented by directories. A * under /proc; non-leaf nodes will be represented by directories. A
* null procname disables /proc mirroring at this node. * null procname disables /proc mirroring at this node.
* *
* sysctl entries with a zero ctl_name will not be available through
* the binary sysctl interface.
*
* sysctl(2) can automatically manage read and write requests through * sysctl(2) can automatically manage read and write requests through
* the sysctl table. The data and maxlen fields of the ctl_table * the sysctl table. The data and maxlen fields of the ctl_table
* struct enable minimal validation of the values being written to be * struct enable minimal validation of the values being written to be
......
...@@ -1315,7 +1315,9 @@ static int parse_table(int __user *name, int nlen, ...@@ -1315,7 +1315,9 @@ static int parse_table(int __user *name, int nlen,
return -ENOTDIR; return -ENOTDIR;
if (get_user(n, name)) if (get_user(n, name))
return -EFAULT; return -EFAULT;
for ( ; table->ctl_name; table++) { for ( ; table->ctl_name || table->procname; table++) {
if (!table->ctl_name)
continue;
if (n == table->ctl_name || table->ctl_name == CTL_ANY) { if (n == table->ctl_name || table->ctl_name == CTL_ANY) {
int error; int error;
if (table->child) { if (table->child) {
...@@ -1532,7 +1534,7 @@ static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, ...@@ -1532,7 +1534,7 @@ static void register_proc_table(ctl_table * table, struct proc_dir_entry *root,
int len; int len;
mode_t mode; mode_t mode;
for (; table->ctl_name; table++) { for (; table->ctl_name || table->procname; table++) {
/* Can't do anything without a proc name. */ /* Can't do anything without a proc name. */
if (!table->procname) if (!table->procname)
continue; continue;
...@@ -1579,7 +1581,7 @@ static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, ...@@ -1579,7 +1581,7 @@ static void register_proc_table(ctl_table * table, struct proc_dir_entry *root,
static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root) static void unregister_proc_table(ctl_table * table, struct proc_dir_entry *root)
{ {
struct proc_dir_entry *de; struct proc_dir_entry *de;
for (; table->ctl_name; table++) { for (; table->ctl_name || table->procname; table++) {
if (!(de = table->de)) if (!(de = table->de))
continue; continue;
if (de->mode & S_IFDIR) { if (de->mode & S_IFDIR) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment