aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/cgroup.h5
-rw-r--r--kernel/cgroup.c30
2 files changed, 25 insertions, 10 deletions
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index f68dfd8dd53a..73d1c730c3c4 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -116,7 +116,7 @@ struct cgroup {
116 struct list_head children; /* my children */ 116 struct list_head children; /* my children */
117 117
118 struct cgroup *parent; /* my parent */ 118 struct cgroup *parent; /* my parent */
119 struct dentry *dentry; /* cgroup fs entry */ 119 struct dentry *dentry; /* cgroup fs entry, RCU protected */
120 120
121 /* Private pointers for each registered subsystem */ 121 /* Private pointers for each registered subsystem */
122 struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT]; 122 struct cgroup_subsys_state *subsys[CGROUP_SUBSYS_COUNT];
@@ -145,6 +145,9 @@ struct cgroup {
145 int pids_use_count; 145 int pids_use_count;
146 /* Length of the current tasks_pids array */ 146 /* Length of the current tasks_pids array */
147 int pids_length; 147 int pids_length;
148
149 /* For RCU-protected deletion */
150 struct rcu_head rcu_head;
148}; 151};
149 152
150/* A css_set is a structure holding pointers to a set of 153/* A css_set is a structure holding pointers to a set of
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);