Commit bb1a1146 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents bbb8ceb5 79a818b5
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -5266,6 +5266,7 @@ F: tools/testing/selftests/cgroup/
CONTROL GROUP - BLOCK IO CONTROLLER (BLKIO)
M:	Tejun Heo <tj@kernel.org>
M:	Josef Bacik <josef@toxicpanda.com>
M:	Jens Axboe <axboe@kernel.dk>
L:	cgroups@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:	block/bfq-cgroup.c
F:	block/blk-cgroup.c
F:	block/blk-iocost.c
F:	block/blk-iolatency.c
F:	block/blk-throttle.c
F:	include/linux/blk-cgroup.h
+1 −0
Original line number Diff line number Diff line
@@ -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_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_transfer_tasks(struct cgroup *to, struct cgroup *from);
+1 −1
Original line number Diff line number Diff line
@@ -196,7 +196,7 @@ static int bpf_iter_attach_cgroup(struct bpf_prog *prog,
		return -EINVAL;

	if (fd)
		cgrp = cgroup_get_from_fd(fd);
		cgrp = cgroup_v1v2_get_from_fd(fd);
	else if (id)
		cgrp = cgroup_get_from_id(id);
	else /* walk the entire hierarchy by default. */
+79 −20
Original line number Diff line number Diff line
@@ -1392,6 +1392,9 @@ static void cgroup_destroy_root(struct cgroup_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,
					    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;
	} else {
		struct cgrp_cset_link *link;
		lockdep_assert_held(&css_set_lock);

		list_for_each_entry(link, &cset->cgrp_links, cgrp_link) {
			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;
}

@@ -1436,23 +1441,36 @@ current_cgns_cgroup_from_root(struct cgroup_root *root)

	rcu_read_unlock();

	BUG_ON(!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 */
static struct cgroup *cset_cgroup_from_root(struct css_set *cset,
					    struct cgroup_root *root)
{
	struct cgroup *res = NULL;

	lockdep_assert_held(&cgroup_mutex);
	lockdep_assert_held(&css_set_lock);

	res = __cset_cgroup_from_root(cset, root);

	BUG_ON(!res);
	return res;
	return __cset_cgroup_from_root(cset, root);
}

/*
@@ -6191,9 +6209,7 @@ struct cgroup *cgroup_get_from_id(u64 id)
	if (!cgrp)
		return ERR_PTR(-ENOENT);

	spin_lock_irq(&css_set_lock);
	root_cgrp = current_cgns_cgroup_from_root(&cgrp_dfl_root);
	spin_unlock_irq(&css_set_lock);
	root_cgrp = current_cgns_cgroup_dfl();
	if (!cgroup_is_descendant(cgrp, root_cgrp)) {
		cgroup_put(cgrp);
		return ERR_PTR(-ENOENT);
@@ -6294,16 +6310,42 @@ void cgroup_fork(struct task_struct *child)
	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 *cgrp;

	css = css_tryget_online_from_dir(f->f_path.dentry, NULL);
	if (IS_ERR(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;
}

@@ -6772,10 +6814,8 @@ struct cgroup *cgroup_get_from_path(const char *path)
	struct cgroup *cgrp = ERR_PTR(-ENOENT);
	struct cgroup *root_cgrp;

	spin_lock_irq(&css_set_lock);
	root_cgrp = current_cgns_cgroup_from_root(&cgrp_dfl_root);
	root_cgrp = current_cgns_cgroup_dfl();
	kn = kernfs_walk_and_get(root_cgrp->kn, path);
	spin_unlock_irq(&css_set_lock);
	if (!kn)
		goto out;

@@ -6800,15 +6840,15 @@ struct cgroup *cgroup_get_from_path(const char *path)
EXPORT_SYMBOL_GPL(cgroup_get_from_path);

/**
 * cgroup_get_from_fd - get a cgroup pointer from a fd
 * @fd: fd obtained by open(cgroup2_dir)
 * cgroup_v1v2_get_from_fd - get a cgroup pointer from a fd
 * @fd: fd obtained by open(cgroup_dir)
 *
 * Find the cgroup from a fd which should be obtained
 * by opening a cgroup directory.  Returns a pointer to the
 * cgroup on success. ERR_PTR is returned if the cgroup
 * cannot be found.
 */
struct cgroup *cgroup_get_from_fd(int fd)
struct cgroup *cgroup_v1v2_get_from_fd(int fd)
{
	struct cgroup *cgrp;
	struct file *f;
@@ -6817,10 +6857,29 @@ struct cgroup *cgroup_get_from_fd(int fd)
	if (!f)
		return ERR_PTR(-EBADF);

	cgrp = cgroup_get_from_file(f);
	cgrp = cgroup_v1v2_get_from_file(f);
	fput(f);
	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);

static u64 power_of_ten(int power)