cgroup: convert cgroup_ida to cgroup_idr
[platform/adaptation/renesas_rcar/renesas_kernel.git] / kernel / cgroup.c
index 345fac8..3f65933 100644 (file)
@@ -466,7 +466,7 @@ static inline void put_css_set_taskexit(struct css_set *cset)
  * @new_cgrp: cgroup that's being entered by the task
  * @template: desired set of css pointers in css_set (pre-calculated)
  *
- * Returns true if "cg" matches "old_cg" except for the hierarchy
+ * Returns true if "cset" matches "old_cset" except for the hierarchy
  * which "new_cgrp" belongs to, for which it should match "new_cgrp".
  */
 static bool compare_css_sets(struct css_set *cset,
@@ -866,8 +866,6 @@ static void cgroup_free_fn(struct work_struct *work)
         */
        dput(cgrp->parent->dentry);
 
-       ida_simple_remove(&cgrp->root->cgroup_ida, cgrp->id);
-
        /*
         * Drop the active superblock reference that we took when we
         * created the cgroup. This will free cgrp->root, if we are
@@ -1379,6 +1377,7 @@ static void init_cgroup_root(struct cgroupfs_root *root)
        cgrp->root = root;
        RCU_INIT_POINTER(cgrp->name, &root_cgroup_name);
        init_cgroup_housekeeping(cgrp);
+       idr_init(&root->cgroup_idr);
 }
 
 static int cgroup_init_root_id(struct cgroupfs_root *root, int start, int end)
@@ -1451,7 +1450,6 @@ static struct cgroupfs_root *cgroup_root_from_opts(struct cgroup_sb_opts *opts)
         */
        root->subsys_mask = opts->subsys_mask;
        root->flags = opts->flags;
-       ida_init(&root->cgroup_ida);
        if (opts->release_agent)
                strcpy(root->release_agent_path, opts->release_agent);
        if (opts->name)
@@ -1467,7 +1465,7 @@ static void cgroup_free_root(struct cgroupfs_root *root)
                /* hierarhcy ID shoulid already have been released */
                WARN_ON_ONCE(root->hierarchy_id);
 
-               ida_destroy(&root->cgroup_ida);
+               idr_destroy(&root->cgroup_idr);
                kfree(root);
        }
 }
@@ -1582,6 +1580,11 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
                mutex_lock(&cgroup_mutex);
                mutex_lock(&cgroup_root_mutex);
 
+               root_cgrp->id = idr_alloc(&root->cgroup_idr, root_cgrp,
+                                          0, 1, GFP_KERNEL);
+               if (root_cgrp->id < 0)
+                       goto unlock_drop;
+
                /* Check for name clashes with existing mounts */
                ret = -EBUSY;
                if (strlen(root->name))
