diff options
-rw-r--r-- | kernel/cgroup/cgroup.c | 140 |
1 files changed, 79 insertions, 61 deletions
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c index d34c170f87ef..228dd9ae708b 100644 --- a/kernel/cgroup/cgroup.c +++ b/kernel/cgroup/cgroup.c | |||
@@ -1989,48 +1989,55 @@ out: | |||
1989 | return ret; | 1989 | return ret; |
1990 | } | 1990 | } |
1991 | 1991 | ||
1992 | static struct dentry *cgroup_mount(struct file_system_type *fs_type, | 1992 | static struct dentry *cgroup_do_mount(struct file_system_type *fs_type, |
1993 | int flags, const char *unused_dev_name, | 1993 | int flags, struct cgroup_root *root, |
1994 | void *data) | 1994 | unsigned long magic, |
1995 | struct cgroup_namespace *ns) | ||
1995 | { | 1996 | { |
1996 | bool is_v2 = fs_type == &cgroup2_fs_type; | ||
1997 | struct super_block *pinned_sb = NULL; | ||
1998 | struct cgroup_namespace *ns = current->nsproxy->cgroup_ns; | ||
1999 | struct cgroup_subsys *ss; | ||
2000 | struct cgroup_root *root; | ||
2001 | struct cgroup_sb_opts opts; | ||
2002 | struct dentry *dentry; | 1997 | struct dentry *dentry; |
2003 | int ret; | ||
2004 | int i; | ||
2005 | bool new_sb; | 1998 | bool new_sb; |
2006 | 1999 | ||
2007 | get_cgroup_ns(ns); | 2000 | dentry = kernfs_mount(fs_type, flags, root->kf_root, magic, &new_sb); |
2008 | |||
2009 | /* Check if the caller has permission to mount. */ | ||
2010 | if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) { | ||
2011 | put_cgroup_ns(ns); | ||
2012 | return ERR_PTR(-EPERM); | ||
2013 | } | ||
2014 | 2001 | ||
2015 | /* | 2002 | /* |
2016 | * The first time anyone tries to mount a cgroup, enable the list | 2003 | * In non-init cgroup namespace, instead of root cgroup's dentry, |
2017 | * linking each css_set to its tasks and fix up all existing tasks. | 2004 | * we return the dentry corresponding to the cgroupns->root_cgrp. |
2018 | */ | 2005 | */ |
2019 | if (!use_task_css_set_links) | 2006 | if (!IS_ERR(dentry) && ns != &init_cgroup_ns) { |
2020 | cgroup_enable_task_cg_lists(); | 2007 | struct dentry *nsdentry; |
2008 | struct cgroup *cgrp; | ||
2021 | 2009 | ||
2022 | if (is_v2) { | 2010 | mutex_lock(&cgroup_mutex); |
2023 | if (data) { | 2011 | spin_lock_irq(&css_set_lock); |
2024 | pr_err("cgroup2: unknown option \"%s\"\n", (char *)data); | 2012 | |
2025 | put_cgroup_ns(ns); | 2013 | cgrp = cset_cgroup_from_root(ns->root_cset, root); |
2026 | return ERR_PTR(-EINVAL); | 2014 | |
2027 | } | 2015 | spin_unlock_irq(&css_set_lock); |
2028 | cgrp_dfl_visible = true; | 2016 | mutex_unlock(&cgroup_mutex); |
2029 | root = &cgrp_dfl_root; | 2017 | |
2030 | cgroup_get(&root->cgrp); | 2018 | nsdentry = kernfs_node_dentry(cgrp->kn, dentry->d_sb); |
2031 | goto out_mount; | 2019 | dput(dentry); |
2020 | dentry = nsdentry; | ||
2032 | } | 2021 | } |
2033 | 2022 | ||
2023 | if (IS_ERR(dentry) || !new_sb) | ||
2024 | cgroup_put(&root->cgrp); | ||
2025 | |||
2026 | return dentry; | ||
2027 | } | ||
2028 | |||
2029 | static struct dentry *cgroup1_mount(struct file_system_type *fs_type, | ||
2030 | int flags, void *data, | ||
2031 | unsigned long magic, | ||
2032 | struct cgroup_namespace *ns) | ||
2033 | { | ||
2034 | struct super_block *pinned_sb = NULL; | ||
2035 | struct cgroup_sb_opts opts; | ||
2036 | struct cgroup_root *root; | ||
2037 | struct cgroup_subsys *ss; | ||
2038 | struct dentry *dentry; | ||
2039 | int i, ret; | ||
2040 | |||
2034 | cgroup_lock_and_drain_offline(&cgrp_dfl_root.cgrp); | 2041 | cgroup_lock_and_drain_offline(&cgrp_dfl_root.cgrp); |
2035 | 2042 | ||
2036 | /* First find the desired set of subsystems */ | 2043 | /* First find the desired set of subsystems */ |
@@ -2152,47 +2159,58 @@ out_free: | |||
2152 | kfree(opts.release_agent); | 2159 | kfree(opts.release_agent); |
2153 | kfree(opts.name); | 2160 | kfree(opts.name); |
2154 | 2161 | ||
2155 | if (ret) { | 2162 | if (ret) |
2156 | put_cgroup_ns(ns); | ||
2157 | return ERR_PTR(ret); | 2163 | return ERR_PTR(ret); |
2158 | } | 2164 | |
2159 | out_mount: | 2165 | dentry = cgroup_do_mount(&cgroup_fs_type, flags, root, |
2160 | dentry = kernfs_mount(fs_type, flags, root->kf_root, | 2166 | CGROUP_SUPER_MAGIC, ns); |
2161 | is_v2 ? CGROUP2_SUPER_MAGIC : CGROUP_SUPER_MAGIC, | ||
2162 | &new_sb); | ||
2163 | 2167 | ||
2164 | /* | 2168 | /* |
2165 | * In non-init cgroup namespace, instead of root cgroup's | 2169 | * If @pinned_sb, we're reusing an existing root and holding an |
2166 | * dentry, we return the dentry corresponding to the | 2170 | * extra ref on its sb. Mount is complete. Put the extra ref. |
2167 | * cgroupns->root_cgrp. | ||
2168 | */ | 2171 | */ |
2169 | if (!IS_ERR(dentry) && ns != &init_cgroup_ns) { | 2172 | if (pinned_sb) |
2170 | struct dentry *nsdentry; | 2173 | deactivate_super(pinned_sb); |
2171 | struct cgroup *cgrp; | ||
2172 | 2174 | ||
2173 | mutex_lock(&cgroup_mutex); | 2175 | return dentry; |
2174 | spin_lock_irq(&css_set_lock); | 2176 | } |
2175 | 2177 | ||
2176 | cgrp = cset_cgroup_from_root(ns->root_cset, root); | 2178 | static struct dentry *cgroup_mount(struct file_system_type *fs_type, |
2179 | int flags, const char *unused_dev_name, | ||
2180 | void *data) | ||
2181 | { | ||
2182 | struct cgroup_namespace *ns = current->nsproxy->cgroup_ns; | ||
2183 | struct dentry *dentry; | ||
2177 | 2184 | ||
2178 | spin_unlock_irq(&css_set_lock); | 2185 | get_cgroup_ns(ns); |
2179 | mutex_unlock(&cgroup_mutex); | ||
2180 | 2186 | ||
2181 | nsdentry = kernfs_node_dentry(cgrp->kn, dentry->d_sb); | 2187 | /* Check if the caller has permission to mount. */ |
2182 | dput(dentry); | 2188 | if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) { |
2183 | dentry = nsdentry; | 2189 | put_cgroup_ns(ns); |
2190 | return ERR_PTR(-EPERM); | ||
2184 | } | 2191 | } |
2185 | 2192 | ||
2186 | if (IS_ERR(dentry) || !new_sb) | ||
2187 | cgroup_put(&root->cgrp); | ||
2188 | |||
2189 | /* | 2193 | /* |
2190 | * If @pinned_sb, we're reusing an existing root and holding an | 2194 | * The first time anyone tries to mount a cgroup, enable the list |
2191 | * extra ref on its sb. Mount is complete. Put the extra ref. | 2195 | * linking each css_set to its tasks and fix up all existing tasks. |
2192 | */ | 2196 | */ |
2193 | if (pinned_sb) { | 2197 | if (!use_task_css_set_links) |
2194 | WARN_ON(new_sb); | 2198 | cgroup_enable_task_cg_lists(); |
2195 | deactivate_super(pinned_sb); | 2199 | |
2200 | if (fs_type == &cgroup2_fs_type) { | ||
2201 | if (data) { | ||
2202 | pr_err("cgroup2: unknown option \"%s\"\n", (char *)data); | ||
2203 | put_cgroup_ns(ns); | ||
2204 | return ERR_PTR(-EINVAL); | ||
2205 | } | ||
2206 | cgrp_dfl_visible = true; | ||
2207 | cgroup_get(&cgrp_dfl_root.cgrp); | ||
2208 | |||
2209 | dentry = cgroup_do_mount(&cgroup2_fs_type, flags, &cgrp_dfl_root, | ||
2210 | CGROUP2_SUPER_MAGIC, ns); | ||
2211 | } else { | ||
2212 | dentry = cgroup1_mount(&cgroup_fs_type, flags, data, | ||
2213 | CGROUP_SUPER_MAGIC, ns); | ||
2196 | } | 2214 | } |
2197 | 2215 | ||
2198 | put_cgroup_ns(ns); | 2216 | put_cgroup_ns(ns); |