diff options
Diffstat (limited to 'kernel/pid.c')
-rw-r--r-- | kernel/pid.c | 49 |
1 files changed, 34 insertions, 15 deletions
diff --git a/kernel/pid.c b/kernel/pid.c index c7346fb801fc..8132a6ddfa10 100644 --- a/kernel/pid.c +++ b/kernel/pid.c | |||
@@ -29,7 +29,8 @@ | |||
29 | #include <linux/pid_namespace.h> | 29 | #include <linux/pid_namespace.h> |
30 | #include <linux/init_task.h> | 30 | #include <linux/init_task.h> |
31 | 31 | ||
32 | #define pid_hashfn(nr) hash_long((unsigned long)nr, pidhash_shift) | 32 | #define pid_hashfn(nr, ns) \ |
33 | hash_long((unsigned long)nr + (unsigned long)ns, pidhash_shift) | ||
33 | static struct hlist_head *pid_hash; | 34 | static struct hlist_head *pid_hash; |
34 | static int pidhash_shift; | 35 | static int pidhash_shift; |
35 | struct pid init_struct_pid = INIT_STRUCT_PID; | 36 | struct pid init_struct_pid = INIT_STRUCT_PID; |
@@ -186,11 +187,13 @@ fastcall void put_pid(struct pid *pid) | |||
186 | if (!pid) | 187 | if (!pid) |
187 | return; | 188 | return; |
188 | 189 | ||
189 | /* FIXME - this must be the namespace this pid lives in */ | 190 | ns = pid->numbers[pid->level].ns; |
190 | ns = &init_pid_ns; | ||
191 | if ((atomic_read(&pid->count) == 1) || | 191 | if ((atomic_read(&pid->count) == 1) || |
192 | atomic_dec_and_test(&pid->count)) | 192 | atomic_dec_and_test(&pid->count)) { |
193 | kmem_cache_free(ns->pid_cachep, pid); | 193 | kmem_cache_free(ns->pid_cachep, pid); |
194 | if (ns != &init_pid_ns) | ||
195 | put_pid_ns(ns); | ||
196 | } | ||
194 | } | 197 | } |
195 | EXPORT_SYMBOL_GPL(put_pid); | 198 | EXPORT_SYMBOL_GPL(put_pid); |
196 | 199 | ||
@@ -203,45 +206,61 @@ static void delayed_put_pid(struct rcu_head *rhp) | |||
203 | fastcall void free_pid(struct pid *pid) | 206 | fastcall void free_pid(struct pid *pid) |
204 | { | 207 | { |
205 | /* We can be called with write_lock_irq(&tasklist_lock) held */ | 208 | /* We can be called with write_lock_irq(&tasklist_lock) held */ |
209 | int i; | ||
206 | unsigned long flags; | 210 | unsigned long flags; |
207 | 211 | ||
208 | spin_lock_irqsave(&pidmap_lock, flags); | 212 | spin_lock_irqsave(&pidmap_lock, flags); |
209 | hlist_del_rcu(&pid->pid_chain); | 213 | hlist_del_rcu(&pid->pid_chain); |
210 | spin_unlock_irqrestore(&pidmap_lock, flags); | 214 | spin_unlock_irqrestore(&pidmap_lock, flags); |
211 | 215 | ||
212 | free_pidmap(&init_pid_ns, pid->nr); | 216 | for (i = 0; i <= pid->level; i++) |
217 | free_pidmap(pid->numbers[i].ns, pid->numbers[i].nr); | ||
218 | |||
213 | call_rcu(&pid->rcu, delayed_put_pid); | 219 | call_rcu(&pid->rcu, delayed_put_pid); |
214 | } | 220 | } |
215 | 221 | ||
216 | struct pid *alloc_pid(void) | 222 | struct pid *alloc_pid(struct pid_namespace *ns) |
217 | { | 223 | { |
218 | struct pid *pid; | 224 | struct pid *pid; |
219 | enum pid_type type; | 225 | enum pid_type type; |
220 | int nr = -1; | 226 | int i, nr; |
221 | struct pid_namespace *ns; | 227 | struct pid_namespace *tmp; |
222 | 228 | ||
223 | ns = task_active_pid_ns(current); | ||
224 | pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL); | 229 | pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL); |
225 | if (!pid) | 230 | if (!pid) |
226 | goto out; | 231 | goto out; |
227 | 232 | ||
228 | nr = alloc_pidmap(ns); | 233 | tmp = ns; |
229 | if (nr < 0) | 234 | for (i = ns->level; i >= 0; i--) { |
230 | goto out_free; | 235 | nr = alloc_pidmap(tmp); |
236 | if (nr < 0) | ||
237 | goto out_free; | ||
231 | 238 | ||
239 | pid->numbers[i].nr = nr; | ||
240 | pid->numbers[i].ns = tmp; | ||
241 | tmp = tmp->parent; | ||
242 | } | ||
243 | |||
244 | if (ns != &init_pid_ns) | ||
245 | get_pid_ns(ns); | ||
246 | |||
247 | pid->level = ns->level; | ||
248 | pid->nr = pid->numbers[0].nr; | ||
232 | atomic_set(&pid->count, 1); | 249 | atomic_set(&pid->count, 1); |
233 | pid->nr = nr; | ||
234 | for (type = 0; type < PIDTYPE_MAX; ++type) | 250 | for (type = 0; type < PIDTYPE_MAX; ++type) |
235 | INIT_HLIST_HEAD(&pid->tasks[type]); | 251 | INIT_HLIST_HEAD(&pid->tasks[type]); |
236 | 252 | ||
237 | spin_lock_irq(&pidmap_lock); | 253 | spin_lock_irq(&pidmap_lock); |
238 | hlist_add_head_rcu(&pid->pid_chain, &pid_hash[pid_hashfn(pid->nr)]); | 254 | hlist_add_head_rcu(&pid->pid_chain, &pid_hash[pid_hashfn(pid->nr, ns)]); |
239 | spin_unlock_irq(&pidmap_lock); | 255 | spin_unlock_irq(&pidmap_lock); |
240 | 256 | ||
241 | out: | 257 | out: |
242 | return pid; | 258 | return pid; |
243 | 259 | ||
244 | out_free: | 260 | out_free: |
261 | for (i++; i <= ns->level; i++) | ||
262 | free_pidmap(pid->numbers[i].ns, pid->numbers[i].nr); | ||
263 | |||
245 | kmem_cache_free(ns->pid_cachep, pid); | 264 | kmem_cache_free(ns->pid_cachep, pid); |
246 | pid = NULL; | 265 | pid = NULL; |
247 | goto out; | 266 | goto out; |
@@ -253,7 +272,7 @@ struct pid * fastcall find_pid(int nr) | |||
253 | struct pid *pid; | 272 | struct pid *pid; |
254 | 273 | ||
255 | hlist_for_each_entry_rcu(pid, elem, | 274 | hlist_for_each_entry_rcu(pid, elem, |
256 | &pid_hash[pid_hashfn(nr)], pid_chain) { | 275 | &pid_hash[pid_hashfn(nr, &init_pid_ns)], pid_chain) { |
257 | if (pid->nr == nr) | 276 | if (pid->nr == nr) |
258 | return pid; | 277 | return pid; |
259 | } | 278 | } |