From 4c177c904778c45ebd992b7f651af4f0039c550c Mon Sep 17 00:00:00 2001 From: Nikolaus Rath Date: Fri, 17 Mar 2023 09:56:55 +0000 Subject: Add support for running xfstests. --- example/passthrough_hp.cc | 58 +++++++++++++++++++++++++++++++++++++++-- xfstests/README.md | 18 +++++++++++++ xfstests/local.config | 12 +++++++++ xfstests/mount.fuse.passthrough | 17 ++++++++++++ 4 files changed, 103 insertions(+), 2 deletions(-) create mode 100644 xfstests/README.md create mode 100644 xfstests/local.config create mode 100755 xfstests/mount.fuse.passthrough diff --git a/example/passthrough_hp.cc b/example/passthrough_hp.cc index 53efd9f..4e32789 100644 --- a/example/passthrough_hp.cc +++ b/example/passthrough_hp.cc @@ -157,6 +157,7 @@ struct Fs { bool nocache; size_t num_threads; bool clone_fd; + std::string fuse_mount_options; }; static Fs fs{}; @@ -1169,8 +1170,36 @@ static cxxopts::ParseResult parse_wrapper(cxxopts::Options& parser, int& argc, c } +static void string_split(std::string s, std::vector& out, std::string delimiter) { + size_t pos_start = 0, pos_end, delim_len = delimiter.length(); + std::string token; + + while ((pos_end = s.find(delimiter, pos_start)) != std::string::npos) { + token = s.substr(pos_start, pos_end - pos_start); + pos_start = pos_end + delim_len; + out.push_back(token); + } + + out.push_back(s.substr(pos_start)); +} + + +static std::string string_join(const std::vector& elems, char delim) +{ + std::ostringstream out; + for (auto ii = elems.begin(); ii != elems.end(); ++ii) { + out << (*ii); + if (ii + 1 != elems.end()) { + out << delim; + } + } + return out.str(); +} + + static cxxopts::ParseResult parse_options(int argc, char **argv) { cxxopts::Options opt_parser(argv[0]); + std::vector mount_options; opt_parser.add_options() ("debug", "Enable filesystem debug messages") ("debug-fuse", "Enable libfuse debug messages") @@ -1179,6 +1208,8 @@ static cxxopts::ParseResult parse_options(int argc, char **argv) { ("nocache", "Disable all caching") ("nosplice", "Do not use splice(2) to transfer data") ("single", "Run single-threaded") + ("o", "Mount options (see mount.fuse(5) - only use if you know what " + "you are doing)", cxxopts::value(mount_options)) ("num-threads", "Number of libfuse worker threads", cxxopts::value()->default_value(SFS_DEFAULT_THREADS)) ("clone-fd", "use separate fuse device fd for each thread", @@ -1220,6 +1251,30 @@ static cxxopts::ParseResult parse_options(int argc, char **argv) { fs.source = std::string {resolved_path}; free(resolved_path); + std::vector flattened_mount_opts; + for (auto opt : mount_options) { + string_split(opt, flattened_mount_opts, ","); + } + + bool found_fsname = false; + for (auto opt : flattened_mount_opts) { + if (opt.find("fsname=") == 0) { + found_fsname = true; + continue; + } + + /* Filter out some obviously incorrect options. */ + if (opt == "fd") { + std::cout << argv[0] << ": Unsupported mount option: " << opt << "\n"; + print_usage(argv[0]); + exit(2); + } + } + if (!found_fsname) { + flattened_mount_opts.push_back("fsname=" + fs.source); + } + flattened_mount_opts.push_back("default_permissions"); + fs.fuse_mount_options = string_join(flattened_mount_opts, ','); return options; } @@ -1245,7 +1300,6 @@ int main(int argc, char *argv[]) { // Parse command line options auto options {parse_options(argc, argv)}; - // We need an fd for every dentry in our the filesystem that the // kernel knows about. This is way more than most processes need, // so try to get rid of any resource softlimit. @@ -1272,7 +1326,7 @@ int main(int argc, char *argv[]) { fuse_args args = FUSE_ARGS_INIT(0, nullptr); if (fuse_opt_add_arg(&args, argv[0]) || fuse_opt_add_arg(&args, "-o") || - fuse_opt_add_arg(&args, "default_permissions,fsname=hpps") || + fuse_opt_add_arg(&args, fs.fuse_mount_options.c_str()) || (fs.debug_fuse && fuse_opt_add_arg(&args, "-odebug"))) errx(3, "ERROR: Out of memory"); diff --git a/xfstests/README.md b/xfstests/README.md new file mode 100644 index 0000000..deda553 --- /dev/null +++ b/xfstests/README.md @@ -0,0 +1,18 @@ +To test FUSE with xfstests¹: + +1. copy the `mount.fuse.passthrough` file into + `/sbin` and edit the `PASSTHROUGH_PATH`, `SCRATCH_SOURCE` and `TEST_SOURCE` variables as needed. + +2. Make sure that the `SCRATCH_SOURCE` and `TEST_SOURCE` directories +exist. + +3. Copy `local.config` into your xfstests directory + +Tests can then be run with e.g.: + +```sh +# make +# sudo ./check -fuse -b +``` + +¹https://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git/about/ diff --git a/xfstests/local.config b/xfstests/local.config new file mode 100644 index 0000000..f20cec0 --- /dev/null +++ b/xfstests/local.config @@ -0,0 +1,12 @@ +export TEST_DEV=non1 +export TEST_DIR=/mnt/test +export SCRATCH_DEV=non2 +export SCRATCH_MNT=/mnt/scratch +export FSTYP=fuse +export FUSE_SUBTYP=.passthrough +export MOUNT_OPTIONS="" +export TEST_FS_MOUNT_OPTS="" + +PASSTHROUGH_PATH=/home/nikratio/libfuse/build/example/passthrough_hp +SCRATCH_SOURCE=/mnt/src/scratch +TEST_SOURCE=/mnt/src/test diff --git a/xfstests/mount.fuse.passthrough b/xfstests/mount.fuse.passthrough new file mode 100755 index 0000000..47208f8 --- /dev/null +++ b/xfstests/mount.fuse.passthrough @@ -0,0 +1,17 @@ +#!/bin/bash + +ulimit -n 1048576 + +# It would be easier if we could just set SCRATCH_DEV and TEST_DEV to the source directory +# path in local.options. Unfortunately, setting these variables to a path seems get +# xfstests all worked up (even though it should treat these as opaque values), and it +# refuses to even start running any tests). +dev="$1" +shift +if [ "$dev" = "${SCRATCH_DEV}" ]; then + source="${SCRATCH_SOURCE}" +else + source="${TEST_SOURCE}" +fi + +exec "$PASSTHROUGH_PATH" -o fsname=$dev,allow_other "${source}" "$@" -- cgit v1.2.1