Linux filesystem development
 help / color / mirror / Atom feed
* [PATCH 0/2] Support overlayfs in the idmapped mount tests
@ 2026-06-15 15:33 Christian Brauner
  2026-06-15 15:33 ` [PATCH 1/2] src/vfs: probe O_TMPFILE support on the base mount in the idmapped tests Christian Brauner
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Christian Brauner @ 2026-06-15 15:33 UTC (permalink / raw)
  To: Miklos Szeredi, Amir Goldstein, Zorro Lang
  Cc: linux-unionfs, linux-fsdevel, fstests,
	Christian Brauner (Amutable)

This change is required to make the series in [1] which makes idmapped
overlayfs mounts work compatible with the idmapped mount test suite.

The vfstest idmapped mount tests behind generic/633, generic/696 and
generic/697 fail on overlayfs for two reasons that are specific to
overlayfs and unrelated to idmapped mount semantics:

  - They create a whiteout device, mknod(S_IFCHR, makedev(0, 0)), as a
    fixture -- it is the only character device an unprivileged caller may
    create, being exempt from the CAP_MKNOD check. overlayfs reserves a
    0:0 character device as its on-disk whiteout marker, so ovl_mknod()
    returns -EPERM and the fixture cannot be created.

  - openat_tmpfile_supported() probes O_TMPFILE on the idmapped mount as
    the test's fsuid, which that mount does not map. On overlayfs the
    backing tmpfile then ends up owned by an unmapped id, overlayfs opens
    it with O_NOATIME, and may_open() returns -EPERM, so the probe
    wrongly concludes O_TMPFILE is unsupported and the tmpfile sub-tests
    are skipped.

Patch 1 fixes the probe: O_TMPFILE support is a property of the
filesystem, not of the idmapped mount or the caller's mapping, so it
probes info->t_dir1_fd (the base mount, which the caller owns) just like
the non-idmapped setgid tests already do. This is a general correctness
fix and a no-op on every other filesystem.

Patch 2 adds an is_overlayfs() helper and skips the whiteout-device
fixtures (and the checks that depend on them) on overlayfs, which
genuinely cannot create them; the makedev(5, 1) "creation must fail"
probes keep running.

With both patches generic/633, generic/696 and generic/697 pass on an
idmapped overlayfs mount with no change on any other filesystem; tested
on overlayfs and tmpfs.

The underlying overlayfs O_NOATIME behaviour that turns an unmapped-fsuid
O_TMPFILE into -EPERM is being addressed separately on the kernel side;
these test changes are independent of it.

Link:
https://patch.msgid.link/20260615-work-idmapped-overlayfs-v1-0-7381632aa402@kernel.org [1]

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
Christian Brauner (2):
      src/vfs: probe O_TMPFILE support on the base mount in the idmapped tests
      src/vfs: skip whiteout-device fixtures on overlayfs

 src/vfs/idmapped-mounts.c | 166 ++++++++++++++++++++++++----------------------
 src/vfs/utils.c           |   5 ++
 src/vfs/utils.h           |   1 +
 3 files changed, 93 insertions(+), 79 deletions(-)
---
base-commit: ffc8bad17e5b2f56e48dbac43f7c5ae8ac368fe5
change-id: 20260615-overlay-idmapped-vfstest-b262d3084eea


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 1/2] src/vfs: probe O_TMPFILE support on the base mount in the idmapped tests
  2026-06-15 15:33 [PATCH 0/2] Support overlayfs in the idmapped mount tests Christian Brauner
@ 2026-06-15 15:33 ` Christian Brauner
  2026-06-15 17:53   ` Amir Goldstein
  2026-07-10  5:34   ` Christoph Hellwig
  2026-06-15 15:33 ` [PATCH 2/2] src/vfs: skip whiteout-device fixtures on overlayfs Christian Brauner
  2026-07-10  5:33 ` [PATCH 0/2] Support overlayfs in the idmapped mount tests Christoph Hellwig
  2 siblings, 2 replies; 8+ messages in thread
From: Christian Brauner @ 2026-06-15 15:33 UTC (permalink / raw)
  To: Miklos Szeredi, Amir Goldstein, Zorro Lang
  Cc: linux-unionfs, linux-fsdevel, fstests,
	Christian Brauner (Amutable)

openat_tmpfile_supported() in the idmapped mount tests probes O_TMPFILE
on the idmapped mount (open_tree_fd) as the test's fsuid -- but that
fsuid is not mapped by the idmapped mount under test, so it really asks
"can this unmapped caller create a tmpfile through this idmap?" instead
of "does the filesystem support O_TMPFILE?".

On overlayfs this is a false negative: the backing tmpfile ends up owned
by an unmapped id, overlayfs opens it with O_NOATIME and may_open()
returns -EPERM, so the tmpfile sub-tests are wrongly skipped.

O_TMPFILE support is a property of the filesystem, not of the idmapped
mount or the caller's mapping. Probe info->t_dir1_fd, the base mount
that the caller owns, exactly as the non-idmapped setgid tests already
do. The probe then succeeds on every filesystem and the tmpfile
sub-tests run as the mapped fsuid.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 src/vfs/idmapped-mounts.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/src/vfs/idmapped-mounts.c b/src/vfs/idmapped-mounts.c
index ed9992f9..8f8441c9 100644
--- a/src/vfs/idmapped-mounts.c
+++ b/src/vfs/idmapped-mounts.c
@@ -3838,7 +3838,7 @@ int tcore_setgid_create_idmapped(const struct vfstest_info *info)
 		goto out;
 	}
 
-	supported = openat_tmpfile_supported(open_tree_fd);
+	supported = openat_tmpfile_supported(info->t_dir1_fd);
 
 	pid = fork();
 	if (pid < 0) {
@@ -4014,7 +4014,7 @@ int tcore_setgid_create_idmapped_in_userns(const struct vfstest_info *info)
 		goto out;
 	}
 
-	supported = openat_tmpfile_supported(open_tree_fd);
+	supported = openat_tmpfile_supported(info->t_dir1_fd);
 
 	pid = fork();
 	if (pid < 0) {
@@ -7733,7 +7733,7 @@ static int setgid_create_umask_idmapped(const struct vfstest_info *info)
 		goto out;
 	}
 
