Skip to content

Commit

Permalink
selftests: add a test for the foreign mnt ns extensions
Browse files Browse the repository at this point in the history
This tests both statmount and listmount to make sure they work with the
extensions that allow us to specify a mount ns to enter in order to find
the mount entries.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Link: https://lore.kernel.org/r/2d1a35bc9ab94b4656c056c420f25e429e7eb0b1.1719243756.git.josef@toxicpanda.com
Signed-off-by: Christian Brauner <brauner@kernel.org>
  • Loading branch information
Josef Bacik authored and Christian Brauner committed Jun 28, 2024
1 parent e8e43a1 commit d896f71
Show file tree
Hide file tree
Showing 4 changed files with 424 additions and 41 deletions.
2 changes: 1 addition & 1 deletion tools/testing/selftests/filesystems/statmount/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-or-later

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

include ../../lib.mk
46 changes: 46 additions & 0 deletions tools/testing/selftests/filesystems/statmount/statmount.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/* SPDX-License-Identifier: GPL-2.0 */

#ifndef __STATMOUNT_H
#define __STATMOUNT_H

#include <stdint.h>
#include <linux/mount.h>
#include <asm/unistd.h>

static inline int statmount(uint64_t mnt_id, uint64_t mnt_ns_id, uint64_t mask,
struct statmount *buf, size_t bufsize,
unsigned int flags)
{
struct mnt_id_req req = {
.size = MNT_ID_REQ_SIZE_VER0,
.mnt_id = mnt_id,
.param = mask,
};

if (mnt_ns_id) {
req.size = MNT_ID_REQ_SIZE_VER1;
req.mnt_ns_id = mnt_ns_id;
}

return syscall(__NR_statmount, &req, buf, bufsize, flags);
}

static ssize_t listmount(uint64_t mnt_id, uint64_t mnt_ns_id,
uint64_t last_mnt_id, uint64_t list[], size_t num,
unsigned int flags)
{
struct mnt_id_req req = {
.size = MNT_ID_REQ_SIZE_VER0,
.mnt_id = mnt_id,
.param = last_mnt_id,
};

if (mnt_ns_id) {
req.size = MNT_ID_REQ_SIZE_VER1;
req.mnt_ns_id = mnt_ns_id;
}

return syscall(__NR_listmount, &req, list, num, flags);
}

#endif /* __STATMOUNT_H */
53 changes: 13 additions & 40 deletions tools/testing/selftests/filesystems/statmount/statmount_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,15 @@

#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <sched.h>
#include <fcntl.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <sys/statfs.h>
#include <linux/mount.h>
#include <linux/stat.h>
#include <asm/unistd.h>

#include "statmount.h"
#include "../../kselftest.h"

