aboutsummaryrefslogtreecommitdiffstats
path: root/fs/proc/base.c
diff options
context:
space:
mode:
authorPavel Emelyanov <xemul@openvz.org>2007-10-19 02:39:54 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-10-19 14:53:37 -0400
commitcf7b708c8d1d7a27736771bcf4c457b332b0f818 (patch)
tree10f80257b052313b283f18ddfe35145882e0b47f /fs/proc/base.c
parenta6f5e06378970a2687332c2d54046245fcff1e7e (diff)
Make access to task's nsproxy lighter
When someone wants to deal with some other taks's namespaces it has to lock the task and then to get the desired namespace if the one exists. This is slow on read-only paths and may be impossible in some cases. E.g. Oleg recently noticed a race between unshare() and the (sent for review in cgroups) pid namespaces - when the task notifies the parent it has to know the parent's namespace, but taking the task_lock() is impossible there - the code is under write locked tasklist lock. On the other hand switching the namespace on task (daemonize) and releasing the namespace (after the last task exit) is rather rare operation and we can sacrifice its speed to solve the issues above. The access to other task namespaces is proposed to be performed like this: rcu_read_lock(); nsproxy = task_nsproxy(tsk); if (nsproxy != NULL) { / * * work with the namespaces here * e.g. get the reference on one of them * / } / * * NULL task_nsproxy() means that this task is * almost dead (zombie) * / rcu_read_unlock(); This patch has passed the review by Eric and Oleg :) and, of course, tested. [clg@fr.ibm.com: fix unshare()] [ebiederm@xmission.com: Update get_net_ns_by_pid] Signed-off-by: Pavel Emelyanov <xemul@openvz.org> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Cc: Oleg Nesterov <oleg@tv-sign.ru> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Serge Hallyn <serue@us.ibm.com> Signed-off-by: Cedric Le Goater <clg@fr.ibm.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/proc/base.c')
-rw-r--r--fs/proc/base.c27
1 files changed, 17 insertions, 10 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c
index fbff900fd5ad..6afca09a6534 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -350,18 +350,21 @@ struct proc_mounts {
350static int mounts_open(struct inode *inode, struct file *file) 350static int mounts_open(struct inode *inode, struct file *file)
351{ 351{
352 struct task_struct *task = get_proc_task(inode); 352 struct task_struct *task = get_proc_task(inode);
353 struct nsproxy *nsp;
353 struct mnt_namespace *ns = NULL; 354 struct mnt_namespace *ns = NULL;
354 struct proc_mounts *p; 355 struct proc_mounts *p;
355 int ret = -EINVAL; 356 int ret = -EINVAL;
356 357
357 if (task) { 358 if (task) {
358 task_lock(task); 359 rcu_read_lock();
359 if (task->nsproxy) { 360 nsp = task_nsproxy(task);
360 ns = task->nsproxy->mnt_ns; 361 if (nsp) {
362 ns = nsp->mnt_ns;
361 if (ns) 363 if (ns)
362 get_mnt_ns(ns); 364 get_mnt_ns(ns);
363 } 365 }
364 task_unlock(task); 366 rcu_read_unlock();
367
365 put_task_struct(task); 368 put_task_struct(task);
366 } 369 }
367 370
@@ -424,16 +427,20 @@ static int mountstats_open(struct inode *inode, struct file *file)
424 427
425 if (!ret) { 428 if (!ret) {
426 struct seq_file *m = file->private_data; 429 struct seq_file *m = file->private_data;
430 struct nsproxy *nsp;
427 struct mnt_namespace *mnt_ns = NULL; 431 struct mnt_namespace *mnt_ns = NULL;
428 struct task_struct *task = get_proc_task(inode); 432 struct task_struct *task = get_proc_task(inode);
429 433
430 if (task) { 434 if (task) {
431 task_lock(task); 435 rcu_read_lock();
432 if (task->nsproxy) 436 nsp = task_nsproxy(task);
433 mnt_ns = task->nsproxy->mnt_ns; 437 if (nsp) {
434 if (mnt_ns) 438 mnt_ns = nsp->mnt_ns;
435 get_mnt_ns(mnt_ns); 439 if (mnt_ns)
436 task_unlock(task); 440 get_mnt_ns(mnt_ns);
441 }
442 rcu_read_unlock();
443
437 put_task_struct(task); 444 put_task_struct(task);
438 } 445 }
439 446