Skip to content

Commit 87fc11a

Browse files
committed
Merge patch series "fs: tweak mntns iteration"
Christian Brauner <[email protected]> says: Make finding the last or first mount to start iterating the mount namespace from an O(1) operation and add selftests for iterating the mount table starting from the first and last mount. * patches from https://lore.kernel.org/r/[email protected]: selftests: add listmount() iteration tests fs: cache first and last mount fs: kill MNT_ONRB Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Christian Brauner <[email protected]>
2 parents c7bb042 + 3ab8a0b commit 87fc11a

File tree

4 files changed

+91
-7
lines changed

4 files changed

+91
-7
lines changed

fs/mount.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88
struct mnt_namespace {
99
struct ns_common ns;
1010
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+
};
1216
struct user_namespace *user_ns;
1317
struct ucounts *ucounts;
1418
u64 seq; /* Sequence number to prevent loops */
@@ -154,8 +158,13 @@ static inline bool mnt_ns_attached(const struct mount *mnt)
154158

155159
static inline void move_from_ns(struct mount *mnt, struct list_head *dt_list)
156160
{
161+
struct mnt_namespace *ns = mnt->mnt_ns;
157162
WARN_ON(!mnt_ns_attached(mnt));
158-
rb_erase(&mnt->mnt_node, &mnt->mnt_ns->mounts);
163+
if (ns->mnt_last_node == &mnt->mnt_node)
164+
ns->mnt_last_node = rb_prev(&mnt->mnt_node);
165+
if (ns->mnt_first_node == &mnt->mnt_node)
166+
ns->mnt_first_node = rb_next(&mnt->mnt_node);
167+
rb_erase(&mnt->mnt_node, &ns->mounts);
159168
RB_CLEAR_NODE(&mnt->mnt_node);
160169
list_add_tail(&mnt->mnt_list, dt_list);
161170
}

fs/namespace.c

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,16 +1155,25 @@ static void mnt_add_to_ns(struct mnt_namespace *ns, struct mount *mnt)
11551155
{
11561156
struct rb_node **link = &ns->mounts.rb_node;
11571157
struct rb_node *parent = NULL;
1158+
bool mnt_first_node = true, mnt_last_node = true;
11581159

11591160
WARN_ON(mnt_ns_attached(mnt));
11601161
mnt->mnt_ns = ns;
11611162
while (*link) {
11621163
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) {
11641165
link = &parent->rb_left;
1165-
else
1166+
mnt_last_node = false;
1167+
} else {
11661168
link = &parent->rb_right;
1169+
mnt_first_node = false;
1170+
}
11671171
}
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;
11681177
rb_link_node(&mnt->mnt_node, parent, link);
11691178
rb_insert_color(&mnt->mnt_node, &ns->mounts);
11701179
}
@@ -5563,9 +5572,9 @@ static ssize_t do_listmount(struct mnt_namespace *ns, u64 mnt_parent_id,
55635572

55645573
if (!last_mnt_id) {
55655574
if (reverse)
5566-
first = node_to_mount(rb_last(&ns->mounts));
5575+
first = node_to_mount(ns->mnt_last_node);
55675576
else
5568-
first = node_to_mount(rb_first(&ns->mounts));
5577+
first = node_to_mount(ns->mnt_first_node);
55695578
} else {
55705579
if (reverse)
55715580
first = mnt_find_id_at_reverse(ns, last_mnt_id - 1);
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# SPDX-License-Identifier: GPL-2.0-or-later
22

33
CFLAGS += -Wall -O2 -g $(KHDR_INCLUDES)
4-
TEST_GEN_PROGS := statmount_test statmount_test_ns
4+
TEST_GEN_PROGS := statmount_test statmount_test_ns listmount_test
55

66
include ../../lib.mk
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// SPDX-License-Identifier: GPL-2.0-or-later
2+
// Copyright (c) 2024 Christian Brauner <[email protected]>
3+
4+
#define _GNU_SOURCE
5+
#include <fcntl.h>
6+
#include <sched.h>
7+
#include <stdio.h>
8+
#include <string.h>
9+
#include <sys/stat.h>
10+
#include <sys/mount.h>
11+
#include <unistd.h>
12+
13+
#include "statmount.h"
14+
#include "../../kselftest_harness.h"
15+
16+
#ifndef LISTMOUNT_REVERSE
17+
#define LISTMOUNT_REVERSE (1 << 0) /* List later mounts first */
18+
#endif
19+
20+
#define LISTMNT_BUFFER 10
21+
22+
/* Check that all mount ids are in increasing order. */
23+
TEST(listmount_forward)
24+
{
25+
uint64_t list[LISTMNT_BUFFER], last_mnt_id = 0;
26+
27+
for (;;) {
28+
ssize_t nr_mounts;
29+
30+
nr_mounts = listmount(LSMT_ROOT, 0, last_mnt_id,
31+
list, LISTMNT_BUFFER, 0);
32+
ASSERT_GE(nr_mounts, 0);
33+
if (nr_mounts == 0)
34+
break;
35+
36+
for (size_t cur = 0; cur < nr_mounts; cur++) {
37+
if (cur < nr_mounts - 1)
38+
ASSERT_LT(list[cur], list[cur + 1]);
39+
last_mnt_id = list[cur];
40+
}
41+
}
42+
}
43+
44+
/* Check that all mount ids are in decreasing order. */
45+
TEST(listmount_backward)
46+
{
47+
uint64_t list[LISTMNT_BUFFER], last_mnt_id = 0;
48+
49+
for (;;) {
50+
ssize_t nr_mounts;
51+
52+
nr_mounts = listmount(LSMT_ROOT, 0, last_mnt_id,
53+
list, LISTMNT_BUFFER, LISTMOUNT_REVERSE);
54+
ASSERT_GE(nr_mounts, 0);
55+
if (nr_mounts == 0)
56+
break;
57+
58+
for (size_t cur = 0; cur < nr_mounts; cur++) {
59+
if (cur < nr_mounts - 1)
60+
ASSERT_GT(list[cur], list[cur + 1]);
61+
last_mnt_id = list[cur];
62+
}
63+
}
64+
}
65+
66+
TEST_HARNESS_MAIN

0 commit comments

Comments
 (0)