Skip to content

Commit 100ceb4

Browse files
committed
Merge tag 'vfs-6.14-rc1.mount.v2' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs mount updates from Christian Brauner: - Add a mountinfo program to demonstrate statmount()/listmount() Add a new "mountinfo" sample userland program that demonstrates how to use statmount() and listmount() to get at the same info that /proc/pid/mountinfo provides - Remove pointless nospec.h include - Prepend statmount.mnt_opts string with security_sb_mnt_opts() Currently these mount options aren't accessible via statmount() - Add new mount namespaces to mount namespace rbtree outside of the namespace semaphore - Lockless mount namespace lookup Currently we take the read lock when looking for a mount namespace to list mounts in. We can make this lockless. The simple search case can just use a sequence counter to detect concurrent changes to the rbtree For walking the list of mount namespaces sequentially via nsfs we keep a separate rcu list as rb_prev() and rb_next() aren't usable safely with rcu. Currently there is no primitive for retrieving the previous list member. To do this we need a new deletion primitive that doesn't poison the prev pointer and a corresponding retrieval helper Since creating mount namespaces is a relatively rare event compared with querying mounts in a foreign mount namespace this is worth it. Once libmount and systemd pick up this mechanism to list mounts in foreign mount namespaces this will be used very frequently - Add extended selftests for lockless mount namespace iteration - Add a sample program to list all mounts on the system, i.e., in all mount namespaces - Improve mount namespace iteration performance 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 - Use an xarray for the old mount id While the ida does use the xarray internally we can use it explicitly which allows us to increment the unique mount id under the xa lock. This allows us to remove the atomic as we're now allocating both ids in one go - Use a shared header for vfs sample programs - Fix build warnings for new sample program to list all mounts * tag 'vfs-6.14-rc1.mount.v2' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: samples/vfs: fix build warnings samples/vfs: use shared header samples/vfs/mountinfo: Use __u64 instead of uint64_t fs: remove useless lockdep assertion fs: use xarray for old mount id selftests: add listmount() iteration tests fs: cache first and last mount samples: add test-list-all-mounts selftests: remove unneeded include selftests: add tests for mntns iteration seltests: move nsfs into filesystems subfolder fs: simplify rwlock to spinlock fs: lockless mntns lookup for nsfs rculist: add list_bidir_{del,prev}_rcu() fs: lockless mntns rbtree lookup fs: add mount namespace to rbtree late fs: prepend statmount.mnt_opts string with security_sb_mnt_opts() mount: remove inlude/nospec.h include samples: add a mountinfo program to demonstrate statmount()/listmount()
2 parents 1a89a69 + 68e6b7d commit 100ceb4

File tree

18 files changed

+1075
-97
lines changed

18 files changed

+1075
-97
lines changed

fs/mount.h

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,23 @@
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 */
15-
wait_queue_head_t poll;
19+
union {
20+
wait_queue_head_t poll;
21+
struct rcu_head mnt_ns_rcu;
22+
};
1623
u64 event;
1724
unsigned int nr_mounts; /* # of mounts in the namespace */
1825
unsigned int pending_mounts;
1926
struct rb_node mnt_ns_tree_node; /* node in the mnt_ns_tree */
27+
struct list_head mnt_ns_list; /* entry in the sequential list of mounts namespace */
2028
refcount_t passive; /* number references not pinning @mounts */
2129
} __randomize_layout;
2230

@@ -150,22 +158,21 @@ static inline bool mnt_ns_attached(const struct mount *mnt)
150158

151159
static inline void move_from_ns(struct mount *mnt, struct list_head *dt_list)
152160
{
161+
struct mnt_namespace *ns = mnt->mnt_ns;
153162
WARN_ON(!mnt_ns_attached(mnt));
154-
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);
155168
RB_CLEAR_NODE(&mnt->mnt_node);
156169
list_add_tail(&mnt->mnt_list, dt_list);
157170
}
158171

159172
bool has_locked_children(struct mount *mnt, struct dentry *dentry);
160-
struct mnt_namespace *__lookup_next_mnt_ns(struct mnt_namespace *mnt_ns, bool previous);
161-
static inline struct mnt_namespace *lookup_next_mnt_ns(struct mnt_namespace *mntns)
162-
{
163-
return __lookup_next_mnt_ns(mntns, false);
164-
}
165-
static inline struct mnt_namespace *lookup_prev_mnt_ns(struct mnt_namespace *mntns)
166-
{
167-
return __lookup_next_mnt_ns(mntns, true);
168-
}
173+
struct mnt_namespace *get_sequential_mnt_ns(struct mnt_namespace *mnt_ns,
174+
bool previous);
175+
169176
static inline struct mnt_namespace *to_mnt_ns(struct ns_common *ns)
170177
{
171178
return container_of(ns, struct mnt_namespace, ns);

0 commit comments

Comments
 (0)