Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[sfrench/cifs-2.6.git] / kernel / cgroup.c
index 470f6536b9e8cfb029eedb5ecdb3c3e8c3c341be..d27904c193daa1d8a8680522093254cfde376177 100644 (file)
@@ -57,8 +57,9 @@
 #include <linux/vmalloc.h> /* TODO: replace with more sophisticated array */
 #include <linux/kthread.h>
 #include <linux/delay.h>
-
 #include <linux/atomic.h>
+#include <linux/cpuset.h>
+#include <net/sock.h>
 
 /*
  * pidlists linger the following amount before being destroyed.  The goal
@@ -211,6 +212,7 @@ static unsigned long have_free_callback __read_mostly;
 /* Ditto for the can_fork callback. */
 static unsigned long have_canfork_callback __read_mostly;
 
+static struct file_system_type cgroup2_fs_type;
 static struct cftype cgroup_dfl_base_files[];
 static struct cftype cgroup_legacy_base_files[];
 
@@ -440,11 +442,6 @@ static bool cgroup_tryget(struct cgroup *cgrp)
        return css_tryget(&cgrp->self);
 }
 
-static void cgroup_put(struct cgroup *cgrp)
-{
-       css_put(&cgrp->self);
-}
-
 struct cgroup_subsys_state *of_css(struct kernfs_open_file *of)
 {
        struct cgroup *cgrp = of->kn->parent->priv;
@@ -465,25 +462,6 @@ struct cgroup_subsys_state *of_css(struct kernfs_open_file *of)
 }
 EXPORT_SYMBOL_GPL(of_css);
 
-/**
- * cgroup_is_descendant - test ancestry
- * @cgrp: the cgroup to be tested
- * @ancestor: possible ancestor of @cgrp
- *
- * Test whether @cgrp is a descendant of @ancestor.  It also returns %true
- * if @cgrp == @ancestor.  This function is safe to call as long as @cgrp
- * and @ancestor are accessible.
- */
-bool cgroup_is_descendant(struct cgroup *cgrp, struct cgroup *ancestor)
-{
-       while (cgrp) {
-               if (cgrp == ancestor)
-                       return true;
-               cgrp = cgroup_parent(cgrp);
-       }
-       return false;
-}
-
 static int notify_on_release(const struct cgroup *cgrp)
 {
        return test_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
@@ -1647,10 +1625,6 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
                        all_ss = true;
                        continue;
                }
-               if (!strcmp(token, "__DEVEL__sane_behavior")) {
-                       opts->flags |= CGRP_ROOT_SANE_BEHAVIOR;
-                       continue;
-               }
                if (!strcmp(token, "noprefix")) {
                        opts->flags |= CGRP_ROOT_NOPREFIX;
                        continue;
@@ -1717,15 +1691,6 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
                        return -ENOENT;
        }
 
-       if (opts->flags & CGRP_ROOT_SANE_BEHAVIOR) {
-               pr_warn("sane_behavior: this is still under development and its behaviors will change, proceed at your own risk\n");
-               if (nr_opts != 1) {
-                       pr_err("sane_behavior: no other mount options allowed\n");
-                       return -EINVAL;
-               }
-               return 0;
-       }
-
        /*
         * If the 'all' option was specified select all the subsystems,
         * otherwise if 'none', 'name=' and a subsystem name options were
@@ -1924,6 +1889,7 @@ static int cgroup_setup_root(struct cgroup_root *root, unsigned long ss_mask)
        if (ret < 0)
                goto out;
        root_cgrp->id = ret;
+       root_cgrp->ancestor_ids[0] = ret;
 
        ret = percpu_ref_init(&root_cgrp->self.refcnt, css_release, 0,
                              GFP_KERNEL);
@@ -2004,6 +1970,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
                         int flags, const char *unused_dev_name,
                         void *data)
 {
+       bool is_v2 = fs_type == &cgroup2_fs_type;
        struct super_block *pinned_sb = NULL;
        struct cgroup_subsys *ss;
        struct cgroup_root *root;
@@ -2020,6 +1987,17 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
        if (!use_task_css_set_links)
                cgroup_enable_task_cg_lists();
 
+       if (is_v2) {
+               if (data) {
+                       pr_err("cgroup2: unknown option \"%s\"\n", (char *)data);
+                       return ERR_PTR(-EINVAL);
+               }
+               cgrp_dfl_root_visible = true;
+               root = &cgrp_dfl_root;
+               cgroup_get(&root->cgrp);
+               goto out_mount;
+       }
+
        mutex_lock(&cgroup_mutex);
 
        /* First find the desired set of subsystems */