static const char *const known_fs[] = {
Expand All @@ -36,18 +34,6 @@ static const char *const known_fs[] = {
"ufs", "v7", "vboxsf", "vfat", "virtiofs", "vxfs", "xenfs", "xfs",
"zonefs", NULL };

static int statmount(uint64_t mnt_id, uint64_t mask, struct statmount *buf,
size_t bufsize, unsigned int flags)
{
struct mnt_id_req req = {
.size = MNT_ID_REQ_SIZE_VER0,
.mnt_id = mnt_id,
.param = mask,
};

return syscall(__NR_statmount, &req, buf, bufsize, flags);
}

static struct statmount *statmount_alloc(uint64_t mnt_id, uint64_t mask, unsigned int flags)
{
size_t bufsize = 1 << 15;
Expand All @@ -56,7 +42,7 @@ static struct statmount *statmount_alloc(uint64_t mnt_id, uint64_t mask, unsigne
int ret;

for (;;) {
ret = statmount(mnt_id, mask, tmp, bufsize, flags);
ret = statmount(mnt_id, 0, mask, tmp, bufsize, flags);
if (ret != -1)
break;
if (tofree)
Expand Down Expand Up @@ -122,7 +108,6 @@ static int orig_root;
static uint64_t root_id, parent_id;
static uint32_t old_root_id, old_parent_id;


static void cleanup_namespace(void)
{
fchdir(orig_root);
Expand All @@ -138,7 +123,7 @@ static void setup_namespace(void)
uid_t uid = getuid();
gid_t gid = getgid();

ret = unshare(CLONE_NEWNS|CLONE_NEWUSER);
ret = unshare(CLONE_NEWNS|CLONE_NEWUSER|CLONE_NEWPID);
if (ret == -1)
ksft_exit_fail_msg("unsharing mountns and userns: %s\n",
strerror(errno));
Expand Down Expand Up @@ -208,25 +193,13 @@ static int setup_mount_tree(int log2_num)
return 0;
}

static ssize_t listmount(uint64_t mnt_id, uint64_t last_mnt_id,
uint64_t list[], size_t num, unsigned int flags)
{
struct mnt_id_req req = {
.size = MNT_ID_REQ_SIZE_VER0,
.mnt_id = mnt_id,
.param = last_mnt_id,
};

return syscall(__NR_listmount, &req, list, num, flags);
}

static void test_listmount_empty_root(void)
{
ssize_t res;
const unsigned int size = 32;
uint64_t list[size];

res = listmount(LSMT_ROOT, 0, list, size, 0);
res = listmount(LSMT_ROOT, 0, 0, list, size, 0);
if (res == -1) {
ksft_test_result_fail("listmount: %s\n", strerror(errno));
return;
Expand All @@ -251,7 +224,7 @@ static void test_statmount_zero_mask(void)
struct statmount sm;
int ret;

ret = statmount(root_id, 0, &sm, sizeof(sm), 0);
ret = statmount(root_id, 0, 0, &sm, sizeof(sm), 0);
if (ret == -1) {
ksft_test_result_fail("statmount zero mask: %s\n",
strerror(errno));
Expand All @@ -277,7 +250,7 @@ static void test_statmount_mnt_basic(void)
int ret;
uint64_t mask = STATMOUNT_MNT_BASIC;

ret = statmount(root_id, mask, &sm, sizeof(sm), 0);
ret = statmount(root_id, 0, mask, &sm, sizeof(sm), 0);
if (ret == -1) {
ksft_test_result_fail("statmount mnt basic: %s\n",
strerror(errno));
Expand Down Expand Up @@ -337,7 +310,7 @@ static void test_statmount_sb_basic(void)
struct statx sx;
struct statfs sf;

ret = statmount(root_id, mask, &sm, sizeof(sm), 0);
ret = statmount(root_id, 0, mask, &sm, sizeof(sm), 0);
if (ret == -1) {
ksft_test_result_fail("statmount sb basic: %s\n",
strerror(errno));
Expand Down Expand Up @@ -498,14 +471,14 @@ static void test_statmount_string(uint64_t mask, size_t off, const char *name)
exactsize = sm->size;
shortsize = sizeof(*sm) + i;

ret = statmount(root_id, mask, sm, exactsize, 0);
ret = statmount(root_id, 0, mask, sm, exactsize, 0);
if (ret == -1) {
ksft_test_result_fail("statmount exact size: %s\n",
strerror(errno));
goto out;
}
errno = 0;
ret = statmount(root_id, mask, sm, shortsize, 0);
ret = statmount(root_id, 0, mask, sm, shortsize, 0);
if (ret != -1 || errno != EOVERFLOW) {
ksft_test_result_fail("should have failed with EOVERFLOW: %s\n",
strerror(errno));
Expand Down Expand Up @@ -533,7 +506,7 @@ static void test_listmount_tree(void)
if (res == -1)
return;

num = res = listmount(LSMT_ROOT, 0, list, size, 0);
num = res = listmount(LSMT_ROOT, 0, 0, list, size, 0);
if (res == -1) {
ksft_test_result_fail("listmount: %s\n", strerror(errno));
return;
Expand All @@ -545,7 +518,7 @@ static void test_listmount_tree(void)
}

for (i = 0; i < size - step;) {
res = listmount(LSMT_ROOT, i ? list2[i - 1] : 0, list2 + i, step, 0);
res = listmount(LSMT_ROOT, 0, i ? list2[i - 1] : 0, list2 + i, step, 0);
if (res == -1)
ksft_test_result_fail("short listmount: %s\n",
strerror(errno));
Expand Down Expand Up @@ -577,11 +550,11 @@ int main(void)
int ret;
uint64_t all_mask = STATMOUNT_SB_BASIC | STATMOUNT_MNT_BASIC |
STATMOUNT_PROPAGATE_FROM | STATMOUNT_MNT_ROOT |
STATMOUNT_MNT_POINT | STATMOUNT_FS_TYPE;
STATMOUNT_MNT_POINT | STATMOUNT_FS_TYPE | STATMOUNT_MNT_NS_ID;

ksft_print_header();

ret = statmount(0, 0, NULL, 0, 0);
ret = statmount(0, 0, 0, NULL, 0, 0);
assert(ret == -1);
if (errno == ENOSYS)
ksft_exit_skip("statmount() syscall not supported\n");
Expand Down
Loading

0 comments on commit d896f71

Please sign in to comment.