mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	cgroup fixes for v6.1-rc1
* Fix a recent regression where a sleeping kernfs function is called with css_set_lock (spinlock) held. * Revert the commit to enable cgroup1 support for cgroup_get_from_fd/file(). Multiple users assume that the lookup only works for cgroup2 and breaks when fed a cgroup1 file. Instead, introduce a separate set of functions to lookup both v1 and v2 and use them where the user explicitly wants to support both versions. * Compat update for tools/perf/util/bpf_skel/bperf_cgroup.bpf.c. * Add Josef Bacik as a blkcg maintainer. -----BEGIN PGP SIGNATURE----- iIQEABYIACwWIQTfIjM1kS57o3GsC/uxYfJx3gVYGQUCY03MlA4cdGpAa2VybmVs Lm9yZwAKCRCxYfJx3gVYGTkUAQD7fNcSPuc2m/BvW+gySKQkp9PZMA6E6yOIqirc QKmIgwEAwWECW7RR1alhOGD50RtYkuYVsLD1+6Ka4eMHe+EhwA4= =kGLI -----END PGP SIGNATURE----- Merge tag 'cgroup-for-6.1-rc1-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup Pull cgroup fixes from Tejun Heo: - Fix a recent regression where a sleeping kernfs function is called with css_set_lock (spinlock) held - Revert the commit to enable cgroup1 support for cgroup_get_from_fd/file() Multiple users assume that the lookup only works for cgroup2 and breaks when fed a cgroup1 file. Instead, introduce a separate set of functions to lookup both v1 and v2 and use them where the user explicitly wants to support both versions. - Compat update for tools/perf/util/bpf_skel/bperf_cgroup.bpf.c. - Add Josef Bacik as a blkcg maintainer. * tag 'cgroup-for-6.1-rc1-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup: blkcg: Update MAINTAINERS entry mm: cgroup: fix comments for get from fd/file helpers perf stat: Support old kernels for bperf cgroup counting bpf: cgroup_iter: support cgroup1 using cgroup fd cgroup: add cgroup_v1v2_get_from_[fd/file]() Revert "cgroup: enable cgroup_get_from_file() on cgroup1" cgroup: Reorganize css_set_lock and kernfs path processing
This commit is contained in:
		
						commit
						bb1a114646
					
				
					 4 changed files with 83 additions and 21 deletions
				
			
		| 
						 | 
					@ -5266,6 +5266,7 @@ F:	tools/testing/selftests/cgroup/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
CONTROL GROUP - BLOCK IO CONTROLLER (BLKIO)
 | 
					CONTROL GROUP - BLOCK IO CONTROLLER (BLKIO)
 | 
				
			||||||
M:	Tejun Heo <tj@kernel.org>
 | 
					M:	Tejun Heo <tj@kernel.org>
 | 
				
			||||||
 | 
					M:	Josef Bacik <josef@toxicpanda.com>
 | 
				
			||||||
M:	Jens Axboe <axboe@kernel.dk>
 | 
					M:	Jens Axboe <axboe@kernel.dk>
 | 
				
			||||||
L:	cgroups@vger.kernel.org
 | 
					L:	cgroups@vger.kernel.org
 | 
				
			||||||
L:	linux-block@vger.kernel.org
 | 
					L:	linux-block@vger.kernel.org
 | 
				
			||||||
| 
						 | 
					@ -5273,6 +5274,7 @@ T:	git git://git.kernel.dk/linux-block
 | 
				
			||||||
F:	Documentation/admin-guide/cgroup-v1/blkio-controller.rst
 | 
					F:	Documentation/admin-guide/cgroup-v1/blkio-controller.rst
 | 
				
			||||||
F:	block/bfq-cgroup.c
 | 
					F:	block/bfq-cgroup.c
 | 
				
			||||||
F:	block/blk-cgroup.c
 | 
					F:	block/blk-cgroup.c
 | 
				
			||||||
 | 
					F:	block/blk-iocost.c
 | 
				
			||||||
F:	block/blk-iolatency.c
 | 
					F:	block/blk-iolatency.c
 | 
				
			||||||
F:	block/blk-throttle.c
 | 
					F:	block/blk-throttle.c
 | 
				
			||||||
