Unverified Commit 87fc11ae authored by Christian Brauner's avatar Christian Brauner
Browse files

Merge patch series "fs: tweak mntns iteration"

Christian Brauner <brauner@kernel.org> 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/20241215-vfs-6-14-mount-work-v1-0-fd55922c4af8@kernel.org:
  selftests: add listmount() iteration tests
  fs: cache first and last mount
  fs: kill MNT_ONRB

Link: https://lore.kernel.org/r/20241215-vfs-6-14-mount-work-v1-0-fd55922c4af8@kernel.org


Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
parents c7bb0420 3ab8a0b2
Loading
Loading
Loading
Loading
+11 −2
Original line number Diff line number Diff line
@@ -8,7 +8,11 @@
struct mnt_namespace {
	struct ns_common	ns;
	struct mount *	root;
	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 */
@@ -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);
}
+13 −4
Original line number Diff line number Diff line
@@ -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);
}
@@ -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);
+1 −1
Original line number Diff line number Diff line
# SPDX-License-Identifier: GPL-2.0-or-later

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

include ../../lib.mk
+66 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-or-later
// Copyright (c) 2024 Christian Brauner <brauner@kernel.org>

#define _GNU_SOURCE
#include <fcntl.h>
#include <sched.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/mount.h>
#include <unistd.h>

#include "statmount.h"
#include "../../kselftest_harness.h"

#ifndef LISTMOUNT_REVERSE
#define LISTMOUNT_REVERSE    (1 << 0) /* List later mounts first */
#endif

#define LISTMNT_BUFFER 10

/* Check that all mount ids are in increasing order. */
TEST(listmount_forward)
{
	uint64_t list[LISTMNT_BUFFER], last_mnt_id = 0;

	for (;;) {
		ssize_t nr_mounts;

		nr_mounts = listmount(LSMT_ROOT, 0, last_mnt_id,
				      list, LISTMNT_BUFFER, 0);
		ASSERT_GE(nr_mounts, 0);
		if (nr_mounts == 0)
			break;

		for (size_t cur = 0; cur < nr_mounts; cur++) {
			if (cur < nr_mounts - 1)
				ASSERT_LT(list[cur], list[cur + 1]);
			last_mnt_id = list[cur];
		}
	}
}

/* Check that all mount ids are in decreasing order. */
TEST(listmount_backward)
{
	uint64_t list[LISTMNT_BUFFER], last_mnt_id = 0;

	for (;;) {
		ssize_t nr_mounts;

		nr_mounts = listmount(LSMT_ROOT, 0, last_mnt_id,
				      list, LISTMNT_BUFFER, LISTMOUNT_REVERSE);
		ASSERT_GE(nr_mounts, 0);
		if (nr_mounts == 0)
			break;

		for (size_t cur = 0; cur < nr_mounts; cur++) {
			if (cur < nr_mounts - 1)
				ASSERT_GT(list[cur], list[cur + 1]);
			last_mnt_id = list[cur];
		}
	}
}

TEST_HARNESS_MAIN