Commit 90129625 authored by Al Viro's avatar Al Viro
Browse files

cgroup: start switching to fs_context



Unfortunately, cgroup is tangled into kernfs infrastructure.
To avoid converting all kernfs-based filesystems at once,
we need to untangle the remount part of things, instead of
having it go through kernfs_sop_remount_fs().  Fortunately,
it's not hard to do.

This commit just gets cgroup/cgroup1 to use fs_context to
deliver options on mount and remount paths.  Parsing those
is going to be done in the next commits; for now we do
pretty much what legacy case does.

Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 935c6912
Loading
Loading
Loading
Loading
+14 −0
Original line number Original line Diff line number Diff line
@@ -7,6 +7,7 @@
#include <linux/workqueue.h>
#include <linux/workqueue.h>
#include <linux/list.h>
#include <linux/list.h>
#include <linux/refcount.h>
#include <linux/refcount.h>
#include <linux/fs_context.h>


#define TRACE_CGROUP_PATH_LEN 1024
#define TRACE_CGROUP_PATH_LEN 1024
extern spinlock_t trace_cgroup_path_lock;
extern spinlock_t trace_cgroup_path_lock;
@@ -36,6 +37,18 @@ extern void __init enable_debug_cgroup(void);
		}							\
		}							\
	} while (0)
	} while (0)


/*
 * The cgroup filesystem superblock creation/mount context.
 */
struct cgroup_fs_context {
	char *data;
};

static inline struct cgroup_fs_context *cgroup_fc2context(struct fs_context *fc)
{
	return fc->fs_private;
}

/*
/*
 * A cgroup can be associated with multiple css_sets as different tasks may
 * A cgroup can be associated with multiple css_sets as different tasks may
 * belong to different cgroups on different hierarchies.  In the other
 * belong to different cgroups on different hierarchies.  In the other
@@ -255,5 +268,6 @@ void cgroup1_check_for_release(struct cgroup *cgrp);
struct dentry *cgroup1_mount(struct file_system_type *fs_type, int flags,
struct dentry *cgroup1_mount(struct file_system_type *fs_type, int flags,
			     void *data, unsigned long magic,
			     void *data, unsigned long magic,
			     struct cgroup_namespace *ns);
			     struct cgroup_namespace *ns);
int cgroup1_reconfigure(struct fs_context *ctx);


#endif /* __CGROUP_INTERNAL_H */
#endif /* __CGROUP_INTERNAL_H */
+5 −4
Original line number Original line Diff line number Diff line
@@ -1046,17 +1046,19 @@ static int parse_cgroupfs_options(char *data, struct cgroup_sb_opts *opts)
	return 0;
	return 0;
}
}


static int cgroup1_remount(struct kernfs_root *kf_root, int *flags, char *data)
int cgroup1_reconfigure(struct fs_context *fc)
{
{
	int ret = 0;
	struct cgroup_fs_context *ctx = cgroup_fc2context(fc);
	struct kernfs_root *kf_root = kernfs_root_from_sb(fc->root->d_sb);
	struct cgroup_root *root = cgroup_root_from_kf(kf_root);
	struct cgroup_root *root = cgroup_root_from_kf(kf_root);
	int ret = 0;
	struct cgroup_sb_opts opts;
	struct cgroup_sb_opts opts;
	u16 added_mask, removed_mask;
	u16 added_mask, removed_mask;


	cgroup_lock_and_drain_offline(&cgrp_dfl_root.cgrp);
	cgroup_lock_and_drain_offline(&cgrp_dfl_root.cgrp);


	/* See what subsystems are wanted */
	/* See what subsystems are wanted */
	ret = parse_cgroupfs_options(data, &opts);
	ret = parse_cgroupfs_options(ctx->data, &opts);
	if (ret)
	if (ret)
		goto out_unlock;
		goto out_unlock;


@@ -1106,7 +1108,6 @@ static int cgroup1_remount(struct kernfs_root *kf_root, int *flags, char *data)
struct kernfs_syscall_ops cgroup1_kf_syscall_ops = {
struct kernfs_syscall_ops cgroup1_kf_syscall_ops = {
	.rename			= cgroup1_rename,
	.rename			= cgroup1_rename,
	.show_options		= cgroup1_show_options,
	.show_options		= cgroup1_show_options,
	.remount_fs		= cgroup1_remount,
	.mkdir			= cgroup_mkdir,
	.mkdir			= cgroup_mkdir,
	.rmdir			= cgroup_rmdir,
	.rmdir			= cgroup_rmdir,
	.show_path		= cgroup_show_path,
	.show_path		= cgroup_show_path,
+97 −37
Original line number Original line Diff line number Diff line
@@ -1811,12 +1811,13 @@ static int cgroup_show_options(struct seq_file *seq, struct kernfs_root *kf_root
	return 0;
	return 0;
}
}


static int cgroup_remount(struct kernfs_root *kf_root, int *flags, char *data)
static int cgroup_reconfigure(struct fs_context *fc)
{
{
	struct cgroup_fs_context *ctx = cgroup_fc2context(fc);
	unsigned int root_flags;
	unsigned int root_flags;
	int ret;
	int ret;


	ret = parse_cgroup_root_flags(data, &root_flags);
	ret = parse_cgroup_root_flags(ctx->data, &root_flags);
	if (ret)
	if (ret)
		return ret;
		return ret;


@@ -2067,52 +2068,112 @@ struct dentry *cgroup_do_mount(struct file_system_type *fs_type, int flags,
	return dentry;
	return dentry;
}
}


static struct dentry *cgroup_mount(struct file_system_type *fs_type,
/*
			 int flags, const char *unused_dev_name,
 * Destroy a cgroup filesystem context.
			 void *data)
 */
static void cgroup_fs_context_free(struct fs_context *fc)
{
{
	struct cgroup_namespace *ns = current->nsproxy->cgroup_ns;
	struct cgroup_fs_context *ctx = cgroup_fc2context(fc);
	struct dentry *dentry;
	int ret;

	get_cgroup_ns(ns);


	/* Check if the caller has permission to mount. */
	kfree(ctx);
	if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN)) {
		put_cgroup_ns(ns);
		return ERR_PTR(-EPERM);
}
}


	/*
static int cgroup_parse_monolithic(struct fs_context *fc, void *data)
	 * The first time anyone tries to mount a cgroup, enable the list
{
	 * linking each css_set to its tasks and fix up all existing tasks.
	struct cgroup_fs_context *ctx = cgroup_fc2context(fc);
	 */
	if (!use_task_css_set_links)
		cgroup_enable_task_cg_lists();


	if (fs_type == &cgroup2_fs_type) {
	ctx->data = data;
	if (ctx->data)
		security_sb_eat_lsm_opts(ctx->data, &fc->security);
	return 0;
}

static int cgroup_get_tree(struct fs_context *fc)
{
	struct cgroup_namespace *ns = current->nsproxy->cgroup_ns;
	struct cgroup_fs_context *ctx = cgroup_fc2context(fc);
	unsigned int root_flags;
	unsigned int root_flags;
	struct dentry *root;
	int ret;


		ret = parse_cgroup_root_flags(data, &root_flags);
	/* Check if the caller has permission to mount. */
		if (ret) {
	if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
			put_cgroup_ns(ns);
		return -EPERM;
			return ERR_PTR(ret);

		}
	ret = parse_cgroup_root_flags(ctx->data, &root_flags);
	if (ret)
		return ret;


	cgrp_dfl_visible = true;
	cgrp_dfl_visible = true;
	cgroup_get_live(&cgrp_dfl_root.cgrp);
	cgroup_get_live(&cgrp_dfl_root.cgrp);


		dentry = cgroup_do_mount(&cgroup2_fs_type, flags, &cgrp_dfl_root,
	root = cgroup_do_mount(&cgroup2_fs_type, fc->sb_flags, &cgrp_dfl_root,
					 CGROUP2_SUPER_MAGIC, ns);
					 CGROUP2_SUPER_MAGIC, ns);
		if (!IS_ERR(dentry))
	if (IS_ERR(root))
		return PTR_ERR(root);

	apply_cgroup_root_flags(root_flags);
	apply_cgroup_root_flags(root_flags);
	} else {
	fc->root = root;
		dentry = cgroup1_mount(&cgroup_fs_type, flags, data,
	return 0;
}

static int cgroup1_get_tree(struct fs_context *fc)
{
	struct cgroup_namespace *ns = current->nsproxy->cgroup_ns;
	struct cgroup_fs_context *ctx = cgroup_fc2context(fc);
	struct dentry *root;

	/* Check if the caller has permission to mount. */
	if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN))
		return -EPERM;

	root = cgroup1_mount(&cgroup_fs_type, fc->sb_flags, ctx->data,
				       CGROUP_SUPER_MAGIC, ns);
				       CGROUP_SUPER_MAGIC, ns);
	if (IS_ERR(root))
		return PTR_ERR(root);

	fc->root = root;
	return 0;
}
}


	put_cgroup_ns(ns);
static const struct fs_context_operations cgroup_fs_context_ops = {
	return dentry;
	.free		= cgroup_fs_context_free,
	.parse_monolithic = cgroup_parse_monolithic,
	.get_tree	= cgroup_get_tree,
	.reconfigure	= cgroup_reconfigure,
};

static const struct fs_context_operations cgroup1_fs_context_ops = {
	.free		= cgroup_fs_context_free,
	.parse_monolithic = cgroup_parse_monolithic,
	.get_tree	= cgroup1_get_tree,
	.reconfigure	= cgroup1_reconfigure,
};

/*
 * Initialise the cgroup filesystem creation/reconfiguration context.
 */
static int cgroup_init_fs_context(struct fs_context *fc)
{
	struct cgroup_fs_context *ctx;

	ctx = kzalloc(sizeof(struct cgroup_fs_context), GFP_KERNEL);
	if (!ctx)
		return -ENOMEM;

	/*
	 * The first time anyone tries to mount a cgroup, enable the list
	 * linking each css_set to its tasks and fix up all existing tasks.
	 */
	if (!use_task_css_set_links)
		cgroup_enable_task_cg_lists();

	fc->fs_private = ctx;
	if (fc->fs_type == &cgroup2_fs_type)
		fc->ops = &cgroup_fs_context_ops;
	else
		fc->ops = &cgroup1_fs_context_ops;
	return 0;
}
}


