diff options
author | Pavel Emelyanov <xemul@openvz.org> | 2008-04-29 04:02:40 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-29 11:06:23 -0400 |
commit | 7708bfb1c855f2a076ef71cc21647deea022ebe7 (patch) | |
tree | 9e4ba2b0074217b30a684eb9e77f6619434f4577 | |
parent | 1a46674b996bf9a15f0333178f5829ca2d7c32e2 (diff) |
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: Pavel Emelyanov <xemul@openvz.org>
Acked-by: "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: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/proc/proc_sysctl.c | 50 |
1 files changed, 11 insertions, 39 deletions
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 614c34b6d1c2..5e31585292a0 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
@@ -165,8 +165,8 @@ out: | |||
165 | return err; | 165 | return err; |
166 | } | 166 | } |
167 | 167 | ||
168 | static ssize_t proc_sys_read(struct file *filp, char __user *buf, | 168 | static ssize_t proc_sys_call_handler(struct file *filp, void __user *buf, |
169 | size_t count, loff_t *ppos) | 169 | size_t count, loff_t *ppos, int write) |
170 | { | 170 | { |
171 | struct dentry *dentry = filp->f_dentry; | 171 | struct dentry *dentry = filp->f_dentry; |
172 | struct ctl_table_header *head; | 172 | struct ctl_table_header *head; |
@@ -190,12 +190,12 @@ static ssize_t proc_sys_read(struct file *filp, char __user *buf, | |||
190 | * and won't be until we finish. | 190 | * and won't be until we finish. |
191 | */ | 191 | */ |
192 | error = -EPERM; | 192 | error = -EPERM; |
193 | if (sysctl_perm(table, MAY_READ)) | 193 | if (sysctl_perm(table, write ? MAY_WRITE : MAY_READ)) |
194 | goto out; | 194 | goto out; |
195 | 195 | ||
196 | /* careful: calling conventions are nasty here */ | 196 | /* careful: calling conventions are nasty here */ |
197 | res = count; | 197 | res = count; |
198 | error = table->proc_handler(table, 0, filp, buf, &res, ppos); | 198 | error = table->proc_handler(table, write, filp, buf, &res, ppos); |
199 | if (!error) | 199 | if (!error) |
200 | error = res; | 200 | error = res; |
201 | out: | 201 | out: |
@@ -204,44 +204,16 @@ out: | |||
204 | return error; | 204 | return error; |
205 | } | 205 | } |
206 | 206 | ||
207 | static ssize_t proc_sys_write(struct file *filp, const char __user *buf, | 207 | static ssize_t proc_sys_read(struct file *filp, char __user *buf, |
208 | size_t count, loff_t *ppos) | 208 | size_t count, loff_t *ppos) |
209 | { | 209 | { |
210 | struct dentry *dentry = filp->f_dentry; | 210 | return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 0); |
211 | struct ctl_table_header *head; | 211 | } |
212 | struct ctl_table *table; | ||
213 | ssize_t error; | ||
214 | size_t res; | ||
215 | |||
216 | table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head); | ||
217 | /* Has the sysctl entry disappeared on us? */ | ||
218 | error = -ENOENT; | ||
219 | if (!table) | ||
220 | goto out; | ||
221 | |||
222 | /* Has the sysctl entry been replaced by a directory? */ | ||
223 | error = -EISDIR; | ||
224 | if (!table->proc_handler) | ||
225 | goto out; | ||
226 | |||
227 | /* | ||
228 | * At this point we know that the sysctl was not unregistered | ||
229 | * and won't be until we finish. | ||
230 | */ | ||
231 | error = -EPERM; | ||
232 | if (sysctl_perm(table, MAY_WRITE)) | ||
233 | goto out; | ||
234 | |||
235 | /* careful: calling conventions are nasty here */ | ||
236 | res = count; | ||
237 | error = table->proc_handler(table, 1, filp, (char __user *)buf, | ||
238 | &res, ppos); | ||
239 | if (!error) | ||
240 | error = res; | ||
241 | out: | ||
242 | sysctl_head_finish(head); | ||
243 | 212 | ||
244 | return error; | 213 | static ssize_t proc_sys_write(struct file *filp, const char __user *buf, |
214 | size_t count, loff_t *ppos) | ||
215 | { | ||
216 | return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 1); | ||
245 | } | 217 | } |
246 | 218 | ||
247 | 219 | ||