Skip to content

Commit

Permalink
selftests: add tests for using detached mount with overlayfs
Browse files Browse the repository at this point in the history
Test that it is possible to use detached mounts as overlayfs layers.

Link: https://lore.kernel.org/r/20250123-erstbesteigung-angeeignet-1d30e64b7df2@brauner
Signed-off-by: Christian Brauner <brauner@kernel.org>
  • Loading branch information
Christian Brauner committed Feb 12, 2025
1 parent db04662 commit ccc829b
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 0 deletions.
130 changes: 130 additions & 0 deletions tools/testing/selftests/filesystems/overlayfs/set_layers_via_fds.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,16 @@ FIXTURE(set_layers_via_fds) {
FIXTURE_SETUP(set_layers_via_fds)
{
ASSERT_EQ(mkdir("/set_layers_via_fds", 0755), 0);
ASSERT_EQ(mkdir("/set_layers_via_fds_tmpfs", 0755), 0);
}

FIXTURE_TEARDOWN(set_layers_via_fds)
{
umount2("/set_layers_via_fds", 0);
ASSERT_EQ(rmdir("/set_layers_via_fds"), 0);

umount2("/set_layers_via_fds_tmpfs", 0);
ASSERT_EQ(rmdir("/set_layers_via_fds_tmpfs"), 0);
}

TEST_F(set_layers_via_fds, set_layers_via_fds)
Expand Down Expand Up @@ -279,4 +283,130 @@ TEST_F(set_layers_via_fds, set_500_layers_via_opath_fds)
ASSERT_EQ(close(fd_overlay), 0);
}

TEST_F(set_layers_via_fds, set_layers_via_detached_mount_fds)
{
int fd_context, fd_tmpfs, fd_overlay, fd_tmp;
int layer_fds[] = { [0 ... 8] = -EBADF };
bool layers_found[] = { [0 ... 8] = false };
size_t len = 0;
char *line = NULL;
FILE *f_mountinfo;

ASSERT_EQ(unshare(CLONE_NEWNS), 0);
ASSERT_EQ(sys_mount(NULL, "/", NULL, MS_SLAVE | MS_REC, NULL), 0);

fd_context = sys_fsopen("tmpfs", 0);
ASSERT_GE(fd_context, 0);

ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0);
fd_tmpfs = sys_fsmount(fd_context, 0, 0);
ASSERT_GE(fd_tmpfs, 0);
ASSERT_EQ(close(fd_context), 0);

ASSERT_EQ(mkdirat(fd_tmpfs, "u", 0755), 0);
ASSERT_EQ(mkdirat(fd_tmpfs, "u/upper", 0755), 0);
ASSERT_EQ(mkdirat(fd_tmpfs, "u/work", 0755), 0);
ASSERT_EQ(mkdirat(fd_tmpfs, "l1", 0755), 0);
ASSERT_EQ(mkdirat(fd_tmpfs, "l2", 0755), 0);
ASSERT_EQ(mkdirat(fd_tmpfs, "l3", 0755), 0);
ASSERT_EQ(mkdirat(fd_tmpfs, "l4", 0755), 0);
ASSERT_EQ(mkdirat(fd_tmpfs, "d1", 0755), 0);
ASSERT_EQ(mkdirat(fd_tmpfs, "d2", 0755), 0);
ASSERT_EQ(mkdirat(fd_tmpfs, "d3", 0755), 0);

ASSERT_EQ(sys_move_mount(fd_tmpfs, "", -EBADF, "/set_layers_via_fds_tmpfs", MOVE_MOUNT_F_EMPTY_PATH), 0);

