diff options
Diffstat (limited to 'kernel/pid.c')
-rw-r--r-- | kernel/pid.c | 88 |
1 files changed, 82 insertions, 6 deletions
diff --git a/kernel/pid.c b/kernel/pid.c index 4b17acdb862f..f76097c60475 100644 --- a/kernel/pid.c +++ b/kernel/pid.c | |||
@@ -18,6 +18,12 @@ | |||
18 | * allocation scenario when all but one out of 1 million PIDs possible are | 18 | * allocation scenario when all but one out of 1 million PIDs possible are |
19 | * allocated already: the scanning of 32 list entries and at most PAGE_SIZE | 19 | * allocated already: the scanning of 32 list entries and at most PAGE_SIZE |
20 | * bytes. The typical fastpath is a single successful setbit. Freeing is O(1). | 20 | * bytes. The typical fastpath is a single successful setbit. Freeing is O(1). |
21 | * | ||
22 | * Pid namespaces: | ||
23 | * (C) 2007 Pavel Emelyanov <xemul@openvz.org>, OpenVZ, SWsoft Inc. | ||
24 | * (C) 2007 Sukadev Bhattiprolu <sukadev@us.ibm.com>, IBM | ||
25 | * Many thanks to Oleg Nesterov for comments and help | ||
26 | * | ||
21 | */ | 27 | */ |
22 | 28 | ||
23 | #include <linux/mm.h> | 29 | #include <linux/mm.h> |
@@ -456,8 +462,8 @@ static struct kmem_cache *create_pid_cachep(int nr_ids) | |||
456 | 462 | ||
457 | snprintf(pcache->name, sizeof(pcache->name), "pid_%d", nr_ids); | 463 | snprintf(pcache->name, sizeof(pcache->name), "pid_%d", nr_ids); |
458 | cachep = kmem_cache_create(pcache->name, | 464 | cachep = kmem_cache_create(pcache->name, |
459 | /* FIXME add numerical ids here */ | 465 | sizeof(struct pid) + (nr_ids - 1) * sizeof(struct upid), |
460 | sizeof(struct pid), 0, SLAB_HWCACHE_ALIGN, NULL); | 466 | 0, SLAB_HWCACHE_ALIGN, NULL); |
461 | if (cachep == NULL) | 467 | if (cachep == NULL) |
462 | goto err_cachep; | 468 | goto err_cachep; |
463 | 469 | ||
@@ -475,19 +481,89 @@ err_alloc: | |||
475 | return NULL; | 481 | return NULL; |
476 | } | 482 | } |
477 | 483 | ||
484 | static struct pid_namespace *create_pid_namespace(int level) | ||
485 | { | ||
486 | struct pid_namespace *ns; | ||
487 | int i; | ||
488 | |||
489 | ns = kmalloc(sizeof(struct pid_namespace), GFP_KERNEL); | ||
490 | if (ns == NULL) | ||
491 | goto out; | ||
492 | |||
493 | ns->pidmap[0].page = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
494 | if (!ns->pidmap[0].page) | ||
495 | goto out_free; | ||
496 | |||
497 | ns->pid_cachep = create_pid_cachep(level + 1); | ||
498 | if (ns->pid_cachep == NULL) | ||
499 | goto out_free_map; | ||
500 | |||
501 | kref_init(&ns->kref); | ||
502 | ns->last_pid = 0; | ||
503 | ns->child_reaper = NULL; | ||
504 | ns->level = level; | ||
505 | |||
506 | set_bit(0, ns->pidmap[0].page); | ||
507 | atomic_set(&ns->pidmap[0].nr_free, BITS_PER_PAGE - 1); | ||
508 | |||
509 | for (i = 1; i < PIDMAP_ENTRIES; i++) { | ||
510 | ns->pidmap[i].page = 0; | ||
511 | atomic_set(&ns->pidmap[i].nr_free, BITS_PER_PAGE); | ||
512 | } | ||
513 | |||
514 | return ns; | ||
515 | |||
516 | out_free_map: | ||
517 | kfree(ns->pidmap[0].page); | ||
518 | out_free: | ||
519 | kfree(ns); | ||
520 | out: | ||
521 | return ERR_PTR(-ENOMEM); | ||
522 | } | ||
523 | |||
524 | static void destroy_pid_namespace(struct pid_namespace *ns) | ||
525 | { | ||
526 | int i; | ||
527 | |||
528 | for (i = 0; i < PIDMAP_ENTRIES; i++) | ||
529 | kfree(ns->pidmap[i].page); | ||
530 | kfree(ns); | ||
531 | } | ||
532 | |||
478 | struct pid_namespace *copy_pid_ns(unsigned long flags, struct pid_namespace *old_ns) | 533 | struct pid_namespace *copy_pid_ns(unsigned long flags, struct pid_namespace *old_ns) |
479 | { | 534 | { |
535 | struct pid_namespace *new_ns; | ||
536 | |||
480 | BUG_ON(!old_ns); | 537 | BUG_ON(!old_ns); |
481 | get_pid_ns(old_ns); | 538 | new_ns = get_pid_ns(old_ns); |
482 | return old_ns; | 539 | if (!(flags & CLONE_NEWPID)) |
540 | goto out; | ||
541 | |||
542 | new_ns = ERR_PTR(-EINVAL); | ||
543 | if (flags & CLONE_THREAD) | ||
544 | goto out_put; | ||
545 | |||
546 | new_ns = create_pid_namespace(old_ns->level + 1); | ||
547 | if (!IS_ERR(new_ns)) | ||
548 | new_ns->parent = get_pid_ns(old_ns); | ||
549 | |||
550 | out_put: | ||
551 | put_pid_ns(old_ns); | ||
552 | out: | ||
553 | return new_ns; | ||
483 | } | 554 | } |
484 | 555 | ||
485 | void free_pid_ns(struct kref *kref) | 556 | void free_pid_ns(struct kref *kref) |
486 | { | 557 | { |
487 | struct pid_namespace *ns; | 558 | struct pid_namespace *ns, *parent; |
488 | 559 | ||
489 | ns = container_of(kref, struct pid_namespace, kref); | 560 | ns = container_of(kref, struct pid_namespace, kref); |
490 | kfree(ns); | 561 | |
562 | parent = ns->parent; | ||
563 | destroy_pid_namespace(ns); | ||
564 | |||
565 | if (parent != NULL) | ||
566 | put_pid_ns(parent); | ||
491 | } | 567 | } |
492 | 568 | ||
493 | /* | 569 | /* |