]> err.no Git - linux-2.6/blobdiff - kernel/cgroup.c
per-zone and reclaim enhancements for memory controller: remember reclaim priority...
[linux-2.6] / kernel / cgroup.c
index 7d207414f2c71cfca74e57c07ede5d4b6f609e1c..4e8b16a8266c31855772c7ce40d50112f0e940f4 100644 (file)
@@ -141,7 +141,7 @@ enum {
        ROOT_NOPREFIX, /* mounted subsystems have no named prefix */
 };
 
-inline int cgroup_is_releasable(const struct cgroup *cgrp)
+static int cgroup_is_releasable(const struct cgroup *cgrp)
 {
        const int bits =
                (1 << CGRP_RELEASABLE) |
@@ -149,7 +149,7 @@ inline int cgroup_is_releasable(const struct cgroup *cgrp)
        return (cgrp->flags & bits) == bits;
 }
 
-inline int notify_on_release(const struct cgroup *cgrp)
+static int notify_on_release(const struct cgroup *cgrp)
 {
        return test_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
 }
@@ -586,11 +586,27 @@ static struct inode *cgroup_new_inode(mode_t mode, struct super_block *sb)
        return inode;
 }
 
+/*
+ * Call subsys's pre_destroy handler.
+ * This is called before css refcnt check.
+ */
+
+static void cgroup_call_pre_destroy(struct cgroup *cgrp)
+{
+       struct cgroup_subsys *ss;
+       for_each_subsys(cgrp->root, ss)
+               if (ss->pre_destroy && cgrp->subsys[ss->subsys_id])
+                       ss->pre_destroy(ss, cgrp);
+       return;
+}
+
+
 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 +615,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 +1363,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 +1407,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 +1477,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 +2157,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;
 
@@ -2139,17 +2175,19 @@ static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry)
        parent = cgrp->parent;
        root = cgrp->root;
        sb = root->sb;
+       /*
+        * Call pre_destroy handlers of subsys
+        */
+       cgroup_call_pre_destroy(cgrp);
+       /*
+        * Notify subsyses that rmdir() request comes.
+        */
 
        if (cgroup_has_css_refs(cgrp)) {
                mutex_unlock(&cgroup_mutex);
                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 +2202,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;
 }