[PATCH 1/2] pid_ns: move destroy_pid_namespace() into workqueue context A separate patch to simplify the review of the next change. Move destroy_pid_namespace() into workqueue context. This allows us to do mntput() from free_pid_ns() paths, see the next patch. Add the new member, "struct work_struct destroy" into struct pid_namespace and change free_pid_ns() to call destroy_pid_namespace() via schedule_work(). The patch looks a bit complicated because it also moves copy_pid_ns() up. Signed-off-by: Oleg Nesterov --- include/linux/pid_namespace.h | 1 + kernel/pid_namespace.c | 25 +++++++++++++++++-------- 2 files changed, 18 insertions(+), 8 deletions(-) --- 35-rc3/include/linux/pid_namespace.h~PNS_5_DESTROY_FROM_WQ 2010-06-23 22:06:07.000000000 +0200 +++ 35-rc3/include/linux/pid_namespace.h 2010-06-24 15:17:46.000000000 +0200 @@ -24,6 +24,7 @@ struct pid_namespace { struct kmem_cache *pid_cachep; unsigned int level; struct pid_namespace *parent; + struct work_struct destroy; #ifdef CONFIG_PROC_FS struct vfsmount *proc_mnt; #endif --- 35-rc3/kernel/pid_namespace.c~PNS_5_DESTROY_FROM_WQ 2010-06-24 15:16:22.000000000 +0200 +++ 35-rc3/kernel/pid_namespace.c 2010-06-24 15:17:46.000000000 +0200 @@ -114,6 +114,16 @@ out: return ERR_PTR(err); } +struct pid_namespace *copy_pid_ns(unsigned long flags, + struct pid_namespace *old_ns) +{ + if (!(flags & CLONE_NEWPID)) + return get_pid_ns(old_ns); + if (flags & (CLONE_THREAD|CLONE_PARENT)) + return ERR_PTR(-EINVAL); + return create_pid_namespace(old_ns); +} + static void destroy_pid_namespace(struct pid_namespace *ns) { int i; @@ -123,13 +133,11 @@ static void destroy_pid_namespace(struct kmem_cache_free(pid_ns_cachep, ns); } -struct pid_namespace *copy_pid_ns(unsigned long flags, struct pid_namespace *old_ns) +static void destroy_pid_namespace_work(struct work_struct *work) { - if (!(flags & CLONE_NEWPID)) - return get_pid_ns(old_ns); - if (flags & (CLONE_THREAD|CLONE_PARENT)) - return ERR_PTR(-EINVAL); - return create_pid_namespace(old_ns); + struct pid_namespace *ns = + container_of(work, struct pid_namespace, destroy); + destroy_pid_namespace(ns); } void free_pid_ns(struct kref *kref) @@ -137,9 +145,10 @@ void free_pid_ns(struct kref *kref) struct pid_namespace *ns, *parent; ns = container_of(kref, struct pid_namespace, kref); - parent = ns->parent; - destroy_pid_namespace(ns); + + INIT_WORK(&ns->destroy, destroy_pid_namespace_work); + schedule_work(&ns->destroy); if (parent != NULL) put_pid_ns(parent);