blob: 86ba2ccad7df6cab010fdc4bee96aacfcc9cff84 [file] [log] [blame]
Lorenz Brun1d801752020-04-02 09:24:51 +02001From fa2ff1a0da263362a2c98c8cfe68bcac3a323ac4 Mon Sep 17 00:00:00 2001
2From: David Howells <dhowells@redhat.com>
3Date: Tue, 3 Mar 2020 14:29:27 +0000
4Subject: [PATCH 4/4] fsinfo: Allow retrieval of superblock devname, options
5 and stats
6
7Provide fsinfo() attributes to retrieve superblock device name, options,
8and statistics in string form. The following attributes are defined:
9
10 FSINFO_ATTR_SOURCE - Mount-specific device name
11 FSINFO_ATTR_CONFIGURATION - Mount options
12 FSINFO_ATTR_FS_STATISTICS - Filesystem statistics
13
14FSINFO_ATTR_SOURCE could be made indexable by params->Nth to handle the
15case where there is more than one source (e.g. the bcachefs filesystem).
16
17Signed-off-by: David Howells <dhowells@redhat.com>
18---
19 fs/fsinfo.c | 41 +++++++++++++++++++++++++++++++++++++
20 fs/internal.h | 2 ++
21 fs/namespace.c | 39 +++++++++++++++++++++++++++++++++++
22 include/uapi/linux/fsinfo.h | 3 +++
23 samples/vfs/test-fsinfo.c | 4 ++++
24 5 files changed, 89 insertions(+)
25
26diff --git a/fs/fsinfo.c b/fs/fsinfo.c
27index 1830c73f37a7..3ed43c5a10e8 100644
28--- a/fs/fsinfo.c
29+++ b/fs/fsinfo.c
30@@ -188,6 +188,44 @@ static int fsinfo_generic_volume_id(struct path *path, struct fsinfo_context *ct
31 return fsinfo_string(path->dentry->d_sb->s_id, ctx);
32 }
33
34+/*
35+ * Retrieve the superblock configuration (mount options) as a comma-separated
36+ * string. The initial comma is stripped off.
37+ */
38+static int fsinfo_generic_seq_read(struct path *path, struct fsinfo_context *ctx)
39+{
40+ struct super_block *sb = path->dentry->d_sb;
41+ struct seq_file m = {
42+ .buf = ctx->buffer,
43+ .size = ctx->buf_size,
44+ };
45+ int ret = 0;
46+
47+ switch (ctx->requested_attr) {
48+ case FSINFO_ATTR_CONFIGURATION:
49+ if (sb->s_op->show_options)
50+ ret = sb->s_op->show_options(&m, path->mnt->mnt_root);
51+ break;
52+
53+ case FSINFO_ATTR_FS_STATISTICS:
54+ if (sb->s_op->show_stats)
55+ ret = sb->s_op->show_stats(&m, path->mnt->mnt_root);
56+ break;
57+ }
58+
59+ if (ret < 0)
60+ return ret;
61+ if (seq_has_overflowed(&m))
62+ return ctx->buf_size + PAGE_SIZE;
63+ if (ctx->requested_attr == FSINFO_ATTR_CONFIGURATION) {
64+ if (m.count > 0 && ((char *)ctx->buffer)[0] == ',') {
65+ m.count--;
66+ ctx->skip = 1;
67+ }
68+ }
69+ return m.count;
70+}
71+
72 static const struct fsinfo_attribute fsinfo_common_attributes[] = {
73 FSINFO_VSTRUCT (FSINFO_ATTR_STATFS, fsinfo_generic_statfs),
74 FSINFO_VSTRUCT (FSINFO_ATTR_IDS, fsinfo_generic_ids),
75@@ -196,6 +234,9 @@ static const struct fsinfo_attribute fsinfo_common_attributes[] = {
76 FSINFO_VSTRUCT (FSINFO_ATTR_TIMESTAMP_INFO, fsinfo_generic_timestamp_info),
77 FSINFO_STRING (FSINFO_ATTR_VOLUME_ID, fsinfo_generic_volume_id),
78 FSINFO_VSTRUCT (FSINFO_ATTR_VOLUME_UUID, fsinfo_generic_volume_uuid),
79+ FSINFO_STRING (FSINFO_ATTR_SOURCE, fsinfo_generic_mount_source),
80+ FSINFO_STRING (FSINFO_ATTR_CONFIGURATION, fsinfo_generic_seq_read),
81+ FSINFO_STRING (FSINFO_ATTR_FS_STATISTICS, fsinfo_generic_seq_read),
82
83 FSINFO_LIST (FSINFO_ATTR_FSINFO_ATTRIBUTES, (void *)123UL),
84 FSINFO_VSTRUCT_N(FSINFO_ATTR_FSINFO_ATTRIBUTE_INFO, (void *)123UL),
85diff --git a/fs/internal.h b/fs/internal.h
86index a0d90f23593c..6f2cc77bf38d 100644
87--- a/fs/internal.h
88+++ b/fs/internal.h
89@@ -91,6 +91,8 @@ extern int __mnt_want_write_file(struct file *);
90 extern void __mnt_drop_write_file(struct file *);
91
92 extern void dissolve_on_fput(struct vfsmount *);
93+extern int fsinfo_generic_mount_source(struct path *, struct fsinfo_context *);
94+
95 /*
96 * fs_struct.c
97 */
98diff --git a/fs/namespace.c b/fs/namespace.c
99index 85b5f7bea82e..b4951e2afae1 100644
100--- a/fs/namespace.c
101+++ b/fs/namespace.c
102@@ -30,6 +30,7 @@
103 #include <uapi/linux/mount.h>
104 #include <linux/fs_context.h>
105 #include <linux/shmem_fs.h>
106+#include <linux/fsinfo.h>
107
108 #include "pnode.h"
109 #include "internal.h"
110@@ -3975,3 +3976,41 @@ const struct proc_ns_operations mntns_operations = {
111 .install = mntns_install,
112 .owner = mntns_owner,
113 };
114+
115+#ifdef CONFIG_FSINFO
116+static inline void mangle(struct seq_file *m, const char *s)
117+{
118+ seq_escape(m, s, " \t\n\\");
119+}
120+
121+/*
122+ * Return the mount source/device name as seen from this mountpoint. Shared
123+ * mounts may vary here and the filesystem is permitted to substitute its own
124+ * rendering.
125+ */
126+int fsinfo_generic_mount_source(struct path *path, struct fsinfo_context *ctx)
127+{
128+ struct super_block *sb = path->mnt->mnt_sb;
129+ struct mount *mnt = real_mount(path->mnt);
130+ struct seq_file m = {
131+ .buf = ctx->buffer,
132+ .size = ctx->buf_size,
133+ };
134+ int ret;
135+
136+ if (sb->s_op->show_devname) {
137+ ret = sb->s_op->show_devname(&m, mnt->mnt.mnt_root);
138+ if (ret < 0)
139+ return ret;
140+ } else {
141+ if (!mnt->mnt_devname)
142+ return fsinfo_string("none", ctx);
143+ mangle(&m, mnt->mnt_devname);
144+ }
145+
146+ if (seq_has_overflowed(&m))
147+ return ctx->buf_size + PAGE_SIZE;
148+ return m.count;
149+}
150+
151+#endif /* CONFIG_FSINFO */
152diff --git a/include/uapi/linux/fsinfo.h b/include/uapi/linux/fsinfo.h
153index e9b35b9b7629..d3722c7142a6 100644
154--- a/include/uapi/linux/fsinfo.h
155+++ b/include/uapi/linux/fsinfo.h
156@@ -23,6 +23,9 @@
157 #define FSINFO_ATTR_VOLUME_ID 0x05 /* Volume ID (string) */
158 #define FSINFO_ATTR_VOLUME_UUID 0x06 /* Volume UUID (LE uuid) */
159 #define FSINFO_ATTR_VOLUME_NAME 0x07 /* Volume name (string) */
160+#define FSINFO_ATTR_SOURCE 0x09 /* Superblock source/device name (string) */
161+#define FSINFO_ATTR_CONFIGURATION 0x0a /* Superblock configuration/options (string) */
162+#define FSINFO_ATTR_FS_STATISTICS 0x0b /* Superblock filesystem statistics (string) */
163
164 #define FSINFO_ATTR_FSINFO_ATTRIBUTE_INFO 0x100 /* Information about attr N (for path) */
165 #define FSINFO_ATTR_FSINFO_ATTRIBUTES 0x101 /* List of supported attrs (for path) */
166diff --git a/samples/vfs/test-fsinfo.c b/samples/vfs/test-fsinfo.c
167index 2b53c735d330..1797f7b8d08a 100644
168--- a/samples/vfs/test-fsinfo.c
169+++ b/samples/vfs/test-fsinfo.c
170@@ -289,6 +289,10 @@ static const struct fsinfo_attribute fsinfo_attributes[] = {
171 FSINFO_STRING (FSINFO_ATTR_VOLUME_ID, string),
172 FSINFO_VSTRUCT (FSINFO_ATTR_VOLUME_UUID, fsinfo_generic_volume_uuid),
173 FSINFO_STRING (FSINFO_ATTR_VOLUME_NAME, string),
174+ FSINFO_STRING (FSINFO_ATTR_SOURCE, string),
175+ FSINFO_STRING (FSINFO_ATTR_CONFIGURATION, string),
176+ FSINFO_STRING (FSINFO_ATTR_FS_STATISTICS, string),
177+
178 FSINFO_VSTRUCT_N(FSINFO_ATTR_FSINFO_ATTRIBUTE_INFO, fsinfo_meta_attribute_info),
179 FSINFO_LIST (FSINFO_ATTR_FSINFO_ATTRIBUTES, fsinfo_meta_attributes),
180 {}
181--
1822.20.1
183