diff options
Diffstat (limited to 'kernel/cgroup.c')
-rw-r--r-- | kernel/cgroup.c | 36 |
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 | ||