cgroup_clear_directroy is called by cgroup_d_remove_dir
and cgroup_remount.

when we call cgroup_remount to remount the cgroup,the subsystem
may be unlinked from cgroupfs_root->subsys_list in rebind_subsystem,this
subsystem's files will not be removed in cgroup_clear_directroy.
And the system will panic when we try to access these files.

this patch fix it.

Signed-off-by: Gao feng <[email protected]>
---
 kernel/cgroup.c |   86 ++++++++++++++++++++++++++++++++++--------------------
 1 files changed, 54 insertions(+), 32 deletions(-)

diff --git a/kernel/cgroup.c b/kernel/cgroup.c
index e5233b7..90429d5 100644
--- a/kernel/cgroup.c
+++ b/kernel/cgroup.c
@@ -982,10 +982,14 @@ static void cgroup_clear_directory(struct dentry *dir, 
bool base_files,
                                   unsigned long subsys_mask)
 {
        struct cgroup *cgrp = __d_cgrp(dir);
-       struct cgroup_subsys *ss;
+       int i;
 
-       for_each_subsys(cgrp->root, ss) {
+       for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
                struct cftype_set *set;
+               struct cgroup_subsys *ss = subsys[i];
+
+               if (ss == NULL)
+                       continue;
                if (!test_bit(ss->subsys_id, &subsys_mask))
                        continue;
                list_for_each_entry(set, &ss->cftsets, node)
@@ -1160,6 +1164,40 @@ static int cgroup_show_options(struct seq_file *seq, 
struct dentry *dentry)
        return 0;
 }
 
+static int cgroup_get_module_refcounts(unsigned long subsys_mask)
+{
+       int i;
+       bool module_pin_failed = false;
+
+       for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
+               unsigned long bit = 1UL << i;
+
+               if (!(bit & subsys_mask))
+                       continue;
+               if (!try_module_get(subsys[i]->module)) {
+                       module_pin_failed = true;
+                       break;
+               }
+       }
+       if (module_pin_failed) {
+               /*
+                * oops, one of the modules was going away. this means that we
+                * raced with a module_delete call, and to the user this is
+                * essentially a "subsystem doesn't exist" case.
+                */
+               for (i--; i >= 0; i--) {
+                       /* drop refcounts only on the ones we took */
+                       unsigned long bit = 1UL << i;
+
+                       if (!(bit & subsys_mask))
+                               continue;
+                       module_put(subsys[i]->module);
+               }
+               return -ENOENT;
+       }
+       return 0;
+}
+
 struct cgroup_sb_opts {
        unsigned long subsys_mask;
        unsigned long flags;
@@ -1185,7 +1223,6 @@ static int parse_cgroupfs_options(char *data, struct 
cgroup_sb_opts *opts)
        bool all_ss = false, one_ss = false;
        unsigned long mask = (unsigned long)-1;
        int i;
-       bool module_pin_failed = false;
 
        BUG_ON(!mutex_is_locked(&cgroup_mutex));
 
@@ -1324,34 +1361,8 @@ static int parse_cgroupfs_options(char *data, struct 
cgroup_sb_opts *opts)
         * take duplicate reference counts on a subsystem that's already used,
         * but rebind_subsystems handles this case.
         */
-       for (i = 0; i < CGROUP_SUBSYS_COUNT; i++) {
-               unsigned long bit = 1UL << i;
 
-               if (!(bit & opts->subsys_mask))
-                       continue;
-               if (!try_module_get(subsys[i]->module)) {
-                       module_pin_failed = true;
-                       break;
-               }
-       }
-       if (module_pin_failed) {
-               /*
-                * oops, one of the modules was going away. this means that we
-                * raced with a module_delete call, and to the user this is
-                * essentially a "subsystem doesn't exist" case.
-                */
-               for (i--; i >= 0; i--) {
-                       /* drop refcounts only on the ones we took */
-                       unsigned long bit = 1UL << i;
-
-                       if (!(bit & opts->subsys_mask))
-                               continue;
-                       module_put(subsys[i]->module);
-               }
-               return -ENOENT;
-       }
-
-       return 0;
+       return cgroup_get_module_refcounts(opts->subsys_mask);
 }
 
 static void drop_parsed_module_refcounts(unsigned long subsys_mask)
@@ -1392,23 +1403,34 @@ static int cgroup_remount(struct super_block *sb, int 
*flags, char *data)
        removed_mask = root->subsys_mask & ~opts.subsys_mask;
 
        /* Don't allow flags or name to change at remount */
+       ret = -EINVAL;
        if (opts.flags != root->flags ||
            (opts.name && strcmp(opts.name, root->name))) {
-               ret = -EINVAL;
                drop_parsed_module_refcounts(opts.subsys_mask);
                goto out_unlock;
        }
 
-       ret = rebind_subsystems(root, opts.subsys_mask);
+       /*
+        * Add the reference of these removed subsystem,we
+        * need use subsystems to remove their cgroup files.
+        */
+       ret = cgroup_get_module_refcounts(removed_mask);
        if (ret) {
                drop_parsed_module_refcounts(opts.subsys_mask);
                goto out_unlock;
        }
 
+       ret = rebind_subsystems(root, opts.subsys_mask);
+       if (ret) {
+               drop_parsed_module_refcounts(opts.subsys_mask | removed_mask);
+               goto out_unlock;
+       }
+
        /* clear out any existing files and repopulate subsystem files */
        cgroup_clear_directory(cgrp->dentry, false, removed_mask);
        /* re-populate subsystem files */
        cgroup_populate_dir(cgrp, false, added_mask);
+       drop_parsed_module_refcounts(removed_mask);
 
        if (opts.release_agent)
                strcpy(root->release_agent_path, opts.release_agent);
-- 
1.7.7.6

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to