diff options
-rw-r--r-- | include/linux/cgroup.h | 4 | ||||
-rw-r--r-- | kernel/cgroup.c | 25 | ||||
-rw-r--r-- | kernel/events/core.c | 17 | ||||
-rw-r--r-- | mm/memcontrol.c | 16 |
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, | |||
825 | int cgroup_attach_task_all(struct task_struct *from, struct task_struct *); | 825 | int cgroup_attach_task_all(struct task_struct *from, struct task_struct *); |
826 | int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from); | 826 | int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from); |
827 | 827 | ||
828 | struct cgroup_subsys_state *css_from_dir(struct dentry *dentry, | 828 | struct 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 | */ |
4989 | struct cgroup_subsys_state *css_from_dir(struct dentry *dentry, | 4989 | struct 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 | ||
373 | static inline bool perf_tryget_cgroup(struct perf_event *event) | ||
374 | { | ||
375 | return css_tryget(&event->cgrp->css); | ||
376 | } | ||
377 | |||
378 | static inline void perf_put_cgroup(struct perf_event *event) | 373 | static 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 | } |
623 | out: | 609 | out: |
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) |