selftests/statmount: add statmount_alloc() helper

Add a helper to allocate a statmount buffer and call statmount(). This
helper will be shared by multiple test suites that need to query mount
information via statmount().

Link: https://patch.msgid.link/20260122-work-fsmount-namespace-v1-5-5ef0a886e646@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
Christian Brauner
2026-01-22 11:48:50 +01:00
parent fc1a05de00
commit be1ca3ee8f
3 changed files with 58 additions and 46 deletions
@@ -115,7 +115,7 @@ static void dump_mounts(struct __test_metadata *_metadata, uint64_t mnt_ns_id)
STATMOUNT_MNT_BASIC |
STATMOUNT_FS_TYPE |
STATMOUNT_MNT_ROOT |
STATMOUNT_MNT_POINT);
STATMOUNT_MNT_POINT, 0);
if (!sm) {
TH_LOG(" [%zd] mnt_id %llu: statmount failed: %s",
i, (unsigned long long)list[i], strerror(errno));
@@ -746,7 +746,7 @@ TEST_F(open_tree_ns_userns, umount_fails_einval)
const char *mnt_point;
sm = statmount_alloc(list[i], new_ns_id,
STATMOUNT_MNT_POINT);
STATMOUNT_MNT_POINT, 0);
if (!sm)
_exit(11);
@@ -863,7 +863,7 @@ TEST_F(open_tree_ns_userns, umount_succeeds)
const char *mnt_point;
sm = statmount_alloc(list[i], new_ns_id,
STATMOUNT_MNT_POINT);
STATMOUNT_MNT_POINT, 0);
if (!sm)
_exit(11);
@@ -1003,7 +1003,7 @@ TEST_F(open_tree_ns_unbindable, recursive_skips_on_unbindable)
struct statmount *sm;
const char *mnt_point;
sm = statmount_alloc(list[i], new_ns_id, STATMOUNT_MNT_POINT);
sm = statmount_alloc(list[i], new_ns_id, STATMOUNT_MNT_POINT, 0);
ASSERT_NE(sm, NULL) {
TH_LOG("statmount_alloc failed for mnt_id %llu",
(unsigned long long)list[i]);
@@ -3,10 +3,14 @@
#ifndef __STATMOUNT_H
#define __STATMOUNT_H
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <linux/mount.h>
#include <asm/unistd.h>
#define STATMOUNT_BUFSIZE (1 << 15)
#ifndef __NR_statmount
#if defined __alpha__
#define __NR_statmount 567
@@ -84,4 +88,51 @@ static inline ssize_t listmount(uint64_t mnt_id, uint64_t mnt_ns_id,
return syscall(__NR_listmount, &req, list, num, flags);
}
static inline struct statmount *statmount_alloc(uint64_t mnt_id, uint64_t mnt_ns_id,
uint64_t mask, unsigned int flags)
{
struct statmount *buf;
size_t bufsize = STATMOUNT_BUFSIZE;
int ret;
for (;;) {
buf = malloc(bufsize);
if (!buf)
return NULL;
ret = statmount(mnt_id, mnt_ns_id, 0, mask, buf, bufsize, flags);
if (ret == 0)
return buf;
free(buf);
if (errno != EOVERFLOW)
return NULL;
bufsize <<= 1;
}
}
static inline struct statmount *statmount_alloc_by_fd(int fd, uint64_t mask)
{
struct statmount *buf;
size_t bufsize = STATMOUNT_BUFSIZE;
int ret;
for (;;) {
buf = malloc(bufsize);
if (!buf)
return NULL;
ret = statmount(0, 0, fd, mask, buf, bufsize, STATMOUNT_BY_FD);
if (ret == 0)
return buf;
free(buf);
if (errno != EOVERFLOW)
return NULL;
bufsize <<= 1;
}
}
#endif /* __STATMOUNT_H */
@@ -33,45 +33,6 @@ static const char *const known_fs[] = {
"sysv", "tmpfs", "tracefs", "ubifs", "udf", "ufs", "v7", "vboxsf",
"vfat", "virtiofs", "vxfs", "xenfs", "xfs", "zonefs", NULL };
static struct statmount *statmount_alloc(uint64_t mnt_id, int fd, uint64_t mask, unsigned int flags)
{
size_t bufsize = 1 << 15;
struct statmount *buf = NULL, *tmp = NULL;
int tofree = 0;
int ret;
if (flags & STATMOUNT_BY_FD && fd < 0)
return NULL;
tmp = alloca(bufsize);
for (;;) {
if (flags & STATMOUNT_BY_FD)
ret = statmount(0, 0, (uint32_t) fd, mask, tmp, bufsize, flags);
else
ret = statmount(mnt_id, 0, 0, mask, tmp, bufsize, flags);
if (ret != -1)
break;
if (tofree)
free(tmp);
if (errno != EOVERFLOW)
return NULL;
bufsize <<= 1;
tofree = 1;
tmp = malloc(bufsize);
if (!tmp)
return NULL;
}
buf = malloc(tmp->size);
if (buf)
memcpy(buf, tmp, tmp->size);
if (tofree)
free(tmp);
return buf;
}
static void write_file(const char *path, const char *val)
{
int fd = open(path, O_WRONLY);
@@ -715,7 +676,7 @@ static void test_statmount_by_fd(void)
goto err_fd;
}
sm = statmount_alloc(0, fd, STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT, STATMOUNT_BY_FD);
sm = statmount_alloc_by_fd(fd, STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT);
if (!sm) {
ksft_test_result_fail("statmount by fd failed: %s\n", strerror(errno));
goto err_chroot;
@@ -750,7 +711,7 @@ static void test_statmount_by_fd(void)
}
free(sm);
sm = statmount_alloc(0, fd, STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT, STATMOUNT_BY_FD);
sm = statmount_alloc_by_fd(fd, STATMOUNT_MNT_ROOT | STATMOUNT_MNT_POINT);
if (!sm) {
ksft_test_result_fail("statmount by fd failed: %s\n", strerror(errno));
goto err_fd;
@@ -844,7 +805,7 @@ static void test_statmount_by_fd_unmounted(void)
goto err_fd;
}
sm = statmount_alloc(0, fd, STATMOUNT_MNT_POINT | STATMOUNT_MNT_ROOT, STATMOUNT_BY_FD);
sm = statmount_alloc_by_fd(fd, STATMOUNT_MNT_POINT | STATMOUNT_MNT_ROOT);
if (!sm) {
ksft_test_result_fail("statmount by fd unmounted: %s\n",
strerror(errno));