diff mbox series

[2/3] fs: cache first and last mount

Message ID 20241215-vfs-6-14-mount-work-v1-2-fd55922c4af8@kernel.org (mailing list archive)
State New
Headers show
Series fs: tweak mntns iteration | expand

Commit Message

Christian Brauner Dec. 15, 2024, 8:17 p.m. UTC
Speed up listmount() by caching the first and last node making retrieval
of the first and last mount of each mount namespace O(1).

Signed-off-by: Christian Brauner <brauner@kernel.org>
---
 fs/mount.h     | 13 +++++++++++--
 fs/namespace.c | 17 +++++++++++++----
 2 files changed, 24 insertions(+), 6 deletions(-)
diff mbox series

Patch

diff --git a/fs/mount.h b/fs/mount.h
index e9f48e563c0fe9c4af77369423db2cc8695fa808..ffb613cdfeee97b99fe9419e8152c166e0a9ac83 100644
--- a/fs/mount.h
+++ b/fs/mount.h
@@ -8,7 +8,11 @@ 
 struct mnt_namespace {
 	struct ns_common	ns;
 	struct mount *	root;
-	struct rb_root		mounts; /* Protected by namespace_sem */
+	struct {
+		struct rb_root	mounts;		 /* Protected by namespace_sem */
+		struct rb_node	*mnt_last_node;	 /* last (rightmost) mount in the rbtree */
+		struct rb_node	*mnt_first_node; /* first (leftmost) mount in the rbtree */
+	};
 	struct user_namespace	*user_ns;
 	struct ucounts		*ucounts;
 	u64			seq;	/* Sequence number to prevent loops */
@@ -154,8 +158,13 @@  static inline bool mnt_ns_attached(const struct mount *mnt)
 
 static inline void move_from_ns(struct mount *mnt, struct list_head *dt_list)
 {
+	struct mnt_namespace *ns = mnt->mnt_ns;
 	WARN_ON(!mnt_ns_attached(mnt));
-	rb_erase(&mnt->mnt_node, &mnt->mnt_ns->mounts);
+	if (ns->mnt_last_node == &mnt->mnt_node)
+		ns->mnt_last_node = rb_prev(&mnt->mnt_node);
+	if (ns->mnt_first_node == &mnt->mnt_node)
+		ns->mnt_first_node = rb_next(&mnt->mnt_node);
+	rb_erase(&mnt->mnt_node, &ns->mounts);
 	RB_CLEAR_NODE(&mnt->mnt_node);
 	list_add_tail(&mnt->mnt_list, dt_list);
 }
diff --git a/fs/namespace.c b/fs/namespace.c
index d67df0fce4dcd1ee5ddf9ff5fbe005bcdcd626f1..d99a3c2c5e5c8a2e2d4e762ebda1226b882cd7f1 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1158,16 +1158,25 @@  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;
+	bool mnt_first_node = true, mnt_last_node = true;
 
 	WARN_ON(mnt_ns_attached(mnt));
 	mnt->mnt_ns = ns;
 	while (*link) {
 		parent = *link;
-		if (mnt->mnt_id_unique < node_to_mount(parent)->mnt_id_unique)
+		if (mnt->mnt_id_unique < node_to_mount(parent)->mnt_id_unique) {
 			link = &parent->rb_left;
-		else
+			mnt_last_node = false;
+		} else {
 			link = &parent->rb_right;
+			mnt_first_node = false;
+		}
 	}
+
+	if (mnt_last_node)
+		ns->mnt_last_node = &mnt->mnt_node;
+	if (mnt_first_node)
+		ns->mnt_first_node = &mnt->mnt_node;
 	rb_link_node(&mnt->mnt_node, parent, link);
 	rb_insert_color(&mnt->mnt_node, &ns->mounts);
 }
@@ -5562,9 +5571,9 @@  static ssize_t do_listmount(struct mnt_namespace *ns, u64 mnt_parent_id,
 
 	if (!last_mnt_id) {
 		if (reverse)
-			first = node_to_mount(rb_last(&ns->mounts));
+			first = node_to_mount(ns->mnt_last_node);
 		else
-			first = node_to_mount(rb_first(&ns->mounts));
+			first = node_to_mount(ns->mnt_first_node);
 	} else {
 		if (reverse)
 			first = mnt_find_id_at_reverse(ns, last_mnt_id - 1);