cgroup: improve css_from_dir() into css_tryget_from_dir()
css_from_dir() returns the matching css (cgroup_subsys_state) given a dentry and subsystem. The function doesn't pin the css before returning and requires the caller to be holding RCU read lock or cgroup_mutex and handling pinning on the caller side. Given that users of the function are likely to want to pin the returned css (both existing users do) and that getting and putting css's are very cheap, there's no reason for the interface to be tricky like this. Rename css_from_dir() to css_tryget_from_dir() and make it try to pin the found css and return it only if pinning succeeded. The callers are updated so that they no longer do RCU locking and pinning around the function and just use the returned css. This will also ease converting cgroup to kernfs. Signed-off-by: Tejun Heo <tj@kernel.org> Acked-by: Michal Hocko <mhocko@suse.cz> Acked-by: Li Zefan <lizefan@huawei.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: Johannes Weiner <hannes@cmpxchg.org> Cc: Balbir Singh <bsingharora@gmail.com> Cc: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com>
This commit is contained in:
parent
398f878789
commit
5a17f543ed
4 changed files with 26 additions and 36 deletions
|
@ -825,7 +825,7 @@ int css_scan_tasks(struct cgroup_subsys_state *css,
|
||||||
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);
|
||||||
|
|
||||||
struct cgroup_subsys_state *css_from_dir(struct dentry *dentry,
|
struct cgroup_subsys_state *css_tryget_from_dir(struct dentry *dentry,
|
||||||
struct cgroup_subsys *ss);
|
struct cgroup_subsys *ss);
|
||||||
|
|
||||||
#else /* !CONFIG_CGROUPS */
|
#else /* !CONFIG_CGROUPS */
|
||||||
|
|
|
@ -4978,28 +4978,35 @@ static int __init cgroup_disable(char *str)
|
||||||
__setup("cgroup_disable=", cgroup_disable);
|
__setup("cgroup_disable=", cgroup_disable);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* css_from_dir - get corresponding css from the dentry of a cgroup dir
|
* css_tryget_from_dir - get corresponding css from the dentry of a cgroup dir
|
||||||
* @dentry: directory dentry of interest
|
* @dentry: directory dentry of interest
|
||||||
* @ss: subsystem of interest
|
* @ss: subsystem of interest
|
||||||
*
|
*
|
||||||
* Must be called under cgroup_mutex or RCU read lock. The caller is
|
* If @dentry is a directory for a cgroup which has @ss enabled on it, try
|
||||||
* responsible for pinning the returned css if it needs to be accessed
|
* to get the corresponding css and return it. If such css doesn't exist
|
||||||
* outside the critical section.
|
* or can't be pinned, an ERR_PTR value is returned.
|
||||||
*/
|
*/
|
||||||
struct cgroup_subsys_state *css_from_dir(struct dentry *dentry,
|
struct cgroup_subsys_state *css_tryget_from_dir(struct dentry *dentry,
|
||||||
struct cgroup_subsys *ss)
|
struct cgroup_subsys *ss)
|
||||||
{
|
{
|
||||||
struct cgroup *cgrp;
|
struct cgroup *cgrp;
|
||||||
|
struct cgroup_subsys_state *css;
|
||||||
cgroup_assert_mutex_or_rcu_locked();
|
|
||||||
|
|
||||||
/* is @dentry a cgroup dir? */
|
/* is @dentry a cgroup dir? */
|
||||||
if (!dentry->d_inode ||
|
if (!dentry->d_inode ||
|
||||||
dentry->d_inode->i_op != &cgroup_dir_inode_operations)
|
dentry->d_inode->i_op != &cgroup_dir_inode_operations)
|
||||||
return ERR_PTR(-EBADF);
|
return ERR_PTR(-EBADF);
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
|
||||||
cgrp = __d_cgrp(dentry);
|
cgrp = __d_cgrp(dentry);
|
||||||
return cgroup_css(cgrp, ss) ?: ERR_PTR(-ENOENT);
|
css = cgroup_css(cgrp, ss);
|
||||||
|
|
||||||
|
if (!css || !css_tryget(css))
|
||||||
|
css = ERR_PTR(-ENOENT);
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
|
return css;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -370,11 +370,6 @@ perf_cgroup_match(struct perf_event *event)
|
||||||
event->cgrp->css.cgroup);
|
event->cgrp->css.cgroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool perf_tryget_cgroup(struct perf_event *event)
|
|
||||||
{
|
|
||||||
return css_tryget(&event->cgrp->css);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void perf_put_cgroup(struct perf_event *event)
|
static inline void perf_put_cgroup(struct perf_event *event)
|
||||||
{
|
{
|
||||||
css_put(&event->cgrp->css);
|
css_put(&event->cgrp->css);
|
||||||
|
@ -593,9 +588,7 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event,
|
||||||
if (!f.file)
|
if (!f.file)
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
|
|
||||||
rcu_read_lock();
|
css = css_tryget_from_dir(f.file->f_dentry, &perf_event_cgrp_subsys);
|
||||||
|
|
||||||
css = css_from_dir(f.file->f_dentry, &perf_event_cgrp_subsys);
|
|
||||||
if (IS_ERR(css)) {
|
if (IS_ERR(css)) {
|
||||||
ret = PTR_ERR(css);
|
ret = PTR_ERR(css);
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -604,13 +597,6 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event,
|
||||||
cgrp = container_of(css, struct perf_cgroup, css);
|
cgrp = container_of(css, struct perf_cgroup, css);
|
||||||
event->cgrp = cgrp;
|
event->cgrp = cgrp;
|
||||||
|
|
||||||
/* must be done before we fput() the file */
|
|
||||||
if (!perf_tryget_cgroup(event)) {
|
|
||||||
event->cgrp = NULL;
|
|
||||||
ret = -ENOENT;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* all events in a group must monitor
|
* all events in a group must monitor
|
||||||
* the same cgroup because a task belongs
|
* the same cgroup because a task belongs
|
||||||
|
@ -621,7 +607,6 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event,
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
rcu_read_unlock();
|
|
||||||
fdput(f);
|
fdput(f);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6183,17 +6183,15 @@ static int memcg_write_event_control(struct cgroup_subsys_state *css,
|
||||||
* automatically removed on cgroup destruction but the removal is
|
* automatically removed on cgroup destruction but the removal is
|
||||||
* asynchronous, so take an extra ref on @css.
|
* asynchronous, so take an extra ref on @css.
|
||||||
*/
|
*/
|
||||||
rcu_read_lock();
|
cfile_css = css_tryget_from_dir(cfile.file->f_dentry->d_parent,
|
||||||
|
|
||||||
ret = -EINVAL;
|
|
||||||
cfile_css = css_from_dir(cfile.file->f_dentry->d_parent,
|
|
||||||
&memory_cgrp_subsys);
|
&memory_cgrp_subsys);
|
||||||
if (cfile_css == css && css_tryget(css))
|
ret = -EINVAL;
|
||||||
ret = 0;
|
if (IS_ERR(cfile_css))
|
||||||
|
|
||||||
rcu_read_unlock();
|
|
||||||
if (ret)
|
|
||||||
goto out_put_cfile;
|
goto out_put_cfile;
|
||||||
|
if (cfile_css != css) {
|
||||||
|
css_put(cfile_css);
|
||||||
|
goto out_put_cfile;
|
||||||
|
}
|
||||||
|
|
||||||
ret = event->register_event(memcg, event->eventfd, buffer);
|
ret = event->register_event(memcg, event->eventfd, buffer);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|
Loading…
Add table
Reference in a new issue