-	supported = openat_tmpfile_supported(open_tree_fd);
+	supported = openat_tmpfile_supported(info->t_dir1_fd);
 
 	pid = fork();
 	if (pid < 0) {
@@ -7947,7 +7947,7 @@ static int setgid_create_umask_idmapped_in_userns(const struct vfstest_info *inf
 		goto out;
 	}
 
-	supported = openat_tmpfile_supported(open_tree_fd);
+	supported = openat_tmpfile_supported(info->t_dir1_fd);
 
 	/*
 	 * Below we verify that setgid inheritance for a newly created file or
@@ -8181,7 +8181,7 @@ static int setgid_create_acl_idmapped(const struct vfstest_info *info)
 		goto out;
 	}
 
-	supported = openat_tmpfile_supported(open_tree_fd);
+	supported = openat_tmpfile_supported(info->t_dir1_fd);
 
 	pid = fork();
 	if (pid < 0) {
@@ -8536,7 +8536,7 @@ static int setgid_create_acl_idmapped_in_userns(const struct vfstest_info *info)
 		goto out;
 	}
 
-	supported = openat_tmpfile_supported(open_tree_fd);
+	supported = openat_tmpfile_supported(info->t_dir1_fd);
 
 	/*
 	 * Below we verify that setgid inheritance for a newly created file or

-- 
2.47.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 2/2] src/vfs: skip whiteout-device fixtures on overlayfs
  2026-06-15 15:33 [PATCH 0/2] Support overlayfs in the idmapped mount tests Christian Brauner
  2026-06-15 15:33 ` [PATCH 1/2] src/vfs: probe O_TMPFILE support on the base mount in the idmapped tests Christian Brauner
@ 2026-06-15 15:33 ` Christian Brauner
  2026-06-15 18:03   ` Amir Goldstein
  2026-07-10  5:33 ` [PATCH 0/2] Support overlayfs in the idmapped mount tests Christoph Hellwig
  2 siblings, 1 reply; 8+ messages in thread
From: Christian Brauner @ 2026-06-15 15:33 UTC (permalink / raw)
  To: Miklos Szeredi, Amir Goldstein, Zorro Lang
  Cc: linux-unionfs, linux-fsdevel, fstests,
	Christian Brauner (Amutable)

The idmapped mount tests create a whiteout device,
mknod(S_IFCHR, makedev(0, 0)), as a fixture: a whiteout device is the
only character device an unprivileged caller may create, since it is
exempt from the CAP_MKNOD check. overlayfs reserves a 0:0 character
device as its on-disk whiteout marker, so ovl_mknod() returns -EPERM
and the fixture cannot be created, failing generic/633, generic/696 and
generic/697 on overlayfs.

Add an is_overlayfs() helper and skip the whiteout-device fixtures and
the checks that depend on them on overlayfs. The makedev(5, 1)
"creation must fail" probes are unaffected and keep running. No-op on
every other filesystem.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 src/vfs/idmapped-mounts.c | 154 ++++++++++++++++++++++++----------------------
 src/vfs/utils.c           |   5 ++
 src/vfs/utils.h           |   1 +
 3 files changed, 87 insertions(+), 73 deletions(-)

diff --git a/src/vfs/idmapped-mounts.c b/src/vfs/idmapped-mounts.c
index 8f8441c9..e3779655 100644
--- a/src/vfs/idmapped-mounts.c
+++ b/src/vfs/idmapped-mounts.c
@@ -433,6 +433,7 @@ out:
 
 int tcore_fsids_mapped(const struct vfstest_info *info)
 {
+	bool whiteout_dev = !is_overlayfs(info->t_fstype);
 	int fret = -1;
 	int file1_fd = -EBADF, hardlink_target_fd = -EBADF, open_tree_fd = -EBADF;
 	struct mount_attr attr = {
@@ -535,7 +536,7 @@ int tcore_fsids_mapped(const struct vfstest_info *info)
 			die("failure: create");
 
 		/* create character device */
-		if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | 0644, makedev(0, 0)))
+		if (whiteout_dev && mknodat(open_tree_fd, CHRDEV1, S_IFCHR | 0644, makedev(0, 0)))
 			die("failure: create");
 
 		/* create symlink */
