Merge branch 'for-5.16' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/cgroup
[platform/kernel/linux-starfive.git] / kernel / cgroup / cgroup.c
index ea08f01..919194d 100644 (file)
@@ -1740,6 +1740,7 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask)
        struct cgroup *dcgrp = &dst_root->cgrp;
        struct cgroup_subsys *ss;
        int ssid, i, ret;
+       u16 dfl_disable_ss_mask = 0;
 
        lockdep_assert_held(&cgroup_mutex);
 
@@ -1756,8 +1757,28 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask)
                /* can't move between two non-dummy roots either */
                if (ss->root != &cgrp_dfl_root && dst_root != &cgrp_dfl_root)
                        return -EBUSY;
+
+               /*
+                * Collect ssid's that need to be disabled from default
+                * hierarchy.
+                */
+               if (ss->root == &cgrp_dfl_root)
+                       dfl_disable_ss_mask |= 1 << ssid;
+
        } while_each_subsys_mask();
 
+       if (dfl_disable_ss_mask) {
+               struct cgroup *scgrp = &cgrp_dfl_root.cgrp;
+
+               /*
+                * Controllers from default hierarchy that need to be rebound
+                * are all disabled together in one go.
+                */
+               cgrp_dfl_root.subsys_mask &= ~dfl_disable_ss_mask;
+               WARN_ON(cgroup_apply_control(scgrp));
+               cgroup_finalize_control(scgrp, 0);
+       }
+
        do_each_subsys_mask(ss, ssid, ss_mask) {
                struct cgroup_root *src_root = ss->root;
                struct cgroup *scgrp = &src_root->cgrp;
@@ -1766,10 +1787,12 @@ int rebind_subsystems(struct cgroup_root *dst_root, u16 ss_mask)
 
                WARN_ON(!css || cgroup_css(dcgrp, ss));
 
-               /* disable from the source */
-               src_root->subsys_mask &= ~(1 << ssid);
-               WARN_ON(cgroup_apply_control(scgrp));
-               cgroup_finalize_control(scgrp, 0);
+               if (src_root != &cgrp_dfl_root) {
+                       /* disable from the source */
+                       src_root->subsys_mask &= ~(1 << ssid);
+                       WARN_ON(cgroup_apply_control(scgrp));
+                       cgroup_finalize_control(scgrp, 0);
+               }
 
                /* rebind */
                RCU_INIT_POINTER(scgrp->subsys[ssid], NULL);
@@ -5911,17 +5934,20 @@ struct cgroup *cgroup_get_from_id(u64 id)
        struct kernfs_node *kn;
        struct cgroup *cgrp = NULL;
 
-       mutex_lock(&cgroup_mutex);
        kn = kernfs_find_and_get_node_by_id(cgrp_dfl_root.kf_root, id);
        if (!kn)
-               goto out_unlock;
+               goto out;
 
-       cgrp = kn->priv;
-       if (cgroup_is_dead(cgrp) || !cgroup_tryget(cgrp))
+       rcu_read_lock();
+
+       cgrp = rcu_dereference(*(void __rcu __force **)&kn->priv);
+       if (cgrp && !cgroup_tryget(cgrp))
                cgrp = NULL;
+
+       rcu_read_unlock();
+
        kernfs_put(kn);
-out_unlock:
-       mutex_unlock(&cgroup_mutex);
+out:
        return cgrp;
 }
 EXPORT_SYMBOL_GPL(cgroup_get_from_id);
@@ -6474,30 +6500,34 @@ struct cgroup_subsys_state *css_from_id(int id, struct cgroup_subsys *ss)
  *
  * 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 doesn't exist and ERR_PTR(-ENOTDIR)
- * if @path points to a non-directory.
+ * success, ERR_PTR(-ENOENT) if @path doesn't exist or if the cgroup has already
+ * been released 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);
+       struct cgroup *cgrp = ERR_PTR(-ENOENT);
 
        kn = kernfs_walk_and_get(cgrp_dfl_root.cgrp.kn, path);
-       if (kn) {
-               if (kernfs_type(kn) == KERNFS_DIR) {
-                       cgrp = kn->priv;
-                       cgroup_get_live(cgrp);
-               } else {
-                       cgrp = ERR_PTR(-ENOTDIR);
-               }
-               kernfs_put(kn);
-       } else {
-               cgrp = ERR_PTR(-ENOENT);
+       if (!kn)
+               goto out;
+
+       if (kernfs_type(kn) != KERNFS_DIR) {
+               cgrp = ERR_PTR(-ENOTDIR);
+               goto out_kernfs;
        }
 
-       mutex_unlock(&cgroup_mutex);
+       rcu_read_lock();
+
+       cgrp = rcu_dereference(*(void __rcu __force **)&kn->priv);
+       if (!cgrp || !cgroup_tryget(cgrp))
+               cgrp = ERR_PTR(-ENOENT);
+
+       rcu_read_unlock();
+
+out_kernfs:
+       kernfs_put(kn);
+out:
        return cgrp;
 }
 EXPORT_SYMBOL_GPL(cgroup_get_from_path);
@@ -6625,44 +6655,6 @@ void cgroup_sk_free(struct sock_cgroup_data *skcd)
 
 #endif /* CONFIG_SOCK_CGROUP_DATA */
 
-#ifdef CONFIG_CGROUP_BPF
-int cgroup_bpf_attach(struct cgroup *cgrp,
-                     struct bpf_prog *prog, struct bpf_prog *replace_prog,
-                     struct bpf_cgroup_link *link,
-                     enum bpf_attach_type type,
-                     u32 flags)
-{
-       int ret;
-
-       mutex_lock(&cgroup_mutex);
-       ret = __cgroup_bpf_attach(cgrp, prog, replace_prog, link, type, flags);
-       mutex_unlock(&cgroup_mutex);
-       return ret;
-}
-
-int cgroup_bpf_detach(struct cgroup *cgrp, struct bpf_prog *prog,
-                     enum bpf_attach_type type)
-{
-       int ret;
-
-       mutex_lock(&cgroup_mutex);
-       ret = __cgroup_bpf_detach(cgrp, prog, NULL, type);
-       mutex_unlock(&cgroup_mutex);
-       return ret;
-}
-
-int cgroup_bpf_query(struct cgroup *cgrp, const union bpf_attr *attr,
-                    union bpf_attr __user *uattr)
-{
-       int ret;
-
-       mutex_lock(&cgroup_mutex);
-       ret = __cgroup_bpf_query(cgrp, attr, uattr);
-       mutex_unlock(&cgroup_mutex);
-       return ret;
-}
-#endif /* CONFIG_CGROUP_BPF */
-
 #ifdef CONFIG_SYSFS
 static ssize_t show_delegatable_files(struct cftype *files, char *buf,
                                      ssize_t size, const char *prefix)