F:	include/linux/blk-cgroup.h
 | 
					F:	include/linux/blk-cgroup.h
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -106,6 +106,7 @@ struct cgroup_subsys_state *css_tryget_online_from_dir(struct dentry *dentry,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct cgroup *cgroup_get_from_path(const char *path);
 | 
					struct cgroup *cgroup_get_from_path(const char *path);
 | 
				
			||||||
struct cgroup *cgroup_get_from_fd(int fd);
 | 
					struct cgroup *cgroup_get_from_fd(int fd);
 | 
				
			||||||
 | 
					struct cgroup *cgroup_v1v2_get_from_fd(int fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int cgroup_attach_task_all(struct task_struct *from, struct task_struct *);
 | 
					int cgroup_attach_task_all(struct task_struct *from, struct task_struct *);
 | 
				
			||||||
int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from);
 | 
					int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -196,7 +196,7 @@ static int bpf_iter_attach_cgroup(struct bpf_prog *prog,
 | 
				
			||||||
		return -EINVAL;
 | 
							return -EINVAL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (fd)
 | 
						if (fd)
 | 
				
			||||||
		cgrp = cgroup_get_from_fd(fd);
 | 
							cgrp = cgroup_v1v2_get_from_fd(fd);
 | 
				
			||||||
	else if (id)
 | 
						else if (id)
 | 
				
			||||||
		cgrp = cgroup_get_from_id(id);
 | 
							cgrp = cgroup_get_from_id(id);
 | 
				
			||||||
	else /* walk the entire hierarchy by default. */
 | 
						else /* walk the entire hierarchy by default. */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1392,6 +1392,9 @@ static void cgroup_destroy_root(struct cgroup_root *root)
 | 
				
			||||||
	cgroup_free_root(root);
 | 
						cgroup_free_root(root);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Returned cgroup is without refcount but it's valid as long as cset pins it.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
static inline struct cgroup *__cset_cgroup_from_root(struct css_set *cset,
 | 
					static inline struct cgroup *__cset_cgroup_from_root(struct css_set *cset,
 | 
				
			||||||
					    struct cgroup_root *root)
 | 
										    struct cgroup_root *root)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -1403,6 +1406,7 @@ static inline struct cgroup *__cset_cgroup_from_root(struct css_set *cset,
 | 
				
			||||||
		res_cgroup = cset->dfl_cgrp;
 | 
							res_cgroup = cset->dfl_cgrp;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		struct cgrp_cset_link *link;
 | 
							struct cgrp_cset_link *link;
 | 
				
			||||||
 | 
							lockdep_assert_held(&css_set_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		list_for_each_entry(link, &cset->cgrp_links, cgrp_link) {
 | 
							list_for_each_entry(link, &cset->cgrp_links, cgrp_link) {
 | 
				
			||||||
			struct cgroup *c = link->cgrp;
 | 
								struct cgroup *c = link->cgrp;
 | 
				
			||||||
| 
						 | 
					@ -1414,6 +1418,7 @@ static inline struct cgroup *__cset_cgroup_from_root(struct css_set *cset,
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						BUG_ON(!res_cgroup);
 | 
				
			||||||
	return res_cgroup;
 | 
						return res_cgroup;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1436,23 +1441,36 @@ current_cgns_cgroup_from_root(struct cgroup_root *root)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	rcu_read_unlock();
 | 
						rcu_read_unlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	BUG_ON(!res);
 | 
					 | 
				
			||||||
	return res;
 | 
						return res;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Look up cgroup associated with current task's cgroup namespace on the default
 | 
				
			||||||
 | 
					 * hierarchy.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Unlike current_cgns_cgroup_from_root(), this doesn't need locks:
 | 
				
			||||||
 | 
					 * - Internal rcu_read_lock is unnecessary because we don't dereference any rcu
 | 
				
			||||||
 | 
					 *   pointers.
 | 
				
			||||||
 | 
					 * - css_set_lock is not needed because we just read cset->dfl_cgrp.
 | 
				
			||||||
 | 
					 * - As a bonus returned cgrp is pinned with the current because it cannot
 | 
				
			||||||
 | 
					 *   switch cgroup_ns asynchronously.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static struct cgroup *current_cgns_cgroup_dfl(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct css_set *cset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						cset = current->nsproxy->cgroup_ns->root_cset;
 | 
				
			||||||
 | 
						return __cset_cgroup_from_root(cset, &cgrp_dfl_root);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* look up cgroup associated with given css_set on the specified hierarchy */
 | 
					/* look up cgroup associated with given css_set on the specified hierarchy */
 | 
				
			||||||
static struct cgroup *cset_cgroup_from_root(struct css_set *cset,
 | 
					static struct cgroup *cset_cgroup_from_root(struct css_set *cset,
 | 
				
			||||||
					    struct cgroup_root *root)
 | 
										    struct cgroup_root *root)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct cgroup *res = NULL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	lockdep_assert_held(&cgroup_mutex);
 | 
						lockdep_assert_held(&cgroup_mutex);
 | 
				
			||||||
	lockdep_assert_held(&css_set_lock);
 | 
						lockdep_assert_held(&css_set_lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	res = __cset_cgroup_from_root(cset, root);
 | 
						return __cset_cgroup_from_root(cset, root);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	BUG_ON(!res);
 | 
					 | 
				
			||||||
	return res;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -6191,9 +6209,7 @@ struct cgroup *cgroup_get_from_id(u64 id)
 | 
				
			||||||
	if (!cgrp)
 | 
						if (!cgrp)
 | 
				
			||||||
		return ERR_PTR(-ENOENT);
 | 
							return ERR_PTR(-ENOENT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock_irq(&css_set_lock);
 | 
						root_cgrp = current_cgns_cgroup_dfl();
 | 
				
			||||||
	root_cgrp = current_cgns_cgroup_from_root(&cgrp_dfl_root);
 | 
					 | 
				
			||||||
	spin_unlock_irq(&css_set_lock);
 | 
					 | 
				
			||||||
	if (!cgroup_is_descendant(cgrp, root_cgrp)) {
 | 
						if (!cgroup_is_descendant(cgrp, root_cgrp)) {
 | 
				
			||||||
		cgroup_put(cgrp);
 | 
							cgroup_put(cgrp);
 | 
				
			||||||
		return ERR_PTR(-ENOENT);
 | 
							return ERR_PTR(-ENOENT);
 | 
				
			||||||
| 
						 | 
					@ -6294,16 +6310,42 @@ void cgroup_fork(struct task_struct *child)
 | 
				
			||||||
	INIT_LIST_HEAD(&child->cg_list);
 | 
						INIT_LIST_HEAD(&child->cg_list);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct cgroup *cgroup_get_from_file(struct file *f)
 | 
					/**
 | 
				
			||||||
 | 
					 * cgroup_v1v2_get_from_file - get a cgroup pointer from a file pointer
 | 
				
			||||||
 | 
					 * @f: file corresponding to cgroup_dir
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Find the cgroup from a file pointer associated with a cgroup directory.
 | 
				
			||||||
 | 
					 * Returns a pointer to the cgroup on success. ERR_PTR is returned if the
 | 
				
			||||||
 | 
					 * cgroup cannot be found.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static struct cgroup *cgroup_v1v2_get_from_file(struct file *f)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct cgroup_subsys_state *css;
 | 
						struct cgroup_subsys_state *css;
 | 
				
			||||||
	struct cgroup *cgrp;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	css = css_tryget_online_from_dir(f->f_path.dentry, NULL);
 | 
						css = css_tryget_online_from_dir(f->f_path.dentry, NULL);
 | 
				
			||||||
	if (IS_ERR(css))
 | 
						if (IS_ERR(css))
 | 
				
			||||||
		return ERR_CAST(css);
 | 
							return ERR_CAST(css);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cgrp = css->cgroup;
 | 
						return css->cgroup;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * cgroup_get_from_file - same as cgroup_v1v2_get_from_file, but only supports
 | 
				
			||||||
 | 
					 * cgroup2.
 | 
				
			||||||
 | 
					 * @f: file corresponding to cgroup2_dir
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static struct cgroup *cgroup_get_from_file(struct file *f)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct cgroup *cgrp = cgroup_v1v2_get_from_file(f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (IS_ERR(cgrp))
 | 
				
			||||||
 | 
							return ERR_CAST(cgrp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!cgroup_on_dfl(cgrp)) {
 | 
				
			||||||
 | 
							cgroup_put(cgrp);
 | 
				
			||||||
 | 
							return ERR_PTR(-EBADF);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return cgrp;
 | 
						return cgrp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6772,10 +6814,8 @@ struct cgroup *cgroup_get_from_path(const char *path)
 | 
				
			||||||
	struct cgroup *cgrp = ERR_PTR(-ENOENT);
 | 
						struct cgroup *cgrp = ERR_PTR(-ENOENT);
 | 
				
			||||||
	struct cgroup *root_cgrp;
 | 
						struct cgroup *root_cgrp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	spin_lock_irq(&css_set_lock);
 | 
						root_cgrp = current_cgns_cgroup_dfl();
 | 
				
			||||||
	root_cgrp = current_cgns_cgroup_from_root(&cgrp_dfl_root);
 | 
					 | 
				
			||||||
	kn = kernfs_walk_and_get(root_cgrp->kn, path);
 | 
						kn = kernfs_walk_and_get(root_cgrp->kn, path);
 | 
				
			||||||
	spin_unlock_irq(&css_set_lock);
 | 
					 | 
				
			||||||
	if (!kn)
 | 
						if (!kn)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6800,15 +6840,15 @@ struct cgroup *cgroup_get_from_path(const char *path)
 | 
				
			||||||
EXPORT_SYMBOL_GPL(cgroup_get_from_path);
 | 
					EXPORT_SYMBOL_GPL(cgroup_get_from_path);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * cgroup_get_from_fd - get a cgroup pointer from a fd
 | 
					 * cgroup_v1v2_get_from_fd - get a cgroup pointer from a fd
 | 
				
			||||||
 * @fd: fd obtained by open(cgroup2_dir)
 | 
					 * @fd: fd obtained by open(cgroup_dir)
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Find the cgroup from a fd which should be obtained
 | 
					 * Find the cgroup from a fd which should be obtained
 | 
				
			||||||
 * by opening a cgroup directory.  Returns a pointer to the
 | 
					 * by opening a cgroup directory.  Returns a pointer to the
 | 
				
			||||||
 * cgroup on success. ERR_PTR is returned if the cgroup
 | 
					 * cgroup on success. ERR_PTR is returned if the cgroup
 | 
				
			||||||
 * cannot be found.
 | 
					 * cannot be found.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct cgroup *cgroup_get_from_fd(int fd)
 | 
					struct cgroup *cgroup_v1v2_get_from_fd(int fd)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct cgroup *cgrp;
 | 
						struct cgroup *cgrp;
 | 
				
			||||||
	struct file *f;
 | 
						struct file *f;
 | 
				
			||||||
| 
						 | 
					@ -6817,10 +6857,29 @@ struct cgroup *cgroup_get_from_fd(int fd)
 | 
				
			||||||
	if (!f)
 | 
						if (!f)
 | 
				
			||||||
		return ERR_PTR(-EBADF);
 | 
							return ERR_PTR(-EBADF);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	cgrp = cgroup_get_from_file(f);
 | 
						cgrp = cgroup_v1v2_get_from_file(f);
 | 
				
			||||||
	fput(f);
 | 
						fput(f);
 | 
				
			||||||
	return cgrp;
 | 
						return cgrp;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * cgroup_get_from_fd - same as cgroup_v1v2_get_from_fd, but only supports
 | 
				
			||||||
 | 
					 * cgroup2.
 | 
				
			||||||
 | 
					 * @fd: fd obtained by open(cgroup2_dir)
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct cgroup *cgroup_get_from_fd(int fd)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct cgroup *cgrp = cgroup_v1v2_get_from_fd(fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (IS_ERR(cgrp))
 | 
				
			||||||
 | 
							return ERR_CAST(cgrp);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!cgroup_on_dfl(cgrp)) {
 | 
				
			||||||
 | 
							cgroup_put(cgrp);
 | 
				
			||||||
 | 
							return ERR_PTR(-EBADF);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return cgrp;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
EXPORT_SYMBOL_GPL(cgroup_get_from_fd);
 | 
					EXPORT_SYMBOL_GPL(cgroup_get_from_fd);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static u64 power_of_ten(int power)
 | 
					static u64 power_of_ten(int power)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue