Unverified Commit bd320736 authored by Christian Brauner's avatar Christian Brauner
Browse files

Merge patch series "fs: listmount()/statmount() fix and sample program"

Jeff Layton <jlayton@kernel.org> says:

We had some recent queries internally asking how to use the new
statmount() and listmount() interfaces. I was doing some other work in
this area, so I whipped up this tool.

My hope is that this will represent something of a "rosetta stone" for
how to translate between mountinfo and statmount(), and an example for
other people looking to use the new interfaces.

It may also be possible to use this as the basis for a listmount() and
statmount() testcase. We can call this program, and compare its output
to the mountinfo file.

The second patch adds security mount options to the existing mnt_opts in
the statmount() interface, which I think is the final missing piece
here. The alternative to doing that would be to add a new string field
for that, but I'm not sure that's worthwhile.

* patches from https://lore.kernel.org/r/20241115-statmount-v2-0-cd29aeff9cbb@kernel.org:
  fs: prepend statmount.mnt_opts string with security_sb_mnt_opts()
  samples: add a mountinfo program to demonstrate statmount()/listmount()

Link: https://lore.kernel.org/r/20241115-statmount-v2-0-cd29aeff9cbb@kernel.org


Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parents 40384c84 056d3313
Loading
Loading
Loading
Loading
+9 −6
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ struct mount {
	struct dentry *mnt_mountpoint;
	struct vfsmount mnt;
	union {
		struct rb_node mnt_node; /* node in the ns->mounts rbtree */
		struct rcu_head mnt_rcu;
		struct llist_node mnt_llist;
	};
@@ -51,10 +52,7 @@ struct mount {
	struct list_head mnt_child;	/* and going through their mnt_child */
	struct list_head mnt_instance;	/* mount instance on sb->s_mounts */
	const char *mnt_devname;	/* Name of device e.g. /dev/dsk/hda1 */
	union {
		struct rb_node mnt_node;	/* Under ns->mounts */
	struct list_head mnt_list;
	};
	struct list_head mnt_expire;	/* link in fs-specific expiry list */
	struct list_head mnt_share;	/* circular list of shared mounts */
	struct list_head mnt_slave_list;/* list of slave mounts */
@@ -145,11 +143,16 @@ static inline bool is_anon_ns(struct mnt_namespace *ns)
	return ns->seq == 0;
}

static inline bool mnt_ns_attached(const struct mount *mnt)
{
	return !RB_EMPTY_NODE(&mnt->mnt_node);
}

static inline void move_from_ns(struct mount *mnt, struct list_head *dt_list)
{
	WARN_ON(!(mnt->mnt.mnt_flags & MNT_ONRB));
	mnt->mnt.mnt_flags &= ~MNT_ONRB;
	WARN_ON(!mnt_ns_attached(mnt));
	rb_erase(&mnt->mnt_node, &mnt->mnt_ns->mounts);
	RB_CLEAR_NODE(&mnt->mnt_node);
	list_add_tail(&mnt->mnt_list, dt_list);
}

+10 −8
Original line number Diff line number Diff line
@@ -344,6 +344,7 @@ static struct mount *alloc_vfsmnt(const char *name)
		INIT_HLIST_NODE(&mnt->mnt_mp_list);
		INIT_LIST_HEAD(&mnt->mnt_umounting);
		INIT_HLIST_HEAD(&mnt->mnt_stuck_children);
		RB_CLEAR_NODE(&mnt->mnt_node);
		mnt->mnt.mnt_idmap = &nop_mnt_idmap;
	}
	return mnt;
