diff mbox series

[4/4] listmount: allow listing in reverse order

Message ID 20240607-vfs-listmount-reverse-v1-4-7877a2bfa5e5@kernel.org (mailing list archive)
State New
Headers show
Series fs: allow listmount() with reversed ordering | expand

Commit Message

Christian Brauner June 7, 2024, 2:55 p.m. UTC
util-linux is about to implement listmount() and statmount() support.
Karel requested the ability to scan the mount table in backwards order
because that's what libmount currently does in order to get the latest
mount first. We currently don't support this in listmount(). Add a new
LISTMOUNT_RESERVE flag to allow listing mounts in reverse order. For
example, listing all child mounts of /sys without LISTMOUNT_REVERSE
gives:

    /sys/kernel/security @ mnt_id: 4294968369
    /sys/fs/cgroup @ mnt_id: 4294968370
    /sys/firmware/efi/efivars @ mnt_id: 4294968371
    /sys/fs/bpf @ mnt_id: 4294968372
    /sys/kernel/tracing @ mnt_id: 4294968373
    /sys/kernel/debug @ mnt_id: 4294968374
    /sys/fs/fuse/connections @ mnt_id: 4294968375
    /sys/kernel/config @ mnt_id: 4294968376

whereas with LISTMOUNT_RESERVE it gives:

    /sys/kernel/config @ mnt_id: 4294968376
    /sys/fs/fuse/connections @ mnt_id: 4294968375
    /sys/kernel/debug @ mnt_id: 4294968374
    /sys/kernel/tracing @ mnt_id: 4294968373
    /sys/fs/bpf @ mnt_id: 4294968372
    /sys/firmware/efi/efivars @ mnt_id: 4294968371
    /sys/fs/cgroup @ mnt_id: 4294968370
    /sys/kernel/security @ mnt_id: 4294968369

Signed-off-by: Christian Brauner <brauner@kernel.org>
---
 fs/namespace.c             | 62 ++++++++++++++++++++++++++++++++++++++--------
 include/uapi/linux/mount.h |  1 +
 2 files changed, 53 insertions(+), 10 deletions(-)

Comments

Matthew Wilcox June 12, 2024, 1:54 p.m. UTC | #1
On Fri, Jun 07, 2024 at 04:55:37PM +0200, Christian Brauner wrote:
> util-linux is about to implement listmount() and statmount() support.
> Karel requested the ability to scan the mount table in backwards order
> because that's what libmount currently does in order to get the latest
> mount first. We currently don't support this in listmount(). Add a new
> LISTMOUNT_RESERVE flag to allow listing mounts in reverse order. For

s/RESERVE/REVERSE/g

> whereas with LISTMOUNT_RESERVE it gives:
Christian Brauner June 13, 2024, 11:41 a.m. UTC | #2
On Wed, Jun 12, 2024 at 02:54:55PM GMT, Matthew Wilcox wrote:
> On Fri, Jun 07, 2024 at 04:55:37PM +0200, Christian Brauner wrote:
> > util-linux is about to implement listmount() and statmount() support.
> > Karel requested the ability to scan the mount table in backwards order
> > because that's what libmount currently does in order to get the latest
> > mount first. We currently don't support this in listmount(). Add a new
> > LISTMOUNT_RESERVE flag to allow listing mounts in reverse order. For
> 
> s/RESERVE/REVERSE/g

Thanks! Fixed!
diff mbox series

Patch

diff --git a/fs/namespace.c b/fs/namespace.c
index 507f310dbf33..911c149c7979 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1448,6 +1448,30 @@  static struct mount *mnt_find_id_at(struct mnt_namespace *ns, u64 mnt_id)
 	return ret;
 }
 
+/*
+ * Returns the mount which either has the specified mnt_id, or has the next
+ * greater id before the specified one.
+ */
+static struct mount *mnt_find_id_at_reverse(struct mnt_namespace *ns, u64 mnt_id)
+{
+	struct rb_node *node = ns->mounts.rb_node;
+	struct mount *ret = NULL;
+
+	while (node) {
+		struct mount *m = node_to_mount(node);
+
+		if (mnt_id >= m->mnt_id_unique) {
+			ret = node_to_mount(node);
+			if (mnt_id == m->mnt_id_unique)
+				break;
+			node = node->rb_right;
+		} else {
+			node = node->rb_left;
+		}
+	}
+	return ret;
+}
+
 #ifdef CONFIG_PROC_FS
 
 /* iterator; we want it to have access to namespace_sem, thus here... */
