aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2014-02-11 11:52:47 -0500
committerTejun Heo <tj@kernel.org>2014-02-11 11:52:47 -0500
commit5a17f543ed6808e9085063277fe46795dea484bd (patch)
tree8b6e2afd5619bcff76438470670247eb55bef908
parent398f878789fceb51bf5e424b753a3756643513c4 (diff)
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>
-rw-r--r--include/linux/cgroup.h4
-rw-r--r--kernel/cgroup.c25
-rw-r--r--kernel/events/core.c17
-rw-r--r--mm/memcontrol.c16
4 files changed, 26 insertions, 36 deletions
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index c86ba7ff7a7e..1ba4fc08f776 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -825,8 +825,8 @@ int css_scan_tasks(struct cgroup_subsys_state *css,
825int cgroup_attach_task_all(struct task_struct *from, struct task_struct *); 825int cgroup_attach_task_all(struct task_struct *from, struct task_struct *);
826int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from); 826int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from);
827 827
828struct cgroup_subsys_state *css_from_dir(struct dentry *dentry, 828struct cgroup_subsys_state *css_tryget_from_dir(struct dentry *dentry,
829 struct cgroup_subsys *ss); 829 struct cgroup_subsys *ss);
830 830
831#else /* !CONFIG_CGROUPS */ 831#else /* !CONFIG_CGROUPS */
832 832
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 2de8decfd99f..fc2db071d95e 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -4978,28 +4978,35 @@ static int __init cgroup_disable(char *str)
4978__setup("cgroup_disable=", cgroup_disable); 4978__setup("cgroup_disable=", cgroup_disable);
4979 4979
4980/** 4980/**
4981 * css_from_dir - get corresponding css from the dentry of a cgroup dir 4981 * css_tryget_from_dir - get corresponding css from the dentry of a cgroup dir
4982 * @dentry: directory dentry of interest 4982 * @dentry: directory dentry of interest
4983 * @ss: subsystem of interest 4983 * @ss: subsystem of interest
4984 * 4984 *
4985 * Must be called under cgroup_mutex or RCU read lock. The caller is 4985 * If @dentry is a directory for a cgroup which has @ss enabled on it, try
4986 * responsible for pinning the returned css if it needs to be accessed 4986 * to get the corresponding css and return it. If such css doesn't exist
4987 * outside the critical section. 4987 * or can't be pinned, an ERR_PTR value is returned.
4988 */ 4988 */
4989struct cgroup_subsys_state *css_from_dir(struct dentry *dentry, 4989struct cgroup_subsys_state *css_tryget_from_dir(struct dentry *dentry,
4990 struct cgroup_subsys *ss) 4990 struct cgroup_subsys *ss)
4991{ 4991{
4992 struct cgroup *cgrp; 4992 struct cgroup *cgrp;
4993 4993 struct cgroup_subsys_state *css;
4994 cgroup_assert_mutex_or_rcu_locked();
4995 4994
4996 /* is @dentry a cgroup dir? */ 4995 /* is @dentry a cgroup dir? */
4997 if (!dentry->d_inode || 4996 if (!dentry->d_inode ||
4998 dentry->d_inode->i_op != &cgroup_dir_inode_operations) 4997 dentry->d_inode->i_op != &cgroup_dir_inode_operations)
4999 return ERR_PTR(-EBADF); 4998 return ERR_PTR(-EBADF);
5000 4999
5000 rcu_read_lock();
5001
5001 cgrp = __d_cgrp(dentry); 5002 cgrp = __d_cgrp(dentry);
5002 return cgroup_css(cgrp, ss) ?: ERR_PTR(-ENOENT); 5003 css = cgroup_css(cgrp, ss);
5004
5005 if (!css || !css_tryget(css))
5006 css = ERR_PTR(-ENOENT);
5007
5008 rcu_read_unlock();
5009 return css;
5003} 5010}
5004 5011
5005/** 5012/**
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 64903731d834..a3c3ab50271a 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -370,11 +370,6 @@ perf_cgroup_match(struct perf_event *event)
370 event->cgrp->css.cgroup); 370 event->cgrp->css.cgroup);
371} 371}
372 372
373static inline bool perf_tryget_cgroup(struct perf_event *event)
374{
375 return css_tryget(&event->cgrp->css);
376}
377
378static inline void perf_put_cgroup(struct perf_event *event) 373static inline void perf_put_cgroup(struct perf_event *event)
379{ 374{
380 css_put(&event->cgrp->css); 375 css_put(&event->cgrp->css);
@@ -593,9 +588,7 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event,
593 if (!f.file) 588 if (!f.file)
594 return -EBADF; 589 return -EBADF;
595 590
596 rcu_read_lock(); 591 css = css_tryget_from_dir(f.file->f_dentry, &perf_event_cgrp_subsys);
597
598 css = css_from_dir(f.file->f_dentry, &perf_event_cgrp_subsys);
599 if (IS_ERR(css)) { 592 if (IS_ERR(css)) {
600 ret = PTR_ERR(css); 593 ret = PTR_ERR(css);
601 goto out; 594 goto out;
@@ -604,13 +597,6 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event,
604 cgrp = container_of(css, struct perf_cgroup, css); 597 cgrp = container_of(css, struct perf_cgroup, css);
605 event->cgrp = cgrp; 598 event->cgrp = cgrp;
606 599
607 /* must be done before we fput() the file */
608 if (!perf_tryget_cgroup(event)) {
609 event->cgrp = NULL;
610 ret = -ENOENT;
611 goto out;
612 }
613
614 /* 600 /*
615 * all events in a group must monitor 601 * all events in a group must monitor
616 * the same cgroup because a task belongs 602 * the same cgroup because a task belongs
@@ -621,7 +607,6 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event,
621 ret = -EINVAL; 607 ret = -EINVAL;
622 } 608 }
623out: 609out:
624 rcu_read_unlock();
625 fdput(f); 610 fdput(f);
626 return ret; 611 return ret;
627} 612}
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index 04a97bce2270..102ab48ffa13 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -6183,17 +6183,15 @@ static int memcg_write_event_control(struct cgroup_subsys_state *css,
6183 * automatically removed on cgroup destruction but the removal is 6183 * automatically removed on cgroup destruction but the removal is
6184 * asynchronous, so take an extra ref on @css. 6184 * asynchronous, so take an extra ref on @css.
6185 */ 6185 */
6186 rcu_read_lock(); 6186 cfile_css = css_tryget_from_dir(cfile.file->f_dentry->d_parent,
6187 6187 &memory_cgrp_subsys);
6188 ret = -EINVAL; 6188 ret = -EINVAL;
6189 cfile_css = css_from_dir(cfile.file->f_dentry->d_parent, 6189 if (IS_ERR(cfile_css))
6190 &memory_cgrp_subsys);
6191 if (cfile_css == css && css_tryget(css))
6192 ret = 0;
6193
6194 rcu_read_unlock();
6195 if (ret)
6196 goto out_put_cfile; 6190 goto out_put_cfile;
6191 if (cfile_css != css) {
6192 css_put(cfile_css);
6193 goto out_put_cfile;
6194 }
6197 6195
6198 ret = event->register_event(memcg, event->eventfd, buffer); 6196 ret = event->register_event(memcg, event->eventfd, buffer);
6199 if (ret) 6197 if (ret)