Commit 7708bfb1 authored by Pavel Emelyanov's avatar Pavel Emelyanov Committed by Linus Torvalds

sysctl: merge equal proc_sys_read and proc_sys_write

Many (most of) sysctls do not have a per-container sense.  E.g.
kernel.print_fatal_signals, vm.panic_on_oom, net.core.netdev_budget and so on
and so forth.  Besides, tuning then from inside a container is not even
secure.  On the other hand, hiding them completely from the container's tasks
sometimes causes user-space to stop working.

When developing net sysctl, the common practice was to duplicate a table and
drop the write bits in table->mode, but this approach was not very elegant,
lead to excessive memory consumption and was not suitable in general.

Here's the alternative solution.  To facilitate the per-container sysctls
ctl_table_root-s were introduced.  Each root contains a list of
ctl_table_header-s that are visible to different namespaces.  The idea of this
set is to add the permissions() callback on the ctl_table_root to allow ctl
root limit permissions to the same ctl_table-s.

The main user of this functionality is the net-namespaces code, but later this
will (should) be used by more and more namespaces, containers and control
groups.

Actually, this idea's core is in a single hunk in the third patch.  First two
patches are cleanups for sysctl code, while the third one mostly extends the
arguments set of some sysctl functions.

This patch:

These ->read and ->write callbacks act in a very similar way, so merge these
paths to reduce the number of places to patch later and shrink the .text size
(a bit).
Signed-off-by: default avatarPavel Emelyanov <xemul@openvz.org>
Acked-by: default avatar"David S. Miller" <davem@davemloft.net>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Alexey Dobriyan <adobriyan@sw.ru>
Cc: Denis V. Lunev <den@openvz.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 1a46674b
...@@ -165,8 +165,8 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry, ...@@ -165,8 +165,8 @@ static struct dentry *proc_sys_lookup(struct inode *dir, struct dentry *dentry,
return err; return err;
} }
static ssize_t proc_sys_read(struct file *filp, char __user *buf, static ssize_t proc_sys_call_handler(struct file *filp, void __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos, int write)
{ {
struct dentry *dentry = filp->f_dentry; struct dentry *dentry = filp->f_dentry;
struct ctl_table_header *head; struct ctl_table_header *head;
...@@ -190,12 +190,12 @@ static ssize_t proc_sys_read(struct file *filp, char __user *buf, ...@@ -190,12 +190,12 @@ static ssize_t proc_sys_read(struct file *filp, char __user *buf,
* and won't be until we finish. * and won't be until we finish.
*/ */
error = -EPERM; error = -EPERM;
if (sysctl_perm(table, MAY_READ)) if (sysctl_perm(table, write ? MAY_WRITE : MAY_READ))
goto out; goto out;
/* careful: calling conventions are nasty here */ /* careful: calling conventions are nasty here */
res = count; res = count;
error = table->proc_handler(table, 0, filp, buf, &res, ppos); error = table->proc_handler(table, write, filp, buf, &res, ppos);
if (!error) if (!error)
error = res; error = res;
out: out:
...@@ -204,44 +204,16 @@ static ssize_t proc_sys_read(struct file *filp, char __user *buf, ...@@ -204,44 +204,16 @@ static ssize_t proc_sys_read(struct file *filp, char __user *buf,
return error; return error;
} }
static ssize_t proc_sys_write(struct file *filp, const char __user *buf, static ssize_t proc_sys_read(struct file *filp, char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct dentry *dentry = filp->f_dentry; return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 0);
struct ctl_table_header *head; }
struct ctl_table *table;
ssize_t error;
size_t res;
table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
/* Has the sysctl entry disappeared on us? */
error = -ENOENT;
if (!table)
goto out;
/* Has the sysctl entry been replaced by a directory? */
error = -EISDIR;
if (!table->proc_handler)
goto out;
/*
* At this point we know that the sysctl was not unregistered
* and won't be until we finish.
*/
error = -EPERM;
if (sysctl_perm(table, MAY_WRITE))
goto out;
/* careful: calling conventions are nasty here */
res = count;
error = table->proc_handler(table, 1, filp, (char __user *)buf,
&res, ppos);
if (!error)
error = res;
out:
sysctl_head_finish(head);
return error; static ssize_t proc_sys_write(struct file *filp, const char __user *buf,
size_t count, loff_t *ppos)
{
return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 1);
} }
......
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