diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/fork.c | 2 | ||||
| -rw-r--r-- | kernel/pid.c | 49 |
2 files changed, 35 insertions, 16 deletions
diff --git a/kernel/fork.c b/kernel/fork.c index d2f4a420a5b9..984d259e172d 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
| @@ -1041,7 +1041,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, | |||
| 1041 | goto bad_fork_cleanup_put_domain; | 1041 | goto bad_fork_cleanup_put_domain; |
| 1042 | 1042 | ||
| 1043 | if (pid != &init_struct_pid) { | 1043 | if (pid != &init_struct_pid) { |
| 1044 | pid = alloc_pid(); | 1044 | pid = alloc_pid(task_active_pid_ns(p)); |
| 1045 | if (!pid) | 1045 | if (!pid) |
| 1046 | goto bad_fork_put_binfmt_module; | 1046 | goto bad_fork_put_binfmt_module; |
| 1047 | } | 1047 | } |
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 | } |
