aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Emelianov <xemul@openvz.org>2006-11-03 01:07:03 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-11-03 15:27:56 -0500
commitc7e12b838989b0e432c7a1cdf1e6c6fd936007f6 (patch)
tree31a6eea1d9ace0b467ab6bb209dd6a883910d682
parent733b72c31efb0d6b29577655939ccfe835381b52 (diff)
[PATCH] Fix ipc entries removal
Fix two issuses related to ipc_ids->entries freeing. 1. When freeing ipc namespace we need to free entries allocated with ipc_init_ids(). 2. When removing old entries in grow_ary() ipc_rcu_putref() may be called on entries set to &ids->nullentry earlier in ipc_init_ids(). This is almost impossible without namespaces, but with them this situation becomes possible. Found during OpenVZ testing after obvious leaks in beancounters. Signed-off-by: Pavel Emelianov <xemul@openvz.org> Cc: Kirill Korotaev <dev@openvz.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--ipc/msg.c1
-rw-r--r--ipc/sem.c1
-rw-r--r--ipc/shm.c1
-rw-r--r--ipc/util.c2
-rw-r--r--ipc/util.h12
5 files changed, 16 insertions, 1 deletions
diff --git a/ipc/msg.c b/ipc/msg.c
index 5b213d952545..600e06f943a6 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -124,6 +124,7 @@ void msg_exit_ns(struct ipc_namespace *ns)
124 } 124 }
125 mutex_unlock(&msg_ids(ns).mutex); 125 mutex_unlock(&msg_ids(ns).mutex);
126 126
127 ipc_fini_ids(ns->ids[IPC_MSG_IDS]);
127 kfree(ns->ids[IPC_MSG_IDS]); 128 kfree(ns->ids[IPC_MSG_IDS]);
128 ns->ids[IPC_MSG_IDS] = NULL; 129 ns->ids[IPC_MSG_IDS] = NULL;
129} 130}
diff --git a/ipc/sem.c b/ipc/sem.c
index 0dafcc455f92..21b3289d640c 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -161,6 +161,7 @@ void sem_exit_ns(struct ipc_namespace *ns)
161 } 161 }
162 mutex_unlock(&sem_ids(ns).mutex); 162 mutex_unlock(&sem_ids(ns).mutex);
163 163
164 ipc_fini_ids(ns->ids[IPC_SEM_IDS]);
164 kfree(ns->ids[IPC_SEM_IDS]); 165 kfree(ns->ids[IPC_SEM_IDS]);
165 ns->ids[IPC_SEM_IDS] = NULL; 166 ns->ids[IPC_SEM_IDS] = NULL;
166} 167}
diff --git a/ipc/shm.c b/ipc/shm.c
index bfbd317ec11c..d1198dd07a1a 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -116,6 +116,7 @@ void shm_exit_ns(struct ipc_namespace *ns)
116 } 116 }
117 mutex_unlock(&shm_ids(ns).mutex); 117 mutex_unlock(&shm_ids(ns).mutex);
118 118
119 ipc_fini_ids(ns->ids[IPC_SHM_IDS]);
119 kfree(ns->ids[IPC_SHM_IDS]); 120 kfree(ns->ids[IPC_SHM_IDS]);
120 ns->ids[IPC_SHM_IDS] = NULL; 121 ns->ids[IPC_SHM_IDS] = NULL;
121} 122}
diff --git a/ipc/util.c b/ipc/util.c
index 42479e4eec59..cd8bb14a431f 100644
--- a/ipc/util.c
+++ b/ipc/util.c
@@ -301,7 +301,7 @@ static int grow_ary(struct ipc_ids* ids, int newsize)
301 */ 301 */
302 rcu_assign_pointer(ids->entries, new); 302 rcu_assign_pointer(ids->entries, new);
303 303
304 ipc_rcu_putref(old); 304 __ipc_fini_ids(ids, old);
305 return newsize; 305 return newsize;
306} 306}
307 307
diff --git a/ipc/util.h b/ipc/util.h
index c8fd6b9d77b5..e3aa2c5c97dc 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -83,6 +83,18 @@ void* ipc_rcu_alloc(int size);
83void ipc_rcu_getref(void *ptr); 83void ipc_rcu_getref(void *ptr);
84void ipc_rcu_putref(void *ptr); 84void ipc_rcu_putref(void *ptr);
85 85
86static inline void __ipc_fini_ids(struct ipc_ids *ids,
87 struct ipc_id_ary *entries)
88{
89 if (entries != &ids->nullentry)
90 ipc_rcu_putref(entries);
91}
92
93static inline void ipc_fini_ids(struct ipc_ids *ids)
94{
95 __ipc_fini_ids(ids, ids->entries);
96}
97
86struct kern_ipc_perm* ipc_get(struct ipc_ids* ids, int id); 98struct kern_ipc_perm* ipc_get(struct ipc_ids* ids, int id);
87struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id); 99struct kern_ipc_perm* ipc_lock(struct ipc_ids* ids, int id);
88void ipc_lock_by_ptr(struct kern_ipc_perm *ipcp); 100void ipc_lock_by_ptr(struct kern_ipc_perm *ipcp);