@@ -735,6 +736,7 @@ out:
 /* Validate that changing file ownership works correctly on idmapped mounts. */
 int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 {
+	bool whiteout_dev = !is_overlayfs(info->t_fstype);
 	int fret = -1;
 	int file1_fd = -EBADF, open_tree_fd1 = -EBADF, open_tree_fd2 = -EBADF;
 	struct mount_attr attr1 = {
@@ -764,7 +766,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 	}
 
 	/* create character device */
-	if (mknodat(info->t_dir1_fd, CHRDEV1, S_IFCHR | 0644, makedev(0, 0))) {
+	if (whiteout_dev && mknodat(info->t_dir1_fd, CHRDEV1, S_IFCHR | 0644, makedev(0, 0))) {
 		log_stderr("failure: mknodat");
 		goto out;
 	}
@@ -825,7 +827,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
-	if (!expected_uid_gid(info->t_dir1_fd, CHRDEV1, 0, 0, 0)) {
+	if (whiteout_dev && !expected_uid_gid(info->t_dir1_fd, CHRDEV1, 0, 0, 0)) {
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
@@ -857,7 +859,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
-	if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 10000, 10000)) {
+	if (whiteout_dev && !expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 10000, 10000)) {
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
@@ -912,7 +914,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
-	if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 30000, 30000)) {
+	if (whiteout_dev && !expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 30000, 30000)) {
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
@@ -942,7 +944,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 		log_stderr("failure: fchownat");
 		goto out;
 	}
-	if (fchownat(info->t_dir1_fd, CHRDEV1, 2000, 2000, 0)) {
+	if (whiteout_dev && fchownat(info->t_dir1_fd, CHRDEV1, 2000, 2000, 0)) {
 		log_stderr("failure: fchownat");
 		goto out;
 	}
@@ -972,7 +974,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
-	if (!expected_uid_gid(info->t_dir1_fd, CHRDEV1, 0, 2000, 2000)) {
+	if (whiteout_dev && !expected_uid_gid(info->t_dir1_fd, CHRDEV1, 0, 2000, 2000)) {
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
@@ -1002,7 +1004,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
-	if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 12000, 12000)) {
+	if (whiteout_dev && !expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 12000, 12000)) {
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
@@ -1032,7 +1034,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
-	if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 32000, 32000)) {
+	if (whiteout_dev && !expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 32000, 32000)) {
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
@@ -1064,7 +1066,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 			die("failure: fchownat");
 		if (!fchownat(info->t_dir1_fd, HARDLINK1, 1000, 1000, 0))
 			die("failure: fchownat");
-		if (!fchownat(info->t_dir1_fd, CHRDEV1, 1000, 1000, 0))
+		if (whiteout_dev && !fchownat(info->t_dir1_fd, CHRDEV1, 1000, 1000, 0))
 			die("failure: fchownat");
 		if (!fchownat(info->t_dir1_fd, SYMLINK1, 2000, 2000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
 			die("failure: fchownat");
@@ -1079,7 +1081,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 			die("failure: fchownat");
 		if (!fchownat(open_tree_fd2, HARDLINK1, 1000, 1000, 0))
 			die("failure: fchownat");
-		if (!fchownat(open_tree_fd2, CHRDEV1, 1000, 1000, 0))
+		if (whiteout_dev && !fchownat(open_tree_fd2, CHRDEV1, 1000, 1000, 0))
 			die("failure: fchownat");
 		if (!fchownat(open_tree_fd2, SYMLINK1, 2000, 2000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
 			die("failure: fchownat");
@@ -1094,7 +1096,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 			die("failure: fchownat");
 		if (fchownat(open_tree_fd1, HARDLINK1, 1000, 1000, 0))
 			die("failure: fchownat");
-		if (fchownat(open_tree_fd1, CHRDEV1, 1000, 1000, 0))
+		if (whiteout_dev && fchownat(open_tree_fd1, CHRDEV1, 1000, 1000, 0))
 			die("failure: fchownat");
 		if (fchownat(open_tree_fd1, SYMLINK1, 2000, 2000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
 			die("failure: fchownat");
@@ -1109,7 +1111,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 			die("failure: expected_uid_gid");
 		if (!expected_uid_gid(info->t_dir1_fd, HARDLINK1, 0, info->t_overflowuid, info->t_overflowgid))
 			die("failure: expected_uid_gid");
-		if (!expected_uid_gid(info->t_dir1_fd, CHRDEV1, 0, info->t_overflowuid, info->t_overflowgid))
+		if (whiteout_dev && !expected_uid_gid(info->t_dir1_fd, CHRDEV1, 0, info->t_overflowuid, info->t_overflowgid))
 			die("failure: expected_uid_gid");
 		if (!expected_uid_gid(info->t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, info->t_overflowuid, info->t_overflowgid))
 			die("failure: expected_uid_gid");
@@ -1124,7 +1126,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 			die("failure: expected_uid_gid");
 		if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, info->t_overflowuid, info->t_overflowgid))
 			die("failure: expected_uid_gid");
-		if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, info->t_overflowuid, info->t_overflowgid))
+		if (whiteout_dev && !expected_uid_gid(open_tree_fd2, CHRDEV1, 0, info->t_overflowuid, info->t_overflowgid))
 			die("failure: expected_uid_gid");
 		if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, info->t_overflowuid, info->t_overflowgid))
 			die("failure: expected_uid_gid");
@@ -1139,7 +1141,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 			die("failure: expected_uid_gid");
 		if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, 1000, 1000))
 			die("failure: expected_uid_gid");
-		if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 1000, 1000))
+		if (whiteout_dev && !expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 1000, 1000))
 			die("failure: expected_uid_gid");
 		if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000))
 			die("failure: expected_uid_gid");
@@ -1167,7 +1169,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
-	if (!expected_uid_gid(info->t_dir1_fd, CHRDEV1, 0, 1000, 1000)) {
+	if (whiteout_dev && !expected_uid_gid(info->t_dir1_fd, CHRDEV1, 0, 1000, 1000)) {
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
@@ -1197,7 +1199,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
-	if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 11000, 11000)) {
+	if (whiteout_dev && !expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 11000, 11000)) {
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
@@ -1227,7 +1229,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
-	if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 31000, 31000)) {
+	if (whiteout_dev && !expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 31000, 31000)) {
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
@@ -1259,7 +1261,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 			die("failure: fchownat");
 		if (!fchownat(info->t_dir1_fd, HARDLINK1, 0, 0, 0))
 			die("failure: fchownat");
-		if (!fchownat(info->t_dir1_fd, CHRDEV1, 0, 0, 0))
+		if (whiteout_dev && !fchownat(info->t_dir1_fd, CHRDEV1, 0, 0, 0))
 			die("failure: fchownat");
 		if (!fchownat(info->t_dir1_fd, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
 			die("failure: fchownat");
@@ -1274,7 +1276,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 			die("failure: fchownat");
 		if (!fchownat(open_tree_fd1, HARDLINK1, 0, 0, 0))
 			die("failure: fchownat");
-		if (!fchownat(open_tree_fd1, CHRDEV1, 0, 0, 0))
+		if (whiteout_dev && !fchownat(open_tree_fd1, CHRDEV1, 0, 0, 0))
 			die("failure: fchownat");
 		if (!fchownat(open_tree_fd1, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
 			die("failure: fchownat");
@@ -1289,7 +1291,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 			die("failure: fchownat");
 		if (fchownat(open_tree_fd2, HARDLINK1, 0, 0, 0))
 			die("failure: fchownat");
-		if (fchownat(open_tree_fd2, CHRDEV1, 0, 0, 0))
+		if (whiteout_dev && fchownat(open_tree_fd2, CHRDEV1, 0, 0, 0))
 			die("failure: fchownat");
 		if (!fchownat(open_tree_fd2, SYMLINK1, 3000, 3000, AT_EMPTY_PATH | AT_SYMLINK_NOFOLLOW))
 			die("failure: fchownat");
@@ -1304,7 +1306,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 			die("failure: expected_uid_gid");
 		if (!expected_uid_gid(info->t_dir1_fd, HARDLINK1, 0, info->t_overflowuid, info->t_overflowgid))
 			die("failure: expected_uid_gid");
-		if (!expected_uid_gid(info->t_dir1_fd, CHRDEV1, 0, info->t_overflowuid, info->t_overflowgid))
+		if (whiteout_dev && !expected_uid_gid(info->t_dir1_fd, CHRDEV1, 0, info->t_overflowuid, info->t_overflowgid))
 			die("failure: expected_uid_gid");
 		if (!expected_uid_gid(info->t_dir1_fd, SYMLINK1, AT_SYMLINK_NOFOLLOW, info->t_overflowuid, info->t_overflowgid))
 			die("failure: expected_uid_gid");
@@ -1319,7 +1321,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 			die("failure: expected_uid_gid");
 		if (!expected_uid_gid(open_tree_fd1, HARDLINK1, 0, info->t_overflowuid, info->t_overflowgid))
 			die("failure: expected_uid_gid");
-		if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, info->t_overflowuid, info->t_overflowgid))
+		if (whiteout_dev && !expected_uid_gid(open_tree_fd1, CHRDEV1, 0, info->t_overflowuid, info->t_overflowgid))
 			die("failure: expected_uid_gid");
 		if (!expected_uid_gid(open_tree_fd1, SYMLINK1, AT_SYMLINK_NOFOLLOW, info->t_overflowuid, info->t_overflowgid))
 			die("failure: expected_uid_gid");
@@ -1334,7 +1336,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 			die("failure: expected_uid_gid");
 		if (!expected_uid_gid(open_tree_fd2, HARDLINK1, 0, 0, 0))
 			die("failure: expected_uid_gid");
-		if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 0, 0))
+		if (whiteout_dev && !expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 0, 0))
 			die("failure: expected_uid_gid");
 		if (!expected_uid_gid(open_tree_fd2, SYMLINK1, AT_SYMLINK_NOFOLLOW, 2000, 2000))
 			die("failure: expected_uid_gid");
