* linux-next: manual merge of the vfs-brauner tree with the vfs-fixes tree
@ 2026-02-17 13:39 Mark Brown
0 siblings, 0 replies; 2+ messages in thread
From: Mark Brown @ 2026-02-17 13:39 UTC (permalink / raw)
To: Christian Brauner; +Cc: Linux Kernel Mailing List, Linux Next Mailing List
[-- Attachment #1: Type: text/plain, Size: 7409 bytes --]
Hi all,
Today's linux-next merge of the vfs-brauner tree got a conflict in:
fs/namespace.c
between commits:
2aca1af473d26 ("mount: unmount copied tree")
85d88a3941593 ("mount: hold namespace_sem across copy in create_new_namespace()")
from the vfs-fixes tree and commit:
f4b0ce91e3795 ("mount: unmount copied tree")
from the vfs-brauner tree.
I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging. You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.
The below is a diff -c since a standard diff ended up showing empty
changes, it's the fixes version more or less:
diff --combined fs/namespace.c
index 188be116f6e63,cbb18285a6312..0000000000000
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@@ -2791,8 -2791,7 +2791,8 @@@ static inline void unlock_mount(struct
}
static void lock_mount_exact(const struct path *path,
- struct pinned_mountpoint *mp);
+ struct pinned_mountpoint *mp, bool copy_mount,
+ unsigned int copy_flags);
#define LOCK_MOUNT_MAYBE_BENEATH(mp, path, beneath) \
struct pinned_mountpoint mp __cleanup(unlock_mount) = {}; \
@@@ -2800,10 -2799,7 +2800,10 @@@
#define LOCK_MOUNT(mp, path) LOCK_MOUNT_MAYBE_BENEATH(mp, (path), false)
#define LOCK_MOUNT_EXACT(mp, path) \
struct pinned_mountpoint mp __cleanup(unlock_mount) = {}; \
- lock_mount_exact((path), &mp)
+ lock_mount_exact((path), &mp, false, 0)
+#define LOCK_MOUNT_EXACT_COPY(mp, path, copy_flags) \
+ struct pinned_mountpoint mp __cleanup(unlock_mount) = {}; \
+ lock_mount_exact((path), &mp, true, (copy_flags))
static int graft_tree(struct mount *mnt, const struct pinned_mountpoint *mp)
{
@@@ -3082,7 -3078,7 +3082,7 @@@ static struct mnt_namespace *create_new
struct mnt_namespace *ns = current->nsproxy->mnt_ns;
struct user_namespace *user_ns = current_user_ns();
struct mnt_namespace *new_ns;
- struct mount *new_ns_root;
+ struct mount *new_ns_root, *old_ns_root;
struct path to_path;
struct mount *mnt;
unsigned int copy_flags = 0;
@@@ -3095,36 -3091,52 +3095,36 @@@
if (IS_ERR(new_ns))
return ERR_CAST(new_ns);
- scoped_guard(namespace_excl) {
- new_ns_root = clone_mnt(ns->root, ns->root->mnt.mnt_root, copy_flags);
- if (IS_ERR(new_ns_root)) {
- emptied_ns = new_ns;
- return ERR_CAST(new_ns_root);
- }
+ old_ns_root = ns->root;
+ to_path.mnt = &old_ns_root->mnt;
+ to_path.dentry = old_ns_root->mnt.mnt_root;
- /*
- * If the real rootfs had a locked mount on top of it somewhere
- * in the stack, lock the new mount tree as well so it can't be
- * exposed.
- */
- mnt = ns->root;
- while (mnt->overmount) {
- mnt = mnt->overmount;
- if (mnt->mnt.mnt_flags & MNT_LOCKED)
- locked = true;
- }
- }
+ VFS_WARN_ON_ONCE(old_ns_root->mnt_id_unique != 1);
+ VFS_WARN_ON_ONCE(old_ns_root->mnt.mnt_sb->s_type != &nullfs_fs_type);
- /*
- * We dropped the namespace semaphore so we can actually lock
- * the copy for mounting. The copied mount isn't attached to any
- * mount namespace and it is thus excluded from any propagation.
- * So realistically we're isolated and the mount can't be
- * overmounted.
- */
-
- /* Borrow the reference from clone_mnt(). */
- to_path.mnt = &new_ns_root->mnt;
- to_path.dentry = new_ns_root->mnt.mnt_root;
-
- /* Now lock for actual mounting. */
- LOCK_MOUNT_EXACT(mp, &to_path);
- if (unlikely(IS_ERR(mp.parent))) {
- guard(namespace_excl)();
- emptied_ns = new_ns;
- guard(mount_writer)();
- umount_tree(new_ns_root, 0);
+ LOCK_MOUNT_EXACT_COPY(mp, &to_path, copy_flags);
+ if (IS_ERR(mp.parent)) {
+ free_mnt_ns(new_ns);
return ERR_CAST(mp.parent);
}
+ new_ns_root = mp.parent;
/*
- * We don't emulate unshare()ing a mount namespace. We stick to the
- * restrictions of creating detached bind-mounts. It has a lot
- * saner and simpler semantics.
+ * If the real rootfs had a locked mount on top of it somewhere
+ * in the stack, lock the new mount tree as well so it can't be
+ * exposed.
+ */
+ mnt = old_ns_root;
+ while (mnt->overmount) {
+ mnt = mnt->overmount;
+ if (mnt->mnt.mnt_flags & MNT_LOCKED)
+ locked = true;
+ }
+
+ /*
+ * We don't emulate unshare()ing a mount namespace. We stick
+ * to the restrictions of creating detached bind-mounts. It
+ * has a lot saner and simpler semantics.
*/
mnt = __do_loopback(path, flags, copy_flags);
scoped_guard(mount_writer) {
@@@ -3137,20 -3149,21 +3137,20 @@@
if (locked)
mnt->mnt.mnt_flags |= MNT_LOCKED;
/*
- * Now mount the detached tree on top of the copy of the
- * real rootfs we created.
+ * now mount the detached tree on top of the copy
+ * of the real rootfs we created.
*/
attach_mnt(mnt, new_ns_root, mp.mp);
if (user_ns != ns->user_ns)
lock_mnt_tree(new_ns_root);
}
- /* Add all mounts to the new namespace. */
for (mnt = new_ns_root; mnt; mnt = next_mnt(mnt, new_ns_root)) {
mnt_add_to_ns(new_ns, mnt);
new_ns->nr_mounts++;
}
- new_ns->root = real_mount(to_path.mnt);
+ new_ns->root = new_ns_root;
ns_tree_add_raw(new_ns);
return new_ns;
}
@@@ -3834,20 -3847,16 +3834,20 @@@ static int do_new_mount(const struct pa
}
static void lock_mount_exact(const struct path *path,
- struct pinned_mountpoint *mp)
+ struct pinned_mountpoint *mp, bool copy_mount,
+ unsigned int copy_flags)
{
struct dentry *dentry = path->dentry;
int err;
+ /* Assert that inode_lock() locked the correct inode. */
+ VFS_WARN_ON_ONCE(copy_mount && !path_mounted(path));
+
inode_lock(dentry->d_inode);
namespace_lock();
if (unlikely(cant_mount(dentry)))
err = -ENOENT;
- else if (path_overmounted(path))
+ else if (!copy_mount && path_overmounted(path))
err = -EBUSY;
else
err = get_mountpoint(dentry, mp);
@@@ -3855,15 -3864,9 +3855,15 @@@
namespace_unlock();
inode_unlock(dentry->d_inode);
mp->parent = ERR_PTR(err);
- } else {
- mp->parent = real_mount(path->mnt);
+ return;
}
+
+ if (copy_mount)
+ mp->parent = clone_mnt(real_mount(path->mnt), dentry, copy_flags);
+ else
+ mp->parent = real_mount(path->mnt);
+ if (unlikely(IS_ERR(mp->parent)))
+ __unlock_mount(mp);
}
int finish_automount(struct vfsmount *__m, const struct path *path)
@@@ -5640,14 -5643,14 +5640,14 @@@ static int grab_requested_root(struct m
if (mnt_ns_empty(ns))
return -ENOENT;
- first = child = ns->root;
- for (;;) {
- child = listmnt_next(child, false);
- if (!child)
- return -ENOENT;
- if (child->mnt_parent == first)
+ first = ns->root;
+ for (child = node_to_mount(ns->mnt_first_node); child;
+ child = listmnt_next(child, false)) {
+ if (child != first && child->mnt_parent == first)
break;
}
+ if (!child)
+ return -ENOENT;
root->mnt = mntget(&child->mnt);
root->dentry = dget(root->mnt->mnt_root);
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 2+ messages in thread* linux-next: manual merge of the vfs-brauner tree with the vfs-fixes tree
@ 2024-08-07 0:04 Stephen Rothwell
0 siblings, 0 replies; 2+ messages in thread
From: Stephen Rothwell @ 2024-08-07 0:04 UTC (permalink / raw)
To: Christian Brauner, Al Viro
Cc: Linux Kernel Mailing List, Linux Next Mailing List
[-- Attachment #1: Type: text/plain, Size: 2938 bytes --]
Hi all,
Today's linux-next merge of the vfs-brauner tree got a conflict in:
tools/testing/selftests/core/close_range_test.c
between commit:
9a2fa1472083 ("fix bitmap corruption on close_range() with CLOSE_RANGE_UNSHARE")
from the vfs-fixes tree and commit:
b7fcee976159 ("selftests: add F_CREATED_QUERY tests")
from the vfs-brauner tree.
I fixed it up (see below) and can carry the fix as necessary. This
is now fixed as far as linux-next is concerned, but any non trivial
conflicts should be mentioned to your upstream maintainer when your tree
is submitted for merging. You may also want to consider cooperating
with the maintainer of the conflicting tree to minimise any particularly
complex conflicts.
--
Cheers,
Stephen Rothwell
diff --cc tools/testing/selftests/core/close_range_test.c
index 12b4eb9d0434,3e829666281d..000000000000
--- a/tools/testing/selftests/core/close_range_test.c
+++ b/tools/testing/selftests/core/close_range_test.c
@@@ -589,39 -593,39 +593,74 @@@ TEST(close_range_cloexec_unshare_syzbot
EXPECT_EQ(close(fd3), 0);
}
+TEST(close_range_bitmap_corruption)
+{
+ pid_t pid;
+ int status;
+ struct __clone_args args = {
+ .flags = CLONE_FILES,
+ .exit_signal = SIGCHLD,
+ };
+
+ /* get the first 128 descriptors open */
+ for (int i = 2; i < 128; i++)
+ EXPECT_GE(dup2(0, i), 0);
+
+ /* get descriptor table shared */
+ pid = sys_clone3(&args, sizeof(args));
+ ASSERT_GE(pid, 0);
+
+ if (pid == 0) {
+ /* unshare and truncate descriptor table down to 64 */
+ if (sys_close_range(64, ~0U, CLOSE_RANGE_UNSHARE))
+ exit(EXIT_FAILURE);
+
+ ASSERT_EQ(fcntl(64, F_GETFD), -1);
+ /* ... and verify that the range 64..127 is not
+ stuck "fully used" according to secondary bitmap */
+ EXPECT_EQ(dup(0), 64)
+ exit(EXIT_FAILURE);
+ exit(EXIT_SUCCESS);
+ }
+
+ EXPECT_EQ(waitpid(pid, &status, 0), pid);
+ EXPECT_EQ(true, WIFEXITED(status));
+ EXPECT_EQ(0, WEXITSTATUS(status));
+}
+
+ TEST(fcntl_created)
+ {
+ for (int i = 0; i < 101; i++) {
+ int fd;
+ char path[PATH_MAX];
+
+ fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
+ ASSERT_GE(fd, 0) {
+ if (errno == ENOENT)
+ SKIP(return,
+ "Skipping test since /dev/null does not exist");
+ }
+
+ /* We didn't create "/dev/null". */
+ EXPECT_EQ(fcntl(fd, F_CREATED_QUERY, 0), 0);
+ close(fd);
+
+ sprintf(path, "aaaa_%d", i);
+ fd = open(path, O_CREAT | O_RDONLY | O_CLOEXEC, 0600);
+ ASSERT_GE(fd, 0);
+
+ /* We created "aaaa_%d". */
+ EXPECT_EQ(fcntl(fd, F_CREATED_QUERY, 0), 1);
+ close(fd);
+
+ fd = open(path, O_RDONLY | O_CLOEXEC);
+ ASSERT_GE(fd, 0);
+
+ /* We're opening it again, so no positive creation check. */
+ EXPECT_EQ(fcntl(fd, F_CREATED_QUERY, 0), 0);
+ close(fd);
+ unlink(path);
+ }
+ }
+
TEST_HARNESS_MAIN
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-02-17 13:39 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-17 13:39 linux-next: manual merge of the vfs-brauner tree with the vfs-fixes tree Mark Brown
-- strict thread matches above, loose matches on Subject: below --
2024-08-07 0:04 Stephen Rothwell
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox