aboutsummaryrefslogtreecommitdiffstats
path: root/include
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 /include
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 'include')
-rw-r--r--include/linux/nsproxy.h43
1 files changed, 34 insertions, 9 deletions
diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h
index f1eca68751a9..0e66b57631fc 100644
--- a/include/linux/nsproxy.h
+++ b/include/linux/nsproxy.h
@@ -32,8 +32,39 @@ struct nsproxy {
32}; 32};
33extern struct nsproxy init_nsproxy; 33extern struct nsproxy init_nsproxy;
34 34
35/*
36 * the namespaces access rules are:
37 *
38 * 1. only current task is allowed to change tsk->nsproxy pointer or
39 * any pointer on the nsproxy itself
40 *
41 * 2. when accessing (i.e. reading) current task's namespaces - no
42 * precautions should be taken - just dereference the pointers
43 *
44 * 3. the access to other task namespaces is performed like this
45 * rcu_read_lock();
46 * nsproxy = task_nsproxy(tsk);
47 * if (nsproxy != NULL) {
48 * / *
49 * * work with the namespaces here
50 * * e.g. get the reference on one of them
51 * * /
52 * } / *
53 * * NULL task_nsproxy() means that this task is
54 * * almost dead (zombie)
55 * * /
56 * rcu_read_unlock();
57 *
58 */
59
60static inline struct nsproxy *task_nsproxy(struct task_struct *tsk)
61{
62 return rcu_dereference(tsk->nsproxy);
63}
64
35int copy_namespaces(unsigned long flags, struct task_struct *tsk); 65int copy_namespaces(unsigned long flags, struct task_struct *tsk);
36void get_task_namespaces(struct task_struct *tsk); 66void exit_task_namespaces(struct task_struct *tsk);
67void switch_task_namespaces(struct task_struct *tsk, struct nsproxy *new);
37void free_nsproxy(struct nsproxy *ns); 68void free_nsproxy(struct nsproxy *ns);
38int unshare_nsproxy_namespaces(unsigned long, struct nsproxy **, 69int unshare_nsproxy_namespaces(unsigned long, struct nsproxy **,
39 struct fs_struct *); 70 struct fs_struct *);
@@ -45,15 +76,9 @@ static inline void put_nsproxy(struct nsproxy *ns)
45 } 76 }
46} 77}
47 78
48static inline void exit_task_namespaces(struct task_struct *p) 79static inline void get_nsproxy(struct nsproxy *ns)
49{ 80{
50 struct nsproxy *ns = p->nsproxy; 81 atomic_inc(&ns->count);
51 if (ns) {
52 task_lock(p);
53 p->nsproxy = NULL;
54 task_unlock(p);
55 put_nsproxy(ns);
56 }
57} 82}
58 83
59#ifdef CONFIG_CGROUP_NS 84#ifdef CONFIG_CGROUP_NS