Skip to content

Commit 2eea9ce

Browse files
Miklos Szeredibrauner
authored andcommitted
mounts: keep list of mounts in an rbtree
When adding a mount to a namespace insert it into an rbtree rooted in the mnt_namespace instead of a linear list. The mnt.mnt_list is still used to set up the mount tree and for propagation, but not after the mount has been added to a namespace. Hence mnt_list can live in union with rb_node. Use MNT_ONRB mount flag to validate that the mount is on the correct list. This allows removing the cursor used for reading /proc/$PID/mountinfo. The mnt_id_unique of the next mount can be used as an index into the seq file. Tested by inserting 100k bind mounts, unsharing the mount namespace, and unmounting. No performance regressions have been observed. For the last mount in the 100k list the statmount() call was more than 100x faster due to the mount ID lookup not having to do a linear search. This patch makes the overhead of mount ID lookup non-observable in this range. Signed-off-by: Miklos Szeredi <[email protected]> Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Ian Kent <[email protected]> Signed-off-by: Christian Brauner <[email protected]>
1 parent 98d2b43 commit 2eea9ce

File tree

5 files changed

+106
-118
lines changed

5 files changed

+106
-118
lines changed

fs/mount.h

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,13 @@
88
struct mnt_namespace {
99
struct ns_common ns;
1010
struct mount * root;
11-
/*
12-
* Traversal and modification of .list is protected by either
13-
* - taking namespace_sem for write, OR
14-
* - taking namespace_sem for read AND taking .ns_lock.
15-
*/
16-
struct list_head list;
17-
spinlock_t ns_lock;
11+
struct rb_root mounts; /* Protected by namespace_sem */
1812
struct user_namespace *user_ns;
1913
struct ucounts *ucounts;
2014
u64 seq; /* Sequence number to prevent loops */
2115
wait_queue_head_t poll;
2216
u64 event;
23-
unsigned int mounts; /* # of mounts in the namespace */
17+
unsigned int nr_mounts; /* # of mounts in the namespace */
2418
unsigned int pending_mounts;
2519
} __randomize_layout;
2620

@@ -55,7 +49,10 @@ struct mount {
5549
struct list_head mnt_child; /* and going through their mnt_child */
5650
struct list_head mnt_instance; /* mount instance on sb->s_mounts */
5751
const char *mnt_devname; /* Name of device e.g. /dev/dsk/hda1 */
58-
struct list_head mnt_list;
52+
union {
53+
struct rb_node mnt_node; /* Under ns->mounts */
54+
struct list_head mnt_list;
55+
};
5956
struct list_head mnt_expire; /* link in fs-specific expiry list */
6057
struct list_head mnt_share; /* circular list of shared mounts */
6158
struct list_head mnt_slave_list;/* list of slave mounts */
@@ -128,7 +125,6 @@ struct proc_mounts {
128125
struct mnt_namespace *ns;
129126
struct path root;
130127
int (*show)(struct seq_file *, struct vfsmount *);
131-
struct mount cursor;
132128
};
133129

134130
extern const struct seq_operations mounts_op;
@@ -147,4 +143,12 @@ static inline bool is_anon_ns(struct mnt_namespace *ns)
147143
return ns->seq == 0;
148144
}
149145

146+
static inline void move_from_ns(struct mount *mnt, struct list_head *dt_list)
147+
{
148+
WARN_ON(!(mnt->mnt.mnt_flags & MNT_ONRB));
149+
mnt->mnt.mnt_flags &= ~MNT_ONRB;
150+
rb_erase(&mnt->mnt_node, &mnt->mnt_ns->mounts);
151+
list_add_tail(&mnt->mnt_list, dt_list);
152+
}
153+
150154
extern void mnt_cursor_del(struct mnt_namespace *ns, struct mount *cursor);

0 commit comments

Comments
 (0)