From: Karel Zak Date: Wed, 15 Jul 2026 10:46:06 +0000 (+0200) Subject: libmount: add VFS test to test_mount_context X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=41fdfa32f86e51f16d928612c54ae8493e45930c;p=thirdparty%2Futil-linux.git libmount: add VFS test to test_mount_context Add --vfs test that exercises the pluggable VFS I/O operations with three sub-options: --table parse a mount table through VFS fopen --cache probe device via cache (udev, then blkid) --blkid probe device directly via libblkid VFS The test sets up VFS callbacks that wrap standard syscalls and report call counts, verifying that I/O is routed through the pluggable layer. Signed-off-by: Karel Zak --- diff --git a/libmount/src/context.c b/libmount/src/context.c index 782ecd96a..098bed02a 100644 --- a/libmount/src/context.c +++ b/libmount/src/context.c @@ -3602,6 +3602,8 @@ struct libmnt_ns *mnt_context_switch_target_ns(struct libmnt_context *cxt) #ifdef TEST_PROGRAM +#include + static int test_search_helper(struct libmnt_test *ts __attribute__((unused)), int argc, char *argv[]) { @@ -3631,6 +3633,70 @@ static int test_search_helper(struct libmnt_test *ts __attribute__((unused)), static struct libmnt_lock *lock; +static unsigned int test_vfs_opens; +static unsigned int test_vfs_closes; +static unsigned int test_vfs_reads; +static unsigned int test_vfs_writes; +static unsigned int test_vfs_lseeks; + +static ssize_t test_vfs_read(int fd, void *buf, size_t count) +{ + test_vfs_reads++; + return read(fd, buf, count); +} + +static ssize_t test_vfs_write(int fd, const void *buf, size_t count) +{ + test_vfs_writes++; + return write(fd, buf, count); +} + +static int test_vfs_open(const char *pathname, int flags, mode_t mode) +{ + test_vfs_opens++; + return open(pathname, flags, mode); +} + +static int test_vfs_close(int fd) +{ + test_vfs_closes++; + return close(fd); +} + +static off_t test_vfs_lseek(int fd, off_t offset, int whence) +{ + test_vfs_lseeks++; + return lseek(fd, offset, whence); +} + +static FILE *test_vfs_fopen(const char *pathname, const char *mode) +{ + fprintf(stderr, "VFS: fopen(\"%s\", \"%s\")\n", pathname, mode); + return fopen(pathname, mode); +} + +static void test_vfs_dump_stats(void) +{ + fprintf(stderr, "VFS calls: open=%u close=%u read=%u write=%u lseek=%u\n", + test_vfs_opens, test_vfs_closes, + test_vfs_reads, test_vfs_writes, test_vfs_lseeks); +} + +static int test_set_vfs(struct libmnt_context *cxt) +{ + struct ul_vfs_ops ops = { + .size = sizeof(ops), + .vfs_read = test_vfs_read, + .vfs_write = test_vfs_write, + .vfs_open = test_vfs_open, + .vfs_close = test_vfs_close, + .vfs_lseek = test_vfs_lseek, + .vfs_fopen = test_vfs_fopen, + }; + + return mnt_context_set_vfs(cxt, &ops); +} + static void lock_fallback(void) { if (lock) @@ -3876,6 +3942,101 @@ static int test_mountall(struct libmnt_test *ts __attribute__((unused)), +static int test_vfs(struct libmnt_test *ts __attribute__((unused)), + int argc, char *argv[]) +{ + int idx = 1, rc = 0; + struct libmnt_context *cxt; + struct libmnt_table *tb = NULL; + + cxt = mnt_new_context(); + if (!cxt) + return -ENOMEM; + + test_set_vfs(cxt); + + if (idx < argc && !strcmp(argv[idx], "--table")) { + idx++; + if (idx >= argc) { + rc = -EINVAL; + goto done; + } + rc = mnt_context_get_table(cxt, argv[idx++], &tb); + if (rc) { + warn("failed to parse table"); + goto done; + } + printf("table: parsed %d entries\n", + mnt_table_get_nents(tb)); + mnt_unref_table(tb); + } + + if (idx < argc && !strcmp(argv[idx], "--cache")) { + struct libmnt_cache *cache; + char *type; + + idx++; + if (idx >= argc) { + rc = -EINVAL; + goto done; + } + cache = mnt_context_get_cache(cxt); + if (!cache) { + warnx("no cache"); + rc = -ENOMEM; + goto done; + } + rc = mnt_cache_read_tags(cache, argv[idx]); + if (rc < 0) { + warn("failed to read tags for %s", argv[idx]); + goto done; + } + type = mnt_get_fstype(argv[idx], NULL, cache); + printf("cache: %s type=%s\n", argv[idx], type ? type : "unknown"); + idx++; + } + + if (idx < argc && !strcmp(argv[idx], "--blkid")) { + blkid_probe pr; + const char *data; + + idx++; + if (idx >= argc) { + rc = -EINVAL; + goto done; + } + pr = blkid_new_probe(); + if (!pr) { + rc = -ENOMEM; + goto done; + } + blkid_probe_set_vfs(pr, cxt->vfs); + if (blkid_probe_open_device(pr, argv[idx], 0)) { + warn("failed to open %s", argv[idx]); + blkid_free_probe(pr); + rc = -errno; + goto done; + } + blkid_probe_enable_superblocks(pr, 1); + blkid_probe_set_superblocks_flags(pr, BLKID_SUBLKS_TYPE); + + rc = blkid_do_safeprobe(pr); + if (!rc && !blkid_probe_lookup_value(pr, "TYPE", &data, NULL)) + printf("blkid: %s type=%s\n", argv[idx], data); + else + printf("blkid: %s type=unknown\n", argv[idx]); + + blkid_free_probe(pr); + idx++; + rc = 0; + } + +done: + test_vfs_dump_stats(); + mnt_free_context(cxt); + return rc; +} + int main(int argc, char *argv[]) { struct libmnt_test tss[] = { @@ -3885,6 +4046,7 @@ int main(int argc, char *argv[]) { "--flags", test_flags, "[-o ] " }, { "--cxtsync", test_cxtsync, " " }, { "--search-helper", test_search_helper, "" }, + { "--vfs", test_vfs, "[--table ] [--cache ] [--blkid ]" }, { NULL }}; umask(S_IWGRP|S_IWOTH); /* to be compatible with mount(8) */