summaryrefslogtreecommitdiff
path: root/kernel/cgroup/cpuset.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/cgroup/cpuset.c')
-rw-r--r--kernel/cgroup/cpuset.c85
1 files changed, 70 insertions, 15 deletions
diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c
index 266f10cb7222..5583b6d69748 100644
--- a/kernel/cgroup/cpuset.c
+++ b/kernel/cgroup/cpuset.c
@@ -38,7 +38,7 @@
#include <linux/mm.h>
#include <linux/memory.h>
#include <linux/export.h>
-#include <linux/mount.h>
+#include <linux/fs_context.h>
#include <linux/namei.h>
#include <linux/pagemap.h>
#include <linux/proc_fs.h>
@@ -315,25 +315,80 @@ static inline bool is_in_v2_mode(void)
* users. If someone tries to mount the "cpuset" filesystem, we
* silently switch it to mount "cgroup" instead
*/
-static struct dentry *cpuset_mount(struct file_system_type *fs_type,
- int flags, const char *unused_dev_name, void *data)
-{
- struct file_system_type *cgroup_fs = get_fs_type("cgroup");
- struct dentry *ret = ERR_PTR(-ENODEV);
- if (cgroup_fs) {
- char mountopts[] =
- "cpuset,noprefix,"
- "release_agent=/sbin/cpuset_release_agent";
- ret = cgroup_fs->mount(cgroup_fs, flags,
- unused_dev_name, mountopts);
- put_filesystem(cgroup_fs);
+static int cpuset_get_tree(struct fs_context *fc)
+{
+ static const char opts[] = "cpuset,noprefix,release_agent=/sbin/cpuset_release_agent";
+ struct file_system_type *cgroup_fs;
+ struct fs_context *cg_fc;
+ char *p;
+ int ret = -ENODEV;
+
+ cgroup_fs = get_fs_type("cgroup");
+ if (!cgroup_fs)
+ goto out;
+
+ cg_fc = vfs_new_fs_context(cgroup_fs, NULL, fc->sb_flags, fc->sb_flags,
+ fc->purpose);
+ put_filesystem(cgroup_fs);
+ if (IS_ERR(cg_fc)) {
+ ret = PTR_ERR(cg_fc);
+ goto out;
+ }
+
+ ret = -ENOMEM;
+ p = kstrdup(opts, GFP_KERNEL);
+ if (!p)
+ goto out_fc;
+
+ ret = generic_parse_monolithic(cg_fc, p, sizeof(opts) - 1);
+ kfree(p);
+ if (ret < 0)
+ goto out_fc;
+
+ /* We can't call vfs_get_tree() as that will do various post-get-tree
+ * things that we want our caller to do.
+ */
+ if (cg_fc->ops->validate) {
+ ret = cg_fc->ops->validate(cg_fc);
+ if (ret < 0)
+ goto out_fc;
}
+
+ ret = security_fs_context_validate(cg_fc);
+ if (ret < 0)
+ goto out_fc;
+
+ /* Get the mountable root in fc->root, with a ref on the root and a ref
+ * on the superblock.
+ */
+ ret = cg_fc->ops->get_tree(cg_fc);
+ if (ret < 0)
+ return ret;
+
+ fc->root = cg_fc->root;
+ cg_fc->root = NULL;
+ ret = 0;
+
+out_fc:
+ put_fs_context(cg_fc);
+out:
return ret;
}
+static const struct fs_context_operations cpuset_fs_context_ops = {
+ .get_tree = cpuset_get_tree,
+};
+
+static int cpuset_init_fs_context(struct fs_context *fc,
+ struct dentry *reference)
+{
+ fc->ops = &cpuset_fs_context_ops;
+ return 0;
+}
+
static struct file_system_type cpuset_fs_type = {
- .name = "cpuset",
- .mount = cpuset_mount,
+ .name = "cpuset",
+ .init_fs_context = cpuset_init_fs_context,
};
/*