Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

fs: cache first and last mount

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>

+24 -6
+11 -2
fs/mount.h
··· 8 8 struct mnt_namespace { 9 9 struct ns_common ns; 10 10 struct mount * root; 11 - struct rb_root mounts; /* Protected by namespace_sem */ 11 + struct { 12 + struct rb_root mounts; /* Protected by namespace_sem */ 13 + struct rb_node *mnt_last_node; /* last (rightmost) mount in the rbtree */ 14 + struct rb_node *mnt_first_node; /* first (leftmost) mount in the rbtree */ 15 + }; 12 16 struct user_namespace *user_ns; 13 17 struct ucounts *ucounts; 14 18 u64 seq; /* Sequence number to prevent loops */ ··· 158 154 159 155 static inline void move_from_ns(struct mount *mnt, struct list_head *dt_list) 160 156 { 157 + struct mnt_namespace *ns = mnt->mnt_ns; 161 158 WARN_ON(!mnt_ns_attached(mnt)); 162 - rb_erase(&mnt->mnt_node, &mnt->mnt_ns->mounts); 159 + if (ns->mnt_last_node == &mnt->mnt_node) 160 + ns->mnt_last_node = rb_prev(&mnt->mnt_node); 161 + if (ns->mnt_first_node == &mnt->mnt_node) 162 + ns->mnt_first_node = rb_next(&mnt->mnt_node); 163 + rb_erase(&mnt->mnt_node, &ns->mounts); 163 164 RB_CLEAR_NODE(&mnt->mnt_node); 164 165 list_add_tail(&mnt->mnt_list, dt_list); 165 166 }
+13 -4
fs/namespace.c
··· 1155 1155 { 1156 1156 struct rb_node **link = &ns->mounts.rb_node; 1157 1157 struct rb_node *parent = NULL; 1158 + bool mnt_first_node = true, mnt_last_node = true; 1158 1159 1159 1160 WARN_ON(mnt_ns_attached(mnt)); 1160 1161 mnt->mnt_ns = ns; 1161 1162 while (*link) { 1162 1163 parent = *link; 1163 - if (mnt->mnt_id_unique < node_to_mount(parent)->mnt_id_unique) 1164 + if (mnt->mnt_id_unique < node_to_mount(parent)->mnt_id_unique) { 1164 1165 link = &parent->rb_left; 1165 - else 1166 + mnt_last_node = false; 1167 + } else { 1166 1168 link = &parent->rb_right; 1169 + mnt_first_node = false; 1170 + } 1167 1171 } 1172 + 1173 + if (mnt_last_node) 1174 + ns->mnt_last_node = &mnt->mnt_node; 1175 + if (mnt_first_node) 1176 + ns->mnt_first_node = &mnt->mnt_node; 1168 1177 rb_link_node(&mnt->mnt_node, parent, link); 1169 1178 rb_insert_color(&mnt->mnt_node, &ns->mounts); 1170 1179 } ··· 5572 5563 5573 5564 if (!last_mnt_id) { 5574 5565 if (reverse) 5575 - first = node_to_mount(rb_last(&ns->mounts)); 5566 + first = node_to_mount(ns->mnt_last_node); 5576 5567 else 5577 - first = node_to_mount(rb_first(&ns->mounts)); 5568 + first = node_to_mount(ns->mnt_first_node); 5578 5569 } else { 5579 5570 if (reverse) 5580 5571 first = mnt_find_id_at_reverse(ns, last_mnt_id - 1);