@@ -2027,15 +2005,6 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
        if (ret)
                goto out_unlock;
 
-       /* look for a matching existing root */
-       if (opts.flags & CGRP_ROOT_SANE_BEHAVIOR) {
-               cgrp_dfl_root_visible = true;
-               root = &cgrp_dfl_root;
-               cgroup_get(&root->cgrp);
-               ret = 0;
-               goto out_unlock;
-       }
-
        /*
         * Destruction of cgroup root is asynchronous, so subsystems may
         * still be dying after the previous unmount.  Let's drain the
@@ -2146,9 +2115,10 @@ out_free:
 
        if (ret)
                return ERR_PTR(ret);
-
+out_mount:
        dentry = kernfs_mount(fs_type, flags, root->kf_root,
-                               CGROUP_SUPER_MAGIC, &new_sb);
+                             is_v2 ? CGROUP2_SUPER_MAGIC : CGROUP_SUPER_MAGIC,
+                             &new_sb);
        if (IS_ERR(dentry) || !new_sb)
                cgroup_put(&root->cgrp);
 
@@ -2191,6 +2161,12 @@ static struct file_system_type cgroup_fs_type = {
        .kill_sb = cgroup_kill_sb,
 };
 
+static struct file_system_type cgroup2_fs_type = {
+       .name = "cgroup2",
+       .mount = cgroup_mount,
+       .kill_sb = cgroup_kill_sb,
+};
+
 /**
  * task_cgroup_path - cgroup path of a task in the first cgroup hierarchy
  * @task: target task
@@ -2764,6 +2740,7 @@ out_unlock_rcu:
 out_unlock_threadgroup:
        percpu_up_write(&cgroup_threadgroup_rwsem);
        cgroup_kn_unlock(of->kn);
+       cpuset_post_attach_flush();
        return ret ?: nbytes;
 }
 
@@ -4062,7 +4039,7 @@ int cgroup_transfer_tasks(struct cgroup *to, struct cgroup *from)
                goto out_err;
 
        /*
-        * Migrate tasks one-by-one until @form is empty.  This fails iff
+        * Migrate tasks one-by-one until @from is empty.  This fails iff
         * ->can_attach() fails.
         */
        do {
@@ -4680,14 +4657,15 @@ static void css_free_work_fn(struct work_struct *work)
 
        if (ss) {
                /* css free path */
+               struct cgroup_subsys_state *parent = css->parent;
                int id = css->id;
 
-               if (css->parent)
-                       css_put(css->parent);
-
                ss->css_free(css);
                cgroup_idr_remove(&ss->css_idr, id);
                cgroup_put(cgrp);
+
+               if (parent)
+                       css_put(parent);
        } else {
                /* cgroup free path */
                atomic_dec(&cgrp->root->nr_cgrps);
@@ -4783,6 +4761,7 @@ static void init_and_link_css(struct cgroup_subsys_state *css,
        INIT_LIST_HEAD(&css->sibling);
        INIT_LIST_HEAD(&css->children);
        css->serial_nr = css_serial_nr_next++;
+       atomic_set(&css->online_cnt, 0);
 
        if (cgroup_parent(cgrp)) {
                css->parent = cgroup_css(cgroup_parent(cgrp), ss);
@@ -4805,6 +4784,10 @@ static int online_css(struct cgroup_subsys_state *css)
        if (!ret) {
                css->flags |= CSS_ONLINE;
                rcu_assign_pointer(css->cgroup->subsys[ss->id], css);
+
+               atomic_inc(&css->online_cnt);
+               if (css->parent)
+                       atomic_inc(&css->parent->online_cnt);
        }
        return ret;
 }
@@ -4903,11 +4886,11 @@ err_free_css:
 static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
                        umode_t mode)
 {
-       struct cgroup *parent, *cgrp;
+       struct cgroup *parent, *cgrp, *tcgrp;
        struct cgroup_root *root;
        struct cgroup_subsys *ss;
        struct kernfs_node *kn;
-       int ssid, ret;
+       int level, ssid, ret;
 
        /* Do not accept '\n' to prevent making /proc/<pid>/cgroup unparsable.
         */
@@ -4918,9 +4901,11 @@ static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
        if (!parent)
                return -ENODEV;
        root = parent->root;
+       level = parent->level + 1;
 
        /* allocate the cgroup and its ID, 0 is reserved for the root */
-       cgrp = kzalloc(sizeof(*cgrp), GFP_KERNEL);
+       cgrp = kzalloc(sizeof(*cgrp) +
+                      sizeof(cgrp->ancestor_ids[0]) * (level + 1), GFP_KERNEL);
        if (!cgrp) {
                ret = -ENOMEM;
                goto out_unlock;
@@ -4944,6 +4929,10 @@ static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name,
 
        cgrp->self.parent = &parent->self;
        cgrp->root = root;
+       cgrp->level = level;
+
+       for (tcgrp = cgrp; tcgrp; tcgrp = cgroup_parent(tcgrp))
+               cgrp->ancestor_ids[tcgrp->level] = tcgrp->id;
 
        if (notify_on_release(parent))
                set_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);
@@ -5036,10 +5025,15 @@ static void css_killed_work_fn(struct work_struct *work)
                container_of(work, struct cgroup_subsys_state, destroy_work);
 
        mutex_lock(&cgroup_mutex);
-       offline_css(css);
-       mutex_unlock(&cgroup_mutex);
 
-       css_put(css);
+       do {
+               offline_css(css);
+               css_put(css);
+               /* @css can't go away while we're holding cgroup_mutex */
+               css = css->parent;
+       } while (css && atomic_dec_and_test(&css->online_cnt));
+
+       mutex_unlock(&cgroup_mutex);
 }
 
 /* css kill confirmation processing requires process context, bounce */
@@ -5048,8 +5042,10 @@ static void css_killed_ref_fn(struct percpu_ref *ref)
        struct cgroup_subsys_state *css =
                container_of(ref, struct cgroup_subsys_state, refcnt);
 
-       INIT_WORK(&css->destroy_work, css_killed_work_fn);
-       queue_work(cgroup_destroy_wq, &css->destroy_work);
+       if (atomic_dec_and_test(&css->online_cnt)) {
+               INIT_WORK(&css->destroy_work, css_killed_work_fn);
+               queue_work(cgroup_destroy_wq, &css->destroy_work);
+       }
 }
 
 /**
@@ -5188,7 +5184,7 @@ static void __init cgroup_init_subsys(struct cgroup_subsys *ss, bool early)
 {
        struct cgroup_subsys_state *css;
 
-       printk(KERN_INFO "Initializing cgroup subsys %s\n", ss->name);
+       pr_debug("Initializing cgroup subsys %s\n", ss->name);
 
        mutex_lock(&cgroup_mutex);
 
@@ -5346,6 +5342,7 @@ int __init cgroup_init(void)
 
        WARN_ON(sysfs_create_mount_point(fs_kobj, "cgroup"));
        WARN_ON(register_filesystem(&cgroup_fs_type));
+       WARN_ON(register_filesystem(&cgroup2_fs_type));
        WARN_ON(!proc_create("cgroups", 0, NULL, &proc_cgroupstats_operations));
 
        return 0;
@@ -5489,19 +5486,6 @@ static const struct file_operations proc_cgroupstats_operations = {
        .release = single_release,
 };
 
-static void **subsys_canfork_priv_p(void *ss_priv[CGROUP_CANFORK_COUNT], int i)
-{
-       if (CGROUP_CANFORK_START <= i && i < CGROUP_CANFORK_END)
-               return &ss_priv[i - CGROUP_CANFORK_START];
-       return NULL;
-}
-
-static void *subsys_canfork_priv(void *ss_priv[CGROUP_CANFORK_COUNT], int i)
-{
-       void **private = subsys_canfork_priv_p(ss_priv, i);
-       return private ? *private : NULL;
-}
-
 /**
  * cgroup_fork - initialize cgroup related fields during copy_process()
  * @child: pointer to task_struct of forking parent process.
@@ -5524,14 +5508,13 @@ void cgroup_fork(struct task_struct *child)
  * returns an error, the fork aborts with that error code. This allows for
  * a cgroup subsystem to conditionally allow or deny new forks.
  */
-int cgroup_can_fork(struct task_struct *child,
-                   void *ss_priv[CGROUP_CANFORK_COUNT])
+int cgroup_can_fork(struct task_struct *child)
 {
        struct cgroup_subsys *ss;
        int i, j, ret;
 
        for_each_subsys_which(ss, i, &have_canfork_callback) {
-               ret = ss->can_fork(child, subsys_canfork_priv_p(ss_priv, i));
+               ret = ss->can_fork(child);
                if (ret)
                        goto out_revert;
        }
@@ -5543,7 +5526,7 @@ out_revert:
                if (j >= i)
                        break;
                if (ss->cancel_fork)
-                       ss->cancel_fork(child, subsys_canfork_priv(ss_priv, j));
+                       ss->cancel_fork(child);
        }
 
        return ret;
@@ -5556,15 +5539,14 @@ out_revert:
  * This calls the cancel_fork() callbacks if a fork failed *after*
  * cgroup_can_fork() succeded.
  */
-void cgroup_cancel_fork(struct task_struct *child,
-                       void *ss_priv[CGROUP_CANFORK_COUNT])
+void cgroup_cancel_fork(struct task_struct *child)
 {
        struct cgroup_subsys *ss;
        int i;
 
        for_each_subsys(ss, i)
                if (ss->cancel_fork)
-                       ss->cancel_fork(child, subsys_canfork_priv(ss_priv, i));
+                       ss->cancel_fork(child);
 }
 
 /**
@@ -5577,8 +5559,7 @@ void cgroup_cancel_fork(struct task_struct *child,
  * cgroup_task_iter_start() - to guarantee that the new task ends up on its
  * list.
  */
-void cgroup_post_fork(struct task_struct *child,
-                     void *old_ss_priv[CGROUP_CANFORK_COUNT])
+void cgroup_post_fork(struct task_struct *child)
 {
        struct cgroup_subsys *ss;
        int i;
@@ -5622,7 +5603,7 @@ void cgroup_post_fork(struct task_struct *child,
         * and addition to css_set.
         */
        for_each_subsys_which(ss, i, &have_fork_callback)
-               ss->fork(child, subsys_canfork_priv(old_ss_priv, i));
+               ss->fork(child);
 }
 
 /**
@@ -5822,6 +5803,93 @@ struct cgroup_subsys_state *css_from_id(int id, struct cgroup_subsys *ss)
        return id > 0 ? idr_find(&ss->css_idr, id) : NULL;
 }
 
+/**
+ * cgroup_get_from_path - lookup and get a cgroup from its default hierarchy path
+ * @path: path on the default hierarchy
+ *
+ * Find the cgroup at @path on the default hierarchy, increment its
+ * reference count and return it.  Returns pointer to the found cgroup on
+ * success, ERR_PTR(-ENOENT) if @path doens't exist and ERR_PTR(-ENOTDIR)
+ * if @path points to a non-directory.
+ */
+struct cgroup *cgroup_get_from_path(const char *path)
+{
+       struct kernfs_node *kn;
+       struct cgroup *cgrp;
+
+       mutex_lock(&cgroup_mutex);
+
+       kn = kernfs_walk_and_get(cgrp_dfl_root.cgrp.kn, path);
+       if (kn) {
+               if (kernfs_type(kn) == KERNFS_DIR) {
+                       cgrp = kn->priv;
+                       cgroup_get(cgrp);
+               } else {
+                       cgrp = ERR_PTR(-ENOTDIR);
+               }
+               kernfs_put(kn);
+       } else {
+               cgrp = ERR_PTR(-ENOENT);
+       }
+
+       mutex_unlock(&cgroup_mutex);
+       return cgrp;
+}
+EXPORT_SYMBOL_GPL(cgroup_get_from_path);
+
+/*
+ * sock->sk_cgrp_data handling.  For more info, see sock_cgroup_data
+ * definition in cgroup-defs.h.
+ */
+#ifdef CONFIG_SOCK_CGROUP_DATA
+
+#if defined(CONFIG_CGROUP_NET_PRIO) || defined(CONFIG_CGROUP_NET_CLASSID)
+
+DEFINE_SPINLOCK(cgroup_sk_update_lock);
+static bool cgroup_sk_alloc_disabled __read_mostly;
+
+void cgroup_sk_alloc_disable(void)
+{
+       if (cgroup_sk_alloc_disabled)
+               return;
+       pr_info("cgroup: disabling cgroup2 socket matching due to net_prio or net_cls activation\n");
+       cgroup_sk_alloc_disabled = true;
+}
+
+#else
+
+#define cgroup_sk_alloc_disabled       false
+
+#endif
+
+void cgroup_sk_alloc(struct sock_cgroup_data *skcd)
+{
+       if (cgroup_sk_alloc_disabled)
+               return;
+
+       rcu_read_lock();
+
+       while (true) {
+               struct css_set *cset;
+
+               cset = task_css_set(current);
+               if (likely(cgroup_tryget(cset->dfl_cgrp))) {
+                       skcd->val = (unsigned long)cset->dfl_cgrp;
+                       break;
+               }
+               cpu_relax();
+       }
+
+       rcu_read_unlock();
+}
+
+void cgroup_sk_free(struct sock_cgroup_data *skcd)
+{
+       cgroup_put(sock_cgroup_ptr(skcd));
+}
+
+#endif /* CONFIG_SOCK_CGROUP_DATA */
+
 #ifdef CONFIG_CGROUP_DEBUG
 static struct cgroup_subsys_state *
 debug_css_alloc(struct cgroup_subsys_state *parent_css)