@@ -1124,7 +1125,7 @@ static void mnt_add_to_ns(struct mnt_namespace *ns, struct mount *mnt)
	struct rb_node **link = &ns->mounts.rb_node;
	struct rb_node *parent = NULL;

	WARN_ON(mnt->mnt.mnt_flags & MNT_ONRB);
	WARN_ON(mnt_ns_attached(mnt));
	mnt->mnt_ns = ns;
	while (*link) {
		parent = *link;
@@ -1135,7 +1136,6 @@ static void mnt_add_to_ns(struct mnt_namespace *ns, struct mount *mnt)
	}
	rb_link_node(&mnt->mnt_node, parent, link);
	rb_insert_color(&mnt->mnt_node, &ns->mounts);
	mnt->mnt.mnt_flags |= MNT_ONRB;
}

/*
@@ -1305,7 +1305,7 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
	}

	mnt->mnt.mnt_flags = old->mnt.mnt_flags;
	mnt->mnt.mnt_flags &= ~(MNT_WRITE_HOLD|MNT_MARKED|MNT_INTERNAL|MNT_ONRB);
	mnt->mnt.mnt_flags &= ~(MNT_WRITE_HOLD|MNT_MARKED|MNT_INTERNAL);

	atomic_inc(&sb->s_active);
	mnt->mnt.mnt_idmap = mnt_idmap_get(mnt_idmap(&old->mnt));
@@ -1763,7 +1763,7 @@ static void umount_tree(struct mount *mnt, enum umount_tree_flags how)
	/* Gather the mounts to umount */
	for (p = mnt; p; p = next_mnt(p, mnt)) {
		p->mnt.mnt_flags |= MNT_UMOUNT;
		if (p->mnt.mnt_flags & MNT_ONRB)
		if (mnt_ns_attached(p))
			move_from_ns(p, &tmp_list);
		else
			list_move(&p->mnt_list, &tmp_list);
@@ -1912,16 +1912,14 @@ static int do_umount(struct mount *mnt, int flags)

	event++;
	if (flags & MNT_DETACH) {
		if (mnt->mnt.mnt_flags & MNT_ONRB ||
		    !list_empty(&mnt->mnt_list))
		if (mnt_ns_attached(mnt) || !list_empty(&mnt->mnt_list))
			umount_tree(mnt, UMOUNT_PROPAGATE);
		retval = 0;
	} else {
		shrink_submounts(mnt);
		retval = -EBUSY;
		if (!propagate_mount_busy(mnt, 2)) {
			if (mnt->mnt.mnt_flags & MNT_ONRB ||
			    !list_empty(&mnt->mnt_list))
			if (mnt_ns_attached(mnt) || !list_empty(&mnt->mnt_list))
				umount_tree(mnt, UMOUNT_PROPAGATE|UMOUNT_SYNC);
			retval = 0;
		}
@@ -5038,6 +5036,10 @@ static int statmount_mnt_opts(struct kstatmount *s, struct seq_file *seq)
	if (sb->s_op->show_options) {
		size_t start = seq->count;

		err = security_sb_show_options(seq, sb);
		if (err)
			return err;

		err = sb->s_op->show_options(seq, mnt->mnt_root);
		if (err)
			return err;
+1 −2
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ struct path;
#define MNT_ATIME_MASK (MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME )

#define MNT_INTERNAL_FLAGS (MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL | \
			    MNT_DOOMED | MNT_SYNC_UMOUNT | MNT_MARKED | MNT_ONRB)
			    MNT_DOOMED | MNT_SYNC_UMOUNT | MNT_MARKED)

#define MNT_INTERNAL	0x4000

@@ -64,7 +64,6 @@ struct path;
#define MNT_SYNC_UMOUNT		0x2000000
#define MNT_MARKED		0x4000000
#define MNT_UMOUNT		0x8000000
#define MNT_ONRB		0x10000000

struct vfsmount {
	struct dentry *mnt_root;	/* root of the mounted tree */
+1 −0
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only
/test-fsmount
/test-statx
/mountinfo
+1 −1
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-only
userprogs-always-y += test-fsmount test-statx
userprogs-always-y += test-fsmount test-statx mountinfo

userccflags += -I usr/include
Loading