ARM: tegra: dvfs: Add GPU scaling trip-points interfaces
[linux-3.10.git] / kernel / cgroup.c
index 192d762..770c43a 100644 (file)
@@ -848,9 +848,12 @@ 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
+        * created the cgroup. This will free cgrp->root, if we are
+        * holding the last reference to @sb.
         */
        deactivate_super(cgrp->root->sb);
 
@@ -862,7 +865,6 @@ static void cgroup_free_fn(struct work_struct *work)
 
        simple_xattrs_free(&cgrp->xattrs);
 
-       ida_simple_remove(&cgrp->root->cgroup_ida, cgrp->id);
        kfree(rcu_dereference_raw(cgrp->name));
        kfree(cgrp);
 }
@@ -1684,11 +1686,14 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
                 */
                cgroup_drop_root(opts.new_root);
 
-               if (((root->flags | opts.flags) & CGRP_ROOT_SANE_BEHAVIOR) &&
-                   root->flags != opts.flags) {
-                       pr_err("cgroup: sane_behavior: new mount options should match the existing superblock\n");
-                       ret = -EINVAL;
-                       goto drop_new_super;
+               if (root->flags != opts.flags) {
+                       if ((root->flags | opts.flags) & CGRP_ROOT_SANE_BEHAVIOR) {
+                               pr_err("cgroup: sane_behavior: new mount options should match the existing superblock\n");
+                               ret = -EINVAL;
+                               goto drop_new_super;
+                       } else {
+                               pr_warning("cgroup: new mount options do not match the existing superblock, will be ignored\n");
+                       }
                }
 
                /* no subsys rebinding, so refcounts don't change */
@@ -2093,6 +2098,24 @@ out_free_group_list:
        return retval;
 }
 
+static int cgroup_allow_attach(struct cgroup *cgrp, struct cgroup_taskset *tset)
+{
+       struct cgroup_subsys *ss;
+       int ret;
+
+       for_each_subsys(cgrp->root, ss) {
+               if (ss->allow_attach) {
+                       ret = ss->allow_attach(cgrp, tset);
+                       if (ret)
+                               return ret;
+               } else {
+                       return -EACCES;
+               }
+       }
+
+       return 0;
+}
+
 /*
  * Find the task_struct of the task to attach by vpid and pass it along to the
  * function to attach either it or all tasks in its threadgroup. Will lock
@@ -2124,9 +2147,18 @@ retry_find_task:
                if (!uid_eq(cred->euid, GLOBAL_ROOT_UID) &&
                    !uid_eq(cred->euid, tcred->uid) &&
                    !uid_eq(cred->euid, tcred->suid)) {
-                       rcu_read_unlock();
-                       ret = -EACCES;
-                       goto out_unlock_cgroup;
+                       /*
+                        * if the default permission check fails, give each
+                        * cgroup a chance to extend the permission check
+                        */
+                       struct cgroup_taskset tset = { };
+                       tset.single.task = tsk;
+                       tset.single.cgrp = cgrp;
+                       ret = cgroup_allow_attach(cgrp, &tset);
+                       if (ret) {
+                               rcu_read_unlock();
+                               goto out_unlock_cgroup;
+                       }
                }
        } else
                tsk = current;
@@ -2135,11 +2167,11 @@ retry_find_task:
                tsk = tsk->group_leader;
 
        /*
-        * Workqueue threads may acquire PF_THREAD_BOUND and become
+        * Workqueue threads may acquire PF_NO_SETAFFINITY and become
         * trapped in a cpuset, or RT worker may be born in a cgroup
         * with no rt_runtime allocated.  Just say no.
         */