@@ -1362,7 +1364,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
-	if (!expected_uid_gid(info->t_dir1_fd, CHRDEV1, 0, 0, 0)) {
+	if (whiteout_dev && !expected_uid_gid(info->t_dir1_fd, CHRDEV1, 0, 0, 0)) {
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
@@ -1392,7 +1394,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
-	if (!expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 10000, 10000)) {
+	if (whiteout_dev && !expected_uid_gid(open_tree_fd1, CHRDEV1, 0, 10000, 10000)) {
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
@@ -1422,7 +1424,7 @@ int tcore_expected_uid_gid_idmapped_mounts(const struct vfstest_info *info)
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
-	if (!expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 30000, 30000)) {
+	if (whiteout_dev && !expected_uid_gid(open_tree_fd2, CHRDEV1, 0, 30000, 30000)) {
 		log_stderr("failure: expected_uid_gid");
 		goto out;
 	}
@@ -3782,6 +3784,7 @@ out:
 
 int tcore_setgid_create_idmapped(const struct vfstest_info *info)
 {
+	bool whiteout_dev = !is_overlayfs(info->t_fstype);
 	int fret = -1;
 	int file1_fd = -EBADF, open_tree_fd = -EBADF;
 	struct mount_attr attr = {
@@ -3882,10 +3885,10 @@ int tcore_setgid_create_idmapped(const struct vfstest_info *info)
 			die("failure: is_setgid");
 
 		/* create a whiteout device via mknodat() vfs_mknod */
-		if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
+		if (whiteout_dev && mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
 			die("failure: mknodat");
 
-		if (is_setgid(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && is_setgid(open_tree_fd, CHRDEV1, 0))
 			die("failure: is_setgid");
 
 		/*
@@ -3907,7 +3910,7 @@ int tcore_setgid_create_idmapped(const struct vfstest_info *info)
 		if (!expected_uid_gid(open_tree_fd, FILE2, 0, 10000, 10000))
 			die("failure: check ownership");
 
-		if (!expected_uid_gid(open_tree_fd, CHRDEV1, 0, 10000, 10000))
+		if (whiteout_dev && !expected_uid_gid(open_tree_fd, CHRDEV1, 0, 10000, 10000))
 			die("failure: check ownership");
 
 		if (unlinkat(open_tree_fd, FILE1, 0))
@@ -3919,7 +3922,7 @@ int tcore_setgid_create_idmapped(const struct vfstest_info *info)
 		if (unlinkat(open_tree_fd, FILE2, 0))
 			die("failure: delete");
 
-		if (unlinkat(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && unlinkat(open_tree_fd, CHRDEV1, 0))
 			die("failure: delete");
 
 		/* create tmpfile via filesystem tmpfile api */
@@ -3958,6 +3961,7 @@ out:
 
 int tcore_setgid_create_idmapped_in_userns(const struct vfstest_info *info)
 {
+	bool whiteout_dev = !is_overlayfs(info->t_fstype);
 	int fret = -1;
 	int file1_fd = -EBADF, open_tree_fd = -EBADF;
 	struct mount_attr attr = {
@@ -4052,10 +4056,10 @@ int tcore_setgid_create_idmapped_in_userns(const struct vfstest_info *info)
 			die("failure: is_setgid");
 
 		/* create a whiteout device via mknodat() vfs_mknod */
-		if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
+		if (whiteout_dev && mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
 			die("failure: mknodat");
 
-		if (!is_setgid(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && !is_setgid(open_tree_fd, CHRDEV1, 0))
 			die("failure: is_setgid");
 
 		if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
@@ -4067,7 +4071,7 @@ int tcore_setgid_create_idmapped_in_userns(const struct vfstest_info *info)
 		if (!expected_uid_gid(open_tree_fd, FILE2, 0, 0, 0))
 			die("failure: check ownership");
 
-		if (!expected_uid_gid(open_tree_fd, CHRDEV1, 0, 0, 0))
+		if (whiteout_dev && !expected_uid_gid(open_tree_fd, CHRDEV1, 0, 0, 0))
 			die("failure: check ownership");
 
 		if (unlinkat(open_tree_fd, FILE1, 0))
@@ -4079,7 +4083,7 @@ int tcore_setgid_create_idmapped_in_userns(const struct vfstest_info *info)
 		if (unlinkat(open_tree_fd, FILE2, 0))
 			die("failure: delete");
 
-		if (unlinkat(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && unlinkat(open_tree_fd, CHRDEV1, 0))
 			die("failure: delete");
 
 		/* create tmpfile via filesystem tmpfile api */
@@ -4169,10 +4173,10 @@ int tcore_setgid_create_idmapped_in_userns(const struct vfstest_info *info)
 			die("failure: is_setgid");
 
 		/* create a whiteout device via mknodat() vfs_mknod */
-		if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
+		if (whiteout_dev && mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
 			die("failure: mknodat");
 
-		if (is_setgid(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && is_setgid(open_tree_fd, CHRDEV1, 0))
 			die("failure: is_setgid");
 
 		/*
@@ -4194,7 +4198,7 @@ int tcore_setgid_create_idmapped_in_userns(const struct vfstest_info *info)
 		if (!expected_uid_gid(open_tree_fd, FILE2, 0, 0, 1000))
 			die("failure: check ownership");
 
-		if (!expected_uid_gid(open_tree_fd, CHRDEV1, 0, 0, 1000))
+		if (whiteout_dev && !expected_uid_gid(open_tree_fd, CHRDEV1, 0, 0, 1000))
 			die("failure: check ownership");
 
 		if (unlinkat(open_tree_fd, FILE1, 0))
@@ -4206,7 +4210,7 @@ int tcore_setgid_create_idmapped_in_userns(const struct vfstest_info *info)
 		if (unlinkat(open_tree_fd, FILE2, 0))
 			die("failure: delete");
 
-		if (unlinkat(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && unlinkat(open_tree_fd, CHRDEV1, 0))
 			die("failure: delete");
 
 		/* create tmpfile via filesystem tmpfile api */
@@ -4294,10 +4298,10 @@ int tcore_setgid_create_idmapped_in_userns(const struct vfstest_info *info)
 			die("failure: is_setgid");
 
 		/* create a whiteout device via mknodat() vfs_mknod */
-		if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
+		if (whiteout_dev && mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
 			die("failure: mknodat");
 
-		if (is_setgid(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && is_setgid(open_tree_fd, CHRDEV1, 0))
 			die("failure: is_setgid");
 
 		if (!expected_uid_gid(open_tree_fd, FILE1, 0, 0, 0))
@@ -4309,7 +4313,7 @@ int tcore_setgid_create_idmapped_in_userns(const struct vfstest_info *info)
 		if (!expected_uid_gid(open_tree_fd, FILE2, 0, 0, 0))
 			die("failure: check ownership");
 
-		if (!expected_uid_gid(open_tree_fd, CHRDEV1, 0, 0, 0))
+		if (whiteout_dev && !expected_uid_gid(open_tree_fd, CHRDEV1, 0, 0, 0))
 			die("failure: check ownership");
 
 		if (unlinkat(open_tree_fd, FILE1, 0))
@@ -4321,7 +4325,7 @@ int tcore_setgid_create_idmapped_in_userns(const struct vfstest_info *info)
 		if (unlinkat(open_tree_fd, FILE2, 0))
 			die("failure: delete");
 
-		if (unlinkat(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && unlinkat(open_tree_fd, CHRDEV1, 0))
 			die("failure: delete");
 
 		/* create tmpfile via filesystem tmpfile api */
@@ -7676,6 +7680,7 @@ out:
  */
 static int setgid_create_umask_idmapped(const struct vfstest_info *info)
 {
+	bool whiteout_dev = !is_overlayfs(info->t_fstype);
 	int fret = -1;
 	int file1_fd = -EBADF, open_tree_fd = -EBADF;
 	struct mount_attr attr = {
@@ -7794,13 +7799,13 @@ static int setgid_create_umask_idmapped(const struct vfstest_info *info)
 			die("failure: is_ixgrp");
 
 		/* create a whiteout device via mknodat() vfs_mknod */
-		if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
+		if (whiteout_dev && mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
 			die("failure: mknodat");
 
-		if (is_setgid(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && is_setgid(open_tree_fd, CHRDEV1, 0))
 			die("failure: is_setgid");
 
-		if (is_ixgrp(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && is_ixgrp(open_tree_fd, CHRDEV1, 0))
 			die("failure: is_ixgrp");
 
 		/*
@@ -7822,7 +7827,7 @@ static int setgid_create_umask_idmapped(const struct vfstest_info *info)
 		if (!expected_uid_gid(open_tree_fd, FILE2, 0, 10000, 10000))
 			die("failure: check ownership");
 
-		if (!expected_uid_gid(open_tree_fd, CHRDEV1, 0, 10000, 10000))
+		if (whiteout_dev && !expected_uid_gid(open_tree_fd, CHRDEV1, 0, 10000, 10000))
 			die("failure: check ownership");
 
 		if (unlinkat(open_tree_fd, FILE1, 0))
@@ -7834,7 +7839,7 @@ static int setgid_create_umask_idmapped(const struct vfstest_info *info)
 		if (unlinkat(open_tree_fd, FILE2, 0))
 			die("failure: delete");
 
-		if (unlinkat(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && unlinkat(open_tree_fd, CHRDEV1, 0))
 			die("failure: delete");
 
 		/* create tmpfile via filesystem tmpfile api */
@@ -7890,6 +7895,7 @@ out:
  */
 static int setgid_create_umask_idmapped_in_userns(const struct vfstest_info *info)
 {
+	bool whiteout_dev = !is_overlayfs(info->t_fstype);
 	int fret = -1;
 	int file1_fd = -EBADF, open_tree_fd = -EBADF;
 	struct mount_attr attr = {
@@ -8029,13 +8035,13 @@ static int setgid_create_umask_idmapped_in_userns(const struct vfstest_info *inf
 			die("failure: is_ixgrp");
 
 		/* create a whiteout device via mknodat() vfs_mknod */
-		if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
+		if (whiteout_dev && mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
 			die("failure: mknodat");
 
-		if (is_setgid(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && is_setgid(open_tree_fd, CHRDEV1, 0))
 			die("failure: is_setgid");
 
-		if (is_ixgrp(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && is_ixgrp(open_tree_fd, CHRDEV1, 0))
 			die("failure: is_ixgrp");
 
 		/*
@@ -8057,7 +8063,7 @@ static int setgid_create_umask_idmapped_in_userns(const struct vfstest_info *inf
 		if (!expected_uid_gid(open_tree_fd, FILE2, 0, 0, 1000))
 			die("failure: check ownership");
 
-		if (!expected_uid_gid(open_tree_fd, CHRDEV1, 0, 0, 1000))
+		if (whiteout_dev && !expected_uid_gid(open_tree_fd, CHRDEV1, 0, 0, 1000))
 			die("failure: check ownership");
 
 		if (unlinkat(open_tree_fd, FILE1, 0))
@@ -8069,7 +8075,7 @@ static int setgid_create_umask_idmapped_in_userns(const struct vfstest_info *inf
 		if (unlinkat(open_tree_fd, FILE2, 0))
 			die("failure: delete");
 
-		if (unlinkat(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && unlinkat(open_tree_fd, CHRDEV1, 0))
 			die("failure: delete");
 
 		/* create tmpfile via filesystem tmpfile api */
@@ -8124,6 +8130,7 @@ out:
  */
 static int setgid_create_acl_idmapped(const struct vfstest_info *info)
 {
+	bool whiteout_dev = !is_overlayfs(info->t_fstype);
 	int fret = -1;
 	int file1_fd = -EBADF, open_tree_fd = -EBADF;
 	struct mount_attr attr = {
@@ -8249,13 +8256,13 @@ static int setgid_create_acl_idmapped(const struct vfstest_info *info)
 			die("failure: is_ixgrp");
 
 		/* create a whiteout device via mknodat() vfs_mknod */
-		if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
+		if (whiteout_dev && mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
 			die("failure: mknodat");
 
-		if (is_setgid(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && is_setgid(open_tree_fd, CHRDEV1, 0))
 			die("failure: is_setgid");
 
-		if (is_ixgrp(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && is_ixgrp(open_tree_fd, CHRDEV1, 0))
 			die("failure: is_ixgrp");
 
 		/*
@@ -8277,7 +8284,7 @@ static int setgid_create_acl_idmapped(const struct vfstest_info *info)
 		if (!expected_uid_gid(open_tree_fd, FILE2, 0, 10000, 10000))
 			die("failure: check ownership");
 
-		if (!expected_uid_gid(open_tree_fd, CHRDEV1, 0, 10000, 10000))
+		if (whiteout_dev && !expected_uid_gid(open_tree_fd, CHRDEV1, 0, 10000, 10000))
 			die("failure: check ownership");
 
 		if (unlinkat(open_tree_fd, FILE1, 0))
@@ -8289,7 +8296,7 @@ static int setgid_create_acl_idmapped(const struct vfstest_info *info)
 		if (unlinkat(open_tree_fd, FILE2, 0))
 			die("failure: delete");
 
-		if (unlinkat(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && unlinkat(open_tree_fd, CHRDEV1, 0))
 			die("failure: delete");
 
 		/* create tmpfile via filesystem tmpfile api */
@@ -8384,13 +8391,13 @@ static int setgid_create_acl_idmapped(const struct vfstest_info *info)
 			die("failure: is_ixgrp");
 
 		/* create a whiteout device via mknodat() vfs_mknod */
-		if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
+		if (whiteout_dev && mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
 			die("failure: mknodat");
 
-		if (is_setgid(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && is_setgid(open_tree_fd, CHRDEV1, 0))
 			die("failure: is_setgid");
 
-		if (!is_ixgrp(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && !is_ixgrp(open_tree_fd, CHRDEV1, 0))
 			die("failure: is_ixgrp");
 
 		/*
@@ -8412,7 +8419,7 @@ static int setgid_create_acl_idmapped(const struct vfstest_info *info)
 		if (!expected_uid_gid(open_tree_fd, FILE2, 0, 10000, 10000))
 			die("failure: check ownership");
 
-		if (!expected_uid_gid(open_tree_fd, CHRDEV1, 0, 10000, 10000))
+		if (whiteout_dev && !expected_uid_gid(open_tree_fd, CHRDEV1, 0, 10000, 10000))
 			die("failure: check ownership");
 
 		if (unlinkat(open_tree_fd, FILE1, 0))
@@ -8424,7 +8431,7 @@ static int setgid_create_acl_idmapped(const struct vfstest_info *info)
 		if (unlinkat(open_tree_fd, FILE2, 0))
 			die("failure: delete");
 
-		if (unlinkat(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && unlinkat(open_tree_fd, CHRDEV1, 0))
 			die("failure: delete");
 
 		/* create tmpfile via filesystem tmpfile api */
@@ -8479,6 +8486,7 @@ out:
  */
 static int setgid_create_acl_idmapped_in_userns(const struct vfstest_info *info)
 {
+	bool whiteout_dev = !is_overlayfs(info->t_fstype);
 	int fret = -1;
 	int file1_fd = -EBADF, open_tree_fd = -EBADF;
 	struct mount_attr attr = {
@@ -8625,13 +8633,13 @@ static int setgid_create_acl_idmapped_in_userns(const struct vfstest_info *info)
 			die("failure: is_ixgrp");
 
 		/* create a whiteout device via mknodat() vfs_mknod */
-		if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
+		if (whiteout_dev && mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
 			die("failure: mknodat");
 
-		if (is_setgid(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && is_setgid(open_tree_fd, CHRDEV1, 0))
 			die("failure: is_setgid");
 
-		if (is_ixgrp(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && is_ixgrp(open_tree_fd, CHRDEV1, 0))
 			die("failure: is_ixgrp");
 
 		/*
@@ -8653,7 +8661,7 @@ static int setgid_create_acl_idmapped_in_userns(const struct vfstest_info *info)
 		if (!expected_uid_gid(open_tree_fd, FILE2, 0, 0, 1000))
 			die("failure: check ownership");
 
-		if (!expected_uid_gid(open_tree_fd, CHRDEV1, 0, 0, 1000))
+		if (whiteout_dev && !expected_uid_gid(open_tree_fd, CHRDEV1, 0, 0, 1000))
 			die("failure: check ownership");
 
 		if (unlinkat(open_tree_fd, FILE1, 0))
@@ -8665,7 +8673,7 @@ static int setgid_create_acl_idmapped_in_userns(const struct vfstest_info *info)
 		if (unlinkat(open_tree_fd, FILE2, 0))
 			die("failure: delete");
 
-		if (unlinkat(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && unlinkat(open_tree_fd, CHRDEV1, 0))
 			die("failure: delete");
 
 		/* create tmpfile via filesystem tmpfile api */
@@ -8767,13 +8775,13 @@ static int setgid_create_acl_idmapped_in_userns(const struct vfstest_info *info)
 		if (!is_ixgrp(open_tree_fd, FILE2, 0))
 			 die("failure: is_ixgrp");
 		/* create a whiteout device via mknodat() vfs_mknod */
-		if (mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
+		if (whiteout_dev && mknodat(open_tree_fd, CHRDEV1, S_IFCHR | S_ISGID | S_IXGRP, 0))
 			die("failure: mknodat");
 
-		if (is_setgid(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && is_setgid(open_tree_fd, CHRDEV1, 0))
 			die("failure: is_setgid");
 
-		if (!is_ixgrp(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && !is_ixgrp(open_tree_fd, CHRDEV1, 0))
 			 die("failure: is_ixgrp");
 
 		/*
@@ -8795,7 +8803,7 @@ static int setgid_create_acl_idmapped_in_userns(const struct vfstest_info *info)
 		if (!expected_uid_gid(open_tree_fd, FILE2, 0, 0, 1000))
 			die("failure: check ownership");
 
-		if (!expected_uid_gid(open_tree_fd, CHRDEV1, 0, 0, 1000))
+		if (whiteout_dev && !expected_uid_gid(open_tree_fd, CHRDEV1, 0, 0, 1000))
 			die("failure: check ownership");
 
 		if (unlinkat(open_tree_fd, FILE1, 0))
@@ -8807,7 +8815,7 @@ static int setgid_create_acl_idmapped_in_userns(const struct vfstest_info *info)
 		if (unlinkat(open_tree_fd, FILE2, 0))
 			die("failure: delete");
 
-		if (unlinkat(open_tree_fd, CHRDEV1, 0))
+		if (whiteout_dev && unlinkat(open_tree_fd, CHRDEV1, 0))
 			die("failure: delete");
 
 		/* create tmpfile via filesystem tmpfile api */
diff --git a/src/vfs/utils.c b/src/vfs/utils.c
index 0b435afe..9cdbeca6 100644
--- a/src/vfs/utils.c
+++ b/src/vfs/utils.c
@@ -742,6 +742,11 @@ static bool is_xfs(const char *fstype)
 	return enabled;
 }
 
+bool is_overlayfs(const char *fstype)
+{
+	return !strcmp(fstype, "overlay");
+}
+
 bool xfs_irix_sgid_inherit_enabled(const char *fstype)
 {
 	static int enabled = -1;
diff --git a/src/vfs/utils.h b/src/vfs/utils.h
index c086885a..70c4001d 100644
--- a/src/vfs/utils.h
+++ b/src/vfs/utils.h
@@ -372,5 +372,6 @@ extern bool is_setgid(int dfd, const char *path, int flags);
 extern bool is_sticky(int dfd, const char *path, int flags);
 extern bool is_ixgrp(int dfd, const char *path, int flags);
 extern bool openat_tmpfile_supported(int dirfd);
+extern bool is_overlayfs(const char *fstype);
 
 #endif /* __IDMAP_UTILS_H */

-- 
2.47.3


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/2] src/vfs: probe O_TMPFILE support on the base mount in the idmapped tests
  2026-06-15 15:33 ` [PATCH 1/2] src/vfs: probe O_TMPFILE support on the base mount in the idmapped tests Christian Brauner
@ 2026-06-15 17:53   ` Amir Goldstein
  2026-07-10  5:34   ` Christoph Hellwig
  1 sibling, 0 replies; 8+ messages in thread
From: Amir Goldstein @ 2026-06-15 17:53 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Miklos Szeredi, Zorro Lang, linux-unionfs, linux-fsdevel, fstests

On Mon, Jun 15, 2026 at 5:33 PM Christian Brauner <brauner@kernel.org> wrote:
>
> openat_tmpfile_supported() in the idmapped mount tests probes O_TMPFILE
> on the idmapped mount (open_tree_fd) as the test's fsuid -- but that
> fsuid is not mapped by the idmapped mount under test, so it really asks
> "can this unmapped caller create a tmpfile through this idmap?" instead
> of "does the filesystem support O_TMPFILE?".
>
> On overlayfs this is a false negative: the backing tmpfile ends up owned
> by an unmapped id, overlayfs opens it with O_NOATIME and may_open()
> returns -EPERM, so the tmpfile sub-tests are wrongly skipped.
>
> O_TMPFILE support is a property of the filesystem, not of the idmapped
> mount or the caller's mapping. Probe info->t_dir1_fd, the base mount
> that the caller owns, exactly as the non-idmapped setgid tests already
> do. The probe then succeeds on every filesystem and the tmpfile
> sub-tests run as the mapped fsuid.
>
> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>

Reviewed-by: Amir Goldstein <amir73il@gmail.com>

> ---
>  src/vfs/idmapped-mounts.c | 12 ++++++------
>  1 file changed, 6 insertions(+), 6 deletions(-)
>
> diff --git a/src/vfs/idmapped-mounts.c b/src/vfs/idmapped-mounts.c
> index ed9992f9..8f8441c9 100644
> --- a/src/vfs/idmapped-mounts.c
> +++ b/src/vfs/idmapped-mounts.c
> @@ -3838,7 +3838,7 @@ int tcore_setgid_create_idmapped(const struct vfstest_info *info)
>                 goto out;
>         }
>
> -       supported = openat_tmpfile_supported(open_tree_fd);
> +       supported = openat_tmpfile_supported(info->t_dir1_fd);
>
>         pid = fork();
>         if (pid < 0) {
> @@ -4014,7 +4014,7 @@ int tcore_setgid_create_idmapped_in_userns(const struct vfstest_info *info)
>                 goto out;
>         }
>
> -       supported = openat_tmpfile_supported(open_tree_fd);
> +       supported = openat_tmpfile_supported(info->t_dir1_fd);
>
>         pid = fork();
>         if (pid < 0) {
> @@ -7733,7 +7733,7 @@ static int setgid_create_umask_idmapped(const struct vfstest_info *info)
>                 goto out;
>         }
>
> -       supported = openat_tmpfile_supported(open_tree_fd);
> +       supported = openat_tmpfile_supported(info->t_dir1_fd);
>
>         pid = fork();
>         if (pid < 0) {
> @@ -7947,7 +7947,7 @@ static int setgid_create_umask_idmapped_in_userns(const struct vfstest_info *inf
>                 goto out;
>         }
>
> -       supported = openat_tmpfile_supported(open_tree_fd);
> +       supported = openat_tmpfile_supported(info->t_dir1_fd);
>
>         /*
>          * Below we verify that setgid inheritance for a newly created file or
> @@ -8181,7 +8181,7 @@ static int setgid_create_acl_idmapped(const struct vfstest_info *info)
>                 goto out;
>         }
>
> -       supported = openat_tmpfile_supported(open_tree_fd);
> +       supported = openat_tmpfile_supported(info->t_dir1_fd);
>
>         pid = fork();
>         if (pid < 0) {
> @@ -8536,7 +8536,7 @@ static int setgid_create_acl_idmapped_in_userns(const struct vfstest_info *info)
>                 goto out;
>         }
>
> -       supported = openat_tmpfile_supported(open_tree_fd);
> +       supported = openat_tmpfile_supported(info->t_dir1_fd);
>
>         /*
>          * Below we verify that setgid inheritance for a newly created file or
>
> --
> 2.47.3
>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] src/vfs: skip whiteout-device fixtures on overlayfs
  2026-06-15 15:33 ` [PATCH 2/2] src/vfs: skip whiteout-device fixtures on overlayfs Christian Brauner
@ 2026-06-15 18:03   ` Amir Goldstein
  2026-07-10  5:34     ` Christoph Hellwig
  0 siblings, 1 reply; 8+ messages in thread
From: Amir Goldstein @ 2026-06-15 18:03 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Miklos Szeredi, Zorro Lang, linux-unionfs, linux-fsdevel, fstests

On Mon, Jun 15, 2026 at 5:33 PM Christian Brauner <brauner@kernel.org> wrote:
>
> The idmapped mount tests create a whiteout device,
> mknod(S_IFCHR, makedev(0, 0)), as a fixture: a whiteout device is the
> only character device an unprivileged caller may create, since it is
> exempt from the CAP_MKNOD check. overlayfs reserves a 0:0 character
> device as its on-disk whiteout marker, so ovl_mknod() returns -EPERM
> and the fixture cannot be created, failing generic/633, generic/696 and
> generic/697 on overlayfs.
>
> Add an is_overlayfs() helper and skip the whiteout-device fixtures and
> the checks that depend on them on overlayfs. The makedev(5, 1)
> "creation must fail" probes are unaffected and keep running. No-op on
> every other filesystem.

I have no strong objection to this patch but there was actually a request to
support makedev(0, 0) in overlayfs for creating overlayfs on an overlayfs root,
so perhaps it would be better to probe for makedev(0, 0) by fs owner instead
of the is_overlayfs() check.

Thanks,
Amir.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 0/2] Support overlayfs in the idmapped mount tests
  2026-06-15 15:33 [PATCH 0/2] Support overlayfs in the idmapped mount tests Christian Brauner
  2026-06-15 15:33 ` [PATCH 1/2] src/vfs: probe O_TMPFILE support on the base mount in the idmapped tests Christian Brauner
  2026-06-15 15:33 ` [PATCH 2/2] src/vfs: skip whiteout-device fixtures on overlayfs Christian Brauner
@ 2026-07-10  5:33 ` Christoph Hellwig
  2 siblings, 0 replies; 8+ messages in thread
From: Christoph Hellwig @ 2026-07-10  5:33 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Miklos Szeredi, Amir Goldstein, Zorro Lang, linux-unionfs,
	linux-fsdevel, fstests

On Mon, Jun 15, 2026 at 05:33:28PM +0200, Christian Brauner wrote:
> This change is required to make the series in [1] which makes idmapped
> overlayfs mounts work compatible with the idmapped mount test suite.
> 
> The vfstest idmapped mount tests behind generic/633, generic/696 and
> generic/697 fail on overlayfs for two reasons that are specific to
> overlayfs and unrelated to idmapped mount semantics:

They also fail on just testing XFS for me now that the commit has
landed, so this description is a little confusing.  As is the patch
series title.


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 1/2] src/vfs: probe O_TMPFILE support on the base mount in the idmapped tests
  2026-06-15 15:33 ` [PATCH 1/2] src/vfs: probe O_TMPFILE support on the base mount in the idmapped tests Christian Brauner
  2026-06-15 17:53   ` Amir Goldstein
@ 2026-07-10  5:34   ` Christoph Hellwig
  1 sibling, 0 replies; 8+ messages in thread
From: Christoph Hellwig @ 2026-07-10  5:34 UTC (permalink / raw)
  To: Christian Brauner
  Cc: Miklos Szeredi, Amir Goldstein, Zorro Lang, linux-unionfs,
	linux-fsdevel, fstests

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 2/2] src/vfs: skip whiteout-device fixtures on overlayfs
  2026-06-15 18:03   ` Amir Goldstein
@ 2026-07-10  5:34     ` Christoph Hellwig
  0 siblings, 0 replies; 8+ messages in thread
From: Christoph Hellwig @ 2026-07-10  5:34 UTC (permalink / raw)
  To: Amir Goldstein
  Cc: Christian Brauner, Miklos Szeredi, Zorro Lang, linux-unionfs,
	linux-fsdevel, fstests

On Mon, Jun 15, 2026 at 08:03:02PM +0200, Amir Goldstein wrote:
> On Mon, Jun 15, 2026 at 5:33 PM Christian Brauner <brauner@kernel.org> wrote:
> >
> > The idmapped mount tests create a whiteout device,
> > mknod(S_IFCHR, makedev(0, 0)), as a fixture: a whiteout device is the
> > only character device an unprivileged caller may create, since it is
> > exempt from the CAP_MKNOD check. overlayfs reserves a 0:0 character
> > device as its on-disk whiteout marker, so ovl_mknod() returns -EPERM
> > and the fixture cannot be created, failing generic/633, generic/696 and
> > generic/697 on overlayfs.
> >
> > Add an is_overlayfs() helper and skip the whiteout-device fixtures and
> > the checks that depend on them on overlayfs. The makedev(5, 1)
> > "creation must fail" probes are unaffected and keep running. No-op on
> > every other filesystem.
> 
> I have no strong objection to this patch but there was actually a request to
> support makedev(0, 0) in overlayfs for creating overlayfs on an overlayfs root,
> so perhaps it would be better to probe for makedev(0, 0) by fs owner instead
> of the is_overlayfs() check.

Where do we stand on this?


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-07-10  5:34 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-15 15:33 [PATCH 0/2] Support overlayfs in the idmapped mount tests Christian Brauner
2026-06-15 15:33 ` [PATCH 1/2] src/vfs: probe O_TMPFILE support on the base mount in the idmapped tests Christian Brauner
2026-06-15 17:53   ` Amir Goldstein
2026-07-10  5:34   ` Christoph Hellwig
2026-06-15 15:33 ` [PATCH 2/2] src/vfs: skip whiteout-device fixtures on overlayfs Christian Brauner
2026-06-15 18:03   ` Amir Goldstein
2026-07-10  5:34     ` Christoph Hellwig
2026-07-10  5:33 ` [PATCH 0/2] Support overlayfs in the idmapped mount tests Christoph Hellwig

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox