[PATCH 12/25] kernfs, cgroup: Add fsinfo support [ver #13]

From: David Howells
Date: Tue May 28 2019 - 11:16:11 EST


Add support for fsinfo() to kernfs and cgroup.

Signed-off-by: David Howells <dhowells@xxxxxxxxxx>
---

fs/kernfs/mount.c | 20 ++++++++++++++++++++
include/linux/kernfs.h | 4 ++++
kernel/cgroup/cgroup-v1.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
kernel/cgroup/cgroup.c | 19 +++++++++++++++++++
4 files changed, 87 insertions(+)

diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
index 9a4646eecb71..f40d467d274b 100644
--- a/fs/kernfs/mount.c
+++ b/fs/kernfs/mount.c
@@ -17,6 +17,7 @@
#include <linux/namei.h>
#include <linux/seq_file.h>
#include <linux/exportfs.h>
+#include <linux/fsinfo.h>

#include "kernfs-internal.h"

@@ -45,6 +46,22 @@ static int kernfs_sop_show_path(struct seq_file *sf, struct dentry *dentry)
return 0;
}

+#ifdef CONFIG_FSINFO
+static int kernfs_sop_fsinfo(struct path *path, struct fsinfo_kparams *params)
+{
+ struct kernfs_root *root = kernfs_root(kernfs_dentry_node(path->dentry));
+ struct kernfs_syscall_ops *scops = root->syscall_ops;
+ int ret;
+
+ if (scops && scops->fsinfo) {
+ ret = scops->fsinfo(root, params);
+ if (ret != -EAGAIN)
+ return ret;
+ }
+ return generic_fsinfo(path, params);
+}
+#endif
+
const struct super_operations kernfs_sops = {
.statfs = simple_statfs,
.drop_inode = generic_delete_inode,
@@ -52,6 +69,9 @@ const struct super_operations kernfs_sops = {

.show_options = kernfs_sop_show_options,
.show_path = kernfs_sop_show_path,
+#ifdef CONFIG_FSINFO
+ .fsinfo = kernfs_sop_fsinfo,
+#endif
};

/*
diff --git a/include/linux/kernfs.h b/include/linux/kernfs.h
index 2bf477f86eb1..d01ec4dc2db1 100644
--- a/include/linux/kernfs.h
+++ b/include/linux/kernfs.h
@@ -27,6 +27,7 @@ struct super_block;
struct file_system_type;
struct poll_table_struct;
struct fs_context;
+struct fsinfo_kparams;

struct kernfs_fs_context;
struct kernfs_open_node;
@@ -171,6 +172,9 @@ struct kernfs_node {
*/
struct kernfs_syscall_ops {
int (*show_options)(struct seq_file *sf, struct kernfs_root *root);
+#ifdef CONFIG_FSINFO
+ int (*fsinfo)(struct kernfs_root *root, struct fsinfo_kparams *params);
+#endif

int (*mkdir)(struct kernfs_node *parent, const char *name,
umode_t mode);
diff --git a/kernel/cgroup/cgroup-v1.c b/kernel/cgroup/cgroup-v1.c
index 68ca5de7ec27..c8a85dfcac87 100644
--- a/kernel/cgroup/cgroup-v1.c
+++ b/kernel/cgroup/cgroup-v1.c
@@ -14,6 +14,7 @@
#include <linux/pid_namespace.h>
#include <linux/cgroupstats.h>
#include <linux/fs_parser.h>
+#include <linux/fsinfo.h>

#include <trace/events/cgroup.h>

@@ -921,6 +922,46 @@ const struct fs_parameter_description cgroup1_fs_parameters = {
.specs = cgroup1_param_specs,
};

+#ifdef CONFIG_FSINFO
+static int cgroup1_fsinfo(struct kernfs_root *kf_root, struct fsinfo_kparams *params)
+{
+ struct cgroup_root *root = cgroup_root_from_kf(kf_root);
+ struct cgroup_subsys *ss;
+ int ssid;
+
+ switch (params->request) {
+ case FSINFO_ATTR_PARAMETERS:
+ if (root->name[0])
+ fsinfo_note_param(params, "name", root->name);
+
+ if (test_bit(CGRP_CPUSET_CLONE_CHILDREN, &root->cgrp.flags))
+ fsinfo_note_param(params, "clone_children", NULL);
+ if (root->flags & CGRP_ROOT_CPUSET_V2_MODE)
+ fsinfo_note_param(params, "noprefix", NULL);
+ if (root->flags & CGRP_ROOT_NOPREFIX)
+ fsinfo_note_param(params, "noprefix", NULL);
+ if (root->flags & CGRP_ROOT_XATTR)
+ fsinfo_note_param(params, "xattr", NULL);
+
+ spin_lock(&release_agent_path_lock);
+ if (root->release_agent_path[0])
+ fsinfo_note_param(params, "release_agent",
+ root->release_agent_path);
+ spin_unlock(&release_agent_path_lock);
+
+
+ for_each_subsys(ss, ssid) {
+ if (root->subsys_mask & (1 << ssid))
+ fsinfo_note_param(params, ss->legacy_name, NULL);
+ }
+ return params->usage;
+
+ default:
+ return -EAGAIN; /* Tell kernfs to call generic_fsinfo() */
+ }
+}
+#endif /* CONFIG_FSINFO */
+
int cgroup1_parse_param(struct fs_context *fc, struct fs_parameter *param)
{
struct cgroup_fs_context *ctx = cgroup_fc2context(fc);
@@ -1114,6 +1155,9 @@ int cgroup1_reconfigure(struct fs_context *fc)
struct kernfs_syscall_ops cgroup1_kf_syscall_ops = {
.rename = cgroup1_rename,
.show_options = cgroup1_show_options,
+#ifdef CONFIG_FSINFO
+ .fsinfo = cgroup1_fsinfo,
+#endif
.mkdir = cgroup_mkdir,
.rmdir = cgroup_rmdir,
.show_path = cgroup_show_path,
diff --git a/kernel/cgroup/cgroup.c b/kernel/cgroup/cgroup.c
index 4a0eb465d17e..7e32570905e9 100644
--- a/kernel/cgroup/cgroup.c
+++ b/kernel/cgroup/cgroup.c
@@ -55,6 +55,7 @@
#include <linux/nsproxy.h>
#include <linux/file.h>
#include <linux/fs_parser.h>
+#include <linux/fsinfo.h>
#include <linux/sched/cputime.h>
#include <linux/psi.h>
#include <net/sock.h>
@@ -1858,6 +1859,21 @@ static int cgroup_show_options(struct seq_file *seq, struct kernfs_root *kf_root
return 0;
}

+#ifdef CONFIG_FSINFO
+static int cgroup_fsinfo(struct kernfs_root *kf_root, struct fsinfo_kparams *params)
+{
+ switch (params->request) {
+ case FSINFO_ATTR_PARAMETERS:
+ if (cgrp_dfl_root.flags & CGRP_ROOT_NS_DELEGATE)
+ fsinfo_note_param(params, "nsdelegate", NULL);
+ return params->usage;
+
+ default:
+ return -EAGAIN; /* Tell kernfs to call generic_fsinfo() */
+ }
+}
+#endif /* CONFIG_FSINFO */
+
static int cgroup_reconfigure(struct fs_context *fc)
{
struct cgroup_fs_context *ctx = cgroup_fc2context(fc);
@@ -5550,6 +5566,9 @@ int cgroup_rmdir(struct kernfs_node *kn)

static struct kernfs_syscall_ops cgroup_kf_syscall_ops = {
.show_options = cgroup_show_options,
+#ifdef CONFIG_FSINFO
+ .fsinfo = cgroup_fsinfo,
+#endif
.mkdir = cgroup_mkdir,
.rmdir = cgroup_rmdir,
.show_path = cgroup_show_path,