diff options
| author | Paul Menage <menage@google.com> | 2009-01-07 21:07:44 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-01-08 11:31:03 -0500 |
| commit | a47295e6bc42ad35f9c15ac66f598aa24debd4e2 (patch) | |
| tree | cb765e996ef35ae88e29d60796655d0d35e8cf5e /kernel | |
| parent | e7b80bb695a5b64c92e314838e083b2f3bdf29b2 (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.c | 30 |
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 | ||
| 597 | static 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 | |||
| 597 | static void cgroup_diput(struct dentry *dentry, struct inode *inode) | 604 | static 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 | */ |
| 1140 | int cgroup_path(const struct cgroup *cgrp, char *buf, int buflen) | 1150 | int 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); |