@@ -5042,14 +5066,22 @@  SYSCALL_DEFINE4(statmount, const struct mnt_id_req __user *, req,
 	return ret;
 }
 
-static struct mount *listmnt_next(struct mount *curr)
+static struct mount *listmnt_next(struct mount *curr, bool reverse)
 {
-	return node_to_mount(rb_next(&curr->mnt_node));
+	struct rb_node *node;
+
+	if (reverse)
+		node = rb_prev(&curr->mnt_node);
+	else
+		node = rb_next(&curr->mnt_node);
+
+	return node_to_mount(node);
 }
 
 static ssize_t do_listmount(struct mount *first, struct path *orig,
 			    u64 mnt_parent_id, u64 __user *mnt_ids,
-			    size_t nr_mnt_ids, const struct path *root)
+			    size_t nr_mnt_ids, const struct path *root,
+			    bool reverse)
 {
 	struct mount *r;
 	ssize_t ret;
@@ -5066,7 +5098,7 @@  static ssize_t do_listmount(struct mount *first, struct path *orig,
 	if (ret)
 		return ret;
 
-	for (ret = 0, r = first; r && nr_mnt_ids; r = listmnt_next(r)) {
+	for (ret = 0, r = first; r && nr_mnt_ids; r = listmnt_next(r, reverse)) {
 		if (r->mnt_id_unique == mnt_parent_id)
 			continue;
 		if (!is_path_reachable(r, r->mnt.mnt_root, orig))
@@ -5090,9 +5122,10 @@  SYSCALL_DEFINE4(listmount, const struct mnt_id_req __user *, req, u64 __user *,
 	struct path orig;
 	u64 mnt_parent_id, last_mnt_id;
 	const size_t maxcount = (size_t)-1 >> 3;
+	bool reverse_order;
 	ssize_t ret;
 
-	if (flags)
+	if (flags & ~LISTMOUNT_REVERSE)
 		return -EINVAL;
 
 	if (unlikely(nr_mnt_ids > maxcount))
@@ -5118,12 +5151,21 @@  SYSCALL_DEFINE4(listmount, const struct mnt_id_req __user *, req, u64 __user *,
 			return -ENOENT;
 		orig.dentry = orig.mnt->mnt_root;
 	}
-	if (!last_mnt_id)
-		first = node_to_mount(rb_first(&ns->mounts));
-	else
-		first = mnt_find_id_at(ns, last_mnt_id + 1);
+	reverse_order = flags & LISTMOUNT_REVERSE;
+	if (!last_mnt_id) {
+		if (reverse_order)
+			first = node_to_mount(rb_last(&ns->mounts));
+		else
+			first = node_to_mount(rb_first(&ns->mounts));
+	} else {
+		if (reverse_order)
+			first = mnt_find_id_at_reverse(ns, last_mnt_id - 1);
+		else
+			first = mnt_find_id_at(ns, last_mnt_id + 1);
+	}
 
-	return do_listmount(first, &orig, mnt_parent_id, mnt_ids, nr_mnt_ids, &root);
+	return do_listmount(first, &orig, mnt_parent_id, mnt_ids, nr_mnt_ids,
+			    &root, reverse_order);
 }
 
 
diff --git a/include/uapi/linux/mount.h b/include/uapi/linux/mount.h
index ad5478dbad00..88d78de1519f 100644
--- a/include/uapi/linux/mount.h
+++ b/include/uapi/linux/mount.h
@@ -207,5 +207,6 @@  struct mnt_id_req {
  * Special @mnt_id values that can be passed to listmount
  */
 #define LSMT_ROOT		0xffffffffffffffff	/* root mount */
+#define LISTMOUNT_REVERSE	(1 << 0) /* List later mounts first */
 
 #endif /* _UAPI_LINUX_MOUNT_H */