static void cgroup_kill_sb(struct super_block *sb)
static void cgroup_kill_sb(struct super_block *sb)
@@ -2136,14 +2197,14 @@ static void cgroup_kill_sb(struct super_block *sb)


struct file_system_type cgroup_fs_type = {
struct file_system_type cgroup_fs_type = {
	.name = "cgroup",
	.name = "cgroup",
	.mount = cgroup_mount,
	.init_fs_context = cgroup_init_fs_context,
	.kill_sb = cgroup_kill_sb,
	.kill_sb = cgroup_kill_sb,
	.fs_flags = FS_USERNS_MOUNT,
	.fs_flags = FS_USERNS_MOUNT,
};
};


static struct file_system_type cgroup2_fs_type = {
static struct file_system_type cgroup2_fs_type = {
	.name = "cgroup2",
	.name = "cgroup2",
	.mount = cgroup_mount,
	.init_fs_context = cgroup_init_fs_context,
	.kill_sb = cgroup_kill_sb,
	.kill_sb = cgroup_kill_sb,
	.fs_flags = FS_USERNS_MOUNT,
	.fs_flags = FS_USERNS_MOUNT,
};
};
@@ -5268,7 +5329,6 @@ int cgroup_rmdir(struct kernfs_node *kn)


static struct kernfs_syscall_ops cgroup_kf_syscall_ops = {
static struct kernfs_syscall_ops cgroup_kf_syscall_ops = {
	.show_options		= cgroup_show_options,
	.show_options		= cgroup_show_options,
	.remount_fs		= cgroup_remount,
	.mkdir			= cgroup_mkdir,
	.mkdir			= cgroup_mkdir,
	.rmdir			= cgroup_rmdir,
	.rmdir			= cgroup_rmdir,
	.show_path		= cgroup_show_path,
	.show_path		= cgroup_show_path,