summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2016-07-30 21:53:37 +0300
committerEric W. Biederman <ebiederm@xmission.com>2016-08-08 17:17:18 +0300
commitb032132c3c218f4a09e9499b3674299a752581c6 (patch)
tree053a27f83f9bf00638197f451f49117cfe110fea /kernel
parent13bcc6a2853435bb5dad368bcbaa9d2a5b9c0ac4 (diff)
downloadlinux-b032132c3c218f4a09e9499b3674299a752581c6.tar.xz
userns: Free user namespaces in process context
Add the necessary boiler plate to move freeing of user namespaces into work queue and thus into process context where things can sleep. This is a necessary precursor to per user namespace sysctls. Signed-off-by: "Eric W. Biederman" <ebiederm@xmission.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/user_namespace.c14
1 files changed, 11 insertions, 3 deletions
diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
index 68f594212759..5247cdb24e62 100644
--- a/kernel/user_namespace.c
+++ b/kernel/user_namespace.c
@@ -29,6 +29,7 @@ static DEFINE_MUTEX(userns_state_mutex);
static bool new_idmap_permitted(const struct file *file,
struct user_namespace *ns, int cap_setid,
struct uid_gid_map *map);
+static void free_user_ns(struct work_struct *work);
static void set_cred_user_ns(struct cred *cred, struct user_namespace *user_ns)
{
@@ -101,6 +102,7 @@ int create_user_ns(struct cred *new)
ns->level = parent_ns->level + 1;
ns->owner = owner;
ns->group = group;
+ INIT_WORK(&ns->work, free_user_ns);
/* Inherit USERNS_SETGROUPS_ALLOWED from our parent */
mutex_lock(&userns_state_mutex);
@@ -135,9 +137,10 @@ int unshare_userns(unsigned long unshare_flags, struct cred **new_cred)
return err;
}
-void free_user_ns(struct user_namespace *ns)
+static void free_user_ns(struct work_struct *work)
{
- struct user_namespace *parent;
+ struct user_namespace *parent, *ns =
+ container_of(work, struct user_namespace, work);
do {
parent = ns->parent;
@@ -149,7 +152,12 @@ void free_user_ns(struct user_namespace *ns)
ns = parent;
} while (atomic_dec_and_test(&parent->count));
}
-EXPORT_SYMBOL(free_user_ns);
+
+void __put_user_ns(struct user_namespace *ns)
+{
+ schedule_work(&ns->work);
+}
+EXPORT_SYMBOL(__put_user_ns);
static u32 map_id_range_down(struct uid_gid_map *map, u32 id, u32 count)
{