@@ -1839,7 +1842,7 @@ EXPORT_SYMBOL_GPL(task_cgroup_path_from_hierarchy);
 struct task_and_cgroup {
        struct task_struct      *task;
        struct cgroup           *cgrp;
-       struct css_set          *cg;
+       struct css_set          *cset;
 };
 
 struct cgroup_taskset {
@@ -2057,8 +2060,8 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,
 
                tc = flex_array_get(group, i);
                old_cset = task_css_set(tc->task);
-               tc->cg = find_css_set(old_cset, cgrp);
-               if (!tc->cg) {
+               tc->cset = find_css_set(old_cset, cgrp);
+               if (!tc->cset) {
                        retval = -ENOMEM;
                        goto out_put_css_set_refs;
                }
@@ -2071,7 +2074,7 @@ static int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk,
         */
        for (i = 0; i < group_size; i++) {
                tc = flex_array_get(group, i);
-               cgroup_task_migrate(tc->cgrp, tc->task, tc->cg);
+               cgroup_task_migrate(tc->cgrp, tc->task, tc->cset);
        }
        /* nothing is sensitive to fork() after this point. */
 
@@ -2091,9 +2094,9 @@ out_put_css_set_refs:
        if (retval) {
                for (i = 0; i < group_size; i++) {
                        tc = flex_array_get(group, i);
-                       if (!tc->cg)
+                       if (!tc->cset)
                                break;
-                       put_css_set(tc->cg);
+                       put_css_set(tc->cset);
                }
        }
 out_cancel_attach:
@@ -2203,9 +2206,9 @@ int cgroup_attach_task_all(struct task_struct *from, struct task_struct *tsk)
 
        mutex_lock(&cgroup_mutex);
        for_each_active_root(root) {
-               struct cgroup *from_cg = task_cgroup_from_root(from, root);
+               struct cgroup *from_cgrp = task_cgroup_from_root(from, root);
 
-               retval = cgroup_attach_task(from_cg, tsk, false);
+               retval = cgroup_attach_task(from_cgrp, tsk, false);
                if (retval)
                        break;
        }
@@ -2397,11 +2400,6 @@ static ssize_t cgroup_file_read(struct file *file, char __user *buf,
  * supports string->u64 maps, but can be extended in future.
  */
 
-struct cgroup_seqfile_state {
-       struct cftype *cft;
-       struct cgroup *cgroup;
-};
-
 static int cgroup_map_add(struct cgroup_map_cb *cb, const char *key, u64 value)
 {
        struct seq_file *sf = cb->state;
@@ -2410,59 +2408,45 @@ static int cgroup_map_add(struct cgroup_map_cb *cb, const char *key, u64 value)
 
 static int cgroup_seqfile_show(struct seq_file *m, void *arg)
 {
-       struct cgroup_seqfile_state *state = m->private;
-       struct cftype *cft = state->cft;
+       struct cfent *cfe = m->private;
+       struct cftype *cft = cfe->type;
+       struct cgroup *cgrp = __d_cgrp(cfe->dentry->d_parent);
+
        if (cft->read_map) {
                struct cgroup_map_cb cb = {
                        .fill = cgroup_map_add,
                        .state = m,
                };
-               return cft->read_map(state->cgroup, cft, &cb);
+               return cft->read_map(cgrp, cft, &cb);
        }
-       return cft->read_seq_string(state->cgroup, cft, m);
-}
-
-static int cgroup_seqfile_release(struct inode *inode, struct file *file)
-{
-       struct seq_file *seq = file->private_data;
-       kfree(seq->private);
-       return single_release(inode, file);
+       return cft->read_seq_string(cgrp, cft, m);
 }
 
 static const struct file_operations cgroup_seqfile_operations = {
        .read = seq_read,
        .write = cgroup_file_write,
        .llseek = seq_lseek,
-       .release = cgroup_seqfile_release,
+       .release = single_release,
 };
 
 static int cgroup_file_open(struct inode *inode, struct file *file)
 {
        int err;
+       struct cfent *cfe;
        struct cftype *cft;
 
        err = generic_file_open(inode, file);
        if (err)
                return err;
-       cft = __d_cft(file->f_dentry);
+       cfe = __d_cfe(file->f_dentry);
+       cft = cfe->type;
 
        if (cft->read_map || cft->read_seq_string) {
-               struct cgroup_seqfile_state *state;
-
-               state = kzalloc(sizeof(*state), GFP_USER);
-               if (!state)
-                       return -ENOMEM;
-
-               state->cft = cft;
-               state->cgroup = __d_cgrp(file->f_dentry->d_parent);
                file->f_op = &cgroup_seqfile_operations;
-               err = single_open(file, cgroup_seqfile_show, state);
-               if (err < 0)
-                       kfree(state);
-       } else if (cft->open)
+               err = single_open(file, cgroup_seqfile_show, cfe);
+       } else if (cft->open) {
                err = cft->open(inode, file);
-       else
-               err = 0;
+       }
 
        return err;
 }
@@ -3324,8 +3308,8 @@ int cgroup_scan_tasks(struct cgroup_scanner *scan)
         * guarantees forward progress and that we don't miss any tasks.
         */
        heap->size = 0;
-       cgroup_iter_start(scan->cg, &it);
-       while ((p = cgroup_iter_next(scan->cg, &it))) {
+       cgroup_iter_start(scan->cgrp, &it);
+       while ((p = cgroup_iter_next(scan->cgrp, &it))) {
                /*
                 * Only affect tasks that qualify per the caller's callback,
                 * if he provided one
@@ -3358,7 +3342,7 @@ int cgroup_scan_tasks(struct cgroup_scanner *scan)
                 * the heap and wasn't inserted
                 */
        }
-       cgroup_iter_end(scan->cg, &it);
+       cgroup_iter_end(scan->cgrp, &it);
 
        if (heap->size) {
                for (i = 0; i < heap->size; i++) {
@@ -3404,7 +3388,7 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from)
 {
        struct cgroup_scanner scan;
 
-       scan.cg = from;
+       scan.cgrp = from;
        scan.test_task = NULL; /* select all tasks in cgroup */
        scan.process_task = cgroup_transfer_one_task;
        scan.heap = NULL;
@@ -4214,7 +4198,7 @@ static void init_cgroup_css(struct cgroup_subsys_state *css,
        INIT_WORK(&css->dput_work, css_dput_fn);
 }
 
-/* invoke ->post_create() on a new CSS and mark it online if successful */
+/* invoke ->css_online() on a new CSS and mark it online if successful */
 static int online_css(struct cgroup_subsys *ss, struct cgroup *cgrp)
 {
        int ret = 0;
@@ -4228,9 +4212,8 @@ static int online_css(struct cgroup_subsys *ss, struct cgroup *cgrp)
        return ret;
 }
 
-/* if the CSS is online, invoke ->pre_destory() on it and mark it offline */
+/* if the CSS is online, invoke ->css_offline() on it and mark it offline */
 static void offline_css(struct cgroup_subsys *ss, struct cgroup *cgrp)
-       __releases(&cgroup_mutex) __acquires(&cgroup_mutex)
 {
        struct cgroup_subsys_state *css = cgrp->subsys[ss->subsys_id];
 
@@ -4273,7 +4256,11 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
                goto err_free_cgrp;
        rcu_assign_pointer(cgrp->name, name);
 
-       cgrp->id = ida_simple_get(&root->cgroup_ida, 1, 0, GFP_KERNEL);
+       /*
+        * Temporarily set the pointer to NULL, so idr_find() won't return
+        * a half-baked cgroup.
+        */
+       cgrp->id = idr_alloc(&root->cgroup_idr, NULL, 1, 0, GFP_KERNEL);
        if (cgrp->id < 0)
                goto err_free_name;
 
@@ -4371,6 +4358,8 @@ static long cgroup_create(struct cgroup *parent, struct dentry *dentry,
                }
        }
 
+       idr_replace(&root->cgroup_idr, cgrp, cgrp->id);
+
        err = cgroup_addrm_files(cgrp, NULL, cgroup_base_files, true);
        if (err)
                goto err_destroy;
@@ -4397,7 +4386,7 @@ err_free_all:
        /* Release the reference count that we took on the superblock */
        deactivate_super(sb);
 err_free_id:
-       ida_simple_remove(&root->cgroup_ida, cgrp->id);
+       idr_remove(&root->cgroup_idr, cgrp->id);
 err_free_name:
        kfree(rcu_dereference_raw(cgrp->name));
 err_free_cgrp:
@@ -4590,6 +4579,14 @@ static void cgroup_offline_fn(struct work_struct *work)
        /* delete this cgroup from parent->children */
        list_del_rcu(&cgrp->sibling);
 
+       /*
+        * We should remove the cgroup object from idr before its grace
+        * period starts, so we won't be looking up a cgroup while the
+        * cgroup is being freed.
+        */
+       idr_remove(&cgrp->root->cgroup_idr, cgrp->id);
+       cgrp->id = -1;
+
        dput(d);
 
        set_bit(CGRP_RELEASABLE, &parent->flags);
@@ -4915,6 +4912,10 @@ int __init cgroup_init(void)
 
        BUG_ON(cgroup_init_root_id(&cgroup_dummy_root, 0, 1));
 
+       err = idr_alloc(&cgroup_dummy_root.cgroup_idr, cgroup_dummy_top,
+                       0, 1, GFP_KERNEL);
+       BUG_ON(err < 0);
+
        mutex_unlock(&cgroup_root_mutex);
        mutex_unlock(&cgroup_mutex);