Skip to content

Commit

Permalink
fs: cache first and last mount
Browse files Browse the repository at this point in the history
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/[email protected]
Signed-off-by: Christian Brauner <[email protected]>
  • Loading branch information
brauner committed Jan 9, 2025
1 parent c7bb042 commit 2ce2328
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 6 deletions.
13 changes: 11 additions & 2 deletions fs/mount.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand Down Expand Up @@ -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);
}
Expand Down
17 changes: 13 additions & 4 deletions fs/namespace.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 2ce2328

Please sign in to comment.