diff options
| author | Tejun Heo <tj@kernel.org> | 2016-12-27 14:49:09 -0500 | 
|---|---|---|
| committer | Tejun Heo <tj@kernel.org> | 2016-12-27 14:49:09 -0500 | 
| commit | dcfe149b9f45aaf89bb95e8b314210da626417d9 (patch) | |
| tree | 7529523e033eb20fdcda9e8ea8561f9cee860433 | |
| parent | d62beb7f3dc6b45f9b9d381897e05fe8ba286d8a (diff) | |
cgroup: move namespace code to kernel/cgroup/namespace.c
get/put_css_set() get exposed in cgroup-internal.h in the process.
Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Acked-by: Zefan Li <lizefan@huawei.com>
| -rw-r--r-- | kernel/cgroup/Makefile | 2 | ||||
| -rw-r--r-- | kernel/cgroup/cgroup-internal.h | 32 | ||||
| -rw-r--r-- | kernel/cgroup/cgroup.c | 175 | ||||
| -rw-r--r-- | kernel/cgroup/namespace.c | 155 | 
4 files changed, 189 insertions, 175 deletions
| diff --git a/kernel/cgroup/Makefile b/kernel/cgroup/Makefile index 719588cb18cd..6d42a3211164 100644 --- a/kernel/cgroup/Makefile +++ b/kernel/cgroup/Makefile @@ -1,4 +1,4 @@ -obj-y := cgroup.o cgroup-v1.o +obj-y := cgroup.o namespace.o cgroup-v1.o  obj-$(CONFIG_CGROUP_FREEZER) += freezer.o  obj-$(CONFIG_CGROUP_PIDS) += pids.o diff --git a/kernel/cgroup/cgroup-internal.h b/kernel/cgroup/cgroup-internal.h index a890c92cb688..589b0e7013ec 100644 --- a/kernel/cgroup/cgroup-internal.h +++ b/kernel/cgroup/cgroup-internal.h @@ -65,6 +65,33 @@ static inline bool notify_on_release(const struct cgroup *cgrp)  	return test_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);  } +void put_css_set_locked(struct css_set *cset); + +static inline void put_css_set(struct css_set *cset) +{ +	unsigned long flags; + +	/* +	 * Ensure that the refcount doesn't hit zero while any readers +	 * can see it. Similar to atomic_dec_and_lock(), but for an +	 * rwlock +	 */ +	if (atomic_add_unless(&cset->refcount, -1, 1)) +		return; + +	spin_lock_irqsave(&css_set_lock, flags); +	put_css_set_locked(cset); +	spin_unlock_irqrestore(&css_set_lock, flags); +} + +/* + * refcounted get/put for css_set objects + */ +static inline void get_css_set(struct css_set *cset) +{ +	atomic_inc(&cset->refcount); +} +  bool cgroup_ssid_enabled(int ssid);  bool cgroup_on_dfl(const struct cgroup *cgrp); @@ -108,6 +135,11 @@ int cgroup_show_path(struct seq_file *sf, struct kernfs_node *kf_node,  		     struct kernfs_root *kf_root);  /* + * namespace.c + */ +extern const struct proc_ns_operations cgroupns_operations; + +/*   * cgroup-v1.c   */  extern struct cftype cgroup1_base_files[]; diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index a05a2dacf5dc..b6b9068ef468 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c @@ -718,7 +718,7 @@ static unsigned long css_set_hash(struct cgroup_subsys_state *css[])  	return key;  } -static void put_css_set_locked(struct css_set *cset) +void put_css_set_locked(struct css_set *cset)  {  	struct cgrp_cset_link *link, *tmp_link;  	struct cgroup_subsys *ss; @@ -748,31 +748,6 @@ static void put_css_set_locked(struct css_set *cset)  	kfree_rcu(cset, rcu_head);  } -static void put_css_set(struct css_set *cset) -{ -	unsigned long flags; - -	/* -	 * Ensure that the refcount doesn't hit zero while any readers -	 * can see it. Similar to atomic_dec_and_lock(), but for an -	 * rwlock -	 */ -	if (atomic_add_unless(&cset->refcount, -1, 1)) -		return; - -	spin_lock_irqsave(&css_set_lock, flags); -	put_css_set_locked(cset); -	spin_unlock_irqrestore(&css_set_lock, flags); -} - -/* - * refcounted get/put for css_set objects - */ -static inline void get_css_set(struct css_set *cset) -{ -	atomic_inc(&cset->refcount); -} -  /**   * compare_css_sets - helper function for find_existing_css_set().   * @cset: candidate css_set being tested @@ -5109,154 +5084,6 @@ void cgroup_sk_free(struct sock_cgroup_data *skcd)  #endif	/* CONFIG_SOCK_CGROUP_DATA */ -/* cgroup namespaces */ - -static struct ucounts *inc_cgroup_namespaces(struct user_namespace *ns) -{ -	return inc_ucount(ns, current_euid(), UCOUNT_CGROUP_NAMESPACES); -} - -static void dec_cgroup_namespaces(struct ucounts *ucounts) -{ -	dec_ucount(ucounts, UCOUNT_CGROUP_NAMESPACES); -} - -static struct cgroup_namespace *alloc_cgroup_ns(void) -{ -	struct cgroup_namespace *new_ns; -	int ret; - -	new_ns = kzalloc(sizeof(struct cgroup_namespace), GFP_KERNEL); -	if (!new_ns) -		return ERR_PTR(-ENOMEM); -	ret = ns_alloc_inum(&new_ns->ns); -	if (ret) { -		kfree(new_ns); -		return ERR_PTR(ret); -	} -	atomic_set(&new_ns->count, 1); -	new_ns->ns.ops = &cgroupns_operations; -	return new_ns; -} - -void free_cgroup_ns(struct cgroup_namespace *ns) -{ -	put_css_set(ns->root_cset); -	dec_cgroup_namespaces(ns->ucounts); -	put_user_ns(ns->user_ns); -	ns_free_inum(&ns->ns); -	kfree(ns); -} -EXPORT_SYMBOL(free_cgroup_ns); - -struct cgroup_namespace *copy_cgroup_ns(unsigned long flags, -					struct user_namespace *user_ns, -					struct cgroup_namespace *old_ns) -{ -	struct cgroup_namespace *new_ns; -	struct ucounts *ucounts; -	struct css_set *cset; - -	BUG_ON(!old_ns); - -	if (!(flags & CLONE_NEWCGROUP)) { -		get_cgroup_ns(old_ns); -		return old_ns; -	} - -	/* Allow only sysadmin to create cgroup namespace. */ -	if (!ns_capable(user_ns, CAP_SYS_ADMIN)) -		return ERR_PTR(-EPERM); - -	ucounts = inc_cgroup_namespaces(user_ns); -	if (!ucounts) -		return ERR_PTR(-ENOSPC); - -	/* It is not safe to take cgroup_mutex here */ -	spin_lock_irq(&css_set_lock); -	cset = task_css_set(current); -	get_css_set(cset); -	spin_unlock_irq(&css_set_lock); - -	new_ns = alloc_cgroup_ns(); -	if (IS_ERR(new_ns)) { -		put_css_set(cset); -		dec_cgroup_namespaces(ucounts); -		return new_ns; -	} - -	new_ns->user_ns = get_user_ns(user_ns); -	new_ns->ucounts = ucounts; -	new_ns->root_cset = cset; - -	return new_ns; -} - -static inline struct cgroup_namespace *to_cg_ns(struct ns_common *ns) -{ -	return container_of(ns, struct cgroup_namespace, ns); -} - -static int cgroupns_install(struct nsproxy *nsproxy, struct ns_common *ns) -{ -	struct cgroup_namespace *cgroup_ns = to_cg_ns(ns); - -	if (!ns_capable(current_user_ns(), CAP_SYS_ADMIN) || -	    !ns_capable(cgroup_ns->user_ns, CAP_SYS_ADMIN)) -		return -EPERM; - -	/* Don't need to do anything if we are attaching to our own cgroupns. */ -	if (cgroup_ns == nsproxy->cgroup_ns) -		return 0; - -	get_cgroup_ns(cgroup_ns); -	put_cgroup_ns(nsproxy->cgroup_ns); -	nsproxy->cgroup_ns = cgroup_ns; - -	return 0; -} - -static struct ns_common *cgroupns_get(struct task_struct *task) -{ -	struct cgroup_namespace *ns = NULL; -	struct nsproxy *nsproxy; - -	task_lock(task); -	nsproxy = task->nsproxy; -	if (nsproxy) { -		ns = nsproxy->cgroup_ns; -		get_cgroup_ns(ns); -	} -	task_unlock(task); - -	return ns ? &ns->ns : NULL; -} - -static void cgroupns_put(struct ns_common *ns) -{ -	put_cgroup_ns(to_cg_ns(ns)); -} - -static struct user_namespace *cgroupns_owner(struct ns_common *ns) -{ -	return to_cg_ns(ns)->user_ns; -} - -const struct proc_ns_operations cgroupns_operations = { -	.name		= "cgroup", -	.type		= CLONE_NEWCGROUP, -	.get		= cgroupns_get, -	.put		= cgroupns_put, -	.install	= cgroupns_install, -	.owner		= cgroupns_owner, -}; - -static __init int cgroup_namespaces_init(void) -{ -	return 0; -} -subsys_initcall(cgroup_namespaces_init); -  #ifdef CONFIG_CGROUP_BPF  void cgroup_bpf_update(struct cgroup *cgrp,  		       struct bpf_prog *prog, diff --git a/kernel/cgroup/namespace.c b/kernel/cgroup/namespace.c new file mode 100644 index 000000000000..cff7ea62c38f --- /dev/null +++ b/kernel/cgroup/namespace.c @@ -0,0 +1,155 @@ +#include "cgroup-internal.h" + +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/nsproxy.h> +#include <linux/proc_ns.h> + + +/* cgroup namespaces */ + +static struct ucounts *inc_cgroup_namespaces(struct user_namespace *ns) +{ +	return inc_ucount(ns, current_euid(), UCOUNT_CGROUP_NAMESPACES); +} + +static void dec_cgroup_namespaces(struct ucounts *ucounts) +{ +	dec_ucount(ucounts, UCOUNT_CGROUP_NAMESPACES); +} + +static struct cgroup_namespace *alloc_cgroup_ns(void) +{ +	struct cgroup_namespace *new_ns; +	int ret; + +	new_ns = kzalloc(sizeof(struct cgroup_namespace), GFP_KERNEL); +	if (!new_ns) +		return ERR_PTR(-ENOMEM); +	ret = ns_alloc_inum(&new_ns->ns); +	if (ret) { +		kfree(new_ns); +		return ERR_PTR(ret); +	} +	atomic_set(&new_ns->count, 1); +	new_ns->ns.ops = &cgroupns_operations; +	return new_ns; +} + +void free_cgroup_ns(struct cgroup_namespace *ns) +{ +	put_css_set(ns->root_cset); +	dec_cgroup_namespaces(ns->ucounts); +	put_user_ns(ns->user_ns); +	ns_free_inum(&ns->ns); +	kfree(ns); +} +EXPORT_SYMBOL(free_cgroup_ns); + +struct cgroup_namespace *copy_cgroup_ns(unsigned long flags, +					struct user_namespace *user_ns, +					struct cgroup_namespace *old_ns) +{ +	struct cgroup_namespace *new_ns; +	struct ucounts *ucounts; +	struct css_set *cset; + +	BUG_ON(!old_ns); + +	if (!(flags & CLONE_NEWCGROUP)) { +		get_cgroup_ns(old_ns); +		return old_ns; +	} + +	/* Allow only sysadmin to create cgroup namespace. */ +	if (!ns_capable(user_ns, CAP_SYS_ADMIN)) +		return ERR_PTR(-EPERM); + +	ucounts = inc_cgroup_namespaces(user_ns); +	if (!ucounts) +		return ERR_PTR(-ENOSPC); + +	/* It is not safe to take cgroup_mutex here */ +	spin_lock_irq(&css_set_lock); +	cset = task_css_set(current); +	get_css_set(cset); +	spin_unlock_irq(&css_set_lock); + +	new_ns = alloc_cgroup_ns(); +	if (IS_ERR(new_ns)) { +		put_css_set(cset); +		dec_cgroup_namespaces(ucounts); +		return new_ns; +	} + +	new_ns->user_ns = get_user_ns(user_ns); +	new_ns->ucounts = ucounts; +	new_ns->root_cset = cset; + +	return new_ns; +} + +static inline struct cgroup_namespace *to_cg_ns(struct ns_common *ns) +{ +	return container_of(ns, struct cgroup_namespace, ns); +} + +static int cgroupns_install(struct nsproxy *nsproxy, struct ns_common *ns) +{ +	struct cgroup_namespace *cgroup_ns = to_cg_ns(ns); + +	if (!ns_capable(current_user_ns(), CAP_SYS_ADMIN) || +	    !ns_capable(cgroup_ns->user_ns, CAP_SYS_ADMIN)) +		return -EPERM; + +	/* Don't need to do anything if we are attaching to our own cgroupns. */ +	if (cgroup_ns == nsproxy->cgroup_ns) +		return 0; + +	get_cgroup_ns(cgroup_ns); +	put_cgroup_ns(nsproxy->cgroup_ns); +	nsproxy->cgroup_ns = cgroup_ns; + +	return 0; +} + +static struct ns_common *cgroupns_get(struct task_struct *task) +{ +	struct cgroup_namespace *ns = NULL; +	struct nsproxy *nsproxy; + +	task_lock(task); +	nsproxy = task->nsproxy; +	if (nsproxy) { +		ns = nsproxy->cgroup_ns; +		get_cgroup_ns(ns); +	} +	task_unlock(task); + +	return ns ? &ns->ns : NULL; +} + +static void cgroupns_put(struct ns_common *ns) +{ +	put_cgroup_ns(to_cg_ns(ns)); +} + +static struct user_namespace *cgroupns_owner(struct ns_common *ns) +{ +	return to_cg_ns(ns)->user_ns; +} + +const struct proc_ns_operations cgroupns_operations = { +	.name		= "cgroup", +	.type		= CLONE_NEWCGROUP, +	.get		= cgroupns_get, +	.put		= cgroupns_put, +	.install	= cgroupns_install, +	.owner		= cgroupns_owner, +}; + +static __init int cgroup_namespaces_init(void) +{ +	return 0; +} +subsys_initcall(cgroup_namespaces_init); | 
