linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: David Howells <dhowells@redhat.com>
To: torvalds@linux-foundation.org, viro@zeniv.linux.org.uk
Cc: dhowells@redhat.com, raven@themaw.net, mszeredi@redhat.com,
	christian@brauner.io, jannh@google.com, darrick.wong@oracle.com,
	kzak@redhat.com, jlayton@redhat.com, linux-api@vger.kernel.org,
	linux-fsdevel@vger.kernel.org,
	linux-security-module@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: [PATCH 07/13] fsinfo: Allow mount topology and propagation info to be retrieved [ver #19]
Date: Wed, 18 Mar 2020 15:09:10 +0000	[thread overview]
Message-ID: <158454415081.2864823.16161601504717586678.stgit@warthog.procyon.org.uk> (raw)
In-Reply-To: <158454408854.2864823.5910520544515668590.stgit@warthog.procyon.org.uk>

Add a couple of attributes to allow information about the mount topology
and propagation to be retrieved:

 (1) FSINFO_ATTR_MOUNT_TOPOLOGY.

     Information about a mount's parentage in the mount topology tree and
     its propagation attributes.

     This has to be collected with the VFS namespace lock held, so it's
     separate from FSINFO_ATTR_MOUNT_INFO.  The topology change counter
     that a subsequent patch will export can be used to work out from the
     cheaper _INFO attribute as to whether the more expensive _TOPOLOGY
     attribute needs requerying.

     MOUNT_PROPAGATION_* flags are added to linux/mount.h for UAPI
     consumption.  At some point a mount_setattr() system call needs to be
     added.

 (2) FSINFO_ATTR_MOUNT_CHILDREN.

     Information about a mount's children in the mount topology tree.

     This is formatted as an array of structures, one for each child and
     capped with one for the argument mount (checked after listing all the
     children).  Each element contains the static IDs of the respective
     mount object along with a sum of its change attributes.

Signed-off-by: David Howells <dhowells@redhat.com>
---

 fs/fsinfo.c                 |    2 +
 fs/internal.h               |    2 +
 fs/namespace.c              |   91 +++++++++++++++++++++++++++++++++++++++++++
 include/uapi/linux/fsinfo.h |   27 +++++++++++++
 include/uapi/linux/mount.h  |   10 ++++-
 samples/vfs/test-fsinfo.c   |   38 ++++++++++++++++++
 6 files changed, 169 insertions(+), 1 deletion(-)

diff --git a/fs/fsinfo.c b/fs/fsinfo.c
index a08b172f71d2..eccea3b1579a 100644
--- a/fs/fsinfo.c
+++ b/fs/fsinfo.c
@@ -280,9 +280,11 @@ static const struct fsinfo_attribute fsinfo_common_attributes[] = {
 	FSINFO_VSTRUCT_N(FSINFO_ATTR_FSINFO_ATTRIBUTE_INFO, (void *)123UL),
 
 	FSINFO_VSTRUCT	(FSINFO_ATTR_MOUNT_INFO,	fsinfo_generic_mount_info),
+	FSINFO_VSTRUCT	(FSINFO_ATTR_MOUNT_TOPOLOGY,	fsinfo_generic_mount_topology),
 	FSINFO_STRING	(FSINFO_ATTR_MOUNT_PATH,	fsinfo_generic_seq_read),
 	FSINFO_STRING	(FSINFO_ATTR_MOUNT_POINT,	fsinfo_generic_mount_point),
 	FSINFO_STRING	(FSINFO_ATTR_MOUNT_POINT_FULL,	fsinfo_generic_mount_point_full),
+	FSINFO_LIST	(FSINFO_ATTR_MOUNT_CHILDREN,	fsinfo_generic_mount_children),
 	{}
 };
 
diff --git a/fs/internal.h b/fs/internal.h
index 68e300a1e9a3..6a30320ea2f8 100644
--- a/fs/internal.h
+++ b/fs/internal.h
@@ -100,8 +100,10 @@ extern void dissolve_on_fput(struct vfsmount *);
 extern int lookup_mount_object(struct path *, int, struct path *);
 extern int fsinfo_generic_mount_source(struct path *, struct fsinfo_context *);
 extern int fsinfo_generic_mount_info(struct path *, struct fsinfo_context *);
+extern int fsinfo_generic_mount_topology(struct path *, struct fsinfo_context *);
 extern int fsinfo_generic_mount_point(struct path *, struct fsinfo_context *);
 extern int fsinfo_generic_mount_point_full(struct path *, struct fsinfo_context *);
+extern int fsinfo_generic_mount_children(struct path *, struct fsinfo_context *);
 
 /*
  * fs_struct.c
diff --git a/fs/namespace.c b/fs/namespace.c
index 483fbbde5c28..61b110149fc5 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -4187,6 +4187,53 @@ int fsinfo_generic_mount_info(struct path *path, struct fsinfo_context *ctx)
 	return sizeof(*p);
 }
 
+/*
+ * Retrieve information about the topology at the nominated mount and
+ * its propogation attributes.
+ */
+int fsinfo_generic_mount_topology(struct path *path, struct fsinfo_context *ctx)
+{
+	struct fsinfo_mount_topology *p = ctx->buffer;
+	struct mount *m;
+	struct path root;
+
+	get_fs_root(current->fs, &root);
+
+	namespace_lock();
+
+	m = real_mount(path->mnt);
+
+	p->parent_id = m->mnt_parent->mnt_id;
+
+	if (path->mnt == root.mnt) {
+		p->parent_id = m->mnt_id;
+	} else {
+		rcu_read_lock();
+		if (!are_paths_connected(&root, path))
+			p->parent_id = m->mnt_id;
+		rcu_read_unlock();
+	}
+
+	if (IS_MNT_SHARED(m)) {
+		p->group_id = m->mnt_group_id;
+		p->propagation |= MOUNT_PROPAGATION_SHARED;
+	}
+	if (IS_MNT_SLAVE(m)) {
+		int master = m->mnt_master->mnt_group_id;
+		int dom = get_dominating_id(m, &root);
+		p->master_id = master;
+		if (dom && dom != master)
+			p->from_id = dom;
+		p->propagation |= MOUNT_PROPAGATION_SLAVE;
+	}
+	if (IS_MNT_UNBINDABLE(m))
+		p->propagation |= MOUNT_PROPAGATION_UNBINDABLE;
+
+	namespace_unlock();
+	path_put(&root);
+	return sizeof(*p);
+}
+
 /*
  * Return the path of this mount relative to its parent and clipped to
  * the current chroot.
@@ -4260,4 +4307,48 @@ int fsinfo_generic_mount_point_full(struct path *path, struct fsinfo_context *ct
 	return (ctx->buffer + ctx->buf_size) - p;
 }
 
+/*
+ * Store a mount record into the fsinfo buffer.
+ */
+static void fsinfo_store_mount(struct fsinfo_context *ctx, const struct mount *p)
+{
+	struct fsinfo_mount_child record = {};
+	unsigned int usage = ctx->usage;
+
+	if (ctx->usage >= INT_MAX)
+		return;
+	ctx->usage = usage + sizeof(record);
+
+	if (ctx->buffer && ctx->usage <= ctx->buf_size) {
+		record.mnt_unique_id	= p->mnt_unique_id;
+		record.mnt_id		= p->mnt_id;
+		memcpy(ctx->buffer + usage, &record, sizeof(record));
+	}
+}
+
+/*
+ * Return information about the submounts relative to path.
+ */
+int fsinfo_generic_mount_children(struct path *path, struct fsinfo_context *ctx)
+{
+	struct mount *m, *child;
+
+	m = real_mount(path->mnt);
+
+	read_seqlock_excl(&mount_lock);
+
+	list_for_each_entry_rcu(child, &m->mnt_mounts, mnt_child) {
+		if (child->mnt_parent != m)
+			continue;
+		fsinfo_store_mount(ctx, child);
+	}
+
+	/* End the list with a copy of the parameter mount's details so that
+	 * userspace can quickly check for changes.
+	 */
+	fsinfo_store_mount(ctx, m);
+	read_sequnlock_excl(&mount_lock);
+	return ctx->usage;
+}
+
 #endif /* CONFIG_FSINFO */
diff --git a/include/uapi/linux/fsinfo.h b/include/uapi/linux/fsinfo.h
index df96301dc612..9410e320d824 100644
--- a/include/uapi/linux/fsinfo.h
+++ b/include/uapi/linux/fsinfo.h
@@ -35,6 +35,8 @@
 #define FSINFO_ATTR_MOUNT_PATH		0x201	/* Bind mount/superblock path (string) */
 #define FSINFO_ATTR_MOUNT_POINT		0x202	/* Relative path of mount in parent (string) */
 #define FSINFO_ATTR_MOUNT_POINT_FULL	0x203	/* Absolute path of mount (string) */
+#define FSINFO_ATTR_MOUNT_TOPOLOGY	0x204	/* Mount object topology */
+#define FSINFO_ATTR_MOUNT_CHILDREN	0x205	/* Children of this mount (list) */
 
 /*
  * Optional fsinfo() parameter structure.
@@ -102,6 +104,31 @@ struct fsinfo_mount_info {
 
 #define FSINFO_ATTR_MOUNT_INFO__STRUCT struct fsinfo_mount_info
 
+/*
+ * Information struct for fsinfo(FSINFO_ATTR_MOUNT_TOPOLOGY).
+ */
+struct fsinfo_mount_topology {
+	__u32	parent_id;		/* Parent mount identifier */
+	__u32	group_id;		/* Mount group ID */
+	__u32	master_id;		/* Slave master group ID */
+	__u32	from_id;		/* Slave propagated from ID */
+	__u32	propagation;		/* MOUNT_PROPAGATION_* flags */
+};
+
+#define FSINFO_ATTR_MOUNT_TOPOLOGY__STRUCT struct fsinfo_mount_topology
+
+/*
+ * Information struct element for fsinfo(FSINFO_ATTR_MOUNT_CHILDREN).
+ * - An extra element is placed on the end representing the parent mount.
+ */
+struct fsinfo_mount_child {
+	__u64	mnt_unique_id;		/* Kernel-lifetime unique mount ID */
+	__u32	mnt_id;			/* Mount identifier (use with AT_FSINFO_MOUNTID_PATH) */
+	__u32	__padding[1];
+};
+
+#define FSINFO_ATTR_MOUNT_CHILDREN__STRUCT struct fsinfo_mount_child
+
 /*
  * Information struct for fsinfo(FSINFO_ATTR_STATFS).
  * - This gives extended filesystem information.
diff --git a/include/uapi/linux/mount.h b/include/uapi/linux/mount.h
index 96a0240f23fe..c18b21de3fdd 100644
--- a/include/uapi/linux/mount.h
+++ b/include/uapi/linux/mount.h
@@ -105,7 +105,7 @@ enum fsconfig_command {
 #define FSMOUNT_CLOEXEC		0x00000001
 
 /*
- * Mount attributes.
+ * Mount object attributes (these are separate to filesystem attributes).
  */
 #define MOUNT_ATTR_RDONLY	0x00000001 /* Mount read-only */
 #define MOUNT_ATTR_NOSUID	0x00000002 /* Ignore suid and sgid bits */
@@ -117,4 +117,12 @@ enum fsconfig_command {
 #define MOUNT_ATTR_STRICTATIME	0x00000020 /* - Always perform atime updates */
 #define MOUNT_ATTR_NODIRATIME	0x00000080 /* Do not update directory access times */
 
+/*
+ * Mount object propagation attributes.
+ */
+#define MOUNT_PROPAGATION_UNBINDABLE	0x00000001 /* Mount is unbindable */
+#define MOUNT_PROPAGATION_SLAVE		0x00000002 /* Mount is slave */
+#define MOUNT_PROPAGATION_PRIVATE	0x00000000 /* Mount is private (ie. not shared) */
+#define MOUNT_PROPAGATION_SHARED	0x00000004 /* Mount is shared */
+
 #endif /* _UAPI_LINUX_MOUNT_H */
diff --git a/samples/vfs/test-fsinfo.c b/samples/vfs/test-fsinfo.c
index b23d0d56988f..762ab4517cd9 100644
--- a/samples/vfs/test-fsinfo.c
+++ b/samples/vfs/test-fsinfo.c
@@ -299,6 +299,42 @@ static void dump_fsinfo_generic_mount_info(void *reply, unsigned int size)
 	printf("\tattr    : %x\n", r->attr);
 }
 
+static void dump_fsinfo_generic_mount_topology(void *reply, unsigned int size)
+{
+	struct fsinfo_mount_topology *r = reply;
+
+	printf("\n");
+	printf("\tparent  : %x\n", r->parent_id);
+	printf("\tgroup   : %x\n", r->group_id);
+	printf("\tmaster  : %x\n", r->master_id);
+	printf("\tfrom    : %x\n", r->from_id);
+	printf("\tpropag  : %x\n", r->propagation);
+}
+
+static void dump_fsinfo_generic_mount_children(void *reply, unsigned int size)
+{
+	struct fsinfo_mount_child *r = reply;
+	ssize_t mplen;
+	char path[32], *mp;
+
+	struct fsinfo_params params = {
+		.flags		= FSINFO_FLAGS_QUERY_MOUNT,
+		.request	= FSINFO_ATTR_MOUNT_POINT,
+	};
+
+	if (!list_last) {
+		sprintf(path, "%u", r->mnt_id);
+		mplen = get_fsinfo(path, "FSINFO_ATTR_MOUNT_POINT", &params, (void **)&mp);
+		if (mplen < 0)
+			mp = "-";
+	} else {
+		mp = "<this>";
+	}
+
+	printf("%8x %16llx %s\n",
+	       r->mnt_id, (unsigned long long)r->mnt_unique_id, mp);
+}
+
 static void dump_string(void *reply, unsigned int size)
 {
 	char *s = reply, *p;
@@ -377,9 +413,11 @@ static const struct fsinfo_attribute fsinfo_attributes[] = {
 	FSINFO_LIST	(FSINFO_ATTR_FSINFO_ATTRIBUTES,	fsinfo_meta_attributes),
 
 	FSINFO_VSTRUCT	(FSINFO_ATTR_MOUNT_INFO,	fsinfo_generic_mount_info),
+	FSINFO_VSTRUCT	(FSINFO_ATTR_MOUNT_TOPOLOGY,	fsinfo_generic_mount_topology),
 	FSINFO_STRING	(FSINFO_ATTR_MOUNT_PATH,	string),
 	FSINFO_STRING_N	(FSINFO_ATTR_MOUNT_POINT,	string),
 	FSINFO_STRING_N	(FSINFO_ATTR_MOUNT_POINT_FULL,	string),
+	FSINFO_LIST	(FSINFO_ATTR_MOUNT_CHILDREN,	fsinfo_generic_mount_children),
 	{}
 };
 



  parent reply	other threads:[~2020-03-18 15:09 UTC|newest]

Thread overview: 25+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-18 15:08 [PATCH 00/13] VFS: Filesystem information [ver #19] David Howells
2020-03-18 15:08 ` [PATCH 01/13] fsinfo: Add fsinfo() syscall to query filesystem " David Howells
2020-03-18 15:08 ` [PATCH 02/13] fsinfo: Provide a bitmap of supported features " David Howells
2020-03-18 15:08 ` [PATCH 03/13] fsinfo: Allow retrieval of superblock devname, options and stats " David Howells
2020-03-18 15:08 ` [PATCH 04/13] fsinfo: Allow fsinfo() to look up a mount object by ID " David Howells
2020-03-18 15:08 ` [PATCH 05/13] fsinfo: Add a uniquifier ID to struct mount " David Howells
2020-03-18 15:09 ` [PATCH 06/13] fsinfo: Allow mount information to be queried " David Howells
2020-03-18 15:09 ` David Howells [this message]
2020-03-18 15:09 ` [PATCH 08/13] fsinfo: Provide notification overrun handling support " David Howells
2020-03-18 15:09 ` [PATCH 09/13] fsinfo: sample: Mount listing program " David Howells
2020-03-18 15:09 ` [PATCH 10/13] fsinfo: Add API documentation " David Howells
2020-03-18 15:09 ` [PATCH 11/13] fsinfo: Add support for AFS " David Howells
2020-03-18 15:09 ` [PATCH 12/13] fsinfo: Example support for Ext4 " David Howells
2020-03-18 15:10 ` [PATCH 13/13] fsinfo: Example support for NFS " David Howells
2020-03-18 16:05 ` [PATCH 00/13] VFS: Filesystem information " Miklos Szeredi
2020-04-01  5:22   ` Ian Kent
2020-04-01  8:18     ` Miklos Szeredi
2020-04-01  8:27     ` David Howells
2020-04-01  8:37       ` Miklos Szeredi
2020-04-01 12:35         ` Miklos Szeredi
2020-04-01 15:51         ` David Howells
2020-04-02  1:38         ` Ian Kent
2020-04-02 14:14           ` Karel Zak
2020-03-19 10:37 ` David Howells
2020-03-19 12:36   ` Miklos Szeredi

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=158454415081.2864823.16161601504717586678.stgit@warthog.procyon.org.uk \
    --to=dhowells@redhat.com \
    --cc=christian@brauner.io \
    --cc=darrick.wong@oracle.com \
    --cc=jannh@google.com \
    --cc=jlayton@redhat.com \
    --cc=kzak@redhat.com \
    --cc=linux-api@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=mszeredi@redhat.com \
    --cc=raven@themaw.net \
    --cc=torvalds@linux-foundation.org \
    --cc=viro@zeniv.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).