-       if (tsk == kthreadd_task || (tsk->flags & PF_THREAD_BOUND)) {
+       if (tsk == kthreadd_task || (tsk->flags & PF_NO_SETAFFINITY)) {
                ret = -EINVAL;
                rcu_read_unlock();
                goto out_unlock_cgroup;
@@ -2697,13 +2729,14 @@ static int cgroup_add_file(struct cgroup *cgrp, struct cgroup_subsys *subsys,
                goto out;
        }
 
+       cfe->type = (void *)cft;
+       cfe->dentry = dentry;
+       dentry->d_fsdata = cfe;
+       simple_xattrs_init(&cfe->xattrs);
+
        mode = cgroup_file_mode(cft);
        error = cgroup_create_file(dentry, mode | S_IFREG, cgrp->root->sb);
        if (!error) {
-               cfe->type = (void *)cft;
-               cfe->dentry = dentry;
-               dentry->d_fsdata = cfe;
-               simple_xattrs_init(&cfe->xattrs);
                list_add_tail(&cfe->node, &parent->files);
                cfe = NULL;
        }
@@ -2763,13 +2796,17 @@ static void cgroup_cfts_commit(struct cgroup_subsys *ss,
 {
        LIST_HEAD(pending);
        struct cgroup *cgrp, *n;
+       struct super_block *sb = ss->root->sb;
 
        /* %NULL @cfts indicates abort and don't bother if @ss isn't attached */
-       if (cfts && ss->root != &rootnode) {
+       if (cfts && ss->root != &rootnode &&
+           atomic_inc_not_zero(&sb->s_active)) {
                list_for_each_entry(cgrp, &ss->root->allcg_list, allcg_node) {
                        dget(cgrp->dentry);
                        list_add_tail(&cgrp->cft_q_node, &pending);
                }
+       } else {
+               sb = NULL;
        }
 
        mutex_unlock(&cgroup_mutex);
@@ -2792,6 +2829,9 @@ static void cgroup_cfts_commit(struct cgroup_subsys *ss,
                dput(cgrp->dentry);
        }
 
+       if (sb)
+               deactivate_super(sb);
+
        mutex_unlock(&cgroup_cft_mutex);
 }
 
@@ -2951,11 +2991,8 @@ struct cgroup *cgroup_next_descendant_pre(struct cgroup *pos,
        WARN_ON_ONCE(!rcu_read_lock_held());
 
        /* if first iteration, pretend we just visited @cgroup */
-       if (!pos) {
-               if (list_empty(&cgroup->children))
-                       return NULL;
+       if (!pos)
                pos = cgroup;
-       }
 
        /* visit the first child if exists */
        next = list_first_or_null_rcu(&pos->children, struct cgroup, sibling);
@@ -2963,14 +3000,14 @@ struct cgroup *cgroup_next_descendant_pre(struct cgroup *pos,
                return next;
 
        /* no child, visit my or the closest ancestor's next sibling */
-       do {
+       while (pos != cgroup) {
                next = list_entry_rcu(pos->sibling.next, struct cgroup,
                                      sibling);
                if (&next->sibling != &pos->parent->children)
                        return next;
 
                pos = pos->parent;
-       } while (pos != cgroup);
+       }
 
        return NULL;
 }
@@ -3724,6 +3761,23 @@ static int cgroup_write_notify_on_release(struct cgroup *cgrp,
 }
 
 /*
+ * When dput() is called asynchronously, if umount has been done and
+ * then deactivate_super() in cgroup_free_fn() kills the superblock,
+ * there's a small window that vfs will see the root dentry with non-zero
+ * refcnt and trigger BUG().
+ *
+ * That's why we hold a reference before dput() and drop it right after.
+ */
+static void cgroup_dput(struct cgroup *cgrp)
+{
+       struct super_block *sb = cgrp->root->sb;
+
+       atomic_inc(&sb->s_active);
+       dput(cgrp->dentry);
+       deactivate_super(sb);
+}
+
+/*
  * Unregister event and free resources.
  *
  * Gets called from workqueue.
@@ -3743,7 +3797,7 @@ static void cgroup_event_remove(struct work_struct *work)
 
        eventfd_ctx_put(event->eventfd);
        kfree(event);
-       dput(cgrp->dentry);
+       cgroup_dput(cgrp);
 }
 
 /*
@@ -3880,6 +3934,8 @@ static int cgroup_write_event_control(struct cgroup *cgrp, struct cftype *cft,
        if (ret)
                goto fail;
 
+       efile->f_op->poll(efile, &event->pt);
+
        /*
         * Events should be removed after rmdir of cgroup directory, but before
         * destroying subsystem state objects. Let's take reference to cgroup
@@ -4026,12 +4082,8 @@ static void css_dput_fn(struct work_struct *work)
 {
        struct cgroup_subsys_state *css =
                container_of(work, struct cgroup_subsys_state, dput_work);
-       struct dentry *dentry = css->cgroup->dentry;
-       struct super_block *sb = dentry->d_sb;
 
-       atomic_inc(&sb->s_active);
-       dput(dentry);
-       deactivate_super(sb);
+       cgroup_dput(css->cgroup);
 }
 
 static void init_cgroup_css(struct cgroup_subsys_state *css,
@@ -4376,7 +4428,6 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss)
         * need to invoke fork callbacks here. */
        BUG_ON(!list_empty(&init_task.tasks));
 
-       ss->active = 1;
        BUG_ON(online_css(ss, dummytop));
 
        mutex_unlock(&cgroup_mutex);
@@ -4481,7 +4532,6 @@ int __init_or_module cgroup_load_subsys(struct cgroup_subsys *ss)
        }
        write_unlock(&css_set_lock);
 
-       ss->active = 1;
        ret = online_css(ss, dummytop);
        if (ret)
                goto err_unload;
@@ -4522,7 +4572,6 @@ void cgroup_unload_subsys(struct cgroup_subsys *ss)
        mutex_lock(&cgroup_mutex);
 
        offline_css(ss, dummytop);
-       ss->active = 0;
 
        if (ss->use_id)
                idr_destroy(&ss->idr);
@@ -4677,7 +4726,7 @@ out:
  */
 
 /* TODO: Use a proper seq_file iterator */
-static int proc_cgroup_show(struct seq_file *m, void *v)
+int proc_cgroup_show(struct seq_file *m, void *v)
 {
        struct pid *pid;
        struct task_struct *tsk;
@@ -4729,19 +4778,6 @@ out:
        return retval;
 }
 
-static int cgroup_open(struct inode *inode, struct file *file)
-{
-       struct pid *pid = PROC_I(inode)->pid;
-       return single_open(file, proc_cgroup_show, pid);
-}
-
-const struct file_operations proc_cgroup_operations = {
-       .open           = cgroup_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
 /* Display information about each subsystem and each hierarchy */
 static int proc_cgroupstats_show(struct seq_file *m, void *v)
 {
@@ -5286,55 +5322,6 @@ struct cgroup_subsys_state *css_lookup(struct cgroup_subsys *ss, int id)
 }
 EXPORT_SYMBOL_GPL(css_lookup);
 
-/**
- * css_get_next - lookup next cgroup under specified hierarchy.
- * @ss: pointer to subsystem
- * @id: current position of iteration.
- * @root: pointer to css. search tree under this.
- * @foundid: position of found object.
- *
- * Search next css under the specified hierarchy of rootid. Calling under
- * rcu_read_lock() is necessary. Returns NULL if it reaches the end.
- */
-struct cgroup_subsys_state *
-css_get_next(struct cgroup_subsys *ss, int id,
-            struct cgroup_subsys_state *root, int *foundid)
-{
-       struct cgroup_subsys_state *ret = NULL;
-       struct css_id *tmp;
-       int tmpid;
-       int rootid = css_id(root);
-       int depth = css_depth(root);
-
-       if (!rootid)
-               return NULL;
-
-       BUG_ON(!ss->use_id);
-       WARN_ON_ONCE(!rcu_read_lock_held());
-
-       /* fill start point for scan */
-       tmpid = id;
-       while (1) {
-               /*
-                * scan next entry from bitmap(tree), tmpid is updated after
-                * idr_get_next().
-                */
-               tmp = idr_get_next(&ss->idr, &tmpid);
-               if (!tmp)
-                       break;
-               if (tmp->depth >= depth && tmp->stack[depth] == rootid) {
-                       ret = rcu_dereference(tmp->css);
-                       if (ret) {
-                               *foundid = tmpid;
-                               break;
-                       }
-               }
-               /* continue to scan from next id */
-               tmpid = tmpid + 1;
-       }
-       return ret;
-}
-
 /*
  * get corresponding css from file open on cgroupfs directory
  */