Commit bb1a1146 authored by Linus Torvalds's avatar Linus Torvalds

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
...@@ -5266,6 +5266,7 @@ F: tools/testing/selftests/cgroup/ ...@@ -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 ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment