aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorPaul Menage <menage@google.com>2009-01-07 21:07:44 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-01-08 11:31:03 -0500
commita47295e6bc42ad35f9c15ac66f598aa24debd4e2 (patch)
treecb765e996ef35ae88e29d60796655d0d35e8cf5e /kernel
parente7b80bb695a5b64c92e314838e083b2f3bdf29b2 (diff)
cgroups: make cgroup_path() RCU-safe
Fix races between /proc/sched_debug by freeing cgroup objects via an RCU callback. Thus any cgroup reference obtained from an RCU-safe source will remain valid during the RCU section. Since dentries are also RCU-safe, this allows us to traverse up the tree safely. Additionally, make cgroup_path() check for a NULL cgrp->dentry to avoid trying to report a path for a partially-created cgroup. [lizf@cn.fujitsu.com: call deactive_super() in cgroup_diput()] Signed-off-by: Paul Menage <menage@google.com> Reviewed-by: Li Zefan <lizf@cn.fujitsu.com> Tested-by: Li Zefan <lizf@cn.fujitsu.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Signed-off-by: Li Zefan <lizf@cn.fujitsu.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/cgroup.c30
1 files changed, 21 insertions, 9 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index cb7c72b91f46..83ea4f524be5 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -271,7 +271,7 @@ static void __put_css_set(struct css_set *cg, int taskexit)
271 271
272 rcu_read_lock(); 272 rcu_read_lock();
273 for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) { 273 for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
274 struct cgroup *cgrp = cg->subsys[i]->cgroup; 274 struct cgroup *cgrp = rcu_dereference(cg->subsys[i]->cgroup);
275 if (atomic_dec_and_test(&cgrp->count) && 275 if (atomic_dec_and_test(&cgrp->count) &&
276 notify_on_release(cgrp)) { 276 notify_on_release(cgrp)) {
277 if (taskexit) 277 if (taskexit)
@@ -594,6 +594,13 @@ static void cgroup_call_pre_destroy(struct cgroup *cgrp)
594 return; 594 return;
595} 595}
596 596
597static void free_cgroup_rcu(struct rcu_head *obj)
598{
599 struct cgroup *cgrp = container_of(obj, struct cgroup, rcu_head);
600
601 kfree(cgrp);
602}
603
597static void cgroup_diput(struct dentry *dentry, struct inode *inode) 604static void cgroup_diput(struct dentry *dentry, struct inode *inode)
598{ 605{
599 /* is dentry a directory ? if so, kfree() associated cgroup */ 606 /* is dentry a directory ? if so, kfree() associated cgroup */
@@ -619,11 +626,13 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
619 cgrp->root->number_of_cgroups--; 626 cgrp->root->number_of_cgroups--;
620 mutex_unlock(&cgroup_mutex); 627 mutex_unlock(&cgroup_mutex);
621 628
622 /* Drop the active superblock reference that we took when we 629 /*
623 * created the cgroup */ 630 * Drop the active superblock reference that we took when we
631 * created the cgroup
632 */
624 deactivate_super(cgrp->root->sb); 633 deactivate_super(cgrp->root->sb);
625 634
626 kfree(cgrp); 635 call_rcu(&cgrp->rcu_head, free_cgroup_rcu);
627 } 636 }
628 iput(inode); 637 iput(inode);
629} 638}
@@ -1134,14 +1143,16 @@ static inline struct cftype *__d_cft(struct dentry *dentry)
1134 * @buf: the buffer to write the path into 1143 * @buf: the buffer to write the path into
1135 * @buflen: the length of the buffer 1144 * @buflen: the length of the buffer
1136 * 1145 *
1137 * Called with cgroup_mutex held. Writes path of cgroup into buf. 1146 * Called with cgroup_mutex held or else with an RCU-protected cgroup
1138 * Returns 0 on success, -errno on error. 1147 * reference. Writes path of cgroup into buf. Returns 0 on success,
1148 * -errno on error.
1139 */ 1149 */
1140int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen) 1150int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
1141{ 1151{
1142 char *start; 1152 char *start;
1153 struct dentry *dentry = rcu_dereference(cgrp->dentry);
1143 1154
1144 if (cgrp == dummytop) { 1155 if (!dentry || cgrp == dummytop) {
1145 /* 1156 /*
1146 * Inactive subsystems have no dentry for their root 1157 * Inactive subsystems have no dentry for their root
1147 * cgroup 1158 * cgroup
@@ -1154,13 +1165,14 @@ int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen)
1154 1165
1155 *--start = '\0'; 1166 *--start = '\0';
1156 for (;;) { 1167 for (;;) {
1157 int len = cgrp->dentry->d_name.len; 1168 int len = dentry->d_name.len;
1158 if ((start -= len) < buf) 1169 if ((start -= len) < buf)
1159 return -ENAMETOOLONG; 1170 return -ENAMETOOLONG;
1160 memcpy(start, cgrp->dentry->d_name.name, len); 1171 memcpy(start, cgrp->dentry->d_name.name, len);
1161 cgrp = cgrp->parent; 1172 cgrp = cgrp->parent;
1162 if (!cgrp) 1173 if (!cgrp)
1163 break; 1174 break;
1175 dentry = rcu_dereference(cgrp->dentry);
1164 if (!cgrp->parent) 1176 if (!cgrp->parent)
1165 continue; 1177 continue;
1166 if (--start < buf) 1178 if (--start < buf)
@@ -1663,7 +1675,7 @@ static int cgroup_create_dir(struct cgroup *cgrp, struct dentry *dentry,
1663 if (!error) { 1675 if (!error) {
1664 dentry->d_fsdata = cgrp; 1676 dentry->d_fsdata = cgrp;
1665 inc_nlink(parent->d_inode); 1677 inc_nlink(parent->d_inode);
1666 cgrp->dentry = dentry; 1678 rcu_assign_pointer(cgrp->dentry, dentry);
1667 dget(dentry); 1679 dget(dentry);
1668 } 1680 }
1669 dput(dentry); 1681 dput(dentry);