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>
This commit is contained in:
Paul Menage
2008-02-07 00:13:45 -08:00
committed by Linus Torvalds
parent 622d42cac9
commit 8dc4f3e17d
2 changed files with 35 additions and 23 deletions

View File

@@ -591,6 +591,7 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
/* is dentry a directory ? if so, kfree() associated cgroup */
if (S_ISDIR(inode->i_mode)) {
struct cgroup *cgrp = dentry->d_fsdata;
struct cgroup_subsys *ss;
BUG_ON(!(cgroup_is_removed(cgrp)));
/* It's possible for external users to be holding css
* reference counts on a cgroup; css_put() needs to
@@ -599,6 +600,23 @@ static void cgroup_diput(struct dentry *dentry, struct inode *inode)
* queue the cgroup to be handled by the release
* agent */
synchronize_rcu();
mutex_lock(&cgroup_mutex);
/*
* Release the subsystem state objects.
*/
for_each_subsys(cgrp->root, ss) {
if (cgrp->subsys[ss->subsys_id])
ss->destroy(ss, cgrp);
}
cgrp->root->number_of_cgroups--;
mutex_unlock(&cgroup_mutex);
/* Drop the active superblock reference that we took when we
* created the cgroup */
deactivate_super(cgrp->root->sb);
kfree(cgrp);
}
iput(inode);
@@ -1330,6 +1348,10 @@ static ssize_t cgroup_common_file_write(struct cgroup *cgrp,
mutex_lock(&cgroup_mutex);
/*
* This was already checked for in cgroup_file_write(), but
* check again now we're holding cgroup_mutex.
*/
if (cgroup_is_removed(cgrp)) {
retval = -ENODEV;
goto out2;
@@ -1370,7 +1392,7 @@ static ssize_t cgroup_file_write(struct file *file, const char __user *buf,
struct cftype *cft = __d_cft(file->f_dentry);
struct cgroup *cgrp = __d_cgrp(file->f_dentry->d_parent);
if (!cft)
if (!cft || cgroup_is_removed(cgrp))
return -ENODEV;
if (cft->write)
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,
struct cftype *cft = __d_cft(file->f_dentry);
struct cgroup *cgrp = __d_cgrp(file->f_dentry->d_parent);
if (!cft)
if (!cft || cgroup_is_removed(cgrp))
return -ENODEV;
if (cft->read)
@@ -2120,7 +2142,6 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
struct cgroup *cgrp = dentry->d_fsdata;
struct dentry *d;
struct cgroup *parent;
struct cgroup_subsys *ss;
struct super_block *sb;
struct cgroupfs_root *root;
@@ -2145,11 +2166,6 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
return -EBUSY;
}
for_each_subsys(root, ss) {
if (cgrp->subsys[ss->subsys_id])
ss->destroy(ss, cgrp);
}
spin_lock(&release_list_lock);
set_bit(CGRP_REMOVED, &cgrp->flags);
if (!list_empty(&cgrp->release_list))
@@ -2164,15 +2180,11 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
cgroup_d_remove_dir(d);
dput(d);
root->number_of_cgroups--;
set_bit(CGRP_RELEASABLE, &parent->flags);
check_for_release(parent);
mutex_unlock(&cgroup_mutex);
/* Drop the active superblock reference that we took when we
* created the cgroup */
deactivate_super(sb);
return 0;
}