aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/cgroup.c
diff options
context:
space:
mode:
authorPaul Menage <menage@google.com>2008-02-07 03:13:45 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-07 11:42:18 -0500
commit8dc4f3e17dd5f7e59ce568155ccd8974af879315 (patch)
tree959b1197fea798c9daae4dd6c9596ab710d41fda /kernel/cgroup.c
parent622d42cac9ed42098aa50c53994f625abfa3d473 (diff)
cgroups: move cgroups destroy() callbacks to cgroup_diput()
Move the calls to the cgroup subsystem destroy() methods from cgroup_rmdir() to cgroup_diput(). This allows control file reads and writes to access their subsystem state without having to be concerned with locking against cgroup destruction - the control file dentry will keep the cgroup and its subsystem state objects alive until the file is closed. The documentation is updated to reflect the changed semantics of destroy(); additionally the locking comments for destroy() and some other methods were clarified and decrustified. Signed-off-by: Paul Menage <menage@google.com> Cc: Paul Jackson <pj@sgi.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r--kernel/cgroup.c36
1 files changed, 24 insertions, 12 deletions
diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index 7d207414f2c7..b0fee0c61445 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -591,6 +591,7 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
591 /* is dentry a directory ? if so, kfree() associated cgroup */ 591 /* is dentry a directory ? if so, kfree() associated cgroup */
592 if (S_ISDIR(inode->i_mode)) { 592 if (S_ISDIR(inode->i_mode)) {
593 struct cgroup *cgrp = dentry->d_fsdata; 593 struct cgroup *cgrp = dentry->d_fsdata;
594 struct cgroup_subsys *ss;
594 BUG_ON(!(cgroup_is_removed(cgrp))); 595 BUG_ON(!(cgroup_is_removed(cgrp)));
595 /* It's possible for external users to be holding css 596 /* It's possible for external users to be holding css
596 * reference counts on a cgroup; css_put() needs to 597 * reference counts on a cgroup; css_put() needs to
@@ -599,6 +600,23 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
599 * queue the cgroup to be handled by the release 600 * queue the cgroup to be handled by the release
600 * agent */ 601 * agent */
601 synchronize_rcu(); 602 synchronize_rcu();
603
604 mutex_lock(&cgroup_mutex);
605 /*
606 * Release the subsystem state objects.
607 */
608 for_each_subsys(cgrp->root, ss) {
609 if (cgrp->subsys[ss->subsys_id])
610 ss->destroy(ss, cgrp);
611 }
612
613 cgrp->root->number_of_cgroups--;
614 mutex_unlock(&cgroup_mutex);
615
616 /* Drop the active superblock reference that we took when we
617 * created the cgroup */
618 deactivate_super(cgrp->root->sb);
619
602 kfree(cgrp); 620 kfree(cgrp);
603 } 621 }
604 iput(inode); 622 iput(inode);
@@ -1330,6 +1348,10 @@ static ssize_t cgroup_common_file_write(struct cgroup *cgrp,
1330 1348
1331 mutex_lock(&cgroup_mutex); 1349 mutex_lock(&cgroup_mutex);
1332 1350
1351 /*
1352 * This was already checked for in cgroup_file_write(), but
1353 * check again now we're holding cgroup_mutex.
1354 */
1333 if (cgroup_is_removed(cgrp)) { 1355 if (cgroup_is_removed(cgrp)) {
1334 retval = -ENODEV; 1356 retval = -ENODEV;
1335 goto out2; 1357 goto out2;
@@ -1370,7 +1392,7 @@ static ssize_t cgroup_file_write(struct file *file, const char __user *buf,
1370 struct cftype *cft = __d_cft(file->f_dentry); 1392 struct cftype *cft = __d_cft(file->f_dentry);
1371 struct cgroup *cgrp = __d_cgrp(file->f_dentry->d_parent); 1393 struct cgroup *cgrp = __d_cgrp(file->f_dentry->d_parent);
1372 1394
1373 if (!cft) 1395 if (!cft || cgroup_is_removed(cgrp))
1374 return -ENODEV; 1396 return -ENODEV;
1375 if (cft->write) 1397 if (cft->write)
1376 return cft->write(cgrp, cft, file, buf, nbytes, ppos); 1398 return cft->write(cgrp, cft, file, buf, nbytes, ppos);
@@ -1440,7 +1462,7 @@ static ssize_t cgroup_file_read(struct file *file, char __user *buf,
1440 struct cftype *cft = __d_cft(file->f_dentry); 1462 struct cftype *cft = __d_cft(file->f_dentry);
1441 struct cgroup *cgrp = __d_cgrp(file->f_dentry->d_parent); 1463 struct cgroup *cgrp = __d_cgrp(file->f_dentry->d_parent);
1442 1464
1443 if (!cft) 1465 if (!cft || cgroup_is_removed(cgrp))
1444 return -ENODEV; 1466 return -ENODEV;
1445 1467
1446 if (cft->read) 1468 if (cft->read)
@@ -2120,7 +2142,6 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
2120 struct cgroup *cgrp = dentry->d_fsdata; 2142 struct cgroup *cgrp = dentry->d_fsdata;
2121 struct dentry *d; 2143 struct dentry *d;
2122 struct cgroup *parent; 2144 struct cgroup *parent;
2123 struct cgroup_subsys *ss;
2124 struct super_block *sb; 2145 struct super_block *sb;
2125 struct cgroupfs_root *root; 2146 struct cgroupfs_root *root;
2126 2147
@@ -2145,11 +2166,6 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
2145 return -EBUSY; 2166 return -EBUSY;
2146 } 2167 }
2147 2168
2148 for_each_subsys(root, ss) {
2149 if (cgrp->subsys[ss->subsys_id])
2150 ss->destroy(ss, cgrp);
2151 }
2152
2153 spin_lock(&release_list_lock); 2169 spin_lock(&release_list_lock);
2154 set_bit(CGRP_REMOVED, &cgrp->flags); 2170 set_bit(CGRP_REMOVED, &cgrp->flags);
2155 if (!list_empty(&cgrp->release_list)) 2171 if (!list_empty(&cgrp->release_list))
@@ -2164,15 +2180,11 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
2164 2180
2165 cgroup_d_remove_dir(d); 2181 cgroup_d_remove_dir(d);
2166 dput(d); 2182 dput(d);
2167 root->number_of_cgroups--;
2168 2183
2169 set_bit(CGRP_RELEASABLE, &parent->flags); 2184 set_bit(CGRP_RELEASABLE, &parent->flags);
2170 check_for_release(parent); 2185 check_for_release(parent);
2171 2186
2172 mutex_unlock(&cgroup_mutex); 2187 mutex_unlock(&cgroup_mutex);
2173 /* Drop the active superblock reference that we took when we
2174 * created the cgroup */
2175 deactivate_super(sb);
2176 return 0; 2188 return 0;
2177} 2189}
2178 2190