/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (c) 2015-2016 Cyril Hrubis * Copyright (c) Linux Test Project, 2016-2024 */ #ifndef TST_TEST_H__ #define TST_TEST_H__ #ifdef __TEST_H__ # error Oldlib test.h already included #endif /* __TEST_H__ */ #include #include #include #include #include #include "tst_common.h" #include "tst_res_flags.h" #include "tst_parse.h" #include "tst_test_macros.h" #include "tst_checkpoint.h" #include "tst_device.h" #include "tst_mkfs.h" #include "tst_fs.h" #include "tst_pid.h" #include "tst_cmd.h" #include "tst_cpu.h" #include "tst_process_state.h" #include "tst_atomic.h" #include "tst_kvercmp.h" #include "tst_kernel.h" #include "tst_minmax.h" #include "tst_get_bad_addr.h" #include "tst_path_has_mnt_flags.h" #include "tst_sys_conf.h" #include "tst_coredump.h" #include "tst_buffers.h" #include "tst_capability.h" #include "tst_hugepage.h" #include "tst_assert.h" #include "tst_security.h" #include "tst_taint.h" #include "tst_memutils.h" #include "tst_arch.h" #include "tst_fd.h" void tst_res_(const char *file, const int lineno, int ttype, const char *fmt, ...) __attribute__ ((format (printf, 4, 5))); /** * tst_res() - Reports a test result. * * @ttype: An enum tst_res_type. * @arg_fmt: A printf-like format. * @...: A printf-like parameters. * * This is the main test reporting function. Each time this function is called * with one of TPASS, TFAIL, TCONF, TBROK or TWARN a counter in page of shared * memory is incremented. This means that there is no need to propagate test * results from children and that results are accounted for once this function * returns. The counters are incremented atomically which makes this function * thread-safe. */ #define tst_res(ttype, arg_fmt, ...) \ ({ \ TST_RES_SUPPORTS_TCONF_TDEBUG_TFAIL_TINFO_TPASS_TWARN(\ !((TTYPE_RESULT(ttype) ?: TCONF) & \ (TCONF | TDEBUG | TFAIL | TINFO | TPASS | TWARN))); \ tst_res_(__FILE__, __LINE__, (ttype), (arg_fmt), ##__VA_ARGS__);\ }) void tst_resm_hexd_(const char *file, const int lineno, int ttype, const void *buf, size_t size, const char *arg_fmt, ...) __attribute__ ((format (printf, 6, 7))); /** * tst_res_hexd() - Reports a test result along with hex dump of a buffer. * * This call is the same as tst_res() but includes a pointer and size of the * buffer that is going to be printed in the output in a hexadecimal format. * * @ttype: An enum tst_res_type. * @buf: A pointer to a buffer to print in hexadecimal format. * @size: A size of the buffer. * @arg_fmt: A printf-like format. * @...: A printf-like parameters. */ #define tst_res_hexd(ttype, buf, size, arg_fmt, ...) \ tst_resm_hexd_(__FILE__, __LINE__, (ttype), (buf), (size), \ (arg_fmt), ##__VA_ARGS__) void tst_brk_(const char *file, const int lineno, int ttype, const char *fmt, ...) __attribute__ ((format (printf, 4, 5))); /** * tst_brk() - Reports a breakage and exits the test. * * @ttype: An enum tst_res_type. * @arg_fmt: A printf-like format. * @...: A printf-like parameters. * * Reports either TBROK or TCONF and exits the test immediately. When called * all children in the same process group as the main test library process are * killed. This function, unless in a test cleanup, calls _exit() and does not * return. * * When test is in cleanup() function TBROK is converted into TWARN by the test * library and we attempt to carry on with a cleanup even when tst_brk() was * called. This makes it possible to use SAFE_FOO() macros in the test cleanup * without interrupting the cleanup process on a failure. */ #define tst_brk(ttype, arg_fmt, ...) \ ({ \ TST_BRK_SUPPORTS_ONLY_TCONF_TBROK(!((ttype) & \ (TBROK | TCONF | TFAIL))); \ tst_brk_(__FILE__, __LINE__, (ttype), (arg_fmt), ##__VA_ARGS__);\ }) void tst_printf(const char *const fmt, ...) __attribute__((nonnull(1), format (printf, 1, 2))); /** * tst_flush() - Flushes the output file streams. * * There are rare cases when we want to flush the output file streams * explicitly, e.g. before we do an action that may crash the test to ensure * that the messages have been written out. * * This is also called by the SAFE_FORK() because otherwise each child would * end up with the same copy of the file in it's memory and any messages in * buffers would be multiplied. */ void tst_flush(void); pid_t safe_fork(const char *filename, unsigned int lineno); /** * SAFE_FORK() - Forks a test child. * * This call makes sure that output file streams are flushed and also handles * errors from fork(). Use this instead of fork() whenever possible! */ #define SAFE_FORK() \ safe_fork(__FILE__, __LINE__) #define TST_TRACE(expr) \ ({int ret = expr; \ ret != 0 ? tst_res(TINFO, #expr " failed"), ret : ret; }) \ /** * tst_strerrno() - Converts an errno number into a name. * * @err: An errno number. * return: An errno name e.g. "EINVAL". */ const char *tst_strerrno(int err); /** * tst_strsig() - Converts a signal number into a name. * * @sig: A signal number. * return: A signal name e.g. "SIGINT". */ const char *tst_strsig(int sig); /** * tst_strstatus() - Returns string describing status as returned by wait(). * * WARNING: Not thread safe. * * @status: A status as returned by wait() * return: A string description for the status e.g. "killed by SIGKILL". */ const char *tst_strstatus(int status); #include "tst_safe_macros.h" #include "tst_safe_file_ops.h" #include "tst_safe_net.h" #include "tst_clone.h" #include "tst_cgroup.h" /** * tst_reap_children() - Waits for all child processes to exit. * * Wait for all children and exit with TBROK if any of them returned a non-zero * exit status. */ void tst_reap_children(void); /** * struct tst_option - Test command line option. * * @optstr: A short command line option, e.g. "a" or "a:". * @arg: A pointer to store the option value to. * @help: A help string for the option displayed when test is passed '-h' on * the command-line. */ struct tst_option { char *optstr; char **arg; char *help; }; /** * struct tst_tag - A test tag. * * @name: A tag name. * @value: A tag value. * * This structure is used to encode pointers to upstream commits in regression * tests as well as CVE numbers or any additional useful hints. * * The content of these tags is printed by the test on a failure to help the * testers with debugging. * * The supported tags are: * * - "linux-git" with first 12 numbers from an upstream kernel git hash. * - "CVE" with a CVE number e.g. "2000-1234". * - "glibc-git" with first 12 numbers from an upstream glibc git hash. * - "musl-git" with first 12 numbers from an upstream musl git hash. * - "known-fail" a message describing something that is supposed to work but * rather than that produces a longstanding failures. */ struct tst_tag { const char *name; const char *value; }; extern unsigned int tst_variant; #define TST_UNLIMITED_RUNTIME (-1) /** * struct tst_ulimit_val - An ulimit resource and value. * * @resource: Which resource limits should be adjusted. See setrlimit(2) for * the list of the RLIMIT_* constants. * @rlim_cur: A limit value. */ struct tst_ulimit_val { int resource; rlim_t rlim_cur; }; /** * struct tst_test - A test description. * * @tcnt: A number of tests. If set the test() callback is called tcnt times * and each time passed an increasing counter value. * @options: An NULL optstr terminated array of struct tst_option. * * @min_kver: A minimal kernel version the test can run on. e.g. "3.10". * * @supported_archs: A NULL terminated array of architectures the test runs on * e.g. {"x86_64, "x86", NULL}. Calls tst_is_on_arch() to * check if current CPU architecture is supported and exits * the test with TCONF if it's not. * * @tconf_msg: If set the test exits with TCONF right after entering the test * library. This is used by the TST_TEST_TCONF() macro to disable * tests at compile time. * * @needs_tmpdir: If set a temporary directory is prepared for the test inside * $TMPDIR and the test $CWD is set to point to it. The content * of the temporary directory is removed automatically after * the test is finished. * * @needs_root: If set the test exit with TCONF unless it's executed under root * user. * * @forks_child: Has to be set if the test intends to fork children. * * @needs_device: If set a block device is prepared for the test, the device * path and size are set in the struct tst_device variable * called tst_device. If $LTP_DEV variable exists in the test * environment the test attempts to use that device first and * only if that fails the test falls back to use loop devices. * This flag implies needs_tmpdir flag because loop device * backing files are created in the test temporary directory. * * @needs_checkpoints: Has to be set if the test wants to use checkpoint * synchronization primitives. * * @needs_overlay: If set overlay file system is mounted on the top of the * file system at tst_test.mntpoint. * * @format_device: Does all tst_test.needs_device would do and also formats * the device with tst_test.dev_fs_type file system as well. * * @mount_device: Does all tst_test.format_device would do and also mounts the * device at tst_test.mntpoint. * * @needs_rofs: If set a read-only file system is mounted at tst_test.mntpoint. * * @child_needs_reinit: Has to be set if the test needs to call tst_reinit() * from a process started by exec(). * * @needs_devfs: If set the devfs is mounted at tst_test.mntpoint. This is * needed for tests that need to create device files since tmpfs * at /tmp is usually mounted with 'nodev' option. * * @restore_wallclock: Saves wall clock at the start of the test and restores * it at the end with the help of monotonic timers. * Testcases that modify system wallclock use this to * restore the system to the previous state. * * @all_filesystems: If set the test is executed for all supported filesytems, * i.e. file system that is supported by the kernel and has * mkfs installed on the system.The file system is mounted at * tst_test.mntpoint and file system details, e.g. type are set * in the struct tst_device. Each execution is independent, * that means that for each iteration tst_test.setup() is * called at the test start and tst_test.cleanup() is called * at the end and tst_brk() only exits test for a single * file system. That especially means that calling * tst_brk(TCONF, ...) in the test setup will skip the * current file system. * * @skip_in_lockdown: Skip the test if kernel lockdown is enabled. * * @skip_in_secureboot: Skip the test if secureboot is enabled. * * @skip_in_compat: Skip the test if we are executing 32bit binary on a 64bit * kernel, i.e. we are testing the kernel compat layer. * * @needs_abi_bits: Skip the test if runs on a different kernel ABI than * requested (on 32bit instead of 64bit or vice versa). * Possible values: 32, 64. * * @needs_hugetlbfs: If set hugetlbfs is mounted at tst_test.mntpoint. * * @skip_filesystems: A NULL terminated array of unsupported file systems. The * test reports TCONF if the file system to be tested is * present in the array. This is especially useful to filter * out unsupported file system when tst_test.all_filesystems * is enabled. * * @min_cpus: Minimal number of online CPUs the test needs to run. * * @min_mem_avail: Minimal amount of available RAM memory in megabytes required * for the test to run. * * @min_swap_avail: Minimal amount of available swap memory in megabytes * required for the test to run. * * @hugepages: An interface to reserve hugepages prior running the test. * Request how many hugepages should be reserved in the global * pool and also if having hugepages is required for the test run * or not, i.e. if test should exit with TCONF if the requested * amount of hugepages cannot be reserved. If TST_REQUEST is set * the library will try it's best to reserve the hugepages and * return the number of available hugepages in tst_hugepages, which * may be 0 if there is no free memory or hugepages are not * supported at all. If TST_NEEDS the requested hugepages are * required for the test and the test exits if it couldn't be * required. It can also be used to disable hugepages by setting * .hugepages = {TST_NO_HUGEPAGES}. The test library restores the * original poll allocations after the test has finished. * * @taint_check: If set the test fails if kernel is tainted during the test run. * That means tst_taint_init() is called during the test setup * and tst_taint_check() at the end of the test. If all_filesystems * is set taint check will be performed after each iteration and * testing will be terminated by TBROK if taint is detected. * * @test_variants: If set denotes number of test variant, the test is executed * variants times each time with tst_variant set to different * number. This allows us to run the same test for different * settings. The intended use is to test different syscall * wrappers/variants but the API is generic and does not limit * usage in any way. * * @dev_min_size: A minimal device size in megabytes. * * @dev_fs_type: If set overrides the default file system type for the device and * sets the tst_device.fs_type. * * @dev_fs_opts: A NULL terminated array of options passed to mkfs in the case * of 'tst_test.format_device'. These options are passed to mkfs * before the device path. * * @dev_extra_opts: A NULL terminated array of extra options passed to mkfs in * the case of 'tst_test.format_device'. Extra options are * passed to mkfs after the device path. Commonly the option * after mkfs is the number of blocks and can be used to limit * the file system not to use the whole block device. * * @mntpoint: A mount point where the test library mounts requested file system. * The directory is created by the library, the test must not create * it itself. * * @mnt_flags: MS_* flags passed to mount(2) when the test library mounts a * device in the case of 'tst_test.mount_device'. * * @mnt_data: The data passed to mount(2) when the test library mounts a device * in the case of 'tst_test.mount_device'. * * @max_runtime: Maximal test runtime in seconds. Any test that runs for more * than a second or two should set this and also use * tst_remaining_runtime() to exit when runtime was used up. * Tests may finish sooner, for example if requested number of * iterations was reached before the runtime runs out. If test * runtime cannot be know in advance it should be set to * TST_UNLIMITED_RUNTIME. * * @setup: Setup callback is called once at the start of the test in order to * prepare the test environment. * * @cleanup: Cleanup callback is either called at the end of the test, or in a * case that tst_brk() was called. That means that cleanup must be * able to handle all possible states the test can be in. This * usually means that we have to check if file descriptor was opened * before we attempt to close it, etc. * * * @test: A main test function, only one of the tst_test.test and test_all can * be set. When this function is set the tst_test.tcnt must be set to a * positive integer and this function will be executed tcnt times * during a single test iteration. May be executed several times if test * was passed '-i' or '-d' command line parameters. * * @test_all: A main test function, only one of the tst_test.test and test_all * can be set. May be executed several times if test was passed '-i' * or '-d' command line parameters. * * @resource_files: A NULL terminated array of filenames that will be copied * to the test temporary directory from the LTP datafiles * directory. * * @needs_drivers: A NULL terminated array of kernel modules required to run * the test. The module has to be build in or present in order * for the test to run. * * @save_restore: A {} terminated array of /proc or /sys files that should * saved at the start of the test and restored at the end. See * tst_sys_conf_save() and struct tst_path_val for details. * * @ulimit: A {} terminated array of process limits RLIMIT_* to be adjusted for * the test. * * @needs_kconfigs: A NULL terminated array of kernel config options that are * required for the test. All strings in the array have to be * evaluated to true for the test to run. Boolean operators * and parenthesis are supported, e.g. * "CONFIG_X86_INTEL_UMIP=y | CONFIG_X86_UIMP=y" is evaluated * to true if at least one of the options is present. * * @bufs: A description of guarded buffers to be allocated for the test. Guarded * buffers are buffers with poisoned page allocated right before the start * of the buffer and canary right after the end of the buffer. See * struct tst_buffers and tst_buffer_alloc() for details. * * @caps: A {} terminated array of capabilities to change before the start of * the test. See struct tst_cap and tst_cap_setup() for details. * * @tags: A {} terminated array of test tags. See struct tst_tag for details. * * @needs_cmds: A NULL terminated array of commands required for the test to run. * * @needs_cgroup_ver: If set the test will run only if the specified cgroup * version is present on the system. * * @needs_cgroup_ctrls: A {} terminated array of cgroup controllers the test * needs to run. * * @needs_cgroup_nsdelegate: If set test the will run only if cgroup2 is mounted * with nsdelegate option. */ struct tst_test { unsigned int tcnt; struct tst_option *options; const char *min_kver; const char *const *supported_archs; const char *tconf_msg; unsigned int needs_tmpdir:1; unsigned int needs_root:1; unsigned int forks_child:1; unsigned int needs_device:1; unsigned int needs_checkpoints:1; unsigned int needs_overlay:1; unsigned int format_device:1; unsigned int mount_device:1; unsigned int needs_rofs:1; unsigned int child_needs_reinit:1; unsigned int needs_devfs:1; unsigned int restore_wallclock:1; unsigned int all_filesystems:1; unsigned int skip_in_lockdown:1; unsigned int skip_in_secureboot:1; unsigned int skip_in_compat:1; int needs_abi_bits; unsigned int needs_hugetlbfs:1; const char *const *skip_filesystems; unsigned long min_cpus; unsigned long min_mem_avail; unsigned long min_swap_avail; struct tst_hugepage hugepages; unsigned int taint_check; unsigned int test_variants; unsigned int dev_min_size; const char *dev_fs_type; const char *const *dev_fs_opts; const char *const *dev_extra_opts; const char *mntpoint; unsigned int mnt_flags; void *mnt_data; int max_runtime; void (*setup)(void); void (*cleanup)(void); void (*test)(unsigned int test_nr); void (*test_all)(void); const char *scall; int (*sample)(int clk_id, long long usec); const char *const *resource_files; const char * const *needs_drivers; const struct tst_path_val *save_restore; const struct tst_ulimit_val *ulimit; const char *const *needs_kconfigs; struct tst_buffers *bufs; struct tst_cap *caps; const struct tst_tag *tags; const char *const *needs_cmds; const enum tst_cg_ver needs_cgroup_ver; const char *const *needs_cgroup_ctrls; int needs_cgroup_nsdelegate:1; }; /** * tst_run_tcases() - Entry point to the test library. * * @argc: An argc that was passed to the main(). * @argv: An argv that was passed to the main(). * @self: The test description and callbacks packed in the struct tst_test * structure. * * A main() function which calls this function is added to each test * automatically by including the tst_test.h header. The test has to define the * struct tst_test called test. * * This function does not return, i.e. calls exit() after the test has finished. */ void tst_run_tcases(int argc, char *argv[], struct tst_test *self) __attribute__ ((noreturn)); #define IPC_ENV_VAR "LTP_IPC_PATH" /** * tst_reinit() - Reinitialize the test library. * * In a cases where a test child process calls exec() it no longer can access * the test library shared memory and therefore use the test reporting * functions, checkpoint library, etc. This function re-initializes the test * library so that it can be used again. * * @important The LTP_IPC_PATH variable must be passed to the program environment. */ void tst_reinit(void); unsigned int tst_multiply_timeout(unsigned int timeout); /* * Returns remaining test runtime. Test that runs for more than a few seconds * should check if they should exit by calling this function regularly. * * The function returns remaining runtime in seconds. If runtime was used up * zero is returned. */ unsigned int tst_remaining_runtime(void); /* * Sets maximal test runtime in seconds. */ void tst_set_max_runtime(int max_runtime); /* * Create and open a random file inside the given dir path. * It unlinks the file after opening and return file descriptor. */ int tst_creat_unlinked(const char *path, int flags); /* * Returns path to the test temporary directory in a newly allocated buffer. */ char *tst_get_tmpdir(void); /* * Returns path to the test temporary directory root (TMPDIR). */ const char *tst_get_tmpdir_root(void); /* * Validates exit status of child processes */ int tst_validate_children_(const char *file, const int lineno, unsigned int count); #define tst_validate_children(child_count) \ tst_validate_children_(__FILE__, __LINE__, (child_count)) #ifndef TST_NO_DEFAULT_MAIN static struct tst_test test; int main(int argc, char *argv[]) { tst_run_tcases(argc, argv, &test); } #endif /* TST_NO_DEFAULT_MAIN */ /** * TST_TEST_TCONF() - Exit tests with a TCONF message. * * This macro is used in test that couldn't be compiled either because current * CPU architecture is unsupported or because of missing development libraries. */ #define TST_TEST_TCONF(message) \ static struct tst_test test = { .tconf_msg = message } \ #endif /* TST_TEST_H__ */