]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
fs: cache first and last mount
authorChristian Brauner <brauner@kernel.org>
Sun, 15 Dec 2024 20:17:06 +0000 (21:17 +0100)
committerChristian Brauner <brauner@kernel.org>
Thu, 9 Jan 2025 15:58:54 +0000 (16:58 +0100)
Speed up listmount() by caching the first and last node making retrieval
of the first and last mount of each mount namespace O(1).

Link: https://lore.kernel.org/r/20241215-vfs-6-14-mount-work-v1-2-fd55922c4af8@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
fs/mount.h
fs/namespace.c

index e9f48e563c0fe9c4af77369423db2cc8695fa808..ffb613cdfeee97b99fe9419e8152c166e0a9ac83 100644 (file)
@@ -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);
 }
index a382be402f62486e24bc1c557e0b7238a489ef5d..5336e5f09996562d755c947ac3eb1fcd89920aa7 100644 (file)
@@ -1155,16 +1155,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);
 }
@@ -5563,9 +5572,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);