fd_tmp = open_tree(fd_tmpfs, "u", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
ASSERT_GE(fd_tmp, 0);

layer_fds[0] = openat(fd_tmp, "upper", O_CLOEXEC | O_DIRECTORY | O_PATH);
ASSERT_GE(layer_fds[0], 0);

layer_fds[1] = openat(fd_tmp, "work", O_CLOEXEC | O_DIRECTORY | O_PATH);
ASSERT_GE(layer_fds[1], 0);

layer_fds[2] = open_tree(fd_tmpfs, "l1", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
ASSERT_GE(layer_fds[2], 0);

layer_fds[3] = open_tree(fd_tmpfs, "l2", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
ASSERT_GE(layer_fds[3], 0);

layer_fds[4] = open_tree(fd_tmpfs, "l3", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
ASSERT_GE(layer_fds[4], 0);

layer_fds[5] = open_tree(fd_tmpfs, "l4", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
ASSERT_GE(layer_fds[5], 0);

layer_fds[6] = open_tree(fd_tmpfs, "d1", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
ASSERT_GE(layer_fds[6], 0);

layer_fds[7] = open_tree(fd_tmpfs, "d2", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
ASSERT_GE(layer_fds[7], 0);

layer_fds[8] = open_tree(fd_tmpfs, "d3", OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC);
ASSERT_GE(layer_fds[8], 0);

ASSERT_EQ(close(fd_tmpfs), 0);

fd_context = sys_fsopen("overlay", 0);
ASSERT_GE(fd_context, 0);

ASSERT_NE(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir", NULL, layer_fds[2]), 0);

ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "upperdir", NULL, layer_fds[0]), 0);
ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "workdir", NULL, layer_fds[1]), 0);
ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, layer_fds[2]), 0);
ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, layer_fds[3]), 0);
ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, layer_fds[4]), 0);
ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "lowerdir+", NULL, layer_fds[5]), 0);
ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "datadir+", NULL, layer_fds[6]), 0);
ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "datadir+", NULL, layer_fds[7]), 0);
ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_FD, "datadir+", NULL, layer_fds[8]), 0);

ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_SET_STRING, "metacopy", "on", 0), 0);

ASSERT_EQ(sys_fsconfig(fd_context, FSCONFIG_CMD_CREATE, NULL, NULL, 0), 0);

fd_overlay = sys_fsmount(fd_context, 0, 0);
ASSERT_GE(fd_overlay, 0);

ASSERT_EQ(sys_move_mount(fd_overlay, "", -EBADF, "/set_layers_via_fds", MOVE_MOUNT_F_EMPTY_PATH), 0);

f_mountinfo = fopen("/proc/self/mountinfo", "r");
ASSERT_NE(f_mountinfo, NULL);

while (getline(&line, &len, f_mountinfo) != -1) {
char *haystack = line;

if (strstr(haystack, "workdir=/tmp/w"))
layers_found[0] = true;
if (strstr(haystack, "upperdir=/tmp/u"))
layers_found[1] = true;
if (strstr(haystack, "lowerdir+=/tmp/l1"))
layers_found[2] = true;
if (strstr(haystack, "lowerdir+=/tmp/l2"))
layers_found[3] = true;
if (strstr(haystack, "lowerdir+=/tmp/l3"))
layers_found[4] = true;
if (strstr(haystack, "lowerdir+=/tmp/l4"))
layers_found[5] = true;
if (strstr(haystack, "datadir+=/tmp/d1"))
layers_found[6] = true;
if (strstr(haystack, "datadir+=/tmp/d2"))
layers_found[7] = true;
if (strstr(haystack, "datadir+=/tmp/d3"))
layers_found[8] = true;
}
free(line);

for (int i = 0; i < ARRAY_SIZE(layer_fds); i++) {
ASSERT_EQ(layers_found[i], true);
ASSERT_EQ(close(layer_fds[i]), 0);
}

ASSERT_EQ(close(fd_context), 0);
ASSERT_EQ(close(fd_overlay), 0);
ASSERT_EQ(fclose(f_mountinfo), 0);
}

TEST_HARNESS_MAIN
17 changes: 17 additions & 0 deletions tools/testing/selftests/filesystems/overlayfs/wrappers.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,4 +44,21 @@ static inline int sys_move_mount(int from_dfd, const char *from_pathname,
to_pathname, flags);
}

#ifndef OPEN_TREE_CLONE
#define OPEN_TREE_CLONE 1
#endif

#ifndef OPEN_TREE_CLOEXEC
#define OPEN_TREE_CLOEXEC O_CLOEXEC
#endif

#ifndef AT_RECURSIVE
#define AT_RECURSIVE 0x8000
#endif

static inline int sys_open_tree(int dfd, const char *filename, unsigned int flags)
{
return syscall(__NR_open_tree, dfd, filename, flags);
}

#endif

0 comments on commit ccc829b

Please sign in to comment.