From 8d5e98a61f52513749e459c98bcafd060d88b79c Mon Sep 17 00:00:00 2001 From: Arthur She Date: Mon, 15 Sep 2014 17:14:06 -0700 Subject: Update to commit b92178623f190a9898fed3632fb40b17f6789673 from upstream kernel --- Makefile | 25 + README.txt | 27 +- breakpoints/breakpoint_test | Bin 13858 -> 0 bytes cpu-hotplug/Makefile | 5 +- cpu-hotplug/on-off-test.sh | 52 +- efivarfs/create-read | Bin 8828 -> 0 bytes efivarfs/open-unlink | Bin 8982 -> 0 bytes firmware/Makefile | 27 + firmware/fw_filesystem.sh | 62 ++ firmware/fw_userhelper.sh | 89 ++ ipc/Makefile | 6 +- ipc/msgque.c | 6 + kcmp/.gitignore | 2 + kcmp/Makefile | 9 +- kcmp/kcmp_test.c | 2 +- memfd/.gitignore | 4 + memfd/Makefile | 41 + memfd/fuse_mnt.c | 110 +++ memfd/fuse_test.c | 311 +++++++ memfd/memfd_test.c | 913 +++++++++++++++++++++ memfd/run_fuse_test.sh | 14 + memory-hotplug/Makefile | 5 +- memory-hotplug/on-off-test.sh | 8 + mount/Makefile | 17 + mount/unprivileged-remount-test.c | 242 ++++++ mqueue/Makefile | 4 +- mqueue/mq_open_tests.c | 20 +- mqueue/mq_perf_tests.c | 40 +- net/Makefile | 8 +- net/psock_tpacket.c | 59 +- powerpc/Makefile | 39 + powerpc/copyloops/Makefile | 29 + powerpc/copyloops/asm/ppc_asm.h | 89 ++ powerpc/copyloops/asm/processor.h | 0 powerpc/copyloops/copyuser_64.S | 1 + powerpc/copyloops/copyuser_power7.S | 1 + powerpc/copyloops/memcpy_64.S | 1 + powerpc/copyloops/memcpy_power7.S | 1 + powerpc/copyloops/validate.c | 99 +++ powerpc/harness.c | 114 +++ powerpc/mm/Makefile | 18 + powerpc/mm/hugetlb_vs_thp_test.c | 72 ++ powerpc/pmu/Makefile | 38 + powerpc/pmu/count_instructions.c | 147 ++++ powerpc/pmu/ebb/Makefile | 33 + powerpc/pmu/ebb/back_to_back_ebbs_test.c | 106 +++ powerpc/pmu/ebb/busy_loop.S | 271 ++++++ powerpc/pmu/ebb/close_clears_pmcc_test.c | 59 ++ powerpc/pmu/ebb/cpu_event_pinned_vs_ebb_test.c | 93 +++ powerpc/pmu/ebb/cpu_event_vs_ebb_test.c | 89 ++ powerpc/pmu/ebb/cycles_test.c | 58 ++ powerpc/pmu/ebb/cycles_with_freeze_test.c | 117 +++ powerpc/pmu/ebb/cycles_with_mmcr2_test.c | 91 ++ powerpc/pmu/ebb/ebb.c | 478 +++++++++++ powerpc/pmu/ebb/ebb.h | 77 ++ powerpc/pmu/ebb/ebb_handler.S | 365 ++++++++ powerpc/pmu/ebb/ebb_on_child_test.c | 86 ++ powerpc/pmu/ebb/ebb_on_willing_child_test.c | 92 +++ powerpc/pmu/ebb/ebb_vs_cpu_event_test.c | 86 ++ powerpc/pmu/ebb/event_attributes_test.c | 131 +++ powerpc/pmu/ebb/fixed_instruction_loop.S | 43 + powerpc/pmu/ebb/fork_cleanup_test.c | 79 ++ powerpc/pmu/ebb/instruction_count_test.c | 164 ++++ powerpc/pmu/ebb/lost_exception_test.c | 100 +++ powerpc/pmu/ebb/multi_counter_test.c | 91 ++ powerpc/pmu/ebb/multi_ebb_procs_test.c | 109 +++ powerpc/pmu/ebb/no_handler_test.c | 61 ++ powerpc/pmu/ebb/pmae_handling_test.c | 106 +++ powerpc/pmu/ebb/pmc56_overflow_test.c | 93 +++ powerpc/pmu/ebb/reg.h | 49 ++ powerpc/pmu/ebb/reg_access_test.c | 39 + powerpc/pmu/ebb/task_event_pinned_vs_ebb_test.c | 91 ++ powerpc/pmu/ebb/task_event_vs_ebb_test.c | 83 ++ powerpc/pmu/ebb/trace.c | 300 +++++++ powerpc/pmu/ebb/trace.h | 41 + powerpc/pmu/event.c | 131 +++ powerpc/pmu/event.h | 43 + powerpc/pmu/l3_bank_test.c | 48 ++ powerpc/pmu/lib.c | 300 +++++++ powerpc/pmu/lib.h | 42 + powerpc/pmu/loop.S | 43 + powerpc/pmu/per_event_excludes.c | 114 +++ powerpc/subunit.h | 52 ++ powerpc/tm/Makefile | 15 + powerpc/tm/tm-resched-dscr.c | 98 +++ powerpc/utils.h | 49 ++ ptrace/peeksiginfo | Bin 13581 -> 0 bytes ptrace/peeksiginfo.c | 4 + rcutorture/.gitignore | 6 + rcutorture/bin/config2frag.sh | 25 + rcutorture/bin/configNR_CPUS.sh | 45 + rcutorture/bin/configcheck.sh | 54 ++ rcutorture/bin/configinit.sh | 74 ++ rcutorture/bin/cpus2use.sh | 41 + rcutorture/bin/functions.sh | 223 +++++ rcutorture/bin/kvm-build.sh | 71 ++ rcutorture/bin/kvm-recheck-lock.sh | 51 ++ rcutorture/bin/kvm-recheck-rcu.sh | 51 ++ rcutorture/bin/kvm-recheck.sh | 69 ++ rcutorture/bin/kvm-test-1-run.sh | 227 +++++ rcutorture/bin/kvm.sh | 413 ++++++++++ rcutorture/bin/parse-build.sh | 57 ++ rcutorture/bin/parse-console.sh | 41 + rcutorture/bin/parse-torture.sh | 106 +++ rcutorture/configs/lock/BUSTED | 6 + rcutorture/configs/lock/BUSTED.boot | 1 + rcutorture/configs/lock/CFLIST | 1 + rcutorture/configs/lock/CFcommon | 2 + rcutorture/configs/lock/LOCK01 | 6 + rcutorture/configs/lock/ver_functions.sh | 43 + rcutorture/configs/rcu/BUSTED | 7 + rcutorture/configs/rcu/BUSTED.boot | 1 + rcutorture/configs/rcu/CFLIST | 13 + rcutorture/configs/rcu/CFcommon | 2 + rcutorture/configs/rcu/SRCU-N | 7 + rcutorture/configs/rcu/SRCU-N.boot | 1 + rcutorture/configs/rcu/SRCU-P | 7 + rcutorture/configs/rcu/SRCU-P.boot | 1 + rcutorture/configs/rcu/TINY01 | 12 + rcutorture/configs/rcu/TINY02 | 12 + rcutorture/configs/rcu/TREE01 | 21 + rcutorture/configs/rcu/TREE01.boot | 1 + rcutorture/configs/rcu/TREE02 | 24 + rcutorture/configs/rcu/TREE02-T | 24 + rcutorture/configs/rcu/TREE03 | 21 + rcutorture/configs/rcu/TREE04 | 23 + rcutorture/configs/rcu/TREE04.boot | 1 + rcutorture/configs/rcu/TREE05 | 23 + rcutorture/configs/rcu/TREE05.boot | 1 + rcutorture/configs/rcu/TREE06 | 24 + rcutorture/configs/rcu/TREE07 | 22 + rcutorture/configs/rcu/TREE08 | 24 + rcutorture/configs/rcu/TREE08-T | 24 + rcutorture/configs/rcu/TREE08.boot | 1 + rcutorture/configs/rcu/TREE09 | 19 + rcutorture/configs/rcu/v0.0/CFLIST | 14 + rcutorture/configs/rcu/v0.0/N1-S-T-NH-SD-SMP-HP | 18 + rcutorture/configs/rcu/v0.0/N2-2-t-nh-sd-SMP-hp | 20 + rcutorture/configs/rcu/v0.0/N3-3-T-nh-SD-SMP-hp | 22 + rcutorture/configs/rcu/v0.0/N4-A-t-NH-sd-SMP-HP | 18 + rcutorture/configs/rcu/v0.0/N5-U-T-NH-sd-SMP-hp | 22 + rcutorture/configs/rcu/v0.0/NT1-nh | 23 + rcutorture/configs/rcu/v0.0/NT3-NH | 20 + rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP | 19 + rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp | 20 + rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp | 20 + rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP | 22 + rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp | 27 + rcutorture/configs/rcu/v0.0/PT1-nh | 23 + rcutorture/configs/rcu/v0.0/PT2-NH | 22 + rcutorture/configs/rcu/v0.0/ver_functions.sh | 33 + rcutorture/configs/rcu/v3.12/CFLIST | 17 + rcutorture/configs/rcu/v3.12/N1-S-T-NH-SD-SMP-HP | 19 + rcutorture/configs/rcu/v3.12/N2-2-t-nh-sd-SMP-hp | 20 + rcutorture/configs/rcu/v3.12/N3-3-T-nh-SD-SMP-hp | 22 + rcutorture/configs/rcu/v3.12/N4-A-t-NH-sd-SMP-HP | 18 + rcutorture/configs/rcu/v3.12/N5-U-T-NH-sd-SMP-hp | 22 + rcutorture/configs/rcu/v3.12/N6---t-nh-SD-smp-hp | 19 + rcutorture/configs/rcu/v3.12/N7-4-T-NH-SD-SMP-HP | 26 + rcutorture/configs/rcu/v3.12/N8-2-T-NH-SD-SMP-HP | 22 + rcutorture/configs/rcu/v3.12/NT1-nh | 23 + rcutorture/configs/rcu/v3.12/NT3-NH | 20 + rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP | 20 + rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp | 20 + rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp | 20 + rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP | 22 + rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp | 27 + rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp | 18 + rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP | 30 + .../configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all | 30 + .../configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none | 30 + rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp | 30 + rcutorture/configs/rcu/v3.12/PT1-nh | 23 + rcutorture/configs/rcu/v3.12/PT2-NH | 22 + rcutorture/configs/rcu/v3.3/CFLIST | 14 + rcutorture/configs/rcu/v3.3/N1-S-T-NH-SD-SMP-HP | 19 + rcutorture/configs/rcu/v3.3/N2-2-t-nh-sd-SMP-hp | 20 + rcutorture/configs/rcu/v3.3/N3-3-T-nh-SD-SMP-hp | 22 + rcutorture/configs/rcu/v3.3/N4-A-t-NH-sd-SMP-HP | 18 + rcutorture/configs/rcu/v3.3/N5-U-T-NH-sd-SMP-hp | 22 + rcutorture/configs/rcu/v3.3/NT1-nh | 23 + rcutorture/configs/rcu/v3.3/NT3-NH | 20 + rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP | 20 + rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp | 20 + rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp | 20 + rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP | 22 + rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp | 27 + rcutorture/configs/rcu/v3.3/PT1-nh | 23 + rcutorture/configs/rcu/v3.3/PT2-NH | 22 + rcutorture/configs/rcu/v3.3/ver_functions.sh | 44 + rcutorture/configs/rcu/v3.5/CFLIST | 14 + rcutorture/configs/rcu/v3.5/N1-S-T-NH-SD-SMP-HP | 19 + rcutorture/configs/rcu/v3.5/N2-2-t-nh-sd-SMP-hp | 20 + rcutorture/configs/rcu/v3.5/N3-3-T-nh-SD-SMP-hp | 22 + rcutorture/configs/rcu/v3.5/N4-A-t-NH-sd-SMP-HP | 18 + rcutorture/configs/rcu/v3.5/N5-U-T-NH-sd-SMP-hp | 22 + rcutorture/configs/rcu/v3.5/NT1-nh | 23 + rcutorture/configs/rcu/v3.5/NT3-NH | 20 + rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP | 20 + rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp | 20 + rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp | 20 + rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP | 22 + rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp | 27 + rcutorture/configs/rcu/v3.5/PT1-nh | 23 + rcutorture/configs/rcu/v3.5/PT2-NH | 22 + rcutorture/configs/rcu/v3.5/ver_functions.sh | 57 ++ rcutorture/configs/rcu/ver_functions.sh | 57 ++ rcutorture/doc/TINY_RCU.txt | 40 + rcutorture/doc/TREE_RCU-kconfig.txt | 94 +++ rcutorture/doc/initrd.txt | 90 ++ rcutorture/doc/rcu-test-image.txt | 42 + sysctl/Makefile | 19 + sysctl/common_tests | 109 +++ sysctl/run_numerictests | 10 + sysctl/run_stringtests | 77 ++ timers/Makefile | 8 + timers/posix_timers.c | 221 +++++ user/Makefile | 13 + vm/.gitignore | 4 + vm/Makefile | 7 +- vm/hugepage-mmap | Bin 8985 -> 0 bytes vm/hugepage-shm | Bin 8931 -> 0 bytes vm/hugetlbfstest.c | 84 ++ vm/map_hugetlb | Bin 8830 -> 0 bytes vm/run_vmtests | 16 + vm/thuge-gen | Bin 14463 -> 0 bytes 226 files changed, 11698 insertions(+), 87 deletions(-) delete mode 100755 breakpoints/breakpoint_test delete mode 100755 efivarfs/create-read delete mode 100755 efivarfs/open-unlink create mode 100644 firmware/Makefile create mode 100644 firmware/fw_filesystem.sh create mode 100644 firmware/fw_userhelper.sh create mode 100644 kcmp/.gitignore create mode 100644 memfd/.gitignore create mode 100644 memfd/Makefile create mode 100644 memfd/fuse_mnt.c create mode 100644 memfd/fuse_test.c create mode 100644 memfd/memfd_test.c create mode 100644 memfd/run_fuse_test.sh create mode 100644 mount/Makefile create mode 100644 mount/unprivileged-remount-test.c create mode 100644 powerpc/Makefile create mode 100644 powerpc/copyloops/Makefile create mode 100644 powerpc/copyloops/asm/ppc_asm.h create mode 100644 powerpc/copyloops/asm/processor.h create mode 120000 powerpc/copyloops/copyuser_64.S create mode 120000 powerpc/copyloops/copyuser_power7.S create mode 120000 powerpc/copyloops/memcpy_64.S create mode 120000 powerpc/copyloops/memcpy_power7.S create mode 100644 powerpc/copyloops/validate.c create mode 100644 powerpc/harness.c create mode 100644 powerpc/mm/Makefile create mode 100644 powerpc/mm/hugetlb_vs_thp_test.c create mode 100644 powerpc/pmu/Makefile create mode 100644 powerpc/pmu/count_instructions.c create mode 100644 powerpc/pmu/ebb/Makefile create mode 100644 powerpc/pmu/ebb/back_to_back_ebbs_test.c create mode 100644 powerpc/pmu/ebb/busy_loop.S create mode 100644 powerpc/pmu/ebb/close_clears_pmcc_test.c create mode 100644 powerpc/pmu/ebb/cpu_event_pinned_vs_ebb_test.c create mode 100644 powerpc/pmu/ebb/cpu_event_vs_ebb_test.c create mode 100644 powerpc/pmu/ebb/cycles_test.c create mode 100644 powerpc/pmu/ebb/cycles_with_freeze_test.c create mode 100644 powerpc/pmu/ebb/cycles_with_mmcr2_test.c create mode 100644 powerpc/pmu/ebb/ebb.c create mode 100644 powerpc/pmu/ebb/ebb.h create mode 100644 powerpc/pmu/ebb/ebb_handler.S create mode 100644 powerpc/pmu/ebb/ebb_on_child_test.c create mode 100644 powerpc/pmu/ebb/ebb_on_willing_child_test.c create mode 100644 powerpc/pmu/ebb/ebb_vs_cpu_event_test.c create mode 100644 powerpc/pmu/ebb/event_attributes_test.c create mode 100644 powerpc/pmu/ebb/fixed_instruction_loop.S create mode 100644 powerpc/pmu/ebb/fork_cleanup_test.c create mode 100644 powerpc/pmu/ebb/instruction_count_test.c create mode 100644 powerpc/pmu/ebb/lost_exception_test.c create mode 100644 powerpc/pmu/ebb/multi_counter_test.c create mode 100644 powerpc/pmu/ebb/multi_ebb_procs_test.c create mode 100644 powerpc/pmu/ebb/no_handler_test.c create mode 100644 powerpc/pmu/ebb/pmae_handling_test.c create mode 100644 powerpc/pmu/ebb/pmc56_overflow_test.c create mode 100644 powerpc/pmu/ebb/reg.h create mode 100644 powerpc/pmu/ebb/reg_access_test.c create mode 100644 powerpc/pmu/ebb/task_event_pinned_vs_ebb_test.c create mode 100644 powerpc/pmu/ebb/task_event_vs_ebb_test.c create mode 100644 powerpc/pmu/ebb/trace.c create mode 100644 powerpc/pmu/ebb/trace.h create mode 100644 powerpc/pmu/event.c create mode 100644 powerpc/pmu/event.h create mode 100644 powerpc/pmu/l3_bank_test.c create mode 100644 powerpc/pmu/lib.c create mode 100644 powerpc/pmu/lib.h create mode 100644 powerpc/pmu/loop.S create mode 100644 powerpc/pmu/per_event_excludes.c create mode 100644 powerpc/subunit.h create mode 100644 powerpc/tm/Makefile create mode 100644 powerpc/tm/tm-resched-dscr.c create mode 100644 powerpc/utils.h delete mode 100755 ptrace/peeksiginfo create mode 100644 rcutorture/.gitignore create mode 100644 rcutorture/bin/config2frag.sh create mode 100755 rcutorture/bin/configNR_CPUS.sh create mode 100755 rcutorture/bin/configcheck.sh create mode 100755 rcutorture/bin/configinit.sh create mode 100755 rcutorture/bin/cpus2use.sh create mode 100644 rcutorture/bin/functions.sh create mode 100755 rcutorture/bin/kvm-build.sh create mode 100755 rcutorture/bin/kvm-recheck-lock.sh create mode 100755 rcutorture/bin/kvm-recheck-rcu.sh create mode 100755 rcutorture/bin/kvm-recheck.sh create mode 100755 rcutorture/bin/kvm-test-1-run.sh create mode 100644 rcutorture/bin/kvm.sh create mode 100755 rcutorture/bin/parse-build.sh create mode 100755 rcutorture/bin/parse-console.sh create mode 100755 rcutorture/bin/parse-torture.sh create mode 100644 rcutorture/configs/lock/BUSTED create mode 100644 rcutorture/configs/lock/BUSTED.boot create mode 100644 rcutorture/configs/lock/CFLIST create mode 100644 rcutorture/configs/lock/CFcommon create mode 100644 rcutorture/configs/lock/LOCK01 create mode 100644 rcutorture/configs/lock/ver_functions.sh create mode 100644 rcutorture/configs/rcu/BUSTED create mode 100644 rcutorture/configs/rcu/BUSTED.boot create mode 100644 rcutorture/configs/rcu/CFLIST create mode 100644 rcutorture/configs/rcu/CFcommon create mode 100644 rcutorture/configs/rcu/SRCU-N create mode 100644 rcutorture/configs/rcu/SRCU-N.boot create mode 100644 rcutorture/configs/rcu/SRCU-P create mode 100644 rcutorture/configs/rcu/SRCU-P.boot create mode 100644 rcutorture/configs/rcu/TINY01 create mode 100644 rcutorture/configs/rcu/TINY02 create mode 100644 rcutorture/configs/rcu/TREE01 create mode 100644 rcutorture/configs/rcu/TREE01.boot create mode 100644 rcutorture/configs/rcu/TREE02 create mode 100644 rcutorture/configs/rcu/TREE02-T create mode 100644 rcutorture/configs/rcu/TREE03 create mode 100644 rcutorture/configs/rcu/TREE04 create mode 100644 rcutorture/configs/rcu/TREE04.boot create mode 100644 rcutorture/configs/rcu/TREE05 create mode 100644 rcutorture/configs/rcu/TREE05.boot create mode 100644 rcutorture/configs/rcu/TREE06 create mode 100644 rcutorture/configs/rcu/TREE07 create mode 100644 rcutorture/configs/rcu/TREE08 create mode 100644 rcutorture/configs/rcu/TREE08-T create mode 100644 rcutorture/configs/rcu/TREE08.boot create mode 100644 rcutorture/configs/rcu/TREE09 create mode 100644 rcutorture/configs/rcu/v0.0/CFLIST create mode 100644 rcutorture/configs/rcu/v0.0/N1-S-T-NH-SD-SMP-HP create mode 100644 rcutorture/configs/rcu/v0.0/N2-2-t-nh-sd-SMP-hp create mode 100644 rcutorture/configs/rcu/v0.0/N3-3-T-nh-SD-SMP-hp create mode 100644 rcutorture/configs/rcu/v0.0/N4-A-t-NH-sd-SMP-HP create mode 100644 rcutorture/configs/rcu/v0.0/N5-U-T-NH-sd-SMP-hp create mode 100644 rcutorture/configs/rcu/v0.0/NT1-nh create mode 100644 rcutorture/configs/rcu/v0.0/NT3-NH create mode 100644 rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP create mode 100644 rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp create mode 100644 rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp create mode 100644 rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP create mode 100644 rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp create mode 100644 rcutorture/configs/rcu/v0.0/PT1-nh create mode 100644 rcutorture/configs/rcu/v0.0/PT2-NH create mode 100644 rcutorture/configs/rcu/v0.0/ver_functions.sh create mode 100644 rcutorture/configs/rcu/v3.12/CFLIST create mode 100644 rcutorture/configs/rcu/v3.12/N1-S-T-NH-SD-SMP-HP create mode 100644 rcutorture/configs/rcu/v3.12/N2-2-t-nh-sd-SMP-hp create mode 100644 rcutorture/configs/rcu/v3.12/N3-3-T-nh-SD-SMP-hp create mode 100644 rcutorture/configs/rcu/v3.12/N4-A-t-NH-sd-SMP-HP create mode 100644 rcutorture/configs/rcu/v3.12/N5-U-T-NH-sd-SMP-hp create mode 100644 rcutorture/configs/rcu/v3.12/N6---t-nh-SD-smp-hp create mode 100644 rcutorture/configs/rcu/v3.12/N7-4-T-NH-SD-SMP-HP create mode 100644 rcutorture/configs/rcu/v3.12/N8-2-T-NH-SD-SMP-HP create mode 100644 rcutorture/configs/rcu/v3.12/NT1-nh create mode 100644 rcutorture/configs/rcu/v3.12/NT3-NH create mode 100644 rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP create mode 100644 rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp create mode 100644 rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp create mode 100644 rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP create mode 100644 rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp create mode 100644 rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp create mode 100644 rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP create mode 100644 rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all create mode 100644 rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none create mode 100644 rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp create mode 100644 rcutorture/configs/rcu/v3.12/PT1-nh create mode 100644 rcutorture/configs/rcu/v3.12/PT2-NH create mode 100644 rcutorture/configs/rcu/v3.3/CFLIST create mode 100644 rcutorture/configs/rcu/v3.3/N1-S-T-NH-SD-SMP-HP create mode 100644 rcutorture/configs/rcu/v3.3/N2-2-t-nh-sd-SMP-hp create mode 100644 rcutorture/configs/rcu/v3.3/N3-3-T-nh-SD-SMP-hp create mode 100644 rcutorture/configs/rcu/v3.3/N4-A-t-NH-sd-SMP-HP create mode 100644 rcutorture/configs/rcu/v3.3/N5-U-T-NH-sd-SMP-hp create mode 100644 rcutorture/configs/rcu/v3.3/NT1-nh create mode 100644 rcutorture/configs/rcu/v3.3/NT3-NH create mode 100644 rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP create mode 100644 rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp create mode 100644 rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp create mode 100644 rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP create mode 100644 rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp create mode 100644 rcutorture/configs/rcu/v3.3/PT1-nh create mode 100644 rcutorture/configs/rcu/v3.3/PT2-NH create mode 100644 rcutorture/configs/rcu/v3.3/ver_functions.sh create mode 100644 rcutorture/configs/rcu/v3.5/CFLIST create mode 100644 rcutorture/configs/rcu/v3.5/N1-S-T-NH-SD-SMP-HP create mode 100644 rcutorture/configs/rcu/v3.5/N2-2-t-nh-sd-SMP-hp create mode 100644 rcutorture/configs/rcu/v3.5/N3-3-T-nh-SD-SMP-hp create mode 100644 rcutorture/configs/rcu/v3.5/N4-A-t-NH-sd-SMP-HP create mode 100644 rcutorture/configs/rcu/v3.5/N5-U-T-NH-sd-SMP-hp create mode 100644 rcutorture/configs/rcu/v3.5/NT1-nh create mode 100644 rcutorture/configs/rcu/v3.5/NT3-NH create mode 100644 rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP create mode 100644 rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp create mode 100644 rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp create mode 100644 rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP create mode 100644 rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp create mode 100644 rcutorture/configs/rcu/v3.5/PT1-nh create mode 100644 rcutorture/configs/rcu/v3.5/PT2-NH create mode 100644 rcutorture/configs/rcu/v3.5/ver_functions.sh create mode 100644 rcutorture/configs/rcu/ver_functions.sh create mode 100644 rcutorture/doc/TINY_RCU.txt create mode 100644 rcutorture/doc/TREE_RCU-kconfig.txt create mode 100644 rcutorture/doc/initrd.txt create mode 100644 rcutorture/doc/rcu-test-image.txt create mode 100644 sysctl/Makefile create mode 100644 sysctl/common_tests create mode 100644 sysctl/run_numerictests create mode 100644 sysctl/run_stringtests create mode 100644 timers/Makefile create mode 100644 timers/posix_timers.c create mode 100644 user/Makefile create mode 100644 vm/.gitignore delete mode 100755 vm/hugepage-mmap delete mode 100755 vm/hugepage-shm create mode 100644 vm/hugetlbfstest.c delete mode 100755 vm/map_hugetlb delete mode 100755 vm/thuge-gen diff --git a/Makefile b/Makefile index 0a63658..36ff2e4 100644 --- a/Makefile +++ b/Makefile @@ -2,11 +2,21 @@ TARGETS = breakpoints TARGETS += cpu-hotplug TARGETS += efivarfs TARGETS += kcmp +TARGETS += memfd TARGETS += memory-hotplug TARGETS += mqueue +TARGETS += mount TARGETS += net TARGETS += ptrace +TARGETS += timers TARGETS += vm +TARGETS += powerpc +TARGETS += user +TARGETS += sysctl +TARGETS += firmware + +TARGETS_HOTPLUG = cpu-hotplug +TARGETS_HOTPLUG += memory-hotplug all: for TARGET in $(TARGETS); do \ @@ -18,6 +28,21 @@ run_tests: all make -C $$TARGET run_tests; \ done; +hotplug: + for TARGET in $(TARGETS_HOTPLUG); do \ + make -C $$TARGET; \ + done; + +run_hotplug: hotplug + for TARGET in $(TARGETS_HOTPLUG); do \ + make -C $$TARGET run_full_test; \ + done; + +clean_hotplug: + for TARGET in $(TARGETS_HOTPLUG); do \ + make -C $$TARGET clean; \ + done; + clean: for TARGET in $(TARGETS); do \ make -C $$TARGET clean; \ diff --git a/README.txt b/README.txt index 5e2faf9..2660d5f 100644 --- a/README.txt +++ b/README.txt @@ -4,8 +4,15 @@ The kernel contains a set of "self tests" under the tools/testing/selftests/ directory. These are intended to be small unit tests to exercise individual code paths in the kernel. -Running the selftests -===================== +On some systems, hot-plug tests could hang forever waiting for cpu and +memory to be ready to be offlined. A special hot-plug target is created +to run full range of hot-plug tests. In default mode, hot-plug tests run +in safe mode with a limited scope. In limited mode, cpu-hotplug test is +run on a single cpu as opposed to all hotplug capable cpus, and memory +hotplug test is run on 2% of hotplug capable memory instead of 10%. + +Running the selftests (hotplug tests are run in limited mode) +============================================================= To build the tests: @@ -18,14 +25,26 @@ To run the tests: - note that some tests will require root privileges. - -To run only tests targetted for a single subsystem: +To run only tests targeted for a single subsystem: (including +hotplug targets in limited mode) $ make -C tools/testing/selftests TARGETS=cpu-hotplug run_tests See the top-level tools/testing/selftests/Makefile for the list of all possible targets. +Running the full range hotplug selftests +======================================== + +To build the tests: + + $ make -C tools/testing/selftests hotplug + +To run the tests: + + $ make -C tools/testing/selftests run_hotplug + +- note that some tests will require root privileges. Contributing new tests ====================== diff --git a/breakpoints/breakpoint_test b/breakpoints/breakpoint_test deleted file mode 100755 index f190bb2..0000000 Binary files a/breakpoints/breakpoint_test and /dev/null differ diff --git a/cpu-hotplug/Makefile b/cpu-hotplug/Makefile index 12657a5..e9c28d8 100644 --- a/cpu-hotplug/Makefile +++ b/cpu-hotplug/Makefile @@ -1,6 +1,9 @@ all: run_tests: - @./on-off-test.sh || echo "cpu-hotplug selftests: [FAIL]" + @/bin/bash ./on-off-test.sh || echo "cpu-hotplug selftests: [FAIL]" + +run_full_test: + @/bin/bash ./on-off-test.sh -a || echo "cpu-hotplug selftests: [FAIL]" clean: diff --git a/cpu-hotplug/on-off-test.sh b/cpu-hotplug/on-off-test.sh index bdde7cf..98b1d65 100644 --- a/cpu-hotplug/on-off-test.sh +++ b/cpu-hotplug/on-off-test.sh @@ -11,6 +11,8 @@ prerequisite() exit 0 fi + taskset -p 01 $$ + SYSFS=`mount -t sysfs | head -1 | awk '{ print $3 }'` if [ ! -d "$SYSFS" ]; then @@ -22,6 +24,19 @@ prerequisite() echo $msg cpu hotplug is not supported >&2 exit 0 fi + + echo "CPU online/offline summary:" + online_cpus=`cat $SYSFS/devices/system/cpu/online` + online_max=${online_cpus##*-} + echo -e "\t Cpus in online state: $online_cpus" + + offline_cpus=`cat $SYSFS/devices/system/cpu/offline` + if [[ "a$offline_cpus" = "a" ]]; then + offline_cpus=0 + else + offline_max=${offline_cpus##*-} + fi + echo -e "\t Cpus in offline state: $offline_cpus" } # @@ -113,15 +128,25 @@ offline_cpu_expect_fail() } error=-12 +allcpus=0 priority=0 +online_cpus=0 +online_max=0 +offline_cpus=0 +offline_max=0 -while getopts e:hp: opt; do +while getopts e:ahp: opt; do case $opt in e) error=$OPTARG ;; + a) + allcpus=1 + ;; h) - echo "Usage $0 [ -e errno ] [ -p notifier-priority ]" + echo "Usage $0 [ -a ] [ -e errno ] [ -p notifier-priority ]" + echo -e "\t default offline one cpu" + echo -e "\t run with -a option to offline all cpus" exit ;; p) @@ -137,6 +162,29 @@ fi prerequisite +# +# Safe test (default) - offline and online one cpu +# +if [ $allcpus -eq 0 ]; then + echo "Limited scope test: one hotplug cpu" + echo -e "\t (leaves cpu in the original state):" + echo -e "\t online to offline to online: cpu $online_max" + offline_cpu_expect_success $online_max + online_cpu_expect_success $online_max + + if [[ $offline_cpus -gt 0 ]]; then + echo -e "\t offline to online to offline: cpu $offline_max" + online_cpu_expect_success $offline_max + offline_cpu_expect_success $offline_max + fi + exit 0 +else + echo "Full scope test: all hotplug cpus" + echo -e "\t online all offline cpus" + echo -e "\t offline all online cpus" + echo -e "\t online all offline cpus" +fi + # # Online all hot-pluggable CPUs # diff --git a/efivarfs/create-read b/efivarfs/create-read deleted file mode 100755 index cbb5009..0000000 Binary files a/efivarfs/create-read and /dev/null differ diff --git a/efivarfs/open-unlink b/efivarfs/open-unlink deleted file mode 100755 index 8bf01d9..0000000 Binary files a/efivarfs/open-unlink and /dev/null differ diff --git a/firmware/Makefile b/firmware/Makefile new file mode 100644 index 0000000..e23cce0 --- /dev/null +++ b/firmware/Makefile @@ -0,0 +1,27 @@ +# Makefile for firmware loading selftests + +# No binaries, but make sure arg-less "make" doesn't trigger "run_tests" +all: + +fw_filesystem: + @if /bin/sh ./fw_filesystem.sh ; then \ + echo "fw_filesystem: ok"; \ + else \ + echo "fw_filesystem: [FAIL]"; \ + exit 1; \ + fi + +fw_userhelper: + @if /bin/sh ./fw_userhelper.sh ; then \ + echo "fw_userhelper: ok"; \ + else \ + echo "fw_userhelper: [FAIL]"; \ + exit 1; \ + fi + +run_tests: all fw_filesystem fw_userhelper + +# Nothing to clean up. +clean: + +.PHONY: all clean run_tests fw_filesystem fw_userhelper diff --git a/firmware/fw_filesystem.sh b/firmware/fw_filesystem.sh new file mode 100644 index 0000000..3fc6c10 --- /dev/null +++ b/firmware/fw_filesystem.sh @@ -0,0 +1,62 @@ +#!/bin/sh +# This validates that the kernel will load firmware out of its list of +# firmware locations on disk. Since the user helper does similar work, +# we reset the custom load directory to a location the user helper doesn't +# know so we can be sure we're not accidentally testing the user helper. +set -e + +modprobe test_firmware + +DIR=/sys/devices/virtual/misc/test_firmware + +OLD_TIMEOUT=$(cat /sys/class/firmware/timeout) +OLD_FWPATH=$(cat /sys/module/firmware_class/parameters/path) + +FWPATH=$(mktemp -d) +FW="$FWPATH/test-firmware.bin" + +test_finish() +{ + echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout + echo -n "$OLD_PATH" >/sys/module/firmware_class/parameters/path + rm -f "$FW" + rmdir "$FWPATH" +} + +trap "test_finish" EXIT + +# Turn down the timeout so failures don't take so long. +echo 1 >/sys/class/firmware/timeout +# Set the kernel search path. +echo -n "$FWPATH" >/sys/module/firmware_class/parameters/path + +# This is an unlikely real-world firmware content. :) +echo "ABCD0123" >"$FW" + +NAME=$(basename "$FW") + +# Request a firmware that doesn't exist, it should fail. +echo -n "nope-$NAME" >"$DIR"/trigger_request +if diff -q "$FW" /dev/test_firmware >/dev/null ; then + echo "$0: firmware was not expected to match" >&2 + exit 1 +else + echo "$0: timeout works" +fi + +# This should succeed via kernel load or will fail after 1 second after +# being handed over to the user helper, which won't find the fw either. +if ! echo -n "$NAME" >"$DIR"/trigger_request ; then + echo "$0: could not trigger request" >&2 + exit 1 +fi + +# Verify the contents are what we expect. +if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then + echo "$0: firmware was not loaded" >&2 + exit 1 +else + echo "$0: filesystem loading works" +fi + +exit 0 diff --git a/firmware/fw_userhelper.sh b/firmware/fw_userhelper.sh new file mode 100644 index 0000000..6efbade --- /dev/null +++ b/firmware/fw_userhelper.sh @@ -0,0 +1,89 @@ +#!/bin/sh +# This validates that the kernel will fall back to using the user helper +# to load firmware it can't find on disk itself. We must request a firmware +# that the kernel won't find, and any installed helper (e.g. udev) also +# won't find so that we can do the load ourself manually. +set -e + +modprobe test_firmware + +DIR=/sys/devices/virtual/misc/test_firmware + +OLD_TIMEOUT=$(cat /sys/class/firmware/timeout) + +FWPATH=$(mktemp -d) +FW="$FWPATH/test-firmware.bin" + +test_finish() +{ + echo "$OLD_TIMEOUT" >/sys/class/firmware/timeout + rm -f "$FW" + rmdir "$FWPATH" +} + +load_fw() +{ + local name="$1" + local file="$2" + + # This will block until our load (below) has finished. + echo -n "$name" >"$DIR"/trigger_request & + + # Give kernel a chance to react. + local timeout=10 + while [ ! -e "$DIR"/"$name"/loading ]; do + sleep 0.1 + timeout=$(( $timeout - 1 )) + if [ "$timeout" -eq 0 ]; then + echo "$0: firmware interface never appeared" >&2 + exit 1 + fi + done + + echo 1 >"$DIR"/"$name"/loading + cat "$file" >"$DIR"/"$name"/data + echo 0 >"$DIR"/"$name"/loading + + # Wait for request to finish. + wait +} + +trap "test_finish" EXIT + +# This is an unlikely real-world firmware content. :) +echo "ABCD0123" >"$FW" +NAME=$(basename "$FW") + +# Test failure when doing nothing (timeout works). +echo 1 >/sys/class/firmware/timeout +echo -n "$NAME" >"$DIR"/trigger_request +if diff -q "$FW" /dev/test_firmware >/dev/null ; then + echo "$0: firmware was not expected to match" >&2 + exit 1 +else + echo "$0: timeout works" +fi + +# Put timeout high enough for us to do work but not so long that failures +# slow down this test too much. +echo 4 >/sys/class/firmware/timeout + +# Load this script instead of the desired firmware. +load_fw "$NAME" "$0" +if diff -q "$FW" /dev/test_firmware >/dev/null ; then + echo "$0: firmware was not expected to match" >&2 + exit 1 +else + echo "$0: firmware comparison works" +fi + +# Do a proper load, which should work correctly. +load_fw "$NAME" "$FW" +if ! diff -q "$FW" /dev/test_firmware >/dev/null ; then + echo "$0: firmware was not loaded" >&2 + exit 1 +else + echo "$0: user helper firmware loading works" +fi + +exit 0 diff --git a/ipc/Makefile b/ipc/Makefile index 5386fd7..74bbefd 100644 --- a/ipc/Makefile +++ b/ipc/Makefile @@ -1,18 +1,18 @@ uname_M := $(shell uname -m 2>/dev/null || echo not) ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/) ifeq ($(ARCH),i386) - ARCH := X86 + ARCH := x86 CFLAGS := -DCONFIG_X86_32 -D__i386__ endif ifeq ($(ARCH),x86_64) - ARCH := X86 + ARCH := x86 CFLAGS := -DCONFIG_X86_64 -D__x86_64__ endif CFLAGS += -I../../../../usr/include/ all: -ifeq ($(ARCH),X86) +ifeq ($(ARCH),x86) gcc $(CFLAGS) msgque.c -o msgque_test else echo "Not an x86 target, can't build msgque selftest" diff --git a/ipc/msgque.c b/ipc/msgque.c index d664182..552f081 100644 --- a/ipc/msgque.c +++ b/ipc/msgque.c @@ -193,6 +193,11 @@ int main(int argc, char **argv) int msg, pid, err; struct msgque_data msgque; + if (getuid() != 0) { + printf("Please run the test as root - Exiting.\n"); + exit(1); + } + msgque.key = ftok(argv[0], 822155650); if (msgque.key == -1) { printf("Can't make key\n"); @@ -201,6 +206,7 @@ int main(int argc, char **argv) msgque.msq_id = msgget(msgque.key, IPC_CREAT | IPC_EXCL | 0666); if (msgque.msq_id == -1) { + err = -errno; printf("Can't create queue\n"); goto err_out; } diff --git a/kcmp/.gitignore b/kcmp/.gitignore new file mode 100644 index 0000000..5a9b373 --- /dev/null +++ b/kcmp/.gitignore @@ -0,0 +1,2 @@ +kcmp_test +kcmp-test-file diff --git a/kcmp/Makefile b/kcmp/Makefile index 56eb552..8aabd82 100644 --- a/kcmp/Makefile +++ b/kcmp/Makefile @@ -1,11 +1,11 @@ uname_M := $(shell uname -m 2>/dev/null || echo not) ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/) ifeq ($(ARCH),i386) - ARCH := X86 + ARCH := x86 CFLAGS := -DCONFIG_X86_32 -D__i386__ endif ifeq ($(ARCH),x86_64) - ARCH := X86 + ARCH := x86 CFLAGS := -DCONFIG_X86_64 -D__x86_64__ endif @@ -15,7 +15,7 @@ CFLAGS += -I../../../../usr/include/ CFLAGS += -I../../../../arch/x86/include/ all: -ifeq ($(ARCH),X86) +ifeq ($(ARCH),x86) gcc $(CFLAGS) kcmp_test.c -o kcmp_test else echo "Not an x86 target, can't build kcmp selftest" @@ -25,5 +25,4 @@ run_tests: all @./kcmp_test || echo "kcmp_test: [FAIL]" clean: - rm -fr ./run_test - rm -fr ./test-file + $(RM) kcmp_test kcmp-test-file diff --git a/kcmp/kcmp_test.c b/kcmp/kcmp_test.c index fa4f1b3..dbba408 100644 --- a/kcmp/kcmp_test.c +++ b/kcmp/kcmp_test.c @@ -81,7 +81,7 @@ int main(int argc, char **argv) /* Compare with self */ ret = sys_kcmp(pid1, pid1, KCMP_VM, 0, 0); if (ret) { - printf("FAIL: 0 expected but %li returned (%s)\n", + printf("FAIL: 0 expected but %d returned (%s)\n", ret, strerror(errno)); ret = -1; } else diff --git a/memfd/.gitignore b/memfd/.gitignore new file mode 100644 index 0000000..afe87c4 --- /dev/null +++ b/memfd/.gitignore @@ -0,0 +1,4 @@ +fuse_mnt +fuse_test +memfd_test +memfd-test-file diff --git a/memfd/Makefile b/memfd/Makefile new file mode 100644 index 0000000..ad4ab01 --- /dev/null +++ b/memfd/Makefile @@ -0,0 +1,41 @@ +uname_M := $(shell uname -m 2>/dev/null || echo not) +ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/i386/) +ifeq ($(ARCH),i386) + ARCH := x86 +endif +ifeq ($(ARCH),x86_64) + ARCH := x86 +endif + +CFLAGS += -D_FILE_OFFSET_BITS=64 +CFLAGS += -I../../../../arch/x86/include/generated/uapi/ +CFLAGS += -I../../../../arch/x86/include/uapi/ +CFLAGS += -I../../../../include/uapi/ +CFLAGS += -I../../../../include/ + +all: +ifeq ($(ARCH),x86) + gcc $(CFLAGS) memfd_test.c -o memfd_test +else + echo "Not an x86 target, can't build memfd selftest" +endif + +run_tests: all +ifeq ($(ARCH),x86) + gcc $(CFLAGS) memfd_test.c -o memfd_test +endif + @./memfd_test || echo "memfd_test: [FAIL]" + +build_fuse: +ifeq ($(ARCH),x86) + gcc $(CFLAGS) fuse_mnt.c `pkg-config fuse --cflags --libs` -o fuse_mnt + gcc $(CFLAGS) fuse_test.c -o fuse_test +else + echo "Not an x86 target, can't build memfd selftest" +endif + +run_fuse: build_fuse + @./run_fuse_test.sh || echo "fuse_test: [FAIL]" + +clean: + $(RM) memfd_test fuse_test diff --git a/memfd/fuse_mnt.c b/memfd/fuse_mnt.c new file mode 100644 index 0000000..feacf12 --- /dev/null +++ b/memfd/fuse_mnt.c @@ -0,0 +1,110 @@ +/* + * memfd test file-system + * This file uses FUSE to create a dummy file-system with only one file /memfd. + * This file is read-only and takes 1s per read. + * + * This file-system is used by the memfd test-cases to force the kernel to pin + * pages during reads(). Due to the 1s delay of this file-system, this is a + * nice way to test race-conditions against get_user_pages() in the kernel. + * + * We use direct_io==1 to force the kernel to use direct-IO for this + * file-system. + */ + +#define FUSE_USE_VERSION 26 + +#include +#include +#include +#include +#include +#include + +static const char memfd_content[] = "memfd-example-content"; +static const char memfd_path[] = "/memfd"; + +static int memfd_getattr(const char *path, struct stat *st) +{ + memset(st, 0, sizeof(*st)); + + if (!strcmp(path, "/")) { + st->st_mode = S_IFDIR | 0755; + st->st_nlink = 2; + } else if (!strcmp(path, memfd_path)) { + st->st_mode = S_IFREG | 0444; + st->st_nlink = 1; + st->st_size = strlen(memfd_content); + } else { + return -ENOENT; + } + + return 0; +} + +static int memfd_readdir(const char *path, + void *buf, + fuse_fill_dir_t filler, + off_t offset, + struct fuse_file_info *fi) +{ + if (strcmp(path, "/")) + return -ENOENT; + + filler(buf, ".", NULL, 0); + filler(buf, "..", NULL, 0); + filler(buf, memfd_path + 1, NULL, 0); + + return 0; +} + +static int memfd_open(const char *path, struct fuse_file_info *fi) +{ + if (strcmp(path, memfd_path)) + return -ENOENT; + + if ((fi->flags & 3) != O_RDONLY) + return -EACCES; + + /* force direct-IO */ + fi->direct_io = 1; + + return 0; +} + +static int memfd_read(const char *path, + char *buf, + size_t size, + off_t offset, + struct fuse_file_info *fi) +{ + size_t len; + + if (strcmp(path, memfd_path) != 0) + return -ENOENT; + + sleep(1); + + len = strlen(memfd_content); + if (offset < len) { + if (offset + size > len) + size = len - offset; + + memcpy(buf, memfd_content + offset, size); + } else { + size = 0; + } + + return size; +} + +static struct fuse_operations memfd_ops = { + .getattr = memfd_getattr, + .readdir = memfd_readdir, + .open = memfd_open, + .read = memfd_read, +}; + +int main(int argc, char *argv[]) +{ + return fuse_main(argc, argv, &memfd_ops, NULL); +} diff --git a/memfd/fuse_test.c b/memfd/fuse_test.c new file mode 100644 index 0000000..67908b1 --- /dev/null +++ b/memfd/fuse_test.c @@ -0,0 +1,311 @@ +/* + * memfd GUP test-case + * This tests memfd interactions with get_user_pages(). We require the + * fuse_mnt.c program to provide a fake direct-IO FUSE mount-point for us. This + * file-system delays _all_ reads by 1s and forces direct-IO. This means, any + * read() on files in that file-system will pin the receive-buffer pages for at + * least 1s via get_user_pages(). + * + * We use this trick to race ADD_SEALS against a write on a memfd object. The + * ADD_SEALS must fail if the memfd pages are still pinned. Note that we use + * the read() syscall with our memory-mapped memfd object as receive buffer to + * force the kernel to write into our memfd object. + */ + +#define _GNU_SOURCE +#define __EXPORTED_HEADERS__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MFD_DEF_SIZE 8192 +#define STACK_SIZE 65535 + +static int sys_memfd_create(const char *name, + unsigned int flags) +{ + return syscall(__NR_memfd_create, name, flags); +} + +static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags) +{ + int r, fd; + + fd = sys_memfd_create(name, flags); + if (fd < 0) { + printf("memfd_create(\"%s\", %u) failed: %m\n", + name, flags); + abort(); + } + + r = ftruncate(fd, sz); + if (r < 0) { + printf("ftruncate(%llu) failed: %m\n", (unsigned long long)sz); + abort(); + } + + return fd; +} + +static __u64 mfd_assert_get_seals(int fd) +{ + long r; + + r = fcntl(fd, F_GET_SEALS); + if (r < 0) { + printf("GET_SEALS(%d) failed: %m\n", fd); + abort(); + } + + return r; +} + +static void mfd_assert_has_seals(int fd, __u64 seals) +{ + __u64 s; + + s = mfd_assert_get_seals(fd); + if (s != seals) { + printf("%llu != %llu = GET_SEALS(%d)\n", + (unsigned long long)seals, (unsigned long long)s, fd); + abort(); + } +} + +static void mfd_assert_add_seals(int fd, __u64 seals) +{ + long r; + __u64 s; + + s = mfd_assert_get_seals(fd); + r = fcntl(fd, F_ADD_SEALS, seals); + if (r < 0) { + printf("ADD_SEALS(%d, %llu -> %llu) failed: %m\n", + fd, (unsigned long long)s, (unsigned long long)seals); + abort(); + } +} + +static int mfd_busy_add_seals(int fd, __u64 seals) +{ + long r; + __u64 s; + + r = fcntl(fd, F_GET_SEALS); + if (r < 0) + s = 0; + else + s = r; + + r = fcntl(fd, F_ADD_SEALS, seals); + if (r < 0 && errno != EBUSY) { + printf("ADD_SEALS(%d, %llu -> %llu) didn't fail as expected with EBUSY: %m\n", + fd, (unsigned long long)s, (unsigned long long)seals); + abort(); + } + + return r; +} + +static void *mfd_assert_mmap_shared(int fd) +{ + void *p; + + p = mmap(NULL, + MFD_DEF_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, + 0); + if (p == MAP_FAILED) { + printf("mmap() failed: %m\n"); + abort(); + } + + return p; +} + +static void *mfd_assert_mmap_private(int fd) +{ + void *p; + + p = mmap(NULL, + MFD_DEF_SIZE, + PROT_READ | PROT_WRITE, + MAP_PRIVATE, + fd, + 0); + if (p == MAP_FAILED) { + printf("mmap() failed: %m\n"); + abort(); + } + + return p; +} + +static int global_mfd = -1; +static void *global_p = NULL; + +static int sealing_thread_fn(void *arg) +{ + int sig, r; + + /* + * This thread first waits 200ms so any pending operation in the parent + * is correctly started. After that, it tries to seal @global_mfd as + * SEAL_WRITE. This _must_ fail as the parent thread has a read() into + * that memory mapped object still ongoing. + * We then wait one more second and try sealing again. This time it + * must succeed as there shouldn't be anyone else pinning the pages. + */ + + /* wait 200ms for FUSE-request to be active */ + usleep(200000); + + /* unmount mapping before sealing to avoid i_mmap_writable failures */ + munmap(global_p, MFD_DEF_SIZE); + + /* Try sealing the global file; expect EBUSY or success. Current + * kernels will never succeed, but in the future, kernels might + * implement page-replacements or other fancy ways to avoid racing + * writes. */ + r = mfd_busy_add_seals(global_mfd, F_SEAL_WRITE); + if (r >= 0) { + printf("HURRAY! This kernel fixed GUP races!\n"); + } else { + /* wait 1s more so the FUSE-request is done */ + sleep(1); + + /* try sealing the global file again */ + mfd_assert_add_seals(global_mfd, F_SEAL_WRITE); + } + + return 0; +} + +static pid_t spawn_sealing_thread(void) +{ + uint8_t *stack; + pid_t pid; + + stack = malloc(STACK_SIZE); + if (!stack) { + printf("malloc(STACK_SIZE) failed: %m\n"); + abort(); + } + + pid = clone(sealing_thread_fn, + stack + STACK_SIZE, + SIGCHLD | CLONE_FILES | CLONE_FS | CLONE_VM, + NULL); + if (pid < 0) { + printf("clone() failed: %m\n"); + abort(); + } + + return pid; +} + +static void join_sealing_thread(pid_t pid) +{ + waitpid(pid, NULL, 0); +} + +int main(int argc, char **argv) +{ + static const char zero[MFD_DEF_SIZE]; + int fd, mfd, r; + void *p; + int was_sealed; + pid_t pid; + + if (argc < 2) { + printf("error: please pass path to file in fuse_mnt mount-point\n"); + abort(); + } + + /* open FUSE memfd file for GUP testing */ + printf("opening: %s\n", argv[1]); + fd = open(argv[1], O_RDONLY | O_CLOEXEC); + if (fd < 0) { + printf("cannot open(\"%s\"): %m\n", argv[1]); + abort(); + } + + /* create new memfd-object */ + mfd = mfd_assert_new("kern_memfd_fuse", + MFD_DEF_SIZE, + MFD_CLOEXEC | MFD_ALLOW_SEALING); + + /* mmap memfd-object for writing */ + p = mfd_assert_mmap_shared(mfd); + + /* pass mfd+mapping to a separate sealing-thread which tries to seal + * the memfd objects with SEAL_WRITE while we write into it */ + global_mfd = mfd; + global_p = p; + pid = spawn_sealing_thread(); + + /* Use read() on the FUSE file to read into our memory-mapped memfd + * object. This races the other thread which tries to seal the + * memfd-object. + * If @fd is on the memfd-fake-FUSE-FS, the read() is delayed by 1s. + * This guarantees that the receive-buffer is pinned for 1s until the + * data is written into it. The racing ADD_SEALS should thus fail as + * the pages are still pinned. */ + r = read(fd, p, MFD_DEF_SIZE); + if (r < 0) { + printf("read() failed: %m\n"); + abort(); + } else if (!r) { + printf("unexpected EOF on read()\n"); + abort(); + } + + was_sealed = mfd_assert_get_seals(mfd) & F_SEAL_WRITE; + + /* Wait for sealing-thread to finish and verify that it + * successfully sealed the file after the second try. */ + join_sealing_thread(pid); + mfd_assert_has_seals(mfd, F_SEAL_WRITE); + + /* *IF* the memfd-object was sealed at the time our read() returned, + * then the kernel did a page-replacement or canceled the read() (or + * whatever magic it did..). In that case, the memfd object is still + * all zero. + * In case the memfd-object was *not* sealed, the read() was successfull + * and the memfd object must *not* be all zero. + * Note that in real scenarios, there might be a mixture of both, but + * in this test-cases, we have explicit 200ms delays which should be + * enough to avoid any in-flight writes. */ + + p = mfd_assert_mmap_private(mfd); + if (was_sealed && memcmp(p, zero, MFD_DEF_SIZE)) { + printf("memfd sealed during read() but data not discarded\n"); + abort(); + } else if (!was_sealed && !memcmp(p, zero, MFD_DEF_SIZE)) { + printf("memfd sealed after read() but data discarded\n"); + abort(); + } + + close(mfd); + close(fd); + + printf("fuse: DONE\n"); + + return 0; +} diff --git a/memfd/memfd_test.c b/memfd/memfd_test.c new file mode 100644 index 0000000..3634c90 --- /dev/null +++ b/memfd/memfd_test.c @@ -0,0 +1,913 @@ +#define _GNU_SOURCE +#define __EXPORTED_HEADERS__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MFD_DEF_SIZE 8192 +#define STACK_SIZE 65535 + +static int sys_memfd_create(const char *name, + unsigned int flags) +{ + return syscall(__NR_memfd_create, name, flags); +} + +static int mfd_assert_new(const char *name, loff_t sz, unsigned int flags) +{ + int r, fd; + + fd = sys_memfd_create(name, flags); + if (fd < 0) { + printf("memfd_create(\"%s\", %u) failed: %m\n", + name, flags); + abort(); + } + + r = ftruncate(fd, sz); + if (r < 0) { + printf("ftruncate(%llu) failed: %m\n", (unsigned long long)sz); + abort(); + } + + return fd; +} + +static void mfd_fail_new(const char *name, unsigned int flags) +{ + int r; + + r = sys_memfd_create(name, flags); + if (r >= 0) { + printf("memfd_create(\"%s\", %u) succeeded, but failure expected\n", + name, flags); + close(r); + abort(); + } +} + +static __u64 mfd_assert_get_seals(int fd) +{ + long r; + + r = fcntl(fd, F_GET_SEALS); + if (r < 0) { + printf("GET_SEALS(%d) failed: %m\n", fd); + abort(); + } + + return r; +} + +static void mfd_assert_has_seals(int fd, __u64 seals) +{ + __u64 s; + + s = mfd_assert_get_seals(fd); + if (s != seals) { + printf("%llu != %llu = GET_SEALS(%d)\n", + (unsigned long long)seals, (unsigned long long)s, fd); + abort(); + } +} + +static void mfd_assert_add_seals(int fd, __u64 seals) +{ + long r; + __u64 s; + + s = mfd_assert_get_seals(fd); + r = fcntl(fd, F_ADD_SEALS, seals); + if (r < 0) { + printf("ADD_SEALS(%d, %llu -> %llu) failed: %m\n", + fd, (unsigned long long)s, (unsigned long long)seals); + abort(); + } +} + +static void mfd_fail_add_seals(int fd, __u64 seals) +{ + long r; + __u64 s; + + r = fcntl(fd, F_GET_SEALS); + if (r < 0) + s = 0; + else + s = r; + + r = fcntl(fd, F_ADD_SEALS, seals); + if (r >= 0) { + printf("ADD_SEALS(%d, %llu -> %llu) didn't fail as expected\n", + fd, (unsigned long long)s, (unsigned long long)seals); + abort(); + } +} + +static void mfd_assert_size(int fd, size_t size) +{ + struct stat st; + int r; + + r = fstat(fd, &st); + if (r < 0) { + printf("fstat(%d) failed: %m\n", fd); + abort(); + } else if (st.st_size != size) { + printf("wrong file size %lld, but expected %lld\n", + (long long)st.st_size, (long long)size); + abort(); + } +} + +static int mfd_assert_dup(int fd) +{ + int r; + + r = dup(fd); + if (r < 0) { + printf("dup(%d) failed: %m\n", fd); + abort(); + } + + return r; +} + +static void *mfd_assert_mmap_shared(int fd) +{ + void *p; + + p = mmap(NULL, + MFD_DEF_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, + 0); + if (p == MAP_FAILED) { + printf("mmap() failed: %m\n"); + abort(); + } + + return p; +} + +static void *mfd_assert_mmap_private(int fd) +{ + void *p; + + p = mmap(NULL, + MFD_DEF_SIZE, + PROT_READ, + MAP_PRIVATE, + fd, + 0); + if (p == MAP_FAILED) { + printf("mmap() failed: %m\n"); + abort(); + } + + return p; +} + +static int mfd_assert_open(int fd, int flags, mode_t mode) +{ + char buf[512]; + int r; + + sprintf(buf, "/proc/self/fd/%d", fd); + r = open(buf, flags, mode); + if (r < 0) { + printf("open(%s) failed: %m\n", buf); + abort(); + } + + return r; +} + +static void mfd_fail_open(int fd, int flags, mode_t mode) +{ + char buf[512]; + int r; + + sprintf(buf, "/proc/self/fd/%d", fd); + r = open(buf, flags, mode); + if (r >= 0) { + printf("open(%s) didn't fail as expected\n"); + abort(); + } +} + +static void mfd_assert_read(int fd) +{ + char buf[16]; + void *p; + ssize_t l; + + l = read(fd, buf, sizeof(buf)); + if (l != sizeof(buf)) { + printf("read() failed: %m\n"); + abort(); + } + + /* verify PROT_READ *is* allowed */ + p = mmap(NULL, + MFD_DEF_SIZE, + PROT_READ, + MAP_PRIVATE, + fd, + 0); + if (p == MAP_FAILED) { + printf("mmap() failed: %m\n"); + abort(); + } + munmap(p, MFD_DEF_SIZE); + + /* verify MAP_PRIVATE is *always* allowed (even writable) */ + p = mmap(NULL, + MFD_DEF_SIZE, + PROT_READ | PROT_WRITE, + MAP_PRIVATE, + fd, + 0); + if (p == MAP_FAILED) { + printf("mmap() failed: %m\n"); + abort(); + } + munmap(p, MFD_DEF_SIZE); +} + +static void mfd_assert_write(int fd) +{ + ssize_t l; + void *p; + int r; + + /* verify write() succeeds */ + l = write(fd, "\0\0\0\0", 4); + if (l != 4) { + printf("write() failed: %m\n"); + abort(); + } + + /* verify PROT_READ | PROT_WRITE is allowed */ + p = mmap(NULL, + MFD_DEF_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, + 0); + if (p == MAP_FAILED) { + printf("mmap() failed: %m\n"); + abort(); + } + *(char *)p = 0; + munmap(p, MFD_DEF_SIZE); + + /* verify PROT_WRITE is allowed */ + p = mmap(NULL, + MFD_DEF_SIZE, + PROT_WRITE, + MAP_SHARED, + fd, + 0); + if (p == MAP_FAILED) { + printf("mmap() failed: %m\n"); + abort(); + } + *(char *)p = 0; + munmap(p, MFD_DEF_SIZE); + + /* verify PROT_READ with MAP_SHARED is allowed and a following + * mprotect(PROT_WRITE) allows writing */ + p = mmap(NULL, + MFD_DEF_SIZE, + PROT_READ, + MAP_SHARED, + fd, + 0); + if (p == MAP_FAILED) { + printf("mmap() failed: %m\n"); + abort(); + } + + r = mprotect(p, MFD_DEF_SIZE, PROT_READ | PROT_WRITE); + if (r < 0) { + printf("mprotect() failed: %m\n"); + abort(); + } + + *(char *)p = 0; + munmap(p, MFD_DEF_SIZE); + + /* verify PUNCH_HOLE works */ + r = fallocate(fd, + FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + 0, + MFD_DEF_SIZE); + if (r < 0) { + printf("fallocate(PUNCH_HOLE) failed: %m\n"); + abort(); + } +} + +static void mfd_fail_write(int fd) +{ + ssize_t l; + void *p; + int r; + + /* verify write() fails */ + l = write(fd, "data", 4); + if (l != -EPERM) { + printf("expected EPERM on write(), but got %d: %m\n", (int)l); + abort(); + } + + /* verify PROT_READ | PROT_WRITE is not allowed */ + p = mmap(NULL, + MFD_DEF_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, + 0); + if (p != MAP_FAILED) { + printf("mmap() didn't fail as expected\n"); + abort(); + } + + /* verify PROT_WRITE is not allowed */ + p = mmap(NULL, + MFD_DEF_SIZE, + PROT_WRITE, + MAP_SHARED, + fd, + 0); + if (p != MAP_FAILED) { + printf("mmap() didn't fail as expected\n"); + abort(); + } + + /* Verify PROT_READ with MAP_SHARED with a following mprotect is not + * allowed. Note that for r/w the kernel already prevents the mmap. */ + p = mmap(NULL, + MFD_DEF_SIZE, + PROT_READ, + MAP_SHARED, + fd, + 0); + if (p != MAP_FAILED) { + r = mprotect(p, MFD_DEF_SIZE, PROT_READ | PROT_WRITE); + if (r >= 0) { + printf("mmap()+mprotect() didn't fail as expected\n"); + abort(); + } + } + + /* verify PUNCH_HOLE fails */ + r = fallocate(fd, + FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE, + 0, + MFD_DEF_SIZE); + if (r >= 0) { + printf("fallocate(PUNCH_HOLE) didn't fail as expected\n"); + abort(); + } +} + +static void mfd_assert_shrink(int fd) +{ + int r, fd2; + + r = ftruncate(fd, MFD_DEF_SIZE / 2); + if (r < 0) { + printf("ftruncate(SHRINK) failed: %m\n"); + abort(); + } + + mfd_assert_size(fd, MFD_DEF_SIZE / 2); + + fd2 = mfd_assert_open(fd, + O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR); + close(fd2); + + mfd_assert_size(fd, 0); +} + +static void mfd_fail_shrink(int fd) +{ + int r; + + r = ftruncate(fd, MFD_DEF_SIZE / 2); + if (r >= 0) { + printf("ftruncate(SHRINK) didn't fail as expected\n"); + abort(); + } + + mfd_fail_open(fd, + O_RDWR | O_CREAT | O_TRUNC, + S_IRUSR | S_IWUSR); +} + +static void mfd_assert_grow(int fd) +{ + int r; + + r = ftruncate(fd, MFD_DEF_SIZE * 2); + if (r < 0) { + printf("ftruncate(GROW) failed: %m\n"); + abort(); + } + + mfd_assert_size(fd, MFD_DEF_SIZE * 2); + + r = fallocate(fd, + 0, + 0, + MFD_DEF_SIZE * 4); + if (r < 0) { + printf("fallocate(ALLOC) failed: %m\n"); + abort(); + } + + mfd_assert_size(fd, MFD_DEF_SIZE * 4); +} + +static void mfd_fail_grow(int fd) +{ + int r; + + r = ftruncate(fd, MFD_DEF_SIZE * 2); + if (r >= 0) { + printf("ftruncate(GROW) didn't fail as expected\n"); + abort(); + } + + r = fallocate(fd, + 0, + 0, + MFD_DEF_SIZE * 4); + if (r >= 0) { + printf("fallocate(ALLOC) didn't fail as expected\n"); + abort(); + } +} + +static void mfd_assert_grow_write(int fd) +{ + static char buf[MFD_DEF_SIZE * 8]; + ssize_t l; + + l = pwrite(fd, buf, sizeof(buf), 0); + if (l != sizeof(buf)) { + printf("pwrite() failed: %m\n"); + abort(); + } + + mfd_assert_size(fd, MFD_DEF_SIZE * 8); +} + +static void mfd_fail_grow_write(int fd) +{ + static char buf[MFD_DEF_SIZE * 8]; + ssize_t l; + + l = pwrite(fd, buf, sizeof(buf), 0); + if (l == sizeof(buf)) { + printf("pwrite() didn't fail as expected\n"); + abort(); + } +} + +static int idle_thread_fn(void *arg) +{ + sigset_t set; + int sig; + + /* dummy waiter; SIGTERM terminates us anyway */ + sigemptyset(&set); + sigaddset(&set, SIGTERM); + sigwait(&set, &sig); + + return 0; +} + +static pid_t spawn_idle_thread(unsigned int flags) +{ + uint8_t *stack; + pid_t pid; + + stack = malloc(STACK_SIZE); + if (!stack) { + printf("malloc(STACK_SIZE) failed: %m\n"); + abort(); + } + + pid = clone(idle_thread_fn, + stack + STACK_SIZE, + SIGCHLD | flags, + NULL); + if (pid < 0) { + printf("clone() failed: %m\n"); + abort(); + } + + return pid; +} + +static void join_idle_thread(pid_t pid) +{ + kill(pid, SIGTERM); + waitpid(pid, NULL, 0); +} + +/* + * Test memfd_create() syscall + * Verify syscall-argument validation, including name checks, flag validation + * and more. + */ +static void test_create(void) +{ + char buf[2048]; + int fd; + + /* test NULL name */ + mfd_fail_new(NULL, 0); + + /* test over-long name (not zero-terminated) */ + memset(buf, 0xff, sizeof(buf)); + mfd_fail_new(buf, 0); + + /* test over-long zero-terminated name */ + memset(buf, 0xff, sizeof(buf)); + buf[sizeof(buf) - 1] = 0; + mfd_fail_new(buf, 0); + + /* verify "" is a valid name */ + fd = mfd_assert_new("", 0, 0); + close(fd); + + /* verify invalid O_* open flags */ + mfd_fail_new("", 0x0100); + mfd_fail_new("", ~MFD_CLOEXEC); + mfd_fail_new("", ~MFD_ALLOW_SEALING); + mfd_fail_new("", ~0); + mfd_fail_new("", 0x80000000U); + + /* verify MFD_CLOEXEC is allowed */ + fd = mfd_assert_new("", 0, MFD_CLOEXEC); + close(fd); + + /* verify MFD_ALLOW_SEALING is allowed */ + fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING); + close(fd); + + /* verify MFD_ALLOW_SEALING | MFD_CLOEXEC is allowed */ + fd = mfd_assert_new("", 0, MFD_ALLOW_SEALING | MFD_CLOEXEC); + close(fd); +} + +/* + * Test basic sealing + * A very basic sealing test to see whether setting/retrieving seals works. + */ +static void test_basic(void) +{ + int fd; + + fd = mfd_assert_new("kern_memfd_basic", + MFD_DEF_SIZE, + MFD_CLOEXEC | MFD_ALLOW_SEALING); + + /* add basic seals */ + mfd_assert_has_seals(fd, 0); + mfd_assert_add_seals(fd, F_SEAL_SHRINK | + F_SEAL_WRITE); + mfd_assert_has_seals(fd, F_SEAL_SHRINK | + F_SEAL_WRITE); + + /* add them again */ + mfd_assert_add_seals(fd, F_SEAL_SHRINK | + F_SEAL_WRITE); + mfd_assert_has_seals(fd, F_SEAL_SHRINK | + F_SEAL_WRITE); + + /* add more seals and seal against sealing */ + mfd_assert_add_seals(fd, F_SEAL_GROW | F_SEAL_SEAL); + mfd_assert_has_seals(fd, F_SEAL_SHRINK | + F_SEAL_GROW | + F_SEAL_WRITE | + F_SEAL_SEAL); + + /* verify that sealing no longer works */ + mfd_fail_add_seals(fd, F_SEAL_GROW); + mfd_fail_add_seals(fd, 0); + + close(fd); + + /* verify sealing does not work without MFD_ALLOW_SEALING */ + fd = mfd_assert_new("kern_memfd_basic", + MFD_DEF_SIZE, + MFD_CLOEXEC); + mfd_assert_has_seals(fd, F_SEAL_SEAL); + mfd_fail_add_seals(fd, F_SEAL_SHRINK | + F_SEAL_GROW | + F_SEAL_WRITE); + mfd_assert_has_seals(fd, F_SEAL_SEAL); + close(fd); +} + +/* + * Test SEAL_WRITE + * Test whether SEAL_WRITE actually prevents modifications. + */ +static void test_seal_write(void) +{ + int fd; + + fd = mfd_assert_new("kern_memfd_seal_write", + MFD_DEF_SIZE, + MFD_CLOEXEC | MFD_ALLOW_SEALING); + mfd_assert_has_seals(fd, 0); + mfd_assert_add_seals(fd, F_SEAL_WRITE); + mfd_assert_has_seals(fd, F_SEAL_WRITE); + + mfd_assert_read(fd); + mfd_fail_write(fd); + mfd_assert_shrink(fd); + mfd_assert_grow(fd); + mfd_fail_grow_write(fd); + + close(fd); +} + +/* + * Test SEAL_SHRINK + * Test whether SEAL_SHRINK actually prevents shrinking + */ +static void test_seal_shrink(void) +{ + int fd; + + fd = mfd_assert_new("kern_memfd_seal_shrink", + MFD_DEF_SIZE, + MFD_CLOEXEC | MFD_ALLOW_SEALING); + mfd_assert_has_seals(fd, 0); + mfd_assert_add_seals(fd, F_SEAL_SHRINK); + mfd_assert_has_seals(fd, F_SEAL_SHRINK); + + mfd_assert_read(fd); + mfd_assert_write(fd); + mfd_fail_shrink(fd); + mfd_assert_grow(fd); + mfd_assert_grow_write(fd); + + close(fd); +} + +/* + * Test SEAL_GROW + * Test whether SEAL_GROW actually prevents growing + */ +static void test_seal_grow(void) +{ + int fd; + + fd = mfd_assert_new("kern_memfd_seal_grow", + MFD_DEF_SIZE, + MFD_CLOEXEC | MFD_ALLOW_SEALING); + mfd_assert_has_seals(fd, 0); + mfd_assert_add_seals(fd, F_SEAL_GROW); + mfd_assert_has_seals(fd, F_SEAL_GROW); + + mfd_assert_read(fd); + mfd_assert_write(fd); + mfd_assert_shrink(fd); + mfd_fail_grow(fd); + mfd_fail_grow_write(fd); + + close(fd); +} + +/* + * Test SEAL_SHRINK | SEAL_GROW + * Test whether SEAL_SHRINK | SEAL_GROW actually prevents resizing + */ +static void test_seal_resize(void) +{ + int fd; + + fd = mfd_assert_new("kern_memfd_seal_resize", + MFD_DEF_SIZE, + MFD_CLOEXEC | MFD_ALLOW_SEALING); + mfd_assert_has_seals(fd, 0); + mfd_assert_add_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW); + mfd_assert_has_seals(fd, F_SEAL_SHRINK | F_SEAL_GROW); + + mfd_assert_read(fd); + mfd_assert_write(fd); + mfd_fail_shrink(fd); + mfd_fail_grow(fd); + mfd_fail_grow_write(fd); + + close(fd); +} + +/* + * Test sharing via dup() + * Test that seals are shared between dupped FDs and they're all equal. + */ +static void test_share_dup(void) +{ + int fd, fd2; + + fd = mfd_assert_new("kern_memfd_share_dup", + MFD_DEF_SIZE, + MFD_CLOEXEC | MFD_ALLOW_SEALING); + mfd_assert_has_seals(fd, 0); + + fd2 = mfd_assert_dup(fd); + mfd_assert_has_seals(fd2, 0); + + mfd_assert_add_seals(fd, F_SEAL_WRITE); + mfd_assert_has_seals(fd, F_SEAL_WRITE); + mfd_assert_has_seals(fd2, F_SEAL_WRITE); + + mfd_assert_add_seals(fd2, F_SEAL_SHRINK); + mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK); + mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK); + + mfd_assert_add_seals(fd, F_SEAL_SEAL); + mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL); + mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL); + + mfd_fail_add_seals(fd, F_SEAL_GROW); + mfd_fail_add_seals(fd2, F_SEAL_GROW); + mfd_fail_add_seals(fd, F_SEAL_SEAL); + mfd_fail_add_seals(fd2, F_SEAL_SEAL); + + close(fd2); + + mfd_fail_add_seals(fd, F_SEAL_GROW); + close(fd); +} + +/* + * Test sealing with active mmap()s + * Modifying seals is only allowed if no other mmap() refs exist. + */ +static void test_share_mmap(void) +{ + int fd; + void *p; + + fd = mfd_assert_new("kern_memfd_share_mmap", + MFD_DEF_SIZE, + MFD_CLOEXEC | MFD_ALLOW_SEALING); + mfd_assert_has_seals(fd, 0); + + /* shared/writable ref prevents sealing WRITE, but allows others */ + p = mfd_assert_mmap_shared(fd); + mfd_fail_add_seals(fd, F_SEAL_WRITE); + mfd_assert_has_seals(fd, 0); + mfd_assert_add_seals(fd, F_SEAL_SHRINK); + mfd_assert_has_seals(fd, F_SEAL_SHRINK); + munmap(p, MFD_DEF_SIZE); + + /* readable ref allows sealing */ + p = mfd_assert_mmap_private(fd); + mfd_assert_add_seals(fd, F_SEAL_WRITE); + mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK); + munmap(p, MFD_DEF_SIZE); + + close(fd); +} + +/* + * Test sealing with open(/proc/self/fd/%d) + * Via /proc we can get access to a separate file-context for the same memfd. + * This is *not* like dup(), but like a real separate open(). Make sure the + * semantics are as expected and we correctly check for RDONLY / WRONLY / RDWR. + */ +static void test_share_open(void) +{ + int fd, fd2; + + fd = mfd_assert_new("kern_memfd_share_open", + MFD_DEF_SIZE, + MFD_CLOEXEC | MFD_ALLOW_SEALING); + mfd_assert_has_seals(fd, 0); + + fd2 = mfd_assert_open(fd, O_RDWR, 0); + mfd_assert_add_seals(fd, F_SEAL_WRITE); + mfd_assert_has_seals(fd, F_SEAL_WRITE); + mfd_assert_has_seals(fd2, F_SEAL_WRITE); + + mfd_assert_add_seals(fd2, F_SEAL_SHRINK); + mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK); + mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK); + + close(fd); + fd = mfd_assert_open(fd2, O_RDONLY, 0); + + mfd_fail_add_seals(fd, F_SEAL_SEAL); + mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK); + mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK); + + close(fd2); + fd2 = mfd_assert_open(fd, O_RDWR, 0); + + mfd_assert_add_seals(fd2, F_SEAL_SEAL); + mfd_assert_has_seals(fd, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL); + mfd_assert_has_seals(fd2, F_SEAL_WRITE | F_SEAL_SHRINK | F_SEAL_SEAL); + + close(fd2); + close(fd); +} + +/* + * Test sharing via fork() + * Test whether seal-modifications work as expected with forked childs. + */ +static void test_share_fork(void) +{ + int fd; + pid_t pid; + + fd = mfd_assert_new("kern_memfd_share_fork", + MFD_DEF_SIZE, + MFD_CLOEXEC | MFD_ALLOW_SEALING); + mfd_assert_has_seals(fd, 0); + + pid = spawn_idle_thread(0); + mfd_assert_add_seals(fd, F_SEAL_SEAL); + mfd_assert_has_seals(fd, F_SEAL_SEAL); + + mfd_fail_add_seals(fd, F_SEAL_WRITE); + mfd_assert_has_seals(fd, F_SEAL_SEAL); + + join_idle_thread(pid); + + mfd_fail_add_seals(fd, F_SEAL_WRITE); + mfd_assert_has_seals(fd, F_SEAL_SEAL); + + close(fd); +} + +int main(int argc, char **argv) +{ + pid_t pid; + + printf("memfd: CREATE\n"); + test_create(); + printf("memfd: BASIC\n"); + test_basic(); + + printf("memfd: SEAL-WRITE\n"); + test_seal_write(); + printf("memfd: SEAL-SHRINK\n"); + test_seal_shrink(); + printf("memfd: SEAL-GROW\n"); + test_seal_grow(); + printf("memfd: SEAL-RESIZE\n"); + test_seal_resize(); + + printf("memfd: SHARE-DUP\n"); + test_share_dup(); + printf("memfd: SHARE-MMAP\n"); + test_share_mmap(); + printf("memfd: SHARE-OPEN\n"); + test_share_open(); + printf("memfd: SHARE-FORK\n"); + test_share_fork(); + + /* Run test-suite in a multi-threaded environment with a shared + * file-table. */ + pid = spawn_idle_thread(CLONE_FILES | CLONE_FS | CLONE_VM); + printf("memfd: SHARE-DUP (shared file-table)\n"); + test_share_dup(); + printf("memfd: SHARE-MMAP (shared file-table)\n"); + test_share_mmap(); + printf("memfd: SHARE-OPEN (shared file-table)\n"); + test_share_open(); + printf("memfd: SHARE-FORK (shared file-table)\n"); + test_share_fork(); + join_idle_thread(pid); + + printf("memfd: DONE\n"); + + return 0; +} diff --git a/memfd/run_fuse_test.sh b/memfd/run_fuse_test.sh new file mode 100644 index 0000000..69b930e --- /dev/null +++ b/memfd/run_fuse_test.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +if test -d "./mnt" ; then + fusermount -u ./mnt + rmdir ./mnt +fi + +set -e + +mkdir mnt +./fuse_mnt ./mnt +./fuse_test ./mnt/memfd +fusermount -u ./mnt +rmdir ./mnt diff --git a/memory-hotplug/Makefile b/memory-hotplug/Makefile index 0f49c3f..d46b8d4 100644 --- a/memory-hotplug/Makefile +++ b/memory-hotplug/Makefile @@ -1,6 +1,9 @@ all: run_tests: - @./on-off-test.sh || echo "memory-hotplug selftests: [FAIL]" + @/bin/bash ./on-off-test.sh -r 2 || echo "memory-hotplug selftests: [FAIL]" + +run_full_test: + @/bin/bash ./on-off-test.sh || echo "memory-hotplug selftests: [FAIL]" clean: diff --git a/memory-hotplug/on-off-test.sh b/memory-hotplug/on-off-test.sh index a2816f6..6cddde0 100644 --- a/memory-hotplug/on-off-test.sh +++ b/memory-hotplug/on-off-test.sh @@ -142,10 +142,16 @@ fi prerequisite +echo "Test scope: $ratio% hotplug memory" +echo -e "\t online all hotplug memory in offline state" +echo -e "\t offline $ratio% hotplug memory in online state" +echo -e "\t online all hotplug memory in offline state" + # # Online all hot-pluggable memory # for memory in `hotplaggable_offline_memory`; do + echo offline-online $memory online_memory_expect_success $memory done @@ -154,6 +160,7 @@ done # for memory in `hotpluggable_online_memory`; do if [ $((RANDOM % 100)) -lt $ratio ]; then + echo online-offline $memory offline_memory_expect_success $memory fi done @@ -162,6 +169,7 @@ done # Online all hot-pluggable memory again # for memory in `hotplaggable_offline_memory`; do + echo offline-online $memory online_memory_expect_success $memory done diff --git a/mount/Makefile b/mount/Makefile new file mode 100644 index 0000000..337d853 --- /dev/null +++ b/mount/Makefile @@ -0,0 +1,17 @@ +# Makefile for mount selftests. + +all: unprivileged-remount-test + +unprivileged-remount-test: unprivileged-remount-test.c + gcc -Wall -O2 unprivileged-remount-test.c -o unprivileged-remount-test + +# Allow specific tests to be selected. +test_unprivileged_remount: unprivileged-remount-test + @if [ -f /proc/self/uid_map ] ; then ./unprivileged-remount-test ; fi + +run_tests: all test_unprivileged_remount + +clean: + rm -f unprivileged-remount-test + +.PHONY: all test_unprivileged_remount diff --git a/mount/unprivileged-remount-test.c b/mount/unprivileged-remount-test.c new file mode 100644 index 0000000..1b3ff2f --- /dev/null +++ b/mount/unprivileged-remount-test.c @@ -0,0 +1,242 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef CLONE_NEWNS +# define CLONE_NEWNS 0x00020000 +#endif +#ifndef CLONE_NEWUTS +# define CLONE_NEWUTS 0x04000000 +#endif +#ifndef CLONE_NEWIPC +# define CLONE_NEWIPC 0x08000000 +#endif +#ifndef CLONE_NEWNET +# define CLONE_NEWNET 0x40000000 +#endif +#ifndef CLONE_NEWUSER +# define CLONE_NEWUSER 0x10000000 +#endif +#ifndef CLONE_NEWPID +# define CLONE_NEWPID 0x20000000 +#endif + +#ifndef MS_RELATIME +#define MS_RELATIME (1 << 21) +#endif +#ifndef MS_STRICTATIME +#define MS_STRICTATIME (1 << 24) +#endif + +static void die(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(EXIT_FAILURE); +} + +static void write_file(char *filename, char *fmt, ...) +{ + char buf[4096]; + int fd; + ssize_t written; + int buf_len; + va_list ap; + + va_start(ap, fmt); + buf_len = vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + if (buf_len < 0) { + die("vsnprintf failed: %s\n", + strerror(errno)); + } + if (buf_len >= sizeof(buf)) { + die("vsnprintf output truncated\n"); + } + + fd = open(filename, O_WRONLY); + if (fd < 0) { + die("open of %s failed: %s\n", + filename, strerror(errno)); + } + written = write(fd, buf, buf_len); + if (written != buf_len) { + if (written >= 0) { + die("short write to %s\n", filename); + } else { + die("write to %s failed: %s\n", + filename, strerror(errno)); + } + } + if (close(fd) != 0) { + die("close of %s failed: %s\n", + filename, strerror(errno)); + } +} + +static void create_and_enter_userns(void) +{ + uid_t uid; + gid_t gid; + + uid = getuid(); + gid = getgid(); + + if (unshare(CLONE_NEWUSER) !=0) { + die("unshare(CLONE_NEWUSER) failed: %s\n", + strerror(errno)); + } + + write_file("/proc/self/uid_map", "0 %d 1", uid); + write_file("/proc/self/gid_map", "0 %d 1", gid); + + if (setgroups(0, NULL) != 0) { + die("setgroups failed: %s\n", + strerror(errno)); + } + if (setgid(0) != 0) { + die ("setgid(0) failed %s\n", + strerror(errno)); + } + if (setuid(0) != 0) { + die("setuid(0) failed %s\n", + strerror(errno)); + } +} + +static +bool test_unpriv_remount(int mount_flags, int remount_flags, int invalid_flags) +{ + pid_t child; + + child = fork(); + if (child == -1) { + die("fork failed: %s\n", + strerror(errno)); + } + if (child != 0) { /* parent */ + pid_t pid; + int status; + pid = waitpid(child, &status, 0); + if (pid == -1) { + die("waitpid failed: %s\n", + strerror(errno)); + } + if (pid != child) { + die("waited for %d got %d\n", + child, pid); + } + if (!WIFEXITED(status)) { + die("child did not terminate cleanly\n"); + } + return WEXITSTATUS(status) == EXIT_SUCCESS ? true : false; + } + + create_and_enter_userns(); + if (unshare(CLONE_NEWNS) != 0) { + die("unshare(CLONE_NEWNS) failed: %s\n", + strerror(errno)); + } + + if (mount("testing", "/tmp", "ramfs", mount_flags, NULL) != 0) { + die("mount of /tmp failed: %s\n", + strerror(errno)); + } + + create_and_enter_userns(); + + if (unshare(CLONE_NEWNS) != 0) { + die("unshare(CLONE_NEWNS) failed: %s\n", + strerror(errno)); + } + + if (mount("/tmp", "/tmp", "none", + MS_REMOUNT | MS_BIND | remount_flags, NULL) != 0) { + /* system("cat /proc/self/mounts"); */ + die("remount of /tmp failed: %s\n", + strerror(errno)); + } + + if (mount("/tmp", "/tmp", "none", + MS_REMOUNT | MS_BIND | invalid_flags, NULL) == 0) { + /* system("cat /proc/self/mounts"); */ + die("remount of /tmp with invalid flags " + "succeeded unexpectedly\n"); + } + exit(EXIT_SUCCESS); +} + +static bool test_unpriv_remount_simple(int mount_flags) +{ + return test_unpriv_remount(mount_flags, mount_flags, 0); +} + +static bool test_unpriv_remount_atime(int mount_flags, int invalid_flags) +{ + return test_unpriv_remount(mount_flags, mount_flags, invalid_flags); +} + +int main(int argc, char **argv) +{ + if (!test_unpriv_remount_simple(MS_RDONLY|MS_NODEV)) { + die("MS_RDONLY malfunctions\n"); + } + if (!test_unpriv_remount_simple(MS_NODEV)) { + die("MS_NODEV malfunctions\n"); + } + if (!test_unpriv_remount_simple(MS_NOSUID|MS_NODEV)) { + die("MS_NOSUID malfunctions\n"); + } + if (!test_unpriv_remount_simple(MS_NOEXEC|MS_NODEV)) { + die("MS_NOEXEC malfunctions\n"); + } + if (!test_unpriv_remount_atime(MS_RELATIME|MS_NODEV, + MS_NOATIME|MS_NODEV)) + { + die("MS_RELATIME malfunctions\n"); + } + if (!test_unpriv_remount_atime(MS_STRICTATIME|MS_NODEV, + MS_NOATIME|MS_NODEV)) + { + die("MS_STRICTATIME malfunctions\n"); + } + if (!test_unpriv_remount_atime(MS_NOATIME|MS_NODEV, + MS_STRICTATIME|MS_NODEV)) + { + die("MS_RELATIME malfunctions\n"); + } + if (!test_unpriv_remount_atime(MS_RELATIME|MS_NODIRATIME|MS_NODEV, + MS_NOATIME|MS_NODEV)) + { + die("MS_RELATIME malfunctions\n"); + } + if (!test_unpriv_remount_atime(MS_STRICTATIME|MS_NODIRATIME|MS_NODEV, + MS_NOATIME|MS_NODEV)) + { + die("MS_RELATIME malfunctions\n"); + } + if (!test_unpriv_remount_atime(MS_NOATIME|MS_NODIRATIME|MS_NODEV, + MS_STRICTATIME|MS_NODEV)) + { + die("MS_RELATIME malfunctions\n"); + } + if (!test_unpriv_remount(MS_STRICTATIME|MS_NODEV, MS_NODEV, + MS_NOATIME|MS_NODEV)) + { + die("Default atime malfunctions\n"); + } + return EXIT_SUCCESS; +} diff --git a/mqueue/Makefile b/mqueue/Makefile index 218a122..8056e2e 100644 --- a/mqueue/Makefile +++ b/mqueue/Makefile @@ -1,6 +1,6 @@ all: - gcc -O2 -lrt mq_open_tests.c -o mq_open_tests - gcc -O2 -lrt -lpthread -lpopt -o mq_perf_tests mq_perf_tests.c + gcc -O2 mq_open_tests.c -o mq_open_tests -lrt + gcc -O2 -o mq_perf_tests mq_perf_tests.c -lrt -lpthread -lpopt run_tests: @./mq_open_tests /test1 || echo "mq_open_tests: [FAIL]" diff --git a/mqueue/mq_open_tests.c b/mqueue/mq_open_tests.c index 711cc29..9c1a5d3 100644 --- a/mqueue/mq_open_tests.c +++ b/mqueue/mq_open_tests.c @@ -80,7 +80,8 @@ void shutdown(int exit_val, char *err_cause, int line_no) if (in_shutdown++) return; - seteuid(0); + if (seteuid(0) == -1) + perror("seteuid() failed"); if (queue != -1) if (mq_close(queue)) @@ -292,8 +293,10 @@ int main(int argc, char *argv[]) /* Tell the user our initial state */ printf("\nInitial system state:\n"); printf("\tUsing queue path:\t\t%s\n", queue_path); - printf("\tRLIMIT_MSGQUEUE(soft):\t\t%d\n", saved_limits.rlim_cur); - printf("\tRLIMIT_MSGQUEUE(hard):\t\t%d\n", saved_limits.rlim_max); + printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n", + (long) saved_limits.rlim_cur); + printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n", + (long) saved_limits.rlim_max); printf("\tMaximum Message Size:\t\t%d\n", saved_max_msgsize); printf("\tMaximum Queue Size:\t\t%d\n", saved_max_msgs); if (default_settings) { @@ -308,8 +311,8 @@ int main(int argc, char *argv[]) validate_current_settings(); printf("Adjusted system state for testing:\n"); - printf("\tRLIMIT_MSGQUEUE(soft):\t\t%d\n", cur_limits.rlim_cur); - printf("\tRLIMIT_MSGQUEUE(hard):\t\t%d\n", cur_limits.rlim_max); + printf("\tRLIMIT_MSGQUEUE(soft):\t\t%ld\n", (long) cur_limits.rlim_cur); + printf("\tRLIMIT_MSGQUEUE(hard):\t\t%ld\n", (long) cur_limits.rlim_max); printf("\tMaximum Message Size:\t\t%d\n", cur_max_msgsize); printf("\tMaximum Queue Size:\t\t%d\n", cur_max_msgs); if (default_settings) { @@ -454,7 +457,12 @@ int main(int argc, char *argv[]) else printf("Queue open with total size > 2GB when euid = 0 " "failed:\t\t\tPASS\n"); - seteuid(99); + + if (seteuid(99) == -1) { + perror("seteuid() failed"); + exit(1); + } + attr.mq_maxmsg = cur_max_msgs; attr.mq_msgsize = cur_max_msgsize; if (test_queue_fail(&attr, &result)) diff --git a/mqueue/mq_perf_tests.c b/mqueue/mq_perf_tests.c index 2fadd4b..94dae65 100644 --- a/mqueue/mq_perf_tests.c +++ b/mqueue/mq_perf_tests.c @@ -296,9 +296,9 @@ static inline void open_queue(struct mq_attr *attr) printf("\n\tQueue %s created:\n", queue_path); printf("\t\tmq_flags:\t\t\t%s\n", result.mq_flags & O_NONBLOCK ? "O_NONBLOCK" : "(null)"); - printf("\t\tmq_maxmsg:\t\t\t%d\n", result.mq_maxmsg); - printf("\t\tmq_msgsize:\t\t\t%d\n", result.mq_msgsize); - printf("\t\tmq_curmsgs:\t\t\t%d\n", result.mq_curmsgs); + printf("\t\tmq_maxmsg:\t\t\t%lu\n", result.mq_maxmsg); + printf("\t\tmq_msgsize:\t\t\t%lu\n", result.mq_msgsize); + printf("\t\tmq_curmsgs:\t\t\t%lu\n", result.mq_curmsgs); } void *fake_cont_thread(void *arg) @@ -440,7 +440,7 @@ void *perf_test_thread(void *arg) shutdown(2, "clock_getres()", __LINE__); printf("\t\tMax priorities:\t\t\t%d\n", mq_prio_max); - printf("\t\tClock resolution:\t\t%d nsec%s\n", res.tv_nsec, + printf("\t\tClock resolution:\t\t%lu nsec%s\n", res.tv_nsec, res.tv_nsec > 1 ? "s" : ""); @@ -454,20 +454,20 @@ void *perf_test_thread(void *arg) recv_total.tv_nsec = 0; for (i = 0; i < TEST1_LOOPS; i++) do_send_recv(); - printf("\t\tSend msg:\t\t\t%d.%ds total time\n", + printf("\t\tSend msg:\t\t\t%ld.%lus total time\n", send_total.tv_sec, send_total.tv_nsec); nsec = ((unsigned long long)send_total.tv_sec * 1000000000 + send_total.tv_nsec) / TEST1_LOOPS; - printf("\t\t\t\t\t\t%d nsec/msg\n", nsec); - printf("\t\tRecv msg:\t\t\t%d.%ds total time\n", + printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec); + printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n", recv_total.tv_sec, recv_total.tv_nsec); nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 + recv_total.tv_nsec) / TEST1_LOOPS; - printf("\t\t\t\t\t\t%d nsec/msg\n", nsec); + printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec); for (cur_test = test2; cur_test->desc != NULL; cur_test++) { - printf(cur_test->desc); + printf("%s:\n", cur_test->desc); printf("\t\t(%d iterations)\n", TEST2_LOOPS); prio_out = 0; send_total.tv_sec = 0; @@ -493,16 +493,16 @@ void *perf_test_thread(void *arg) cur_test->func(&prio_out); } printf("done.\n"); - printf("\t\tSend msg:\t\t\t%d.%ds total time\n", + printf("\t\tSend msg:\t\t\t%ld.%lus total time\n", send_total.tv_sec, send_total.tv_nsec); nsec = ((unsigned long long)send_total.tv_sec * 1000000000 + send_total.tv_nsec) / TEST2_LOOPS; - printf("\t\t\t\t\t\t%d nsec/msg\n", nsec); - printf("\t\tRecv msg:\t\t\t%d.%ds total time\n", + printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec); + printf("\t\tRecv msg:\t\t\t%ld.%lus total time\n", recv_total.tv_sec, recv_total.tv_nsec); nsec = ((unsigned long long)recv_total.tv_sec * 1000000000 + recv_total.tv_nsec) / TEST2_LOOPS; - printf("\t\t\t\t\t\t%d nsec/msg\n", nsec); + printf("\t\t\t\t\t\t%lld nsec/msg\n", nsec); printf("\t\tDraining queue..."); fflush(stdout); clock_gettime(clock, &start); @@ -653,8 +653,10 @@ int main(int argc, char *argv[]) /* Tell the user our initial state */ printf("\nInitial system state:\n"); printf("\tUsing queue path:\t\t\t%s\n", queue_path); - printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%d\n", saved_limits.rlim_cur); - printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%d\n", saved_limits.rlim_max); + printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n", + (long) saved_limits.rlim_cur); + printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n", + (long) saved_limits.rlim_max); printf("\tMaximum Message Size:\t\t\t%d\n", saved_max_msgsize); printf("\tMaximum Queue Size:\t\t\t%d\n", saved_max_msgs); printf("\tNice value:\t\t\t\t%d\n", cur_nice); @@ -667,10 +669,10 @@ int main(int argc, char *argv[]) printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t(unlimited)\n"); printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t(unlimited)\n"); } else { - printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%d\n", - cur_limits.rlim_cur); - printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%d\n", - cur_limits.rlim_max); + printf("\tRLIMIT_MSGQUEUE(soft):\t\t\t%ld\n", + (long) cur_limits.rlim_cur); + printf("\tRLIMIT_MSGQUEUE(hard):\t\t\t%ld\n", + (long) cur_limits.rlim_max); } printf("\tMaximum Message Size:\t\t\t%d\n", cur_max_msgsize); printf("\tMaximum Queue Size:\t\t\t%d\n", cur_max_msgs); diff --git a/net/Makefile b/net/Makefile index 750512b..c7493b8 100644 --- a/net/Makefile +++ b/net/Makefile @@ -14,6 +14,12 @@ all: $(NET_PROGS) run_tests: all @/bin/sh ./run_netsocktests || echo "sockettests: [FAIL]" @/bin/sh ./run_afpackettests || echo "afpackettests: [FAIL]" - + @if /sbin/modprobe test_bpf ; then \ + /sbin/rmmod test_bpf; \ + echo "test_bpf: ok"; \ + else \ + echo "test_bpf: [FAIL]"; \ + exit 1; \ + fi clean: $(RM) $(NET_PROGS) diff --git a/net/psock_tpacket.c b/net/psock_tpacket.c index c41b586..24adf70 100644 --- a/net/psock_tpacket.c +++ b/net/psock_tpacket.c @@ -1,6 +1,7 @@ /* * Copyright 2013 Red Hat, Inc. * Author: Daniel Borkmann + * Chetan Loke (TPACKET_V3 usage example) * * A basic test of packet socket's TPACKET_V1/TPACKET_V2/TPACKET_V3 behavior. * @@ -71,18 +72,8 @@ # define __align_tpacket(x) __attribute__((aligned(TPACKET_ALIGN(x)))) #endif -#define BLOCK_STATUS(x) ((x)->h1.block_status) -#define BLOCK_NUM_PKTS(x) ((x)->h1.num_pkts) -#define BLOCK_O2FP(x) ((x)->h1.offset_to_first_pkt) -#define BLOCK_LEN(x) ((x)->h1.blk_len) -#define BLOCK_SNUM(x) ((x)->h1.seq_num) -#define BLOCK_O2PRIV(x) ((x)->offset_to_priv) -#define BLOCK_PRIV(x) ((void *) ((uint8_t *) (x) + BLOCK_O2PRIV(x))) -#define BLOCK_HDR_LEN (ALIGN_8(sizeof(struct block_desc))) -#define ALIGN_8(x) (((x) + 8 - 1) & ~(8 - 1)) -#define BLOCK_PLUS_PRIV(sz_pri) (BLOCK_HDR_LEN + ALIGN_8((sz_pri))) - #define NUM_PACKETS 100 +#define ALIGN_8(x) (((x) + 8 - 1) & ~(8 - 1)) struct ring { struct iovec *rd; @@ -476,41 +467,30 @@ static uint64_t __v3_prev_block_seq_num = 0; void __v3_test_block_seq_num(struct block_desc *pbd) { - if (__v3_prev_block_seq_num + 1 != BLOCK_SNUM(pbd)) { + if (__v3_prev_block_seq_num + 1 != pbd->h1.seq_num) { fprintf(stderr, "\nprev_block_seq_num:%"PRIu64", expected " "seq:%"PRIu64" != actual seq:%"PRIu64"\n", __v3_prev_block_seq_num, __v3_prev_block_seq_num + 1, - (uint64_t) BLOCK_SNUM(pbd)); + (uint64_t) pbd->h1.seq_num); exit(1); } - __v3_prev_block_seq_num = BLOCK_SNUM(pbd); + __v3_prev_block_seq_num = pbd->h1.seq_num; } static void __v3_test_block_len(struct block_desc *pbd, uint32_t bytes, int block_num) { - if (BLOCK_NUM_PKTS(pbd)) { - if (bytes != BLOCK_LEN(pbd)) { - fprintf(stderr, "\nblock:%u with %upackets, expected " - "len:%u != actual len:%u\n", block_num, - BLOCK_NUM_PKTS(pbd), bytes, BLOCK_LEN(pbd)); - exit(1); - } - } else { - if (BLOCK_LEN(pbd) != BLOCK_PLUS_PRIV(13)) { - fprintf(stderr, "\nblock:%u, expected len:%lu != " - "actual len:%u\n", block_num, BLOCK_HDR_LEN, - BLOCK_LEN(pbd)); - exit(1); - } + if (pbd->h1.num_pkts && bytes != pbd->h1.blk_len) { + fprintf(stderr, "\nblock:%u with %upackets, expected " + "len:%u != actual len:%u\n", block_num, + pbd->h1.num_pkts, bytes, pbd->h1.blk_len); + exit(1); } } static void __v3_test_block_header(struct block_desc *pbd, const int block_num) { - uint32_t block_status = BLOCK_STATUS(pbd); - - if ((block_status & TP_STATUS_USER) == 0) { + if ((pbd->h1.block_status & TP_STATUS_USER) == 0) { fprintf(stderr, "\nblock %u: not in TP_STATUS_USER\n", block_num); exit(1); } @@ -520,14 +500,15 @@ static void __v3_test_block_header(struct block_desc *pbd, const int block_num) static void __v3_walk_block(struct block_desc *pbd, const int block_num) { - int num_pkts = BLOCK_NUM_PKTS(pbd), i; - unsigned long bytes = 0; - unsigned long bytes_with_padding = BLOCK_PLUS_PRIV(13); + int num_pkts = pbd->h1.num_pkts, i; + unsigned long bytes = 0, bytes_with_padding = ALIGN_8(sizeof(*pbd)); struct tpacket3_hdr *ppd; __v3_test_block_header(pbd, block_num); - ppd = (struct tpacket3_hdr *) ((uint8_t *) pbd + BLOCK_O2FP(pbd)); + ppd = (struct tpacket3_hdr *) ((uint8_t *) pbd + + pbd->h1.offset_to_first_pkt); + for (i = 0; i < num_pkts; ++i) { bytes += ppd->tp_snaplen; @@ -551,7 +532,7 @@ static void __v3_walk_block(struct block_desc *pbd, const int block_num) void __v3_flush_block(struct block_desc *pbd) { - BLOCK_STATUS(pbd) = TP_STATUS_KERNEL; + pbd->h1.block_status = TP_STATUS_KERNEL; __sync_synchronize(); } @@ -577,7 +558,7 @@ static void walk_v3_rx(int sock, struct ring *ring) while (total_packets < NUM_PACKETS * 2) { pbd = (struct block_desc *) ring->rd[block_num].iov_base; - while ((BLOCK_STATUS(pbd) & TP_STATUS_USER) == 0) + while ((pbd->h1.block_status & TP_STATUS_USER) == 0) poll(&pfd, 1, 1); __v3_walk_block(pbd, block_num); @@ -624,8 +605,8 @@ static void __v1_v2_fill(struct ring *ring, unsigned int blocks) static void __v3_fill(struct ring *ring, unsigned int blocks) { ring->req3.tp_retire_blk_tov = 64; - ring->req3.tp_sizeof_priv = 13; - ring->req3.tp_feature_req_word |= TP_FT_REQ_FILL_RXHASH; + ring->req3.tp_sizeof_priv = 0; + ring->req3.tp_feature_req_word = TP_FT_REQ_FILL_RXHASH; ring->req3.tp_block_size = getpagesize() << 2; ring->req3.tp_frame_size = TPACKET_ALIGNMENT << 7; diff --git a/powerpc/Makefile b/powerpc/Makefile new file mode 100644 index 0000000..74a78ce --- /dev/null +++ b/powerpc/Makefile @@ -0,0 +1,39 @@ +# Makefile for powerpc selftests + +# ARCH can be overridden by the user for cross compiling +ARCH ?= $(shell uname -m) +ARCH := $(shell echo $(ARCH) | sed -e s/ppc.*/powerpc/) + +ifeq ($(ARCH),powerpc) + +GIT_VERSION = $(shell git describe --always --long --dirty || echo "unknown") + +CC := $(CROSS_COMPILE)$(CC) +CFLAGS := -Wall -O2 -flto -Wall -Werror -DGIT_VERSION='"$(GIT_VERSION)"' -I$(CURDIR) $(CFLAGS) + +export CC CFLAGS + +TARGETS = pmu copyloops mm tm + +endif + +all: $(TARGETS) + +$(TARGETS): + $(MAKE) -k -C $@ all + +run_tests: all + @for TARGET in $(TARGETS); do \ + $(MAKE) -C $$TARGET run_tests; \ + done; + +clean: + @for TARGET in $(TARGETS); do \ + $(MAKE) -C $$TARGET clean; \ + done; + rm -f tags + +tags: + find . -name '*.c' -o -name '*.h' | xargs ctags + +.PHONY: all run_tests clean tags $(TARGETS) diff --git a/powerpc/copyloops/Makefile b/powerpc/copyloops/Makefile new file mode 100644 index 0000000..6f2d3be --- /dev/null +++ b/powerpc/copyloops/Makefile @@ -0,0 +1,29 @@ +# The loops are all 64-bit code +CFLAGS += -m64 +CFLAGS += -I$(CURDIR) +CFLAGS += -D SELFTEST + +# Use our CFLAGS for the implicit .S rule +ASFLAGS = $(CFLAGS) + +PROGS := copyuser_64 copyuser_power7 memcpy_64 memcpy_power7 +EXTRA_SOURCES := validate.c ../harness.c + +all: $(PROGS) + +copyuser_64: CPPFLAGS += -D COPY_LOOP=test___copy_tofrom_user_base +copyuser_power7: CPPFLAGS += -D COPY_LOOP=test___copy_tofrom_user_power7 +memcpy_64: CPPFLAGS += -D COPY_LOOP=test_memcpy +memcpy_power7: CPPFLAGS += -D COPY_LOOP=test_memcpy_power7 + +$(PROGS): $(EXTRA_SOURCES) + +run_tests: all + @-for PROG in $(PROGS); do \ + ./$$PROG; \ + done; + +clean: + rm -f $(PROGS) *.o + +.PHONY: all run_tests clean diff --git a/powerpc/copyloops/asm/ppc_asm.h b/powerpc/copyloops/asm/ppc_asm.h new file mode 100644 index 0000000..d1dc374 --- /dev/null +++ b/powerpc/copyloops/asm/ppc_asm.h @@ -0,0 +1,89 @@ +#include + +#define CONFIG_ALTIVEC + +#define r1 1 + +#define vr0 0 +#define vr1 1 +#define vr2 2 +#define vr3 3 +#define vr4 4 +#define vr5 5 +#define vr6 6 +#define vr7 7 +#define vr8 8 +#define vr9 9 +#define vr10 10 +#define vr11 11 +#define vr12 12 +#define vr13 13 +#define vr14 14 +#define vr15 15 +#define vr16 16 +#define vr17 17 +#define vr18 18 +#define vr19 19 +#define vr20 20 +#define vr21 21 +#define vr22 22 +#define vr23 23 +#define vr24 24 +#define vr25 25 +#define vr26 26 +#define vr27 27 +#define vr28 28 +#define vr29 29 +#define vr30 30 +#define vr31 31 + +#define R14 r14 +#define R15 r15 +#define R16 r16 +#define R17 r17 +#define R18 r18 +#define R19 r19 +#define R20 r20 +#define R21 r21 +#define R22 r22 +#define R29 r29 +#define R30 r30 +#define R31 r31 + +#define STACKFRAMESIZE 256 +#define STK_REG(i) (112 + ((i)-14)*8) + +#define _GLOBAL(A) FUNC_START(test_ ## A) +#define _GLOBAL_TOC(A) _GLOBAL(A) + +#define PPC_MTOCRF(A, B) mtocrf A, B + +FUNC_START(enter_vmx_usercopy) + li r3,1 + blr + +FUNC_START(exit_vmx_usercopy) + li r3,0 + blr + +FUNC_START(enter_vmx_copy) + li r3,1 + blr + +FUNC_START(exit_vmx_copy) + blr + +FUNC_START(memcpy_power7) + blr + +FUNC_START(__copy_tofrom_user_power7) + blr + +FUNC_START(__copy_tofrom_user_base) + blr + +#define BEGIN_FTR_SECTION +#define FTR_SECTION_ELSE +#define ALT_FTR_SECTION_END_IFCLR(x) +#define ALT_FTR_SECTION_END(x, y) +#define END_FTR_SECTION_IFCLR(x) diff --git a/powerpc/copyloops/asm/processor.h b/powerpc/copyloops/asm/processor.h new file mode 100644 index 0000000..e69de29 diff --git a/powerpc/copyloops/copyuser_64.S b/powerpc/copyloops/copyuser_64.S new file mode 120000 index 0000000..f1c418a --- /dev/null +++ b/powerpc/copyloops/copyuser_64.S @@ -0,0 +1 @@ +../../../../../arch/powerpc/lib/copyuser_64.S \ No newline at end of file diff --git a/powerpc/copyloops/copyuser_power7.S b/powerpc/copyloops/copyuser_power7.S new file mode 120000 index 0000000..4786895 --- /dev/null +++ b/powerpc/copyloops/copyuser_power7.S @@ -0,0 +1 @@ +../../../../../arch/powerpc/lib/copyuser_power7.S \ No newline at end of file diff --git a/powerpc/copyloops/memcpy_64.S b/powerpc/copyloops/memcpy_64.S new file mode 120000 index 0000000..cce33fb --- /dev/null +++ b/powerpc/copyloops/memcpy_64.S @@ -0,0 +1 @@ +../../../../../arch/powerpc/lib/memcpy_64.S \ No newline at end of file diff --git a/powerpc/copyloops/memcpy_power7.S b/powerpc/copyloops/memcpy_power7.S new file mode 120000 index 0000000..0d6fbfa --- /dev/null +++ b/powerpc/copyloops/memcpy_power7.S @@ -0,0 +1 @@ +../../../../../arch/powerpc/lib/memcpy_power7.S \ No newline at end of file diff --git a/powerpc/copyloops/validate.c b/powerpc/copyloops/validate.c new file mode 100644 index 0000000..1750ff5 --- /dev/null +++ b/powerpc/copyloops/validate.c @@ -0,0 +1,99 @@ +#include +#include +#include +#include + +#include "../utils.h" + +#define MAX_LEN 8192 +#define MAX_OFFSET 16 +#define MIN_REDZONE 128 +#define BUFLEN (MAX_LEN+MAX_OFFSET+2*MIN_REDZONE) +#define POISON 0xa5 + +unsigned long COPY_LOOP(void *to, const void *from, unsigned long size); + +static void do_one(char *src, char *dst, unsigned long src_off, + unsigned long dst_off, unsigned long len, void *redzone, + void *fill) +{ + char *srcp, *dstp; + unsigned long ret; + unsigned long i; + + srcp = src + MIN_REDZONE + src_off; + dstp = dst + MIN_REDZONE + dst_off; + + memset(src, POISON, BUFLEN); + memset(dst, POISON, BUFLEN); + memcpy(srcp, fill, len); + + ret = COPY_LOOP(dstp, srcp, len); + if (ret && ret != (unsigned long)dstp) { + printf("(%p,%p,%ld) returned %ld\n", dstp, srcp, len, ret); + abort(); + } + + if (memcmp(dstp, srcp, len)) { + printf("(%p,%p,%ld) miscompare\n", dstp, srcp, len); + printf("src: "); + for (i = 0; i < len; i++) + printf("%02x ", srcp[i]); + printf("\ndst: "); + for (i = 0; i < len; i++) + printf("%02x ", dstp[i]); + printf("\n"); + abort(); + } + + if (memcmp(dst, redzone, dstp - dst)) { + printf("(%p,%p,%ld) redzone before corrupted\n", + dstp, srcp, len); + abort(); + } + + if (memcmp(dstp+len, redzone, dst+BUFLEN-(dstp+len))) { + printf("(%p,%p,%ld) redzone after corrupted\n", + dstp, srcp, len); + abort(); + } +} + +int test_copy_loop(void) +{ + char *src, *dst, *redzone, *fill; + unsigned long len, src_off, dst_off; + unsigned long i; + + src = memalign(BUFLEN, BUFLEN); + dst = memalign(BUFLEN, BUFLEN); + redzone = malloc(BUFLEN); + fill = malloc(BUFLEN); + + if (!src || !dst || !redzone || !fill) { + fprintf(stderr, "malloc failed\n"); + exit(1); + } + + memset(redzone, POISON, BUFLEN); + + /* Fill with sequential bytes */ + for (i = 0; i < BUFLEN; i++) + fill[i] = i & 0xff; + + for (len = 1; len < MAX_LEN; len++) { + for (src_off = 0; src_off < MAX_OFFSET; src_off++) { + for (dst_off = 0; dst_off < MAX_OFFSET; dst_off++) { + do_one(src, dst, src_off, dst_off, len, + redzone, fill); + } + } + } + + return 0; +} + +int main(void) +{ + return test_harness(test_copy_loop, str(COPY_LOOP)); +} diff --git a/powerpc/harness.c b/powerpc/harness.c new file mode 100644 index 0000000..8ebc58a --- /dev/null +++ b/powerpc/harness.c @@ -0,0 +1,114 @@ +/* + * Copyright 2013, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "subunit.h" +#include "utils.h" + +#define TIMEOUT 120 +#define KILL_TIMEOUT 5 + + +int run_test(int (test_function)(void), char *name) +{ + bool terminated; + int rc, status; + pid_t pid; + + /* Make sure output is flushed before forking */ + fflush(stdout); + + pid = fork(); + if (pid == 0) { + setpgid(0, 0); + exit(test_function()); + } else if (pid == -1) { + perror("fork"); + return 1; + } + + setpgid(pid, pid); + + /* Wake us up in timeout seconds */ + alarm(TIMEOUT); + terminated = false; + +wait: + rc = waitpid(pid, &status, 0); + if (rc == -1) { + if (errno != EINTR) { + printf("unknown error from waitpid\n"); + return 1; + } + + if (terminated) { + printf("!! force killing %s\n", name); + kill(-pid, SIGKILL); + return 1; + } else { + printf("!! killing %s\n", name); + kill(-pid, SIGTERM); + terminated = true; + alarm(KILL_TIMEOUT); + goto wait; + } + } + + /* Kill anything else in the process group that is still running */ + kill(-pid, SIGTERM); + + if (WIFEXITED(status)) + status = WEXITSTATUS(status); + else { + if (WIFSIGNALED(status)) + printf("!! child died by signal %d\n", WTERMSIG(status)); + else + printf("!! child died by unknown cause\n"); + + status = 1; /* Signal or other */ + } + + return status; +} + +static void alarm_handler(int signum) +{ + /* Jut wake us up from waitpid */ +} + +static struct sigaction alarm_action = { + .sa_handler = alarm_handler, +}; + +int test_harness(int (test_function)(void), char *name) +{ + int rc; + + test_start(name); + test_set_git_version(GIT_VERSION); + + if (sigaction(SIGALRM, &alarm_action, NULL)) { + perror("sigaction"); + test_error(name); + return 1; + } + + rc = run_test(test_function, name); + + if (rc == MAGIC_SKIP_RETURN_VALUE) + test_skip(name); + else + test_finish(name, rc); + + return rc; +} diff --git a/powerpc/mm/Makefile b/powerpc/mm/Makefile new file mode 100644 index 0000000..357ccbd --- /dev/null +++ b/powerpc/mm/Makefile @@ -0,0 +1,18 @@ +noarg: + $(MAKE) -C ../ + +PROGS := hugetlb_vs_thp_test + +all: $(PROGS) + +$(PROGS): ../harness.c + +run_tests: all + @-for PROG in $(PROGS); do \ + ./$$PROG; \ + done; + +clean: + rm -f $(PROGS) + +.PHONY: all run_tests clean diff --git a/powerpc/mm/hugetlb_vs_thp_test.c b/powerpc/mm/hugetlb_vs_thp_test.c new file mode 100644 index 0000000..3d8e5b0 --- /dev/null +++ b/powerpc/mm/hugetlb_vs_thp_test.c @@ -0,0 +1,72 @@ +#include +#include +#include + +#include "utils.h" + +/* This must match the huge page & THP size */ +#define SIZE (16 * 1024 * 1024) + +static int test_body(void) +{ + void *addr; + char *p; + + addr = (void *)0xa0000000; + + p = mmap(addr, SIZE, PROT_READ | PROT_WRITE, + MAP_HUGETLB | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (p != MAP_FAILED) { + /* + * Typically the mmap will fail because no huge pages are + * allocated on the system. But if there are huge pages + * allocated the mmap will succeed. That's fine too, we just + * munmap here before continuing. + */ + munmap(addr, SIZE); + } + + p = mmap(addr, SIZE, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (p == MAP_FAILED) { + printf("Mapping failed @ %p\n", addr); + perror("mmap"); + return 1; + } + + /* + * Either a user or kernel access is sufficient to trigger the bug. + * A kernel access is easier to spot & debug, as it will trigger the + * softlockup or RCU stall detectors, and when the system is kicked + * into xmon we get a backtrace in the kernel. + * + * A good option is: + * getcwd(p, SIZE); + * + * For the purposes of this testcase it's preferable to spin in + * userspace, so the harness can kill us if we get stuck. That way we + * see a test failure rather than a dead system. + */ + *p = 0xf; + + munmap(addr, SIZE); + + return 0; +} + +static int test_main(void) +{ + int i; + + /* 10,000 because it's a "bunch", and completes reasonably quickly */ + for (i = 0; i < 10000; i++) + if (test_body()) + return 1; + + return 0; +} + +int main(void) +{ + return test_harness(test_main, "hugetlb_vs_thp"); +} diff --git a/powerpc/pmu/Makefile b/powerpc/pmu/Makefile new file mode 100644 index 0000000..c9f4263 --- /dev/null +++ b/powerpc/pmu/Makefile @@ -0,0 +1,38 @@ +noarg: + $(MAKE) -C ../ + +PROGS := count_instructions l3_bank_test per_event_excludes +EXTRA_SOURCES := ../harness.c event.c lib.c + +SUB_TARGETS = ebb + +all: $(PROGS) $(SUB_TARGETS) + +$(PROGS): $(EXTRA_SOURCES) + +# loop.S can only be built 64-bit +count_instructions: loop.S count_instructions.c $(EXTRA_SOURCES) + $(CC) $(CFLAGS) -m64 -o $@ $^ + +run_tests: all sub_run_tests + @-for PROG in $(PROGS); do \ + ./$$PROG; \ + done; + +clean: sub_clean + rm -f $(PROGS) loop.o + +$(SUB_TARGETS): + $(MAKE) -k -C $@ all + +sub_run_tests: all + @for TARGET in $(SUB_TARGETS); do \ + $(MAKE) -C $$TARGET run_tests; \ + done; + +sub_clean: + @for TARGET in $(SUB_TARGETS); do \ + $(MAKE) -C $$TARGET clean; \ + done; + +.PHONY: all run_tests clean sub_run_tests sub_clean $(SUB_TARGETS) diff --git a/powerpc/pmu/count_instructions.c b/powerpc/pmu/count_instructions.c new file mode 100644 index 0000000..4622117 --- /dev/null +++ b/powerpc/pmu/count_instructions.c @@ -0,0 +1,147 @@ +/* + * Copyright 2013, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include + +#include "event.h" +#include "utils.h" +#include "lib.h" + +extern void thirty_two_instruction_loop(u64 loops); + +static void setup_event(struct event *e, u64 config, char *name) +{ + event_init_opts(e, config, PERF_TYPE_HARDWARE, name); + + e->attr.disabled = 1; + e->attr.exclude_kernel = 1; + e->attr.exclude_hv = 1; + e->attr.exclude_idle = 1; +} + +static int do_count_loop(struct event *events, u64 instructions, + u64 overhead, bool report) +{ + s64 difference, expected; + double percentage; + + prctl(PR_TASK_PERF_EVENTS_ENABLE); + + /* Run for 1M instructions */ + thirty_two_instruction_loop(instructions >> 5); + + prctl(PR_TASK_PERF_EVENTS_DISABLE); + + event_read(&events[0]); + event_read(&events[1]); + + expected = instructions + overhead; + difference = events[0].result.value - expected; + percentage = (double)difference / events[0].result.value * 100; + + if (report) { + event_report(&events[0]); + event_report(&events[1]); + + printf("Looped for %llu instructions, overhead %llu\n", instructions, overhead); + printf("Expected %llu\n", expected); + printf("Actual %llu\n", events[0].result.value); + printf("Delta %lld, %f%%\n", difference, percentage); + } + + event_reset(&events[0]); + event_reset(&events[1]); + + if (difference < 0) + difference = -difference; + + /* Tolerate a difference below 0.0001 % */ + difference *= 10000 * 100; + if (difference / events[0].result.value) + return -1; + + return 0; +} + +/* Count how many instructions it takes to do a null loop */ +static u64 determine_overhead(struct event *events) +{ + u64 current, overhead; + int i; + + do_count_loop(events, 0, 0, false); + overhead = events[0].result.value; + + for (i = 0; i < 100; i++) { + do_count_loop(events, 0, 0, false); + current = events[0].result.value; + if (current < overhead) { + printf("Replacing overhead %llu with %llu\n", overhead, current); + overhead = current; + } + } + + return overhead; +} + +static int test_body(void) +{ + struct event events[2]; + u64 overhead; + + setup_event(&events[0], PERF_COUNT_HW_INSTRUCTIONS, "instructions"); + setup_event(&events[1], PERF_COUNT_HW_CPU_CYCLES, "cycles"); + + if (event_open(&events[0])) { + perror("perf_event_open"); + return -1; + } + + if (event_open_with_group(&events[1], events[0].fd)) { + perror("perf_event_open"); + return -1; + } + + overhead = determine_overhead(events); + printf("Overhead of null loop: %llu instructions\n", overhead); + + /* Run for 1Mi instructions */ + FAIL_IF(do_count_loop(events, 1000000, overhead, true)); + + /* Run for 10Mi instructions */ + FAIL_IF(do_count_loop(events, 10000000, overhead, true)); + + /* Run for 100Mi instructions */ + FAIL_IF(do_count_loop(events, 100000000, overhead, true)); + + /* Run for 1Bi instructions */ + FAIL_IF(do_count_loop(events, 1000000000, overhead, true)); + + /* Run for 16Bi instructions */ + FAIL_IF(do_count_loop(events, 16000000000, overhead, true)); + + /* Run for 64Bi instructions */ + FAIL_IF(do_count_loop(events, 64000000000, overhead, true)); + + event_close(&events[0]); + event_close(&events[1]); + + return 0; +} + +static int count_instructions(void) +{ + return eat_cpu(test_body); +} + +int main(void) +{ + return test_harness(count_instructions, "count_instructions"); +} diff --git a/powerpc/pmu/ebb/Makefile b/powerpc/pmu/ebb/Makefile new file mode 100644 index 0000000..3dc4332 --- /dev/null +++ b/powerpc/pmu/ebb/Makefile @@ -0,0 +1,33 @@ +noarg: + $(MAKE) -C ../../ + +# The EBB handler is 64-bit code and everything links against it +CFLAGS += -m64 + +PROGS := reg_access_test event_attributes_test cycles_test \ + cycles_with_freeze_test pmc56_overflow_test \ + ebb_vs_cpu_event_test cpu_event_vs_ebb_test \ + cpu_event_pinned_vs_ebb_test task_event_vs_ebb_test \ + task_event_pinned_vs_ebb_test multi_ebb_procs_test \ + multi_counter_test pmae_handling_test \ + close_clears_pmcc_test instruction_count_test \ + fork_cleanup_test ebb_on_child_test \ + ebb_on_willing_child_test back_to_back_ebbs_test \ + lost_exception_test no_handler_test \ + cycles_with_mmcr2_test + +all: $(PROGS) + +$(PROGS): ../../harness.c ../event.c ../lib.c ebb.c ebb_handler.S trace.c busy_loop.S + +instruction_count_test: ../loop.S + +lost_exception_test: ../lib.c + +run_tests: all + @-for PROG in $(PROGS); do \ + ./$$PROG; \ + done; + +clean: + rm -f $(PROGS) diff --git a/powerpc/pmu/ebb/back_to_back_ebbs_test.c b/powerpc/pmu/ebb/back_to_back_ebbs_test.c new file mode 100644 index 0000000..66ea765 --- /dev/null +++ b/powerpc/pmu/ebb/back_to_back_ebbs_test.c @@ -0,0 +1,106 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include +#include + +#include "ebb.h" + + +#define NUMBER_OF_EBBS 50 + +/* + * Test that if we overflow the counter while in the EBB handler, we take + * another EBB on exiting from the handler. + * + * We do this by counting with a stupidly low sample period, causing us to + * overflow the PMU while we're still in the EBB handler, leading to another + * EBB. + * + * We get out of what would otherwise be an infinite loop by leaving the + * counter frozen once we've taken enough EBBs. + */ + +static void ebb_callee(void) +{ + uint64_t siar, val; + + val = mfspr(SPRN_BESCR); + if (!(val & BESCR_PMEO)) { + ebb_state.stats.spurious++; + goto out; + } + + ebb_state.stats.ebb_count++; + trace_log_counter(ebb_state.trace, ebb_state.stats.ebb_count); + + /* Resets the PMC */ + count_pmc(1, sample_period); + +out: + if (ebb_state.stats.ebb_count == NUMBER_OF_EBBS) + /* Reset but leave counters frozen */ + reset_ebb_with_clear_mask(MMCR0_PMAO); + else + /* Unfreezes */ + reset_ebb(); + + /* Do some stuff to chew some cycles and pop the counter */ + siar = mfspr(SPRN_SIAR); + trace_log_reg(ebb_state.trace, SPRN_SIAR, siar); + + val = mfspr(SPRN_PMC1); + trace_log_reg(ebb_state.trace, SPRN_PMC1, val); + + val = mfspr(SPRN_MMCR0); + trace_log_reg(ebb_state.trace, SPRN_MMCR0, val); +} + +int back_to_back_ebbs(void) +{ + struct event event; + + event_init_named(&event, 0x1001e, "cycles"); + event_leader_ebb_init(&event); + + event.attr.exclude_kernel = 1; + event.attr.exclude_hv = 1; + event.attr.exclude_idle = 1; + + FAIL_IF(event_open(&event)); + + setup_ebb_handler(ebb_callee); + + FAIL_IF(ebb_event_enable(&event)); + + sample_period = 5; + + ebb_freeze_pmcs(); + mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); + ebb_global_enable(); + ebb_unfreeze_pmcs(); + + while (ebb_state.stats.ebb_count < NUMBER_OF_EBBS) + FAIL_IF(core_busy_loop()); + + ebb_global_disable(); + ebb_freeze_pmcs(); + + count_pmc(1, sample_period); + + dump_ebb_state(); + + event_close(&event); + + FAIL_IF(ebb_state.stats.ebb_count != NUMBER_OF_EBBS); + + return 0; +} + +int main(void) +{ + return test_harness(back_to_back_ebbs, "back_to_back_ebbs"); +} diff --git a/powerpc/pmu/ebb/busy_loop.S b/powerpc/pmu/ebb/busy_loop.S new file mode 100644 index 0000000..c7e4093 --- /dev/null +++ b/powerpc/pmu/ebb/busy_loop.S @@ -0,0 +1,271 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include + + .text + +FUNC_START(core_busy_loop) + stdu %r1, -168(%r1) + std r14, 160(%r1) + std r15, 152(%r1) + std r16, 144(%r1) + std r17, 136(%r1) + std r18, 128(%r1) + std r19, 120(%r1) + std r20, 112(%r1) + std r21, 104(%r1) + std r22, 96(%r1) + std r23, 88(%r1) + std r24, 80(%r1) + std r25, 72(%r1) + std r26, 64(%r1) + std r27, 56(%r1) + std r28, 48(%r1) + std r29, 40(%r1) + std r30, 32(%r1) + std r31, 24(%r1) + + li r3, 0x3030 + std r3, -96(%r1) + li r4, 0x4040 + std r4, -104(%r1) + li r5, 0x5050 + std r5, -112(%r1) + li r6, 0x6060 + std r6, -120(%r1) + li r7, 0x7070 + std r7, -128(%r1) + li r8, 0x0808 + std r8, -136(%r1) + li r9, 0x0909 + std r9, -144(%r1) + li r10, 0x1010 + std r10, -152(%r1) + li r11, 0x1111 + std r11, -160(%r1) + li r14, 0x1414 + std r14, -168(%r1) + li r15, 0x1515 + std r15, -176(%r1) + li r16, 0x1616 + std r16, -184(%r1) + li r17, 0x1717 + std r17, -192(%r1) + li r18, 0x1818 + std r18, -200(%r1) + li r19, 0x1919 + std r19, -208(%r1) + li r20, 0x2020 + std r20, -216(%r1) + li r21, 0x2121 + std r21, -224(%r1) + li r22, 0x2222 + std r22, -232(%r1) + li r23, 0x2323 + std r23, -240(%r1) + li r24, 0x2424 + std r24, -248(%r1) + li r25, 0x2525 + std r25, -256(%r1) + li r26, 0x2626 + std r26, -264(%r1) + li r27, 0x2727 + std r27, -272(%r1) + li r28, 0x2828 + std r28, -280(%r1) + li r29, 0x2929 + std r29, -288(%r1) + li r30, 0x3030 + li r31, 0x3131 + + li r3, 0 +0: addi r3, r3, 1 + cmpwi r3, 100 + blt 0b + + /* Return 1 (fail) unless we get through all the checks */ + li r3, 1 + + /* Check none of our registers have been corrupted */ + cmpwi r4, 0x4040 + bne 1f + cmpwi r5, 0x5050 + bne 1f + cmpwi r6, 0x6060 + bne 1f + cmpwi r7, 0x7070 + bne 1f + cmpwi r8, 0x0808 + bne 1f + cmpwi r9, 0x0909 + bne 1f + cmpwi r10, 0x1010 + bne 1f + cmpwi r11, 0x1111 + bne 1f + cmpwi r14, 0x1414 + bne 1f + cmpwi r15, 0x1515 + bne 1f + cmpwi r16, 0x1616 + bne 1f + cmpwi r17, 0x1717 + bne 1f + cmpwi r18, 0x1818 + bne 1f + cmpwi r19, 0x1919 + bne 1f + cmpwi r20, 0x2020 + bne 1f + cmpwi r21, 0x2121 + bne 1f + cmpwi r22, 0x2222 + bne 1f + cmpwi r23, 0x2323 + bne 1f + cmpwi r24, 0x2424 + bne 1f + cmpwi r25, 0x2525 + bne 1f + cmpwi r26, 0x2626 + bne 1f + cmpwi r27, 0x2727 + bne 1f + cmpwi r28, 0x2828 + bne 1f + cmpwi r29, 0x2929 + bne 1f + cmpwi r30, 0x3030 + bne 1f + cmpwi r31, 0x3131 + bne 1f + + /* Load junk into all our registers before we reload them from the stack. */ + li r3, 0xde + li r4, 0xad + li r5, 0xbe + li r6, 0xef + li r7, 0xde + li r8, 0xad + li r9, 0xbe + li r10, 0xef + li r11, 0xde + li r14, 0xad + li r15, 0xbe + li r16, 0xef + li r17, 0xde + li r18, 0xad + li r19, 0xbe + li r20, 0xef + li r21, 0xde + li r22, 0xad + li r23, 0xbe + li r24, 0xef + li r25, 0xde + li r26, 0xad + li r27, 0xbe + li r28, 0xef + li r29, 0xdd + + ld r3, -96(%r1) + cmpwi r3, 0x3030 + bne 1f + ld r4, -104(%r1) + cmpwi r4, 0x4040 + bne 1f + ld r5, -112(%r1) + cmpwi r5, 0x5050 + bne 1f + ld r6, -120(%r1) + cmpwi r6, 0x6060 + bne 1f + ld r7, -128(%r1) + cmpwi r7, 0x7070 + bne 1f + ld r8, -136(%r1) + cmpwi r8, 0x0808 + bne 1f + ld r9, -144(%r1) + cmpwi r9, 0x0909 + bne 1f + ld r10, -152(%r1) + cmpwi r10, 0x1010 + bne 1f + ld r11, -160(%r1) + cmpwi r11, 0x1111 + bne 1f + ld r14, -168(%r1) + cmpwi r14, 0x1414 + bne 1f + ld r15, -176(%r1) + cmpwi r15, 0x1515 + bne 1f + ld r16, -184(%r1) + cmpwi r16, 0x1616 + bne 1f + ld r17, -192(%r1) + cmpwi r17, 0x1717 + bne 1f + ld r18, -200(%r1) + cmpwi r18, 0x1818 + bne 1f + ld r19, -208(%r1) + cmpwi r19, 0x1919 + bne 1f + ld r20, -216(%r1) + cmpwi r20, 0x2020 + bne 1f + ld r21, -224(%r1) + cmpwi r21, 0x2121 + bne 1f + ld r22, -232(%r1) + cmpwi r22, 0x2222 + bne 1f + ld r23, -240(%r1) + cmpwi r23, 0x2323 + bne 1f + ld r24, -248(%r1) + cmpwi r24, 0x2424 + bne 1f + ld r25, -256(%r1) + cmpwi r25, 0x2525 + bne 1f + ld r26, -264(%r1) + cmpwi r26, 0x2626 + bne 1f + ld r27, -272(%r1) + cmpwi r27, 0x2727 + bne 1f + ld r28, -280(%r1) + cmpwi r28, 0x2828 + bne 1f + ld r29, -288(%r1) + cmpwi r29, 0x2929 + bne 1f + + /* Load 0 (success) to return */ + li r3, 0 + +1: ld r14, 160(%r1) + ld r15, 152(%r1) + ld r16, 144(%r1) + ld r17, 136(%r1) + ld r18, 128(%r1) + ld r19, 120(%r1) + ld r20, 112(%r1) + ld r21, 104(%r1) + ld r22, 96(%r1) + ld r23, 88(%r1) + ld r24, 80(%r1) + ld r25, 72(%r1) + ld r26, 64(%r1) + ld r27, 56(%r1) + ld r28, 48(%r1) + ld r29, 40(%r1) + ld r30, 32(%r1) + ld r31, 24(%r1) + addi %r1, %r1, 168 + blr diff --git a/powerpc/pmu/ebb/close_clears_pmcc_test.c b/powerpc/pmu/ebb/close_clears_pmcc_test.c new file mode 100644 index 0000000..0f0423d --- /dev/null +++ b/powerpc/pmu/ebb/close_clears_pmcc_test.c @@ -0,0 +1,59 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include +#include +#include + +#include "ebb.h" + + +/* + * Test that closing the EBB event clears MMCR0_PMCC, preventing further access + * by userspace to the PMU hardware. + */ + +int close_clears_pmcc(void) +{ + struct event event; + + event_init_named(&event, 0x1001e, "cycles"); + event_leader_ebb_init(&event); + + FAIL_IF(event_open(&event)); + + ebb_enable_pmc_counting(1); + setup_ebb_handler(standard_ebb_callee); + ebb_global_enable(); + FAIL_IF(ebb_event_enable(&event)); + + mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); + + while (ebb_state.stats.ebb_count < 1) + FAIL_IF(core_busy_loop()); + + ebb_global_disable(); + event_close(&event); + + FAIL_IF(ebb_state.stats.ebb_count == 0); + + /* The real test is here, do we take a SIGILL when writing PMU regs now + * that we have closed the event. We expect that we will. */ + + FAIL_IF(catch_sigill(write_pmc1)); + + /* We should still be able to read EBB regs though */ + mfspr(SPRN_EBBHR); + mfspr(SPRN_EBBRR); + mfspr(SPRN_BESCR); + + return 0; +} + +int main(void) +{ + return test_harness(close_clears_pmcc, "close_clears_pmcc"); +} diff --git a/powerpc/pmu/ebb/cpu_event_pinned_vs_ebb_test.c b/powerpc/pmu/ebb/cpu_event_pinned_vs_ebb_test.c new file mode 100644 index 0000000..d3ed64d --- /dev/null +++ b/powerpc/pmu/ebb/cpu_event_pinned_vs_ebb_test.c @@ -0,0 +1,93 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ebb.h" + + +/* + * Tests a pinned cpu event vs an EBB - in that order. The pinned cpu event + * should remain and the EBB event should fail to enable. + */ + +static int setup_cpu_event(struct event *event, int cpu) +{ + event_init_named(event, 0x400FA, "PM_RUN_INST_CMPL"); + + event->attr.pinned = 1; + + event->attr.exclude_kernel = 1; + event->attr.exclude_hv = 1; + event->attr.exclude_idle = 1; + + SKIP_IF(require_paranoia_below(1)); + FAIL_IF(event_open_with_cpu(event, cpu)); + FAIL_IF(event_enable(event)); + + return 0; +} + +int cpu_event_pinned_vs_ebb(void) +{ + union pipe read_pipe, write_pipe; + struct event event; + int cpu, rc; + pid_t pid; + + cpu = pick_online_cpu(); + FAIL_IF(cpu < 0); + FAIL_IF(bind_to_cpu(cpu)); + + FAIL_IF(pipe(read_pipe.fds) == -1); + FAIL_IF(pipe(write_pipe.fds) == -1); + + pid = fork(); + if (pid == 0) { + /* NB order of pipes looks reversed */ + exit(ebb_child(write_pipe, read_pipe)); + } + + /* We setup the cpu event first */ + rc = setup_cpu_event(&event, cpu); + if (rc) { + kill_child_and_wait(pid); + return rc; + } + + /* Signal the child to install its EBB event and wait */ + if (sync_with_child(read_pipe, write_pipe)) + /* If it fails, wait for it to exit */ + goto wait; + + /* Signal the child to run */ + FAIL_IF(sync_with_child(read_pipe, write_pipe)); + +wait: + /* We expect it to fail to read the event */ + FAIL_IF(wait_for_child(pid) != 2); + + FAIL_IF(event_disable(&event)); + FAIL_IF(event_read(&event)); + + event_report(&event); + + /* The cpu event should have run */ + FAIL_IF(event.result.value == 0); + FAIL_IF(event.result.enabled != event.result.running); + + return 0; +} + +int main(void) +{ + return test_harness(cpu_event_pinned_vs_ebb, "cpu_event_pinned_vs_ebb"); +} diff --git a/powerpc/pmu/ebb/cpu_event_vs_ebb_test.c b/powerpc/pmu/ebb/cpu_event_vs_ebb_test.c new file mode 100644 index 0000000..8b972c2 --- /dev/null +++ b/powerpc/pmu/ebb/cpu_event_vs_ebb_test.c @@ -0,0 +1,89 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ebb.h" + + +/* + * Tests a cpu event vs an EBB - in that order. The EBB should force the cpu + * event off the PMU. + */ + +static int setup_cpu_event(struct event *event, int cpu) +{ + event_init_named(event, 0x400FA, "PM_RUN_INST_CMPL"); + + event->attr.exclude_kernel = 1; + event->attr.exclude_hv = 1; + event->attr.exclude_idle = 1; + + SKIP_IF(require_paranoia_below(1)); + FAIL_IF(event_open_with_cpu(event, cpu)); + FAIL_IF(event_enable(event)); + + return 0; +} + +int cpu_event_vs_ebb(void) +{ + union pipe read_pipe, write_pipe; + struct event event; + int cpu, rc; + pid_t pid; + + cpu = pick_online_cpu(); + FAIL_IF(cpu < 0); + FAIL_IF(bind_to_cpu(cpu)); + + FAIL_IF(pipe(read_pipe.fds) == -1); + FAIL_IF(pipe(write_pipe.fds) == -1); + + pid = fork(); + if (pid == 0) { + /* NB order of pipes looks reversed */ + exit(ebb_child(write_pipe, read_pipe)); + } + + /* We setup the cpu event first */ + rc = setup_cpu_event(&event, cpu); + if (rc) { + kill_child_and_wait(pid); + return rc; + } + + /* Signal the child to install its EBB event and wait */ + if (sync_with_child(read_pipe, write_pipe)) + /* If it fails, wait for it to exit */ + goto wait; + + /* Signal the child to run */ + FAIL_IF(sync_with_child(read_pipe, write_pipe)); + +wait: + /* We expect the child to succeed */ + FAIL_IF(wait_for_child(pid)); + + FAIL_IF(event_disable(&event)); + FAIL_IF(event_read(&event)); + + event_report(&event); + + /* The cpu event may have run */ + + return 0; +} + +int main(void) +{ + return test_harness(cpu_event_vs_ebb, "cpu_event_vs_ebb"); +} diff --git a/powerpc/pmu/ebb/cycles_test.c b/powerpc/pmu/ebb/cycles_test.c new file mode 100644 index 0000000..8590fc1 --- /dev/null +++ b/powerpc/pmu/ebb/cycles_test.c @@ -0,0 +1,58 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include + +#include "ebb.h" + + +/* + * Basic test that counts user cycles and takes EBBs. + */ +int cycles(void) +{ + struct event event; + + event_init_named(&event, 0x1001e, "cycles"); + event_leader_ebb_init(&event); + + event.attr.exclude_kernel = 1; + event.attr.exclude_hv = 1; + event.attr.exclude_idle = 1; + + FAIL_IF(event_open(&event)); + + ebb_enable_pmc_counting(1); + setup_ebb_handler(standard_ebb_callee); + ebb_global_enable(); + FAIL_IF(ebb_event_enable(&event)); + + mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); + + while (ebb_state.stats.ebb_count < 10) { + FAIL_IF(core_busy_loop()); + FAIL_IF(ebb_check_mmcr0()); + } + + ebb_global_disable(); + ebb_freeze_pmcs(); + + count_pmc(1, sample_period); + + dump_ebb_state(); + + event_close(&event); + + FAIL_IF(ebb_state.stats.ebb_count == 0); + FAIL_IF(!ebb_check_count(1, sample_period, 100)); + + return 0; +} + +int main(void) +{ + return test_harness(cycles, "cycles"); +} diff --git a/powerpc/pmu/ebb/cycles_with_freeze_test.c b/powerpc/pmu/ebb/cycles_with_freeze_test.c new file mode 100644 index 0000000..754b3f2 --- /dev/null +++ b/powerpc/pmu/ebb/cycles_with_freeze_test.c @@ -0,0 +1,117 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include +#include + +#include "ebb.h" + + +/* + * Test of counting cycles while using MMCR0_FC (freeze counters) to only count + * parts of the code. This is complicated by the fact that FC is set by the + * hardware when the event overflows. We may take the EBB after we have set FC, + * so we have to be careful about whether we clear FC at the end of the EBB + * handler or not. + */ + +static bool counters_frozen = false; +static int ebbs_while_frozen = 0; + +static void ebb_callee(void) +{ + uint64_t mask, val; + + mask = MMCR0_PMAO | MMCR0_FC; + + val = mfspr(SPRN_BESCR); + if (!(val & BESCR_PMEO)) { + ebb_state.stats.spurious++; + goto out; + } + + ebb_state.stats.ebb_count++; + trace_log_counter(ebb_state.trace, ebb_state.stats.ebb_count); + + val = mfspr(SPRN_MMCR0); + trace_log_reg(ebb_state.trace, SPRN_MMCR0, val); + + if (counters_frozen) { + trace_log_string(ebb_state.trace, "frozen"); + ebbs_while_frozen++; + mask &= ~MMCR0_FC; + } + + count_pmc(1, sample_period); +out: + reset_ebb_with_clear_mask(mask); +} + +int cycles_with_freeze(void) +{ + struct event event; + uint64_t val; + bool fc_cleared; + + event_init_named(&event, 0x1001e, "cycles"); + event_leader_ebb_init(&event); + + event.attr.exclude_kernel = 1; + event.attr.exclude_hv = 1; + event.attr.exclude_idle = 1; + + FAIL_IF(event_open(&event)); + + setup_ebb_handler(ebb_callee); + ebb_global_enable(); + FAIL_IF(ebb_event_enable(&event)); + + mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); + + fc_cleared = false; + + /* Make sure we loop until we take at least one EBB */ + while ((ebb_state.stats.ebb_count < 20 && !fc_cleared) || + ebb_state.stats.ebb_count < 1) + { + counters_frozen = false; + mb(); + mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC); + + FAIL_IF(core_busy_loop()); + + counters_frozen = true; + mb(); + mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC); + + val = mfspr(SPRN_MMCR0); + if (! (val & MMCR0_FC)) { + printf("Outside of loop, FC NOT set MMCR0 0x%lx\n", val); + fc_cleared = true; + } + } + + ebb_global_disable(); + ebb_freeze_pmcs(); + + count_pmc(1, sample_period); + + dump_ebb_state(); + + printf("EBBs while frozen %d\n", ebbs_while_frozen); + + event_close(&event); + + FAIL_IF(ebb_state.stats.ebb_count == 0); + FAIL_IF(fc_cleared); + + return 0; +} + +int main(void) +{ + return test_harness(cycles_with_freeze, "cycles_with_freeze"); +} diff --git a/powerpc/pmu/ebb/cycles_with_mmcr2_test.c b/powerpc/pmu/ebb/cycles_with_mmcr2_test.c new file mode 100644 index 0000000..d43029b --- /dev/null +++ b/powerpc/pmu/ebb/cycles_with_mmcr2_test.c @@ -0,0 +1,91 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include +#include + +#include "ebb.h" + + +/* + * Test of counting cycles while manipulating the user accessible bits in MMCR2. + */ + +/* We use two values because the first freezes PMC1 and so we would get no EBBs */ +#define MMCR2_EXPECTED_1 0x4020100804020000UL /* (FC1P|FC2P|FC3P|FC4P|FC5P|FC6P) */ +#define MMCR2_EXPECTED_2 0x0020100804020000UL /* ( FC2P|FC3P|FC4P|FC5P|FC6P) */ + + +int cycles_with_mmcr2(void) +{ + struct event event; + uint64_t val, expected[2], actual; + int i; + bool bad_mmcr2; + + event_init_named(&event, 0x1001e, "cycles"); + event_leader_ebb_init(&event); + + event.attr.exclude_kernel = 1; + event.attr.exclude_hv = 1; + event.attr.exclude_idle = 1; + + FAIL_IF(event_open(&event)); + + ebb_enable_pmc_counting(1); + setup_ebb_handler(standard_ebb_callee); + ebb_global_enable(); + + FAIL_IF(ebb_event_enable(&event)); + + mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); + + /* XXX Set of MMCR2 must be after enable */ + expected[0] = MMCR2_EXPECTED_1; + expected[1] = MMCR2_EXPECTED_2; + i = 0; + bad_mmcr2 = false; + + /* Make sure we loop until we take at least one EBB */ + while ((ebb_state.stats.ebb_count < 20 && !bad_mmcr2) || + ebb_state.stats.ebb_count < 1) + { + mtspr(SPRN_MMCR2, expected[i % 2]); + + FAIL_IF(core_busy_loop()); + + val = mfspr(SPRN_MMCR2); + if (val != expected[i % 2]) { + bad_mmcr2 = true; + actual = val; + } + + i++; + } + + ebb_global_disable(); + ebb_freeze_pmcs(); + + count_pmc(1, sample_period); + + dump_ebb_state(); + + event_close(&event); + + FAIL_IF(ebb_state.stats.ebb_count == 0); + + if (bad_mmcr2) + printf("Bad MMCR2 value seen is 0x%lx\n", actual); + + FAIL_IF(bad_mmcr2); + + return 0; +} + +int main(void) +{ + return test_harness(cycles_with_mmcr2, "cycles_with_mmcr2"); +} diff --git a/powerpc/pmu/ebb/ebb.c b/powerpc/pmu/ebb/ebb.c new file mode 100644 index 0000000..d7a72ce --- /dev/null +++ b/powerpc/pmu/ebb/ebb.c @@ -0,0 +1,478 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#define _GNU_SOURCE /* For CPU_ZERO etc. */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "trace.h" +#include "reg.h" +#include "ebb.h" + + +void (*ebb_user_func)(void); + +void ebb_hook(void) +{ + if (ebb_user_func) + ebb_user_func(); +} + +struct ebb_state ebb_state; + +u64 sample_period = 0x40000000ull; + +void reset_ebb_with_clear_mask(unsigned long mmcr0_clear_mask) +{ + u64 val; + + /* 2) clear MMCR0[PMAO] - docs say BESCR[PMEO] should do this */ + /* 3) set MMCR0[PMAE] - docs say BESCR[PME] should do this */ + val = mfspr(SPRN_MMCR0); + mtspr(SPRN_MMCR0, (val & ~mmcr0_clear_mask) | MMCR0_PMAE); + + /* 4) clear BESCR[PMEO] */ + mtspr(SPRN_BESCRR, BESCR_PMEO); + + /* 5) set BESCR[PME] */ + mtspr(SPRN_BESCRS, BESCR_PME); + + /* 6) rfebb 1 - done in our caller */ +} + +void reset_ebb(void) +{ + reset_ebb_with_clear_mask(MMCR0_PMAO | MMCR0_FC); +} + +/* Called outside of the EBB handler to check MMCR0 is sane */ +int ebb_check_mmcr0(void) +{ + u64 val; + + val = mfspr(SPRN_MMCR0); + if ((val & (MMCR0_FC | MMCR0_PMAO)) == MMCR0_FC) { + /* It's OK if we see FC & PMAO, but not FC by itself */ + printf("Outside of loop, only FC set 0x%llx\n", val); + return 1; + } + + return 0; +} + +bool ebb_check_count(int pmc, u64 sample_period, int fudge) +{ + u64 count, upper, lower; + + count = ebb_state.stats.pmc_count[PMC_INDEX(pmc)]; + + lower = ebb_state.stats.ebb_count * (sample_period - fudge); + + if (count < lower) { + printf("PMC%d count (0x%llx) below lower limit 0x%llx (-0x%llx)\n", + pmc, count, lower, lower - count); + return false; + } + + upper = ebb_state.stats.ebb_count * (sample_period + fudge); + + if (count > upper) { + printf("PMC%d count (0x%llx) above upper limit 0x%llx (+0x%llx)\n", + pmc, count, upper, count - upper); + return false; + } + + printf("PMC%d count (0x%llx) is between 0x%llx and 0x%llx delta +0x%llx/-0x%llx\n", + pmc, count, lower, upper, count - lower, upper - count); + + return true; +} + +void standard_ebb_callee(void) +{ + int found, i; + u64 val; + + val = mfspr(SPRN_BESCR); + if (!(val & BESCR_PMEO)) { + ebb_state.stats.spurious++; + goto out; + } + + ebb_state.stats.ebb_count++; + trace_log_counter(ebb_state.trace, ebb_state.stats.ebb_count); + + val = mfspr(SPRN_MMCR0); + trace_log_reg(ebb_state.trace, SPRN_MMCR0, val); + + found = 0; + for (i = 1; i <= 6; i++) { + if (ebb_state.pmc_enable[PMC_INDEX(i)]) + found += count_pmc(i, sample_period); + } + + if (!found) + ebb_state.stats.no_overflow++; + +out: + reset_ebb(); +} + +extern void ebb_handler(void); + +void setup_ebb_handler(void (*callee)(void)) +{ + u64 entry; + +#if defined(_CALL_ELF) && _CALL_ELF == 2 + entry = (u64)ebb_handler; +#else + struct opd + { + u64 entry; + u64 toc; + } *opd; + + opd = (struct opd *)ebb_handler; + entry = opd->entry; +#endif + printf("EBB Handler is at %#llx\n", entry); + + ebb_user_func = callee; + + /* Ensure ebb_user_func is set before we set the handler */ + mb(); + mtspr(SPRN_EBBHR, entry); + + /* Make sure the handler is set before we return */ + mb(); +} + +void clear_ebb_stats(void) +{ + memset(&ebb_state.stats, 0, sizeof(ebb_state.stats)); +} + +void dump_summary_ebb_state(void) +{ + printf("ebb_state:\n" \ + " ebb_count = %d\n" \ + " spurious = %d\n" \ + " negative = %d\n" \ + " no_overflow = %d\n" \ + " pmc[1] count = 0x%llx\n" \ + " pmc[2] count = 0x%llx\n" \ + " pmc[3] count = 0x%llx\n" \ + " pmc[4] count = 0x%llx\n" \ + " pmc[5] count = 0x%llx\n" \ + " pmc[6] count = 0x%llx\n", + ebb_state.stats.ebb_count, ebb_state.stats.spurious, + ebb_state.stats.negative, ebb_state.stats.no_overflow, + ebb_state.stats.pmc_count[0], ebb_state.stats.pmc_count[1], + ebb_state.stats.pmc_count[2], ebb_state.stats.pmc_count[3], + ebb_state.stats.pmc_count[4], ebb_state.stats.pmc_count[5]); +} + +static char *decode_mmcr0(u32 value) +{ + static char buf[16]; + + buf[0] = '\0'; + + if (value & (1 << 31)) + strcat(buf, "FC "); + if (value & (1 << 26)) + strcat(buf, "PMAE "); + if (value & (1 << 7)) + strcat(buf, "PMAO "); + + return buf; +} + +static char *decode_bescr(u64 value) +{ + static char buf[16]; + + buf[0] = '\0'; + + if (value & (1ull << 63)) + strcat(buf, "GE "); + if (value & (1ull << 32)) + strcat(buf, "PMAE "); + if (value & 1) + strcat(buf, "PMAO "); + + return buf; +} + +void dump_ebb_hw_state(void) +{ + u64 bescr; + u32 mmcr0; + + mmcr0 = mfspr(SPRN_MMCR0); + bescr = mfspr(SPRN_BESCR); + + printf("HW state:\n" \ + "MMCR0 0x%016x %s\n" \ + "MMCR2 0x%016lx\n" \ + "EBBHR 0x%016lx\n" \ + "BESCR 0x%016llx %s\n" \ + "PMC1 0x%016lx\n" \ + "PMC2 0x%016lx\n" \ + "PMC3 0x%016lx\n" \ + "PMC4 0x%016lx\n" \ + "PMC5 0x%016lx\n" \ + "PMC6 0x%016lx\n" \ + "SIAR 0x%016lx\n", + mmcr0, decode_mmcr0(mmcr0), mfspr(SPRN_MMCR2), + mfspr(SPRN_EBBHR), bescr, decode_bescr(bescr), + mfspr(SPRN_PMC1), mfspr(SPRN_PMC2), mfspr(SPRN_PMC3), + mfspr(SPRN_PMC4), mfspr(SPRN_PMC5), mfspr(SPRN_PMC6), + mfspr(SPRN_SIAR)); +} + +void dump_ebb_state(void) +{ + dump_summary_ebb_state(); + + dump_ebb_hw_state(); + + trace_buffer_print(ebb_state.trace); +} + +int count_pmc(int pmc, uint32_t sample_period) +{ + uint32_t start_value; + u64 val; + + /* 0) Read PMC */ + start_value = pmc_sample_period(sample_period); + + val = read_pmc(pmc); + if (val < start_value) + ebb_state.stats.negative++; + else + ebb_state.stats.pmc_count[PMC_INDEX(pmc)] += val - start_value; + + trace_log_reg(ebb_state.trace, SPRN_PMC1 + pmc - 1, val); + + /* 1) Reset PMC */ + write_pmc(pmc, start_value); + + /* Report if we overflowed */ + return val >= COUNTER_OVERFLOW; +} + +int ebb_event_enable(struct event *e) +{ + int rc; + + /* Ensure any SPR writes are ordered vs us */ + mb(); + + rc = ioctl(e->fd, PERF_EVENT_IOC_ENABLE); + if (rc) + return rc; + + rc = event_read(e); + + /* Ditto */ + mb(); + + return rc; +} + +void ebb_freeze_pmcs(void) +{ + mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC); + mb(); +} + +void ebb_unfreeze_pmcs(void) +{ + /* Unfreeze counters */ + mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC); + mb(); +} + +void ebb_global_enable(void) +{ + /* Enable EBBs globally and PMU EBBs */ + mtspr(SPRN_BESCR, 0x8000000100000000ull); + mb(); +} + +void ebb_global_disable(void) +{ + /* Disable EBBs & freeze counters, events are still scheduled */ + mtspr(SPRN_BESCRR, BESCR_PME); + mb(); +} + +void event_ebb_init(struct event *e) +{ + e->attr.config |= (1ull << 63); +} + +void event_bhrb_init(struct event *e, unsigned ifm) +{ + e->attr.config |= (1ull << 62) | ((u64)ifm << 60); +} + +void event_leader_ebb_init(struct event *e) +{ + event_ebb_init(e); + + e->attr.exclusive = 1; + e->attr.pinned = 1; +} + +int ebb_child(union pipe read_pipe, union pipe write_pipe) +{ + struct event event; + uint64_t val; + + FAIL_IF(wait_for_parent(read_pipe)); + + event_init_named(&event, 0x1001e, "cycles"); + event_leader_ebb_init(&event); + + event.attr.exclude_kernel = 1; + event.attr.exclude_hv = 1; + event.attr.exclude_idle = 1; + + FAIL_IF(event_open(&event)); + + ebb_enable_pmc_counting(1); + setup_ebb_handler(standard_ebb_callee); + ebb_global_enable(); + + FAIL_IF(event_enable(&event)); + + if (event_read(&event)) { + /* + * Some tests expect to fail here, so don't report an error on + * this line, and return a distinguisable error code. Tell the + * parent an error happened. + */ + notify_parent_of_error(write_pipe); + return 2; + } + + mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); + + FAIL_IF(notify_parent(write_pipe)); + FAIL_IF(wait_for_parent(read_pipe)); + FAIL_IF(notify_parent(write_pipe)); + + while (ebb_state.stats.ebb_count < 20) { + FAIL_IF(core_busy_loop()); + + /* To try and hit SIGILL case */ + val = mfspr(SPRN_MMCRA); + val |= mfspr(SPRN_MMCR2); + val |= mfspr(SPRN_MMCR0); + } + + ebb_global_disable(); + ebb_freeze_pmcs(); + + count_pmc(1, sample_period); + + dump_ebb_state(); + + event_close(&event); + + FAIL_IF(ebb_state.stats.ebb_count == 0); + + return 0; +} + +static jmp_buf setjmp_env; + +static void sigill_handler(int signal) +{ + printf("Took sigill\n"); + longjmp(setjmp_env, 1); +} + +static struct sigaction sigill_action = { + .sa_handler = sigill_handler, +}; + +int catch_sigill(void (*func)(void)) +{ + if (sigaction(SIGILL, &sigill_action, NULL)) { + perror("sigaction"); + return 1; + } + + if (setjmp(setjmp_env) == 0) { + func(); + return 1; + } + + return 0; +} + +void write_pmc1(void) +{ + mtspr(SPRN_PMC1, 0); +} + +void write_pmc(int pmc, u64 value) +{ + switch (pmc) { + case 1: mtspr(SPRN_PMC1, value); break; + case 2: mtspr(SPRN_PMC2, value); break; + case 3: mtspr(SPRN_PMC3, value); break; + case 4: mtspr(SPRN_PMC4, value); break; + case 5: mtspr(SPRN_PMC5, value); break; + case 6: mtspr(SPRN_PMC6, value); break; + } +} + +u64 read_pmc(int pmc) +{ + switch (pmc) { + case 1: return mfspr(SPRN_PMC1); + case 2: return mfspr(SPRN_PMC2); + case 3: return mfspr(SPRN_PMC3); + case 4: return mfspr(SPRN_PMC4); + case 5: return mfspr(SPRN_PMC5); + case 6: return mfspr(SPRN_PMC6); + } + + return 0; +} + +static void term_handler(int signal) +{ + dump_summary_ebb_state(); + dump_ebb_hw_state(); + abort(); +} + +struct sigaction term_action = { + .sa_handler = term_handler, +}; + +static void __attribute__((constructor)) ebb_init(void) +{ + clear_ebb_stats(); + + if (sigaction(SIGTERM, &term_action, NULL)) + perror("sigaction"); + + ebb_state.trace = trace_buffer_allocate(1 * 1024 * 1024); +} diff --git a/powerpc/pmu/ebb/ebb.h b/powerpc/pmu/ebb/ebb.h new file mode 100644 index 0000000..e44eee5 --- /dev/null +++ b/powerpc/pmu/ebb/ebb.h @@ -0,0 +1,77 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#ifndef _SELFTESTS_POWERPC_PMU_EBB_EBB_H +#define _SELFTESTS_POWERPC_PMU_EBB_EBB_H + +#include "../event.h" +#include "../lib.h" +#include "trace.h" +#include "reg.h" + +#define PMC_INDEX(pmc) ((pmc)-1) + +#define NUM_PMC_VALUES 128 + +struct ebb_state +{ + struct { + u64 pmc_count[6]; + volatile int ebb_count; + int spurious; + int negative; + int no_overflow; + } stats; + + bool pmc_enable[6]; + struct trace_buffer *trace; +}; + +extern struct ebb_state ebb_state; + +#define COUNTER_OVERFLOW 0x80000000ull + +static inline uint32_t pmc_sample_period(uint32_t value) +{ + return COUNTER_OVERFLOW - value; +} + +static inline void ebb_enable_pmc_counting(int pmc) +{ + ebb_state.pmc_enable[PMC_INDEX(pmc)] = true; +} + +bool ebb_check_count(int pmc, u64 sample_period, int fudge); +void event_leader_ebb_init(struct event *e); +void event_ebb_init(struct event *e); +void event_bhrb_init(struct event *e, unsigned ifm); +void setup_ebb_handler(void (*callee)(void)); +void standard_ebb_callee(void); +int ebb_event_enable(struct event *e); +void ebb_global_enable(void); +void ebb_global_disable(void); +void ebb_freeze_pmcs(void); +void ebb_unfreeze_pmcs(void); +void event_ebb_init(struct event *e); +void event_leader_ebb_init(struct event *e); +int count_pmc(int pmc, uint32_t sample_period); +void dump_ebb_state(void); +void dump_summary_ebb_state(void); +void dump_ebb_hw_state(void); +void clear_ebb_stats(void); +void write_pmc(int pmc, u64 value); +u64 read_pmc(int pmc); +void reset_ebb_with_clear_mask(unsigned long mmcr0_clear_mask); +void reset_ebb(void); +int ebb_check_mmcr0(void); + +extern u64 sample_period; + +int core_busy_loop(void); +int ebb_child(union pipe read_pipe, union pipe write_pipe); +int catch_sigill(void (*func)(void)); +void write_pmc1(void); + +#endif /* _SELFTESTS_POWERPC_PMU_EBB_EBB_H */ diff --git a/powerpc/pmu/ebb/ebb_handler.S b/powerpc/pmu/ebb/ebb_handler.S new file mode 100644 index 0000000..14274ea --- /dev/null +++ b/powerpc/pmu/ebb/ebb_handler.S @@ -0,0 +1,365 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include "reg.h" + + +/* ppc-asm.h defines most of the reg aliases, but not r1/r2. */ +#define r1 1 +#define r2 2 + +#define RFEBB .long 0x4c000924 + +/* Stack layout: + * + * ^ + * User stack | + * Back chain ------+ <- r1 <-------+ + * ... | + * Red zone / ABI Gap | + * ... | + * vr63 <+ | + * vr0 | | + * VSCR | | + * FSCR | | + * r31 | Save area | + * r0 | | + * XER | | + * CTR | | + * LR | | + * CCR <+ | + * ... <+ | + * LR | Caller frame | + * CCR | | + * Back chain <+ <- updated r1 --------+ + * + */ + +#if defined(_CALL_ELF) && _CALL_ELF == 2 +#define ABIGAP 512 +#else +#define ABIGAP 288 +#endif + +#define NR_GPR 32 +#define NR_SPR 6 +#define NR_VSR 64 + +#define SAVE_AREA ((NR_GPR + NR_SPR) * 8 + (NR_VSR * 16)) +#define CALLER_FRAME 112 + +#define STACK_FRAME (ABIGAP + SAVE_AREA + CALLER_FRAME) + +#define CCR_SAVE (CALLER_FRAME) +#define LR_SAVE (CCR_SAVE + 8) +#define CTR_SAVE (LR_SAVE + 8) +#define XER_SAVE (CTR_SAVE + 8) +#define GPR_SAVE(n) (XER_SAVE + 8 + (8 * n)) +#define FSCR_SAVE (GPR_SAVE(31) + 8) +#define VSCR_SAVE (FSCR_SAVE + 8) +#define VSR_SAVE(n) (VSCR_SAVE + 8 + (16 * n)) + +#define SAVE_GPR(n) std n,GPR_SAVE(n)(r1) +#define REST_GPR(n) ld n,GPR_SAVE(n)(r1) +#define TRASH_GPR(n) lis n,0xaaaa + +#define SAVE_VSR(n, b) li b, VSR_SAVE(n); stxvd2x n,b,r1 +#define LOAD_VSR(n, b) li b, VSR_SAVE(n); lxvd2x n,b,r1 + +#define LOAD_REG_IMMEDIATE(reg,expr) \ + lis reg,(expr)@highest; \ + ori reg,reg,(expr)@higher; \ + rldicr reg,reg,32,31; \ + oris reg,reg,(expr)@h; \ + ori reg,reg,(expr)@l; + + +#if defined(_CALL_ELF) && _CALL_ELF == 2 +#define ENTRY_POINT(name) \ + .type FUNC_NAME(name),@function; \ + .globl FUNC_NAME(name); \ + FUNC_NAME(name): + +#define RESTORE_TOC(name) \ + /* Restore our TOC pointer using our entry point */ \ + LOAD_REG_IMMEDIATE(r12, name) \ +0: addis r2,r12,(.TOC.-0b)@ha; \ + addi r2,r2,(.TOC.-0b)@l; + +#else +#define ENTRY_POINT(name) FUNC_START(name) +#define RESTORE_TOC(name) \ + /* Restore our TOC pointer via our opd entry */ \ + LOAD_REG_IMMEDIATE(r2, name) \ + ld r2,8(r2); +#endif + + .text + +ENTRY_POINT(ebb_handler) + stdu r1,-STACK_FRAME(r1) + SAVE_GPR(0) + mflr r0 + std r0,LR_SAVE(r1) + mfcr r0 + std r0,CCR_SAVE(r1) + mfctr r0 + std r0,CTR_SAVE(r1) + mfxer r0 + std r0,XER_SAVE(r1) + SAVE_GPR(2) + SAVE_GPR(3) + SAVE_GPR(4) + SAVE_GPR(5) + SAVE_GPR(6) + SAVE_GPR(7) + SAVE_GPR(8) + SAVE_GPR(9) + SAVE_GPR(10) + SAVE_GPR(11) + SAVE_GPR(12) + SAVE_GPR(13) + SAVE_GPR(14) + SAVE_GPR(15) + SAVE_GPR(16) + SAVE_GPR(17) + SAVE_GPR(18) + SAVE_GPR(19) + SAVE_GPR(20) + SAVE_GPR(21) + SAVE_GPR(22) + SAVE_GPR(23) + SAVE_GPR(24) + SAVE_GPR(25) + SAVE_GPR(26) + SAVE_GPR(27) + SAVE_GPR(28) + SAVE_GPR(29) + SAVE_GPR(30) + SAVE_GPR(31) + SAVE_VSR(0, r3) + mffs f0 + stfd f0, FSCR_SAVE(r1) + mfvscr f0 + stfd f0, VSCR_SAVE(r1) + SAVE_VSR(1, r3) + SAVE_VSR(2, r3) + SAVE_VSR(3, r3) + SAVE_VSR(4, r3) + SAVE_VSR(5, r3) + SAVE_VSR(6, r3) + SAVE_VSR(7, r3) + SAVE_VSR(8, r3) + SAVE_VSR(9, r3) + SAVE_VSR(10, r3) + SAVE_VSR(11, r3) + SAVE_VSR(12, r3) + SAVE_VSR(13, r3) + SAVE_VSR(14, r3) + SAVE_VSR(15, r3) + SAVE_VSR(16, r3) + SAVE_VSR(17, r3) + SAVE_VSR(18, r3) + SAVE_VSR(19, r3) + SAVE_VSR(20, r3) + SAVE_VSR(21, r3) + SAVE_VSR(22, r3) + SAVE_VSR(23, r3) + SAVE_VSR(24, r3) + SAVE_VSR(25, r3) + SAVE_VSR(26, r3) + SAVE_VSR(27, r3) + SAVE_VSR(28, r3) + SAVE_VSR(29, r3) + SAVE_VSR(30, r3) + SAVE_VSR(31, r3) + SAVE_VSR(32, r3) + SAVE_VSR(33, r3) + SAVE_VSR(34, r3) + SAVE_VSR(35, r3) + SAVE_VSR(36, r3) + SAVE_VSR(37, r3) + SAVE_VSR(38, r3) + SAVE_VSR(39, r3) + SAVE_VSR(40, r3) + SAVE_VSR(41, r3) + SAVE_VSR(42, r3) + SAVE_VSR(43, r3) + SAVE_VSR(44, r3) + SAVE_VSR(45, r3) + SAVE_VSR(46, r3) + SAVE_VSR(47, r3) + SAVE_VSR(48, r3) + SAVE_VSR(49, r3) + SAVE_VSR(50, r3) + SAVE_VSR(51, r3) + SAVE_VSR(52, r3) + SAVE_VSR(53, r3) + SAVE_VSR(54, r3) + SAVE_VSR(55, r3) + SAVE_VSR(56, r3) + SAVE_VSR(57, r3) + SAVE_VSR(58, r3) + SAVE_VSR(59, r3) + SAVE_VSR(60, r3) + SAVE_VSR(61, r3) + SAVE_VSR(62, r3) + SAVE_VSR(63, r3) + + TRASH_GPR(2) + TRASH_GPR(3) + TRASH_GPR(4) + TRASH_GPR(5) + TRASH_GPR(6) + TRASH_GPR(7) + TRASH_GPR(8) + TRASH_GPR(9) + TRASH_GPR(10) + TRASH_GPR(11) + TRASH_GPR(12) + TRASH_GPR(14) + TRASH_GPR(15) + TRASH_GPR(16) + TRASH_GPR(17) + TRASH_GPR(18) + TRASH_GPR(19) + TRASH_GPR(20) + TRASH_GPR(21) + TRASH_GPR(22) + TRASH_GPR(23) + TRASH_GPR(24) + TRASH_GPR(25) + TRASH_GPR(26) + TRASH_GPR(27) + TRASH_GPR(28) + TRASH_GPR(29) + TRASH_GPR(30) + TRASH_GPR(31) + + RESTORE_TOC(ebb_handler) + + /* + * r13 is our TLS pointer. We leave whatever value was in there when the + * EBB fired. That seems to be OK because once set the TLS pointer is not + * changed - but presumably that could change in future. + */ + + bl ebb_hook + nop + + /* r2 may be changed here but we don't care */ + + lfd f0, FSCR_SAVE(r1) + mtfsf 0xff,f0 + lfd f0, VSCR_SAVE(r1) + mtvscr f0 + LOAD_VSR(0, r3) + LOAD_VSR(1, r3) + LOAD_VSR(2, r3) + LOAD_VSR(3, r3) + LOAD_VSR(4, r3) + LOAD_VSR(5, r3) + LOAD_VSR(6, r3) + LOAD_VSR(7, r3) + LOAD_VSR(8, r3) + LOAD_VSR(9, r3) + LOAD_VSR(10, r3) + LOAD_VSR(11, r3) + LOAD_VSR(12, r3) + LOAD_VSR(13, r3) + LOAD_VSR(14, r3) + LOAD_VSR(15, r3) + LOAD_VSR(16, r3) + LOAD_VSR(17, r3) + LOAD_VSR(18, r3) + LOAD_VSR(19, r3) + LOAD_VSR(20, r3) + LOAD_VSR(21, r3) + LOAD_VSR(22, r3) + LOAD_VSR(23, r3) + LOAD_VSR(24, r3) + LOAD_VSR(25, r3) + LOAD_VSR(26, r3) + LOAD_VSR(27, r3) + LOAD_VSR(28, r3) + LOAD_VSR(29, r3) + LOAD_VSR(30, r3) + LOAD_VSR(31, r3) + LOAD_VSR(32, r3) + LOAD_VSR(33, r3) + LOAD_VSR(34, r3) + LOAD_VSR(35, r3) + LOAD_VSR(36, r3) + LOAD_VSR(37, r3) + LOAD_VSR(38, r3) + LOAD_VSR(39, r3) + LOAD_VSR(40, r3) + LOAD_VSR(41, r3) + LOAD_VSR(42, r3) + LOAD_VSR(43, r3) + LOAD_VSR(44, r3) + LOAD_VSR(45, r3) + LOAD_VSR(46, r3) + LOAD_VSR(47, r3) + LOAD_VSR(48, r3) + LOAD_VSR(49, r3) + LOAD_VSR(50, r3) + LOAD_VSR(51, r3) + LOAD_VSR(52, r3) + LOAD_VSR(53, r3) + LOAD_VSR(54, r3) + LOAD_VSR(55, r3) + LOAD_VSR(56, r3) + LOAD_VSR(57, r3) + LOAD_VSR(58, r3) + LOAD_VSR(59, r3) + LOAD_VSR(60, r3) + LOAD_VSR(61, r3) + LOAD_VSR(62, r3) + LOAD_VSR(63, r3) + + ld r0,XER_SAVE(r1) + mtxer r0 + ld r0,CTR_SAVE(r1) + mtctr r0 + ld r0,LR_SAVE(r1) + mtlr r0 + ld r0,CCR_SAVE(r1) + mtcr r0 + REST_GPR(0) + REST_GPR(2) + REST_GPR(3) + REST_GPR(4) + REST_GPR(5) + REST_GPR(6) + REST_GPR(7) + REST_GPR(8) + REST_GPR(9) + REST_GPR(10) + REST_GPR(11) + REST_GPR(12) + REST_GPR(13) + REST_GPR(14) + REST_GPR(15) + REST_GPR(16) + REST_GPR(17) + REST_GPR(18) + REST_GPR(19) + REST_GPR(20) + REST_GPR(21) + REST_GPR(22) + REST_GPR(23) + REST_GPR(24) + REST_GPR(25) + REST_GPR(26) + REST_GPR(27) + REST_GPR(28) + REST_GPR(29) + REST_GPR(30) + REST_GPR(31) + addi r1,r1,STACK_FRAME + RFEBB +FUNC_END(ebb_handler) diff --git a/powerpc/pmu/ebb/ebb_on_child_test.c b/powerpc/pmu/ebb/ebb_on_child_test.c new file mode 100644 index 0000000..c45f948 --- /dev/null +++ b/powerpc/pmu/ebb/ebb_on_child_test.c @@ -0,0 +1,86 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ebb.h" + + +/* + * Tests we can setup an EBB on our child. Nothing interesting happens, because + * even though the event is enabled and running the child hasn't enabled the + * actual delivery of the EBBs. + */ + +static int victim_child(union pipe read_pipe, union pipe write_pipe) +{ + int i; + + FAIL_IF(wait_for_parent(read_pipe)); + FAIL_IF(notify_parent(write_pipe)); + + /* Parent creates EBB event */ + + FAIL_IF(wait_for_parent(read_pipe)); + FAIL_IF(notify_parent(write_pipe)); + + /* Check the EBB is enabled by writing PMC1 */ + write_pmc1(); + + /* EBB event is enabled here */ + for (i = 0; i < 1000000; i++) ; + + return 0; +} + +int ebb_on_child(void) +{ + union pipe read_pipe, write_pipe; + struct event event; + pid_t pid; + + FAIL_IF(pipe(read_pipe.fds) == -1); + FAIL_IF(pipe(write_pipe.fds) == -1); + + pid = fork(); + if (pid == 0) { + /* NB order of pipes looks reversed */ + exit(victim_child(write_pipe, read_pipe)); + } + + FAIL_IF(sync_with_child(read_pipe, write_pipe)); + + /* Child is running now */ + + event_init_named(&event, 0x1001e, "cycles"); + event_leader_ebb_init(&event); + + event.attr.exclude_kernel = 1; + event.attr.exclude_hv = 1; + event.attr.exclude_idle = 1; + + FAIL_IF(event_open_with_pid(&event, pid)); + FAIL_IF(ebb_event_enable(&event)); + + FAIL_IF(sync_with_child(read_pipe, write_pipe)); + + /* Child should just exit happily */ + FAIL_IF(wait_for_child(pid)); + + event_close(&event); + + return 0; +} + +int main(void) +{ + return test_harness(ebb_on_child, "ebb_on_child"); +} diff --git a/powerpc/pmu/ebb/ebb_on_willing_child_test.c b/powerpc/pmu/ebb/ebb_on_willing_child_test.c new file mode 100644 index 0000000..11acf1d --- /dev/null +++ b/powerpc/pmu/ebb/ebb_on_willing_child_test.c @@ -0,0 +1,92 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ebb.h" + + +/* + * Tests we can setup an EBB on our child. The child expects this and enables + * EBBs, which are then delivered to the child, even though the event is + * created by the parent. + */ + +static int victim_child(union pipe read_pipe, union pipe write_pipe) +{ + FAIL_IF(wait_for_parent(read_pipe)); + + /* Setup our EBB handler, before the EBB event is created */ + ebb_enable_pmc_counting(1); + setup_ebb_handler(standard_ebb_callee); + ebb_global_enable(); + + FAIL_IF(notify_parent(write_pipe)); + + while (ebb_state.stats.ebb_count < 20) { + FAIL_IF(core_busy_loop()); + } + + ebb_global_disable(); + ebb_freeze_pmcs(); + + count_pmc(1, sample_period); + + dump_ebb_state(); + + FAIL_IF(ebb_state.stats.ebb_count == 0); + + return 0; +} + +/* Tests we can setup an EBB on our child - if it's expecting it */ +int ebb_on_willing_child(void) +{ + union pipe read_pipe, write_pipe; + struct event event; + pid_t pid; + + FAIL_IF(pipe(read_pipe.fds) == -1); + FAIL_IF(pipe(write_pipe.fds) == -1); + + pid = fork(); + if (pid == 0) { + /* NB order of pipes looks reversed */ + exit(victim_child(write_pipe, read_pipe)); + } + + /* Signal the child to setup its EBB handler */ + FAIL_IF(sync_with_child(read_pipe, write_pipe)); + + /* Child is running now */ + + event_init_named(&event, 0x1001e, "cycles"); + event_leader_ebb_init(&event); + + event.attr.exclude_kernel = 1; + event.attr.exclude_hv = 1; + event.attr.exclude_idle = 1; + + FAIL_IF(event_open_with_pid(&event, pid)); + FAIL_IF(ebb_event_enable(&event)); + + /* Child show now take EBBs and then exit */ + FAIL_IF(wait_for_child(pid)); + + event_close(&event); + + return 0; +} + +int main(void) +{ + return test_harness(ebb_on_willing_child, "ebb_on_willing_child"); +} diff --git a/powerpc/pmu/ebb/ebb_vs_cpu_event_test.c b/powerpc/pmu/ebb/ebb_vs_cpu_event_test.c new file mode 100644 index 0000000..be4dd5a --- /dev/null +++ b/powerpc/pmu/ebb/ebb_vs_cpu_event_test.c @@ -0,0 +1,86 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ebb.h" + + +/* + * Tests an EBB vs a cpu event - in that order. The EBB should force the cpu + * event off the PMU. + */ + +static int setup_cpu_event(struct event *event, int cpu) +{ + event_init_named(event, 0x400FA, "PM_RUN_INST_CMPL"); + + event->attr.exclude_kernel = 1; + event->attr.exclude_hv = 1; + event->attr.exclude_idle = 1; + + SKIP_IF(require_paranoia_below(1)); + FAIL_IF(event_open_with_cpu(event, cpu)); + FAIL_IF(event_enable(event)); + + return 0; +} + +int ebb_vs_cpu_event(void) +{ + union pipe read_pipe, write_pipe; + struct event event; + int cpu, rc; + pid_t pid; + + cpu = pick_online_cpu(); + FAIL_IF(cpu < 0); + FAIL_IF(bind_to_cpu(cpu)); + + FAIL_IF(pipe(read_pipe.fds) == -1); + FAIL_IF(pipe(write_pipe.fds) == -1); + + pid = fork(); + if (pid == 0) { + /* NB order of pipes looks reversed */ + exit(ebb_child(write_pipe, read_pipe)); + } + + /* Signal the child to install its EBB event and wait */ + FAIL_IF(sync_with_child(read_pipe, write_pipe)); + + /* Now try to install our CPU event */ + rc = setup_cpu_event(&event, cpu); + if (rc) { + kill_child_and_wait(pid); + return rc; + } + + /* Signal the child to run */ + FAIL_IF(sync_with_child(read_pipe, write_pipe)); + + /* .. and wait for it to complete */ + FAIL_IF(wait_for_child(pid)); + FAIL_IF(event_disable(&event)); + FAIL_IF(event_read(&event)); + + event_report(&event); + + /* The cpu event may have run, but we don't expect 100% */ + FAIL_IF(event.result.enabled >= event.result.running); + + return 0; +} + +int main(void) +{ + return test_harness(ebb_vs_cpu_event, "ebb_vs_cpu_event"); +} diff --git a/powerpc/pmu/ebb/event_attributes_test.c b/powerpc/pmu/ebb/event_attributes_test.c new file mode 100644 index 0000000..7e78153 --- /dev/null +++ b/powerpc/pmu/ebb/event_attributes_test.c @@ -0,0 +1,131 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include + +#include "ebb.h" + + +/* + * Test various attributes of the EBB event are enforced. + */ +int event_attributes(void) +{ + struct event event, leader; + + event_init(&event, 0x1001e); + event_leader_ebb_init(&event); + /* Expected to succeed */ + FAIL_IF(event_open(&event)); + event_close(&event); + + + event_init(&event, 0x001e); /* CYCLES - no PMC specified */ + event_leader_ebb_init(&event); + /* Expected to fail, no PMC specified */ + FAIL_IF(event_open(&event) == 0); + + + event_init(&event, 0x2001e); + event_leader_ebb_init(&event); + event.attr.exclusive = 0; + /* Expected to fail, not exclusive */ + FAIL_IF(event_open(&event) == 0); + + + event_init(&event, 0x3001e); + event_leader_ebb_init(&event); + event.attr.freq = 1; + /* Expected to fail, sets freq */ + FAIL_IF(event_open(&event) == 0); + + + event_init(&event, 0x4001e); + event_leader_ebb_init(&event); + event.attr.sample_period = 1; + /* Expected to fail, sets sample_period */ + FAIL_IF(event_open(&event) == 0); + + + event_init(&event, 0x1001e); + event_leader_ebb_init(&event); + event.attr.enable_on_exec = 1; + /* Expected to fail, sets enable_on_exec */ + FAIL_IF(event_open(&event) == 0); + + + event_init(&event, 0x1001e); + event_leader_ebb_init(&event); + event.attr.inherit = 1; + /* Expected to fail, sets inherit */ + FAIL_IF(event_open(&event) == 0); + + + event_init(&leader, 0x1001e); + event_leader_ebb_init(&leader); + FAIL_IF(event_open(&leader)); + + event_init(&event, 0x20002); + event_ebb_init(&event); + + /* Expected to succeed */ + FAIL_IF(event_open_with_group(&event, leader.fd)); + event_close(&leader); + event_close(&event); + + + event_init(&leader, 0x1001e); + event_leader_ebb_init(&leader); + FAIL_IF(event_open(&leader)); + + event_init(&event, 0x20002); + + /* Expected to fail, event doesn't request EBB, leader does */ + FAIL_IF(event_open_with_group(&event, leader.fd) == 0); + event_close(&leader); + + + event_init(&leader, 0x1001e); + event_leader_ebb_init(&leader); + /* Clear the EBB flag */ + leader.attr.config &= ~(1ull << 63); + + FAIL_IF(event_open(&leader)); + + event_init(&event, 0x20002); + event_ebb_init(&event); + + /* Expected to fail, leader doesn't request EBB */ + FAIL_IF(event_open_with_group(&event, leader.fd) == 0); + event_close(&leader); + + + event_init(&leader, 0x1001e); + event_leader_ebb_init(&leader); + leader.attr.exclusive = 0; + /* Expected to fail, leader isn't exclusive */ + FAIL_IF(event_open(&leader) == 0); + + + event_init(&leader, 0x1001e); + event_leader_ebb_init(&leader); + leader.attr.pinned = 0; + /* Expected to fail, leader isn't pinned */ + FAIL_IF(event_open(&leader) == 0); + + event_init(&event, 0x1001e); + event_leader_ebb_init(&event); + /* Expected to fail, not a task event */ + SKIP_IF(require_paranoia_below(1)); + FAIL_IF(event_open_with_cpu(&event, 0) == 0); + + return 0; +} + +int main(void) +{ + return test_harness(event_attributes, "event_attributes"); +} diff --git a/powerpc/pmu/ebb/fixed_instruction_loop.S b/powerpc/pmu/ebb/fixed_instruction_loop.S new file mode 100644 index 0000000..b866a05 --- /dev/null +++ b/powerpc/pmu/ebb/fixed_instruction_loop.S @@ -0,0 +1,43 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include + + .text + +FUNC_START(thirty_two_instruction_loop) + cmpwi r3,0 + beqlr + addi r4,r3,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 # 28 addi's + subi r3,r3,1 + b FUNC_NAME(thirty_two_instruction_loop) +FUNC_END(thirty_two_instruction_loop) diff --git a/powerpc/pmu/ebb/fork_cleanup_test.c b/powerpc/pmu/ebb/fork_cleanup_test.c new file mode 100644 index 0000000..9e7af6e --- /dev/null +++ b/powerpc/pmu/ebb/fork_cleanup_test.c @@ -0,0 +1,79 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ebb.h" + + +/* + * Test that a fork clears the PMU state of the child. eg. BESCR/EBBHR/EBBRR + * are cleared, and MMCR0_PMCC is reset, preventing the child from accessing + * the PMU. + */ + +static struct event event; + +static int child(void) +{ + /* Even though we have EBE=0 we can still see the EBB regs */ + FAIL_IF(mfspr(SPRN_BESCR) != 0); + FAIL_IF(mfspr(SPRN_EBBHR) != 0); + FAIL_IF(mfspr(SPRN_EBBRR) != 0); + + FAIL_IF(catch_sigill(write_pmc1)); + + /* We can still read from the event, though it is on our parent */ + FAIL_IF(event_read(&event)); + + return 0; +} + +/* Tests that fork clears EBB state */ +int fork_cleanup(void) +{ + pid_t pid; + + event_init_named(&event, 0x1001e, "cycles"); + event_leader_ebb_init(&event); + + FAIL_IF(event_open(&event)); + + ebb_enable_pmc_counting(1); + setup_ebb_handler(standard_ebb_callee); + ebb_global_enable(); + + FAIL_IF(ebb_event_enable(&event)); + + mtspr(SPRN_MMCR0, MMCR0_FC); + mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); + + /* Don't need to actually take any EBBs */ + + pid = fork(); + if (pid == 0) + exit(child()); + + /* Child does the actual testing */ + FAIL_IF(wait_for_child(pid)); + + /* After fork */ + event_close(&event); + + return 0; +} + +int main(void) +{ + return test_harness(fork_cleanup, "fork_cleanup"); +} diff --git a/powerpc/pmu/ebb/instruction_count_test.c b/powerpc/pmu/ebb/instruction_count_test.c new file mode 100644 index 0000000..f8190fa --- /dev/null +++ b/powerpc/pmu/ebb/instruction_count_test.c @@ -0,0 +1,164 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include + +#include "ebb.h" + + +/* + * Run a calibrated instruction loop and count instructions executed using + * EBBs. Make sure the counts look right. + */ + +extern void thirty_two_instruction_loop(uint64_t loops); + +static bool counters_frozen = true; + +static int do_count_loop(struct event *event, uint64_t instructions, + uint64_t overhead, bool report) +{ + int64_t difference, expected; + double percentage; + + clear_ebb_stats(); + + counters_frozen = false; + mb(); + mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC); + + thirty_two_instruction_loop(instructions >> 5); + + counters_frozen = true; + mb(); + mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC); + + count_pmc(4, sample_period); + + event->result.value = ebb_state.stats.pmc_count[4-1]; + expected = instructions + overhead; + difference = event->result.value - expected; + percentage = (double)difference / event->result.value * 100; + + if (report) { + printf("Looped for %lu instructions, overhead %lu\n", instructions, overhead); + printf("Expected %lu\n", expected); + printf("Actual %llu\n", event->result.value); + printf("Error %ld, %f%%\n", difference, percentage); + printf("Took %d EBBs\n", ebb_state.stats.ebb_count); + } + + if (difference < 0) + difference = -difference; + + /* Tolerate a difference of up to 0.0001 % */ + difference *= 10000 * 100; + if (difference / event->result.value) + return -1; + + return 0; +} + +/* Count how many instructions it takes to do a null loop */ +static uint64_t determine_overhead(struct event *event) +{ + uint64_t current, overhead; + int i; + + do_count_loop(event, 0, 0, false); + overhead = event->result.value; + + for (i = 0; i < 100; i++) { + do_count_loop(event, 0, 0, false); + current = event->result.value; + if (current < overhead) { + printf("Replacing overhead %lu with %lu\n", overhead, current); + overhead = current; + } + } + + return overhead; +} + +static void pmc4_ebb_callee(void) +{ + uint64_t val; + + val = mfspr(SPRN_BESCR); + if (!(val & BESCR_PMEO)) { + ebb_state.stats.spurious++; + goto out; + } + + ebb_state.stats.ebb_count++; + count_pmc(4, sample_period); +out: + if (counters_frozen) + reset_ebb_with_clear_mask(MMCR0_PMAO); + else + reset_ebb(); +} + +int instruction_count(void) +{ + struct event event; + uint64_t overhead; + + event_init_named(&event, 0x400FA, "PM_RUN_INST_CMPL"); + event_leader_ebb_init(&event); + event.attr.exclude_kernel = 1; + event.attr.exclude_hv = 1; + event.attr.exclude_idle = 1; + + FAIL_IF(event_open(&event)); + FAIL_IF(ebb_event_enable(&event)); + + sample_period = COUNTER_OVERFLOW; + + setup_ebb_handler(pmc4_ebb_callee); + mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC); + ebb_global_enable(); + + overhead = determine_overhead(&event); + printf("Overhead of null loop: %lu instructions\n", overhead); + + /* Run for 1M instructions */ + FAIL_IF(do_count_loop(&event, 0x100000, overhead, true)); + + /* Run for 10M instructions */ + FAIL_IF(do_count_loop(&event, 0xa00000, overhead, true)); + + /* Run for 100M instructions */ + FAIL_IF(do_count_loop(&event, 0x6400000, overhead, true)); + + /* Run for 1G instructions */ + FAIL_IF(do_count_loop(&event, 0x40000000, overhead, true)); + + /* Run for 16G instructions */ + FAIL_IF(do_count_loop(&event, 0x400000000, overhead, true)); + + /* Run for 64G instructions */ + FAIL_IF(do_count_loop(&event, 0x1000000000, overhead, true)); + + /* Run for 128G instructions */ + FAIL_IF(do_count_loop(&event, 0x2000000000, overhead, true)); + + ebb_global_disable(); + event_close(&event); + + printf("Finished OK\n"); + + return 0; +} + +int main(void) +{ + return test_harness(instruction_count, "instruction_count"); +} diff --git a/powerpc/pmu/ebb/lost_exception_test.c b/powerpc/pmu/ebb/lost_exception_test.c new file mode 100644 index 0000000..0c9dd9b --- /dev/null +++ b/powerpc/pmu/ebb/lost_exception_test.c @@ -0,0 +1,100 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include +#include +#include +#include + +#include "ebb.h" + + +/* + * Test that tries to trigger CPU_FTR_PMAO_BUG. Which is a hardware defect + * where an exception triggers but we context switch before it is delivered and + * lose the exception. + */ + +static int test_body(void) +{ + int i, orig_period, max_period; + struct event event; + + /* We use PMC4 to make sure the kernel switches all counters correctly */ + event_init_named(&event, 0x40002, "instructions"); + event_leader_ebb_init(&event); + + event.attr.exclude_kernel = 1; + event.attr.exclude_hv = 1; + event.attr.exclude_idle = 1; + + FAIL_IF(event_open(&event)); + + ebb_enable_pmc_counting(4); + setup_ebb_handler(standard_ebb_callee); + ebb_global_enable(); + FAIL_IF(ebb_event_enable(&event)); + + /* + * We want a low sample period, but we also want to get out of the EBB + * handler without tripping up again. + * + * This value picked after much experimentation. + */ + orig_period = max_period = sample_period = 400; + + mtspr(SPRN_PMC4, pmc_sample_period(sample_period)); + + while (ebb_state.stats.ebb_count < 1000000) { + /* + * We are trying to get the EBB exception to race exactly with + * us entering the kernel to do the syscall. We then need the + * kernel to decide our timeslice is up and context switch to + * the other thread. When we come back our EBB will have been + * lost and we'll spin in this while loop forever. + */ + + for (i = 0; i < 100000; i++) + sched_yield(); + + /* Change the sample period slightly to try and hit the race */ + if (sample_period >= (orig_period + 200)) + sample_period = orig_period; + else + sample_period++; + + if (sample_period > max_period) + max_period = sample_period; + } + + ebb_freeze_pmcs(); + ebb_global_disable(); + + count_pmc(4, sample_period); + mtspr(SPRN_PMC4, 0xdead); + + dump_summary_ebb_state(); + dump_ebb_hw_state(); + + event_close(&event); + + FAIL_IF(ebb_state.stats.ebb_count == 0); + + /* We vary our sample period so we need extra fudge here */ + FAIL_IF(!ebb_check_count(4, orig_period, 2 * (max_period - orig_period))); + + return 0; +} + +static int lost_exception(void) +{ + return eat_cpu(test_body); +} + +int main(void) +{ + return test_harness(lost_exception, "lost_exception"); +} diff --git a/powerpc/pmu/ebb/multi_counter_test.c b/powerpc/pmu/ebb/multi_counter_test.c new file mode 100644 index 0000000..67d78af --- /dev/null +++ b/powerpc/pmu/ebb/multi_counter_test.c @@ -0,0 +1,91 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include +#include + +#include "ebb.h" + + +/* + * Test counting multiple events using EBBs. + */ +int multi_counter(void) +{ + struct event events[6]; + int i, group_fd; + + event_init_named(&events[0], 0x1001C, "PM_CMPLU_STALL_THRD"); + event_init_named(&events[1], 0x2D016, "PM_CMPLU_STALL_FXU"); + event_init_named(&events[2], 0x30006, "PM_CMPLU_STALL_OTHER_CMPL"); + event_init_named(&events[3], 0x4000A, "PM_CMPLU_STALL"); + event_init_named(&events[4], 0x600f4, "PM_RUN_CYC"); + event_init_named(&events[5], 0x500fa, "PM_RUN_INST_CMPL"); + + event_leader_ebb_init(&events[0]); + for (i = 1; i < 6; i++) + event_ebb_init(&events[i]); + + group_fd = -1; + for (i = 0; i < 6; i++) { + events[i].attr.exclude_kernel = 1; + events[i].attr.exclude_hv = 1; + events[i].attr.exclude_idle = 1; + + FAIL_IF(event_open_with_group(&events[i], group_fd)); + if (group_fd == -1) + group_fd = events[0].fd; + } + + ebb_enable_pmc_counting(1); + ebb_enable_pmc_counting(2); + ebb_enable_pmc_counting(3); + ebb_enable_pmc_counting(4); + ebb_enable_pmc_counting(5); + ebb_enable_pmc_counting(6); + setup_ebb_handler(standard_ebb_callee); + + FAIL_IF(ioctl(events[0].fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP)); + FAIL_IF(event_read(&events[0])); + + ebb_global_enable(); + + mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); + mtspr(SPRN_PMC2, pmc_sample_period(sample_period)); + mtspr(SPRN_PMC3, pmc_sample_period(sample_period)); + mtspr(SPRN_PMC4, pmc_sample_period(sample_period)); + mtspr(SPRN_PMC5, pmc_sample_period(sample_period)); + mtspr(SPRN_PMC6, pmc_sample_period(sample_period)); + + while (ebb_state.stats.ebb_count < 50) { + FAIL_IF(core_busy_loop()); + FAIL_IF(ebb_check_mmcr0()); + } + + ebb_global_disable(); + ebb_freeze_pmcs(); + + count_pmc(1, sample_period); + count_pmc(2, sample_period); + count_pmc(3, sample_period); + count_pmc(4, sample_period); + count_pmc(5, sample_period); + count_pmc(6, sample_period); + + dump_ebb_state(); + + for (i = 0; i < 6; i++) + event_close(&events[i]); + + FAIL_IF(ebb_state.stats.ebb_count == 0); + + return 0; +} + +int main(void) +{ + return test_harness(multi_counter, "multi_counter"); +} diff --git a/powerpc/pmu/ebb/multi_ebb_procs_test.c b/powerpc/pmu/ebb/multi_ebb_procs_test.c new file mode 100644 index 0000000..b8dc371 --- /dev/null +++ b/powerpc/pmu/ebb/multi_ebb_procs_test.c @@ -0,0 +1,109 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include +#include +#include + +#include "ebb.h" + + +/* + * Test running multiple EBB using processes at once on a single CPU. They + * should all run happily without interfering with each other. + */ + +static bool child_should_exit; + +static void sigint_handler(int signal) +{ + child_should_exit = true; +} + +struct sigaction sigint_action = { + .sa_handler = sigint_handler, +}; + +static int cycles_child(void) +{ + struct event event; + + if (sigaction(SIGINT, &sigint_action, NULL)) { + perror("sigaction"); + return 1; + } + + event_init_named(&event, 0x1001e, "cycles"); + event_leader_ebb_init(&event); + + event.attr.exclude_kernel = 1; + event.attr.exclude_hv = 1; + event.attr.exclude_idle = 1; + + FAIL_IF(event_open(&event)); + + ebb_enable_pmc_counting(1); + setup_ebb_handler(standard_ebb_callee); + ebb_global_enable(); + + FAIL_IF(ebb_event_enable(&event)); + + mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); + + while (!child_should_exit) { + FAIL_IF(core_busy_loop()); + FAIL_IF(ebb_check_mmcr0()); + } + + ebb_global_disable(); + ebb_freeze_pmcs(); + + count_pmc(1, sample_period); + + dump_summary_ebb_state(); + + event_close(&event); + + FAIL_IF(ebb_state.stats.ebb_count == 0); + + return 0; +} + +#define NR_CHILDREN 4 + +int multi_ebb_procs(void) +{ + pid_t pids[NR_CHILDREN]; + int cpu, rc, i; + + cpu = pick_online_cpu(); + FAIL_IF(cpu < 0); + FAIL_IF(bind_to_cpu(cpu)); + + for (i = 0; i < NR_CHILDREN; i++) { + pids[i] = fork(); + if (pids[i] == 0) + exit(cycles_child()); + } + + /* Have them all run for "a while" */ + sleep(10); + + rc = 0; + for (i = 0; i < NR_CHILDREN; i++) { + /* Tell them to stop */ + kill(pids[i], SIGINT); + /* And wait */ + rc |= wait_for_child(pids[i]); + } + + return rc; +} + +int main(void) +{ + return test_harness(multi_ebb_procs, "multi_ebb_procs"); +} diff --git a/powerpc/pmu/ebb/no_handler_test.c b/powerpc/pmu/ebb/no_handler_test.c new file mode 100644 index 0000000..2f9bf8e --- /dev/null +++ b/powerpc/pmu/ebb/no_handler_test.c @@ -0,0 +1,61 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include +#include +#include + +#include "ebb.h" + + +/* Test that things work sanely if we have no handler */ + +static int no_handler_test(void) +{ + struct event event; + u64 val; + int i; + + event_init_named(&event, 0x1001e, "cycles"); + event_leader_ebb_init(&event); + + event.attr.exclude_kernel = 1; + event.attr.exclude_hv = 1; + event.attr.exclude_idle = 1; + + FAIL_IF(event_open(&event)); + FAIL_IF(ebb_event_enable(&event)); + + val = mfspr(SPRN_EBBHR); + FAIL_IF(val != 0); + + /* Make sure it overflows quickly */ + sample_period = 1000; + mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); + + /* Spin to make sure the event has time to overflow */ + for (i = 0; i < 1000; i++) + mb(); + + dump_ebb_state(); + + /* We expect to see the PMU frozen & PMAO set */ + val = mfspr(SPRN_MMCR0); + FAIL_IF(val != 0x0000000080000080); + + event_close(&event); + + dump_ebb_state(); + + /* The real test is that we never took an EBB at 0x0 */ + + return 0; +} + +int main(void) +{ + return test_harness(no_handler_test,"no_handler_test"); +} diff --git a/powerpc/pmu/ebb/pmae_handling_test.c b/powerpc/pmu/ebb/pmae_handling_test.c new file mode 100644 index 0000000..986500f --- /dev/null +++ b/powerpc/pmu/ebb/pmae_handling_test.c @@ -0,0 +1,106 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include +#include +#include +#include + +#include "ebb.h" + + +/* + * Test that the kernel properly handles PMAE across context switches. + * + * We test this by calling into the kernel inside our EBB handler, where PMAE + * is clear. A cpu eater companion thread is running on the same CPU as us to + * encourage the scheduler to switch us. + * + * The kernel must make sure that when it context switches us back in, it + * honours the fact that we had PMAE clear. + * + * Observed to hit the failing case on the first EBB with a broken kernel. + */ + +static bool mmcr0_mismatch; +static uint64_t before, after; + +static void syscall_ebb_callee(void) +{ + uint64_t val; + + val = mfspr(SPRN_BESCR); + if (!(val & BESCR_PMEO)) { + ebb_state.stats.spurious++; + goto out; + } + + ebb_state.stats.ebb_count++; + count_pmc(1, sample_period); + + before = mfspr(SPRN_MMCR0); + + /* Try and get ourselves scheduled, to force a PMU context switch */ + sched_yield(); + + after = mfspr(SPRN_MMCR0); + if (before != after) + mmcr0_mismatch = true; + +out: + reset_ebb(); +} + +static int test_body(void) +{ + struct event event; + + event_init_named(&event, 0x1001e, "cycles"); + event_leader_ebb_init(&event); + + event.attr.exclude_kernel = 1; + event.attr.exclude_hv = 1; + event.attr.exclude_idle = 1; + + FAIL_IF(event_open(&event)); + + setup_ebb_handler(syscall_ebb_callee); + ebb_global_enable(); + + FAIL_IF(ebb_event_enable(&event)); + + mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); + + while (ebb_state.stats.ebb_count < 20 && !mmcr0_mismatch) + FAIL_IF(core_busy_loop()); + + ebb_global_disable(); + ebb_freeze_pmcs(); + + count_pmc(1, sample_period); + + dump_ebb_state(); + + if (mmcr0_mismatch) + printf("Saw MMCR0 before 0x%lx after 0x%lx\n", before, after); + + event_close(&event); + + FAIL_IF(ebb_state.stats.ebb_count == 0); + FAIL_IF(mmcr0_mismatch); + + return 0; +} + +int pmae_handling(void) +{ + return eat_cpu(test_body); +} + +int main(void) +{ + return test_harness(pmae_handling, "pmae_handling"); +} diff --git a/powerpc/pmu/ebb/pmc56_overflow_test.c b/powerpc/pmu/ebb/pmc56_overflow_test.c new file mode 100644 index 0000000..a503fa7 --- /dev/null +++ b/powerpc/pmu/ebb/pmc56_overflow_test.c @@ -0,0 +1,93 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include + +#include "ebb.h" + + +/* + * Test that PMC5 & 6 are frozen (ie. don't overflow) when they are not being + * used. Tests the MMCR0_FC56 logic in the kernel. + */ + +static int pmc56_overflowed; + +static void ebb_callee(void) +{ + uint64_t val; + + val = mfspr(SPRN_BESCR); + if (!(val & BESCR_PMEO)) { + ebb_state.stats.spurious++; + goto out; + } + + ebb_state.stats.ebb_count++; + count_pmc(2, sample_period); + + val = mfspr(SPRN_PMC5); + if (val >= COUNTER_OVERFLOW) + pmc56_overflowed++; + + count_pmc(5, COUNTER_OVERFLOW); + + val = mfspr(SPRN_PMC6); + if (val >= COUNTER_OVERFLOW) + pmc56_overflowed++; + + count_pmc(6, COUNTER_OVERFLOW); + +out: + reset_ebb(); +} + +int pmc56_overflow(void) +{ + struct event event; + + /* Use PMC2 so we set PMCjCE, which enables PMC5/6 */ + event_init(&event, 0x2001e); + event_leader_ebb_init(&event); + + event.attr.exclude_kernel = 1; + event.attr.exclude_hv = 1; + event.attr.exclude_idle = 1; + + FAIL_IF(event_open(&event)); + + setup_ebb_handler(ebb_callee); + ebb_global_enable(); + + FAIL_IF(ebb_event_enable(&event)); + + mtspr(SPRN_PMC1, pmc_sample_period(sample_period)); + mtspr(SPRN_PMC5, 0); + mtspr(SPRN_PMC6, 0); + + while (ebb_state.stats.ebb_count < 10) + FAIL_IF(core_busy_loop()); + + ebb_global_disable(); + ebb_freeze_pmcs(); + + count_pmc(2, sample_period); + + dump_ebb_state(); + + printf("PMC5/6 overflow %d\n", pmc56_overflowed); + + event_close(&event); + + FAIL_IF(ebb_state.stats.ebb_count == 0 || pmc56_overflowed != 0); + + return 0; +} + +int main(void) +{ + return test_harness(pmc56_overflow, "pmc56_overflow"); +} diff --git a/powerpc/pmu/ebb/reg.h b/powerpc/pmu/ebb/reg.h new file mode 100644 index 0000000..5921b0d --- /dev/null +++ b/powerpc/pmu/ebb/reg.h @@ -0,0 +1,49 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#ifndef _SELFTESTS_POWERPC_REG_H +#define _SELFTESTS_POWERPC_REG_H + +#define __stringify_1(x) #x +#define __stringify(x) __stringify_1(x) + +#define mfspr(rn) ({unsigned long rval; \ + asm volatile("mfspr %0," __stringify(rn) \ + : "=r" (rval)); rval; }) +#define mtspr(rn, v) asm volatile("mtspr " __stringify(rn) ",%0" : \ + : "r" ((unsigned long)(v)) \ + : "memory") + +#define mb() asm volatile("sync" : : : "memory"); + +#define SPRN_MMCR2 769 +#define SPRN_MMCRA 770 +#define SPRN_MMCR0 779 +#define MMCR0_PMAO 0x00000080 +#define MMCR0_PMAE 0x04000000 +#define MMCR0_FC 0x80000000 +#define SPRN_EBBHR 804 +#define SPRN_EBBRR 805 +#define SPRN_BESCR 806 /* Branch event status & control register */ +#define SPRN_BESCRS 800 /* Branch event status & control set (1 bits set to 1) */ +#define SPRN_BESCRSU 801 /* Branch event status & control set upper */ +#define SPRN_BESCRR 802 /* Branch event status & control REset (1 bits set to 0) */ +#define SPRN_BESCRRU 803 /* Branch event status & control REset upper */ + +#define BESCR_PMEO 0x1 /* PMU Event-based exception Occurred */ +#define BESCR_PME (0x1ul << 32) /* PMU Event-based exception Enable */ + +#define SPRN_PMC1 771 +#define SPRN_PMC2 772 +#define SPRN_PMC3 773 +#define SPRN_PMC4 774 +#define SPRN_PMC5 775 +#define SPRN_PMC6 776 + +#define SPRN_SIAR 780 +#define SPRN_SDAR 781 +#define SPRN_SIER 768 + +#endif /* _SELFTESTS_POWERPC_REG_H */ diff --git a/powerpc/pmu/ebb/reg_access_test.c b/powerpc/pmu/ebb/reg_access_test.c new file mode 100644 index 0000000..0cae66f --- /dev/null +++ b/powerpc/pmu/ebb/reg_access_test.c @@ -0,0 +1,39 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include + +#include "ebb.h" +#include "reg.h" + + +/* + * Test basic access to the EBB regs, they should be user accessible with no + * kernel interaction required. + */ +int reg_access(void) +{ + uint64_t val, expected; + + expected = 0x8000000100000000ull; + mtspr(SPRN_BESCR, expected); + val = mfspr(SPRN_BESCR); + + FAIL_IF(val != expected); + + expected = 0x0000000001000000ull; + mtspr(SPRN_EBBHR, expected); + val = mfspr(SPRN_EBBHR); + + FAIL_IF(val != expected); + + return 0; +} + +int main(void) +{ + return test_harness(reg_access, "reg_access"); +} diff --git a/powerpc/pmu/ebb/task_event_pinned_vs_ebb_test.c b/powerpc/pmu/ebb/task_event_pinned_vs_ebb_test.c new file mode 100644 index 0000000..d56607e --- /dev/null +++ b/powerpc/pmu/ebb/task_event_pinned_vs_ebb_test.c @@ -0,0 +1,91 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ebb.h" + + +/* + * Tests a pinned per-task event vs an EBB - in that order. The pinned per-task + * event should prevent the EBB event from being enabled. + */ + +static int setup_child_event(struct event *event, pid_t child_pid) +{ + event_init_named(event, 0x400FA, "PM_RUN_INST_CMPL"); + + event->attr.pinned = 1; + + event->attr.exclude_kernel = 1; + event->attr.exclude_hv = 1; + event->attr.exclude_idle = 1; + + FAIL_IF(event_open_with_pid(event, child_pid)); + FAIL_IF(event_enable(event)); + + return 0; +} + +int task_event_pinned_vs_ebb(void) +{ + union pipe read_pipe, write_pipe; + struct event event; + pid_t pid; + int rc; + + FAIL_IF(pipe(read_pipe.fds) == -1); + FAIL_IF(pipe(write_pipe.fds) == -1); + + pid = fork(); + if (pid == 0) { + /* NB order of pipes looks reversed */ + exit(ebb_child(write_pipe, read_pipe)); + } + + /* We setup the task event first */ + rc = setup_child_event(&event, pid); + if (rc) { + kill_child_and_wait(pid); + return rc; + } + + /* Signal the child to install its EBB event and wait */ + if (sync_with_child(read_pipe, write_pipe)) + /* If it fails, wait for it to exit */ + goto wait; + + /* Signal the child to run */ + FAIL_IF(sync_with_child(read_pipe, write_pipe)); + +wait: + /* We expect it to fail to read the event */ + FAIL_IF(wait_for_child(pid) != 2); + FAIL_IF(event_disable(&event)); + FAIL_IF(event_read(&event)); + + event_report(&event); + + FAIL_IF(event.result.value == 0); + /* + * For reasons I don't understand enabled is usually just slightly + * lower than running. Would be good to confirm why. + */ + FAIL_IF(event.result.enabled == 0); + FAIL_IF(event.result.running == 0); + + return 0; +} + +int main(void) +{ + return test_harness(task_event_pinned_vs_ebb, "task_event_pinned_vs_ebb"); +} diff --git a/powerpc/pmu/ebb/task_event_vs_ebb_test.c b/powerpc/pmu/ebb/task_event_vs_ebb_test.c new file mode 100644 index 0000000..eba3219 --- /dev/null +++ b/powerpc/pmu/ebb/task_event_vs_ebb_test.c @@ -0,0 +1,83 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "ebb.h" + + +/* + * Tests a per-task event vs an EBB - in that order. The EBB should push the + * per-task event off the PMU. + */ + +static int setup_child_event(struct event *event, pid_t child_pid) +{ + event_init_named(event, 0x400FA, "PM_RUN_INST_CMPL"); + + event->attr.exclude_kernel = 1; + event->attr.exclude_hv = 1; + event->attr.exclude_idle = 1; + + FAIL_IF(event_open_with_pid(event, child_pid)); + FAIL_IF(event_enable(event)); + + return 0; +} + +int task_event_vs_ebb(void) +{ + union pipe read_pipe, write_pipe; + struct event event; + pid_t pid; + int rc; + + FAIL_IF(pipe(read_pipe.fds) == -1); + FAIL_IF(pipe(write_pipe.fds) == -1); + + pid = fork(); + if (pid == 0) { + /* NB order of pipes looks reversed */ + exit(ebb_child(write_pipe, read_pipe)); + } + + /* We setup the task event first */ + rc = setup_child_event(&event, pid); + if (rc) { + kill_child_and_wait(pid); + return rc; + } + + /* Signal the child to install its EBB event and wait */ + if (sync_with_child(read_pipe, write_pipe)) + /* If it fails, wait for it to exit */ + goto wait; + + /* Signal the child to run */ + FAIL_IF(sync_with_child(read_pipe, write_pipe)); + +wait: + /* The EBB event should push the task event off so the child should succeed */ + FAIL_IF(wait_for_child(pid)); + FAIL_IF(event_disable(&event)); + FAIL_IF(event_read(&event)); + + event_report(&event); + + /* The task event may have run, or not so we can't assert anything about it */ + + return 0; +} + +int main(void) +{ + return test_harness(task_event_vs_ebb, "task_event_vs_ebb"); +} diff --git a/powerpc/pmu/ebb/trace.c b/powerpc/pmu/ebb/trace.c new file mode 100644 index 0000000..251e66a --- /dev/null +++ b/powerpc/pmu/ebb/trace.c @@ -0,0 +1,300 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include +#include +#include +#include + +#include "trace.h" + + +struct trace_buffer *trace_buffer_allocate(u64 size) +{ + struct trace_buffer *tb; + + if (size < sizeof(*tb)) { + fprintf(stderr, "Error: trace buffer too small\n"); + return NULL; + } + + tb = mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (tb == MAP_FAILED) { + perror("mmap"); + return NULL; + } + + tb->size = size; + tb->tail = tb->data; + tb->overflow = false; + + return tb; +} + +static bool trace_check_bounds(struct trace_buffer *tb, void *p) +{ + return p < ((void *)tb + tb->size); +} + +static bool trace_check_alloc(struct trace_buffer *tb, void *p) +{ + /* + * If we ever overflowed don't allow any more input. This prevents us + * from dropping a large item and then later logging a small one. The + * buffer should just stop when overflow happened, not be patchy. If + * you're overflowing, make your buffer bigger. + */ + if (tb->overflow) + return false; + + if (!trace_check_bounds(tb, p)) { + tb->overflow = true; + return false; + } + + return true; +} + +static void *trace_alloc(struct trace_buffer *tb, int bytes) +{ + void *p, *newtail; + + p = tb->tail; + newtail = tb->tail + bytes; + if (!trace_check_alloc(tb, newtail)) + return NULL; + + tb->tail = newtail; + + return p; +} + +static struct trace_entry *trace_alloc_entry(struct trace_buffer *tb, int payload_size) +{ + struct trace_entry *e; + + e = trace_alloc(tb, sizeof(*e) + payload_size); + if (e) + e->length = payload_size; + + return e; +} + +int trace_log_reg(struct trace_buffer *tb, u64 reg, u64 value) +{ + struct trace_entry *e; + u64 *p; + + e = trace_alloc_entry(tb, sizeof(reg) + sizeof(value)); + if (!e) + return -ENOSPC; + + e->type = TRACE_TYPE_REG; + p = (u64 *)e->data; + *p++ = reg; + *p++ = value; + + return 0; +} + +int trace_log_counter(struct trace_buffer *tb, u64 value) +{ + struct trace_entry *e; + u64 *p; + + e = trace_alloc_entry(tb, sizeof(value)); + if (!e) + return -ENOSPC; + + e->type = TRACE_TYPE_COUNTER; + p = (u64 *)e->data; + *p++ = value; + + return 0; +} + +int trace_log_string(struct trace_buffer *tb, char *str) +{ + struct trace_entry *e; + char *p; + int len; + + len = strlen(str); + + /* We NULL terminate to make printing easier */ + e = trace_alloc_entry(tb, len + 1); + if (!e) + return -ENOSPC; + + e->type = TRACE_TYPE_STRING; + p = (char *)e->data; + memcpy(p, str, len); + p += len; + *p = '\0'; + + return 0; +} + +int trace_log_indent(struct trace_buffer *tb) +{ + struct trace_entry *e; + + e = trace_alloc_entry(tb, 0); + if (!e) + return -ENOSPC; + + e->type = TRACE_TYPE_INDENT; + + return 0; +} + +int trace_log_outdent(struct trace_buffer *tb) +{ + struct trace_entry *e; + + e = trace_alloc_entry(tb, 0); + if (!e) + return -ENOSPC; + + e->type = TRACE_TYPE_OUTDENT; + + return 0; +} + +static void trace_print_header(int seq, int prefix) +{ + printf("%*s[%d]: ", prefix, "", seq); +} + +static char *trace_decode_reg(int reg) +{ + switch (reg) { + case 769: return "SPRN_MMCR2"; break; + case 770: return "SPRN_MMCRA"; break; + case 779: return "SPRN_MMCR0"; break; + case 804: return "SPRN_EBBHR"; break; + case 805: return "SPRN_EBBRR"; break; + case 806: return "SPRN_BESCR"; break; + case 800: return "SPRN_BESCRS"; break; + case 801: return "SPRN_BESCRSU"; break; + case 802: return "SPRN_BESCRR"; break; + case 803: return "SPRN_BESCRRU"; break; + case 771: return "SPRN_PMC1"; break; + case 772: return "SPRN_PMC2"; break; + case 773: return "SPRN_PMC3"; break; + case 774: return "SPRN_PMC4"; break; + case 775: return "SPRN_PMC5"; break; + case 776: return "SPRN_PMC6"; break; + case 780: return "SPRN_SIAR"; break; + case 781: return "SPRN_SDAR"; break; + case 768: return "SPRN_SIER"; break; + } + + return NULL; +} + +static void trace_print_reg(struct trace_entry *e) +{ + u64 *p, *reg, *value; + char *name; + + p = (u64 *)e->data; + reg = p++; + value = p; + + name = trace_decode_reg(*reg); + if (name) + printf("register %-10s = 0x%016llx\n", name, *value); + else + printf("register %lld = 0x%016llx\n", *reg, *value); +} + +static void trace_print_counter(struct trace_entry *e) +{ + u64 *value; + + value = (u64 *)e->data; + printf("counter = %lld\n", *value); +} + +static void trace_print_string(struct trace_entry *e) +{ + char *str; + + str = (char *)e->data; + puts(str); +} + +#define BASE_PREFIX 2 +#define PREFIX_DELTA 8 + +static void trace_print_entry(struct trace_entry *e, int seq, int *prefix) +{ + switch (e->type) { + case TRACE_TYPE_REG: + trace_print_header(seq, *prefix); + trace_print_reg(e); + break; + case TRACE_TYPE_COUNTER: + trace_print_header(seq, *prefix); + trace_print_counter(e); + break; + case TRACE_TYPE_STRING: + trace_print_header(seq, *prefix); + trace_print_string(e); + break; + case TRACE_TYPE_INDENT: + trace_print_header(seq, *prefix); + puts("{"); + *prefix += PREFIX_DELTA; + break; + case TRACE_TYPE_OUTDENT: + *prefix -= PREFIX_DELTA; + if (*prefix < BASE_PREFIX) + *prefix = BASE_PREFIX; + trace_print_header(seq, *prefix); + puts("}"); + break; + default: + trace_print_header(seq, *prefix); + printf("entry @ %p type %d\n", e, e->type); + break; + } +} + +void trace_buffer_print(struct trace_buffer *tb) +{ + struct trace_entry *e; + int i, prefix; + void *p; + + printf("Trace buffer dump:\n"); + printf(" address %p \n", tb); + printf(" tail %p\n", tb->tail); + printf(" size %llu\n", tb->size); + printf(" overflow %s\n", tb->overflow ? "TRUE" : "false"); + printf(" Content:\n"); + + p = tb->data; + + i = 0; + prefix = BASE_PREFIX; + + while (trace_check_bounds(tb, p) && p < tb->tail) { + e = p; + + trace_print_entry(e, i, &prefix); + + i++; + p = (void *)e + sizeof(*e) + e->length; + } +} + +void trace_print_location(struct trace_buffer *tb) +{ + printf("Trace buffer 0x%llx bytes @ %p\n", tb->size, tb); +} diff --git a/powerpc/pmu/ebb/trace.h b/powerpc/pmu/ebb/trace.h new file mode 100644 index 0000000..926458e --- /dev/null +++ b/powerpc/pmu/ebb/trace.h @@ -0,0 +1,41 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#ifndef _SELFTESTS_POWERPC_PMU_EBB_TRACE_H +#define _SELFTESTS_POWERPC_PMU_EBB_TRACE_H + +#include "utils.h" + +#define TRACE_TYPE_REG 1 +#define TRACE_TYPE_COUNTER 2 +#define TRACE_TYPE_STRING 3 +#define TRACE_TYPE_INDENT 4 +#define TRACE_TYPE_OUTDENT 5 + +struct trace_entry +{ + u8 type; + u8 length; + u8 data[0]; +}; + +struct trace_buffer +{ + u64 size; + bool overflow; + void *tail; + u8 data[0]; +}; + +struct trace_buffer *trace_buffer_allocate(u64 size); +int trace_log_reg(struct trace_buffer *tb, u64 reg, u64 value); +int trace_log_counter(struct trace_buffer *tb, u64 value); +int trace_log_string(struct trace_buffer *tb, char *str); +int trace_log_indent(struct trace_buffer *tb); +int trace_log_outdent(struct trace_buffer *tb); +void trace_buffer_print(struct trace_buffer *tb); +void trace_print_location(struct trace_buffer *tb); + +#endif /* _SELFTESTS_POWERPC_PMU_EBB_TRACE_H */ diff --git a/powerpc/pmu/event.c b/powerpc/pmu/event.c new file mode 100644 index 0000000..184b368 --- /dev/null +++ b/powerpc/pmu/event.c @@ -0,0 +1,131 @@ +/* + * Copyright 2013, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include + +#include "event.h" + + +int perf_event_open(struct perf_event_attr *attr, pid_t pid, int cpu, + int group_fd, unsigned long flags) +{ + return syscall(__NR_perf_event_open, attr, pid, cpu, + group_fd, flags); +} + +void event_init_opts(struct event *e, u64 config, int type, char *name) +{ + memset(e, 0, sizeof(*e)); + + e->name = name; + + e->attr.type = type; + e->attr.config = config; + e->attr.size = sizeof(e->attr); + /* This has to match the structure layout in the header */ + e->attr.read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | \ + PERF_FORMAT_TOTAL_TIME_RUNNING; +} + +void event_init_named(struct event *e, u64 config, char *name) +{ + event_init_opts(e, config, PERF_TYPE_RAW, name); +} + +void event_init(struct event *e, u64 config) +{ + event_init_opts(e, config, PERF_TYPE_RAW, "event"); +} + +#define PERF_CURRENT_PID 0 +#define PERF_NO_PID -1 +#define PERF_NO_CPU -1 +#define PERF_NO_GROUP -1 + +int event_open_with_options(struct event *e, pid_t pid, int cpu, int group_fd) +{ + e->fd = perf_event_open(&e->attr, pid, cpu, group_fd, 0); + if (e->fd == -1) { + perror("perf_event_open"); + return -1; + } + + return 0; +} + +int event_open_with_group(struct event *e, int group_fd) +{ + return event_open_with_options(e, PERF_CURRENT_PID, PERF_NO_CPU, group_fd); +} + +int event_open_with_pid(struct event *e, pid_t pid) +{ + return event_open_with_options(e, pid, PERF_NO_CPU, PERF_NO_GROUP); +} + +int event_open_with_cpu(struct event *e, int cpu) +{ + return event_open_with_options(e, PERF_NO_PID, cpu, PERF_NO_GROUP); +} + +int event_open(struct event *e) +{ + return event_open_with_options(e, PERF_CURRENT_PID, PERF_NO_CPU, PERF_NO_GROUP); +} + +void event_close(struct event *e) +{ + close(e->fd); +} + +int event_enable(struct event *e) +{ + return ioctl(e->fd, PERF_EVENT_IOC_ENABLE); +} + +int event_disable(struct event *e) +{ + return ioctl(e->fd, PERF_EVENT_IOC_DISABLE); +} + +int event_reset(struct event *e) +{ + return ioctl(e->fd, PERF_EVENT_IOC_RESET); +} + +int event_read(struct event *e) +{ + int rc; + + rc = read(e->fd, &e->result, sizeof(e->result)); + if (rc != sizeof(e->result)) { + fprintf(stderr, "read error on event %p!\n", e); + return -1; + } + + return 0; +} + +void event_report_justified(struct event *e, int name_width, int result_width) +{ + printf("%*s: result %*llu ", name_width, e->name, result_width, + e->result.value); + + if (e->result.running == e->result.enabled) + printf("running/enabled %llu\n", e->result.running); + else + printf("running %llu enabled %llu\n", e->result.running, + e->result.enabled); +} + +void event_report(struct event *e) +{ + event_report_justified(e, 0, 0); +} diff --git a/powerpc/pmu/event.h b/powerpc/pmu/event.h new file mode 100644 index 0000000..a0ea6b1 --- /dev/null +++ b/powerpc/pmu/event.h @@ -0,0 +1,43 @@ +/* + * Copyright 2013, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#ifndef _SELFTESTS_POWERPC_PMU_EVENT_H +#define _SELFTESTS_POWERPC_PMU_EVENT_H + +#include +#include + +#include "utils.h" + + +struct event { + struct perf_event_attr attr; + char *name; + int fd; + /* This must match the read_format we use */ + struct { + u64 value; + u64 running; + u64 enabled; + } result; +}; + +void event_init(struct event *e, u64 config); +void event_init_named(struct event *e, u64 config, char *name); +void event_init_opts(struct event *e, u64 config, int type, char *name); +int event_open_with_options(struct event *e, pid_t pid, int cpu, int group_fd); +int event_open_with_group(struct event *e, int group_fd); +int event_open_with_pid(struct event *e, pid_t pid); +int event_open_with_cpu(struct event *e, int cpu); +int event_open(struct event *e); +void event_close(struct event *e); +int event_enable(struct event *e); +int event_disable(struct event *e); +int event_reset(struct event *e); +int event_read(struct event *e); +void event_report_justified(struct event *e, int name_width, int result_width); +void event_report(struct event *e); + +#endif /* _SELFTESTS_POWERPC_PMU_EVENT_H */ diff --git a/powerpc/pmu/l3_bank_test.c b/powerpc/pmu/l3_bank_test.c new file mode 100644 index 0000000..77472f3 --- /dev/null +++ b/powerpc/pmu/l3_bank_test.c @@ -0,0 +1,48 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include +#include + +#include "event.h" +#include "utils.h" + +#define MALLOC_SIZE (0x10000 * 10) /* Ought to be enough .. */ + +/* + * Tests that the L3 bank handling is correct. We fixed it in commit e9aaac1. + */ +static int l3_bank_test(void) +{ + struct event event; + char *p; + int i; + + p = malloc(MALLOC_SIZE); + FAIL_IF(!p); + + event_init(&event, 0x84918F); + + FAIL_IF(event_open(&event)); + + for (i = 0; i < MALLOC_SIZE; i += 0x10000) + p[i] = i; + + event_read(&event); + event_report(&event); + + FAIL_IF(event.result.running == 0); + FAIL_IF(event.result.enabled == 0); + + event_close(&event); + free(p); + + return 0; +} + +int main(void) +{ + return test_harness(l3_bank_test, "l3_bank_test"); +} diff --git a/powerpc/pmu/lib.c b/powerpc/pmu/lib.c new file mode 100644 index 0000000..9768dea --- /dev/null +++ b/powerpc/pmu/lib.c @@ -0,0 +1,300 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#define _GNU_SOURCE /* For CPU_ZERO etc. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utils.h" +#include "lib.h" + + +int pick_online_cpu(void) +{ + cpu_set_t mask; + int cpu; + + CPU_ZERO(&mask); + + if (sched_getaffinity(0, sizeof(mask), &mask)) { + perror("sched_getaffinity"); + return -1; + } + + /* We prefer a primary thread, but skip 0 */ + for (cpu = 8; cpu < CPU_SETSIZE; cpu += 8) + if (CPU_ISSET(cpu, &mask)) + return cpu; + + /* Search for anything, but in reverse */ + for (cpu = CPU_SETSIZE - 1; cpu >= 0; cpu--) + if (CPU_ISSET(cpu, &mask)) + return cpu; + + printf("No cpus in affinity mask?!\n"); + return -1; +} + +int bind_to_cpu(int cpu) +{ + cpu_set_t mask; + + printf("Binding to cpu %d\n", cpu); + + CPU_ZERO(&mask); + CPU_SET(cpu, &mask); + + return sched_setaffinity(0, sizeof(mask), &mask); +} + +#define PARENT_TOKEN 0xAA +#define CHILD_TOKEN 0x55 + +int sync_with_child(union pipe read_pipe, union pipe write_pipe) +{ + char c = PARENT_TOKEN; + + FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1); + FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1); + if (c != CHILD_TOKEN) /* sometimes expected */ + return 1; + + return 0; +} + +int wait_for_parent(union pipe read_pipe) +{ + char c; + + FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1); + FAIL_IF(c != PARENT_TOKEN); + + return 0; +} + +int notify_parent(union pipe write_pipe) +{ + char c = CHILD_TOKEN; + + FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1); + + return 0; +} + +int notify_parent_of_error(union pipe write_pipe) +{ + char c = ~CHILD_TOKEN; + + FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1); + + return 0; +} + +int wait_for_child(pid_t child_pid) +{ + int rc; + + if (waitpid(child_pid, &rc, 0) == -1) { + perror("waitpid"); + return 1; + } + + if (WIFEXITED(rc)) + rc = WEXITSTATUS(rc); + else + rc = 1; /* Signal or other */ + + return rc; +} + +int kill_child_and_wait(pid_t child_pid) +{ + kill(child_pid, SIGTERM); + + return wait_for_child(child_pid); +} + +static int eat_cpu_child(union pipe read_pipe, union pipe write_pipe) +{ + volatile int i = 0; + + /* + * We are just here to eat cpu and die. So make sure we can be killed, + * and also don't do any custom SIGTERM handling. + */ + signal(SIGTERM, SIG_DFL); + + notify_parent(write_pipe); + wait_for_parent(read_pipe); + + /* Soak up cpu forever */ + while (1) i++; + + return 0; +} + +pid_t eat_cpu(int (test_function)(void)) +{ + union pipe read_pipe, write_pipe; + int cpu, rc; + pid_t pid; + + cpu = pick_online_cpu(); + FAIL_IF(cpu < 0); + FAIL_IF(bind_to_cpu(cpu)); + + if (pipe(read_pipe.fds) == -1) + return -1; + + if (pipe(write_pipe.fds) == -1) + return -1; + + pid = fork(); + if (pid == 0) + exit(eat_cpu_child(write_pipe, read_pipe)); + + if (sync_with_child(read_pipe, write_pipe)) { + rc = -1; + goto out; + } + + printf("main test running as pid %d\n", getpid()); + + rc = test_function(); +out: + kill(pid, SIGKILL); + + return rc; +} + +struct addr_range libc, vdso; + +int parse_proc_maps(void) +{ + unsigned long start, end; + char execute, name[128]; + FILE *f; + int rc; + + f = fopen("/proc/self/maps", "r"); + if (!f) { + perror("fopen"); + return -1; + } + + do { + /* This skips line with no executable which is what we want */ + rc = fscanf(f, "%lx-%lx %*c%*c%c%*c %*x %*d:%*d %*d %127s\n", + &start, &end, &execute, name); + if (rc <= 0) + break; + + if (execute != 'x') + continue; + + if (strstr(name, "libc")) { + libc.first = start; + libc.last = end - 1; + } else if (strstr(name, "[vdso]")) { + vdso.first = start; + vdso.last = end - 1; + } + } while(1); + + fclose(f); + + return 0; +} + +#define PARANOID_PATH "/proc/sys/kernel/perf_event_paranoid" + +bool require_paranoia_below(int level) +{ + unsigned long current; + char *end, buf[16]; + FILE *f; + int rc; + + rc = -1; + + f = fopen(PARANOID_PATH, "r"); + if (!f) { + perror("fopen"); + goto out; + } + + if (!fgets(buf, sizeof(buf), f)) { + printf("Couldn't read " PARANOID_PATH "?\n"); + goto out_close; + } + + current = strtoul(buf, &end, 10); + + if (end == buf) { + printf("Couldn't parse " PARANOID_PATH "?\n"); + goto out_close; + } + + if (current >= level) + goto out; + + rc = 0; +out_close: + fclose(f); +out: + return rc; +} + +static char auxv[4096]; + +void *get_auxv_entry(int type) +{ + ElfW(auxv_t) *p; + void *result; + ssize_t num; + int fd; + + fd = open("/proc/self/auxv", O_RDONLY); + if (fd == -1) { + perror("open"); + return NULL; + } + + result = NULL; + + num = read(fd, auxv, sizeof(auxv)); + if (num < 0) { + perror("read"); + goto out; + } + + if (num > sizeof(auxv)) { + printf("Overflowed auxv buffer\n"); + goto out; + } + + p = (ElfW(auxv_t) *)auxv; + + while (p->a_type != AT_NULL) { + if (p->a_type == type) { + result = (void *)p->a_un.a_val; + break; + } + + p++; + } +out: + close(fd); + return result; +} diff --git a/powerpc/pmu/lib.h b/powerpc/pmu/lib.h new file mode 100644 index 0000000..0f0339c --- /dev/null +++ b/powerpc/pmu/lib.h @@ -0,0 +1,42 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#ifndef __SELFTESTS_POWERPC_PMU_LIB_H +#define __SELFTESTS_POWERPC_PMU_LIB_H + +#include +#include +#include +#include + +union pipe { + struct { + int read_fd; + int write_fd; + }; + int fds[2]; +}; + +extern int pick_online_cpu(void); +extern int bind_to_cpu(int cpu); +extern int kill_child_and_wait(pid_t child_pid); +extern int wait_for_child(pid_t child_pid); +extern int sync_with_child(union pipe read_pipe, union pipe write_pipe); +extern int wait_for_parent(union pipe read_pipe); +extern int notify_parent(union pipe write_pipe); +extern int notify_parent_of_error(union pipe write_pipe); +extern pid_t eat_cpu(int (test_function)(void)); +extern bool require_paranoia_below(int level); +extern void *get_auxv_entry(int type); + +struct addr_range { + uint64_t first, last; +}; + +extern struct addr_range libc, vdso; + +int parse_proc_maps(void); + +#endif /* __SELFTESTS_POWERPC_PMU_LIB_H */ diff --git a/powerpc/pmu/loop.S b/powerpc/pmu/loop.S new file mode 100644 index 0000000..20c1f08 --- /dev/null +++ b/powerpc/pmu/loop.S @@ -0,0 +1,43 @@ +/* + * Copyright 2013, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include + + .text + +FUNC_START(thirty_two_instruction_loop) + cmpdi r3,0 + beqlr + addi r4,r3,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 + addi r4,r4,1 # 28 addi's + subi r3,r3,1 + b FUNC_NAME(thirty_two_instruction_loop) +FUNC_END(thirty_two_instruction_loop) diff --git a/powerpc/pmu/per_event_excludes.c b/powerpc/pmu/per_event_excludes.c new file mode 100644 index 0000000..fddbbc9 --- /dev/null +++ b/powerpc/pmu/per_event_excludes.c @@ -0,0 +1,114 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +#include "event.h" +#include "lib.h" +#include "utils.h" + +/* + * Test that per-event excludes work. + */ + +static int per_event_excludes(void) +{ + struct event *e, events[4]; + char *platform; + int i; + + platform = (char *)get_auxv_entry(AT_BASE_PLATFORM); + FAIL_IF(!platform); + SKIP_IF(strcmp(platform, "power8") != 0); + + /* + * We need to create the events disabled, otherwise the running/enabled + * counts don't match up. + */ + e = &events[0]; + event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS, + PERF_TYPE_HARDWARE, "instructions"); + e->attr.disabled = 1; + + e = &events[1]; + event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS, + PERF_TYPE_HARDWARE, "instructions(k)"); + e->attr.disabled = 1; + e->attr.exclude_user = 1; + e->attr.exclude_hv = 1; + + e = &events[2]; + event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS, + PERF_TYPE_HARDWARE, "instructions(h)"); + e->attr.disabled = 1; + e->attr.exclude_user = 1; + e->attr.exclude_kernel = 1; + + e = &events[3]; + event_init_opts(e, PERF_COUNT_HW_INSTRUCTIONS, + PERF_TYPE_HARDWARE, "instructions(u)"); + e->attr.disabled = 1; + e->attr.exclude_hv = 1; + e->attr.exclude_kernel = 1; + + FAIL_IF(event_open(&events[0])); + + /* + * The open here will fail if we don't have per event exclude support, + * because the second event has an incompatible set of exclude settings + * and we're asking for the events to be in a group. + */ + for (i = 1; i < 4; i++) + FAIL_IF(event_open_with_group(&events[i], events[0].fd)); + + /* + * Even though the above will fail without per-event excludes we keep + * testing in order to be thorough. + */ + prctl(PR_TASK_PERF_EVENTS_ENABLE); + + /* Spin for a while */ + for (i = 0; i < INT_MAX; i++) + asm volatile("" : : : "memory"); + + prctl(PR_TASK_PERF_EVENTS_DISABLE); + + for (i = 0; i < 4; i++) { + FAIL_IF(event_read(&events[i])); + event_report(&events[i]); + } + + /* + * We should see that all events have enabled == running. That + * shows that they were all on the PMU at once. + */ + for (i = 0; i < 4; i++) + FAIL_IF(events[i].result.running != events[i].result.enabled); + + /* + * We can also check that the result for instructions is >= all the + * other counts. That's because it is counting all instructions while + * the others are counting a subset. + */ + for (i = 1; i < 4; i++) + FAIL_IF(events[0].result.value < events[i].result.value); + + for (i = 0; i < 4; i++) + event_close(&events[i]); + + return 0; +} + +int main(void) +{ + return test_harness(per_event_excludes, "per_event_excludes"); +} diff --git a/powerpc/subunit.h b/powerpc/subunit.h new file mode 100644 index 0000000..9c6c4e9 --- /dev/null +++ b/powerpc/subunit.h @@ -0,0 +1,52 @@ +/* + * Copyright 2013, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#ifndef _SELFTESTS_POWERPC_SUBUNIT_H +#define _SELFTESTS_POWERPC_SUBUNIT_H + +static inline void test_start(char *name) +{ + printf("test: %s\n", name); +} + +static inline void test_failure_detail(char *name, char *detail) +{ + printf("failure: %s [%s]\n", name, detail); +} + +static inline void test_failure(char *name) +{ + printf("failure: %s\n", name); +} + +static inline void test_error(char *name) +{ + printf("error: %s\n", name); +} + +static inline void test_skip(char *name) +{ + printf("skip: %s\n", name); +} + +static inline void test_success(char *name) +{ + printf("success: %s\n", name); +} + +static inline void test_finish(char *name, int status) +{ + if (status) + test_failure(name); + else + test_success(name); +} + +static inline void test_set_git_version(char *value) +{ + printf("tags: git_version:%s\n", value); +} + +#endif /* _SELFTESTS_POWERPC_SUBUNIT_H */ diff --git a/powerpc/tm/Makefile b/powerpc/tm/Makefile new file mode 100644 index 0000000..2cede23 --- /dev/null +++ b/powerpc/tm/Makefile @@ -0,0 +1,15 @@ +PROGS := tm-resched-dscr + +all: $(PROGS) + +$(PROGS): ../harness.c + +run_tests: all + @-for PROG in $(PROGS); do \ + ./$$PROG; \ + done; + +clean: + rm -f $(PROGS) *.o + +.PHONY: all run_tests clean diff --git a/powerpc/tm/tm-resched-dscr.c b/powerpc/tm/tm-resched-dscr.c new file mode 100644 index 0000000..42d4c8c --- /dev/null +++ b/powerpc/tm/tm-resched-dscr.c @@ -0,0 +1,98 @@ +/* Test context switching to see if the DSCR SPR is correctly preserved + * when within a transaction. + * + * Note: We assume that the DSCR has been left at the default value (0) + * for all CPUs. + * + * Method: + * + * Set a value into the DSCR. + * + * Start a transaction, and suspend it (*). + * + * Hard loop checking to see if the transaction has become doomed. + * + * Now that we *may* have been preempted, record the DSCR and TEXASR SPRS. + * + * If the abort was because of a context switch, check the DSCR value. + * Otherwise, try again. + * + * (*) If the transaction is not suspended we can't see the problem because + * the transaction abort handler will restore the DSCR to it's checkpointed + * value before we regain control. + */ + +#include +#include +#include +#include +#include + +#include "utils.h" + +#define TBEGIN ".long 0x7C00051D ;" +#define TEND ".long 0x7C00055D ;" +#define TCHECK ".long 0x7C00059C ;" +#define TSUSPEND ".long 0x7C0005DD ;" +#define TRESUME ".long 0x7C2005DD ;" +#define SPRN_TEXASR 0x82 +#define SPRN_DSCR 0x03 + +int test_body(void) +{ + uint64_t rv, dscr1 = 1, dscr2, texasr; + + printf("Check DSCR TM context switch: "); + fflush(stdout); + for (;;) { + rv = 1; + asm __volatile__ ( + /* set a known value into the DSCR */ + "ld 3, %[dscr1];" + "mtspr %[sprn_dscr], 3;" + + /* start and suspend a transaction */ + TBEGIN + "beq 1f;" + TSUSPEND + + /* hard loop until the transaction becomes doomed */ + "2: ;" + TCHECK + "bc 4, 0, 2b;" + + /* record DSCR and TEXASR */ + "mfspr 3, %[sprn_dscr];" + "std 3, %[dscr2];" + "mfspr 3, %[sprn_texasr];" + "std 3, %[texasr];" + + TRESUME + TEND + "li %[rv], 0;" + "1: ;" + : [rv]"=r"(rv), [dscr2]"=m"(dscr2), [texasr]"=m"(texasr) + : [dscr1]"m"(dscr1) + , [sprn_dscr]"i"(SPRN_DSCR), [sprn_texasr]"i"(SPRN_TEXASR) + : "memory", "r3" + ); + assert(rv); /* make sure the transaction aborted */ + if ((texasr >> 56) != TM_CAUSE_RESCHED) { + putchar('.'); + fflush(stdout); + continue; + } + if (dscr2 != dscr1) { + printf(" FAIL\n"); + return 1; + } else { + printf(" OK\n"); + return 0; + } + } +} + +int main(void) +{ + return test_harness(test_body, "tm_resched_dscr"); +} diff --git a/powerpc/utils.h b/powerpc/utils.h new file mode 100644 index 0000000..a93777a --- /dev/null +++ b/powerpc/utils.h @@ -0,0 +1,49 @@ +/* + * Copyright 2013, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#ifndef _SELFTESTS_POWERPC_UTILS_H +#define _SELFTESTS_POWERPC_UTILS_H + +#include +#include + +/* Avoid headaches with PRI?64 - just use %ll? always */ +typedef unsigned long long u64; +typedef signed long long s64; + +/* Just for familiarity */ +typedef uint32_t u32; +typedef uint8_t u8; + + +int test_harness(int (test_function)(void), char *name); + + +/* Yes, this is evil */ +#define FAIL_IF(x) \ +do { \ + if ((x)) { \ + fprintf(stderr, \ + "[FAIL] Test FAILED on line %d\n", __LINE__); \ + return 1; \ + } \ +} while (0) + +/* The test harness uses this, yes it's gross */ +#define MAGIC_SKIP_RETURN_VALUE 99 + +#define SKIP_IF(x) \ +do { \ + if ((x)) { \ + fprintf(stderr, \ + "[SKIP] Test skipped on line %d\n", __LINE__); \ + return MAGIC_SKIP_RETURN_VALUE; \ + } \ +} while (0) + +#define _str(s) #s +#define str(s) _str(s) + +#endif /* _SELFTESTS_POWERPC_UTILS_H */ diff --git a/ptrace/peeksiginfo b/ptrace/peeksiginfo deleted file mode 100755 index 0d13439..0000000 Binary files a/ptrace/peeksiginfo and /dev/null differ diff --git a/ptrace/peeksiginfo.c b/ptrace/peeksiginfo.c index d46558b..c34cd8a 100644 --- a/ptrace/peeksiginfo.c +++ b/ptrace/peeksiginfo.c @@ -31,6 +31,10 @@ static int sys_ptrace(int request, pid_t pid, void *addr, void *data) #define TEST_SICODE_PRIV -1 #define TEST_SICODE_SHARE -2 +#ifndef PAGE_SIZE +#define PAGE_SIZE sysconf(_SC_PAGESIZE) +#endif + #define err(fmt, ...) \ fprintf(stderr, \ "Error (%s:%d): " fmt, \ diff --git a/rcutorture/.gitignore b/rcutorture/.gitignore new file mode 100644 index 0000000..05838f6 --- /dev/null +++ b/rcutorture/.gitignore @@ -0,0 +1,6 @@ +initrd +linux-2.6 +b[0-9]* +rcu-test-image +res +*.swp diff --git a/rcutorture/bin/config2frag.sh b/rcutorture/bin/config2frag.sh new file mode 100644 index 0000000..9f9ffcd --- /dev/null +++ b/rcutorture/bin/config2frag.sh @@ -0,0 +1,25 @@ +#!/bin/sh +# Usage: sh config2frag.sh < .config > configfrag +# +# Converts the "# CONFIG_XXX is not set" to "CONFIG_XXX=n" so that the +# resulting file becomes a legitimate Kconfig fragment. +# +# 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, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2013 +# +# Authors: Paul E. McKenney + +LANG=C sed -e 's/^# CONFIG_\([a-zA-Z0-9_]*\) is not set$/CONFIG_\1=n/' diff --git a/rcutorture/bin/configNR_CPUS.sh b/rcutorture/bin/configNR_CPUS.sh new file mode 100755 index 0000000..43540f1 --- /dev/null +++ b/rcutorture/bin/configNR_CPUS.sh @@ -0,0 +1,45 @@ +#!/bin/bash +# +# Extract the number of CPUs expected from the specified Kconfig-file +# fragment by checking CONFIG_SMP and CONFIG_NR_CPUS. If the specified +# file gives no clue, base the number on the number of idle CPUs on +# the system. +# +# Usage: configNR_CPUS.sh config-frag +# +# 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, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2013 +# +# Authors: Paul E. McKenney + +cf=$1 +if test ! -r $cf +then + echo Unreadable config fragment $cf 1>&2 + exit -1 +fi +if grep -q '^CONFIG_SMP=n$' $cf +then + echo 1 + exit 0 +fi +if grep -q '^CONFIG_NR_CPUS=' $cf +then + grep '^CONFIG_NR_CPUS=' $cf | + sed -e 's/^CONFIG_NR_CPUS=\([0-9]*\).*$/\1/' + exit 0 +fi +cpus2use.sh diff --git a/rcutorture/bin/configcheck.sh b/rcutorture/bin/configcheck.sh new file mode 100755 index 0000000..d686537 --- /dev/null +++ b/rcutorture/bin/configcheck.sh @@ -0,0 +1,54 @@ +#!/bin/sh +# Usage: sh configcheck.sh .config .config-template +# +# 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, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2011 +# +# Authors: Paul E. McKenney + +T=/tmp/abat-chk-config.sh.$$ +trap 'rm -rf $T' 0 +mkdir $T + +cat $1 > $T/.config + +cat $2 | sed -e 's/\(.*\)=n/# \1 is not set/' -e 's/^#CHECK#//' | +awk ' +BEGIN { + print "if grep -q \"" $0 "\" < '"$T/.config"'"; + print "then"; + print "\t:"; + print "else"; + if ($1 == "#") { + print "\tif grep -q \"" $2 "\" < '"$T/.config"'"; + print "\tthen"; + print "\t\tif test \"$firsttime\" = \"\"" + print "\t\tthen" + print "\t\t\tfirsttime=1" + print "\t\tfi" + print "\t\techo \":" $2 ": improperly set\""; + print "\telse"; + print "\t\t:"; + print "\tfi"; + } else { + print "\tif test \"$firsttime\" = \"\"" + print "\tthen" + print "\t\tfirsttime=1" + print "\tfi" + print "\techo \":" $0 ": improperly set\""; + } + print "fi"; + }' | sh diff --git a/rcutorture/bin/configinit.sh b/rcutorture/bin/configinit.sh new file mode 100755 index 0000000..9c3f3d3 --- /dev/null +++ b/rcutorture/bin/configinit.sh @@ -0,0 +1,74 @@ +#!/bin/sh +# +# sh configinit.sh config-spec-file [ build output dir ] +# +# Create a .config file from the spec file. Run from the kernel source tree. +# Exits with 0 if all went well, with 1 if all went well but the config +# did not match, and some other number for other failures. +# +# The first argument is the .config specification file, which contains +# desired settings, for example, "CONFIG_NO_HZ=y". For best results, +# this should be a full pathname. +# +# The second argument is a optional path to a build output directory, +# for example, "O=/tmp/foo". If this argument is omitted, the .config +# file will be generated directly in the current directory. +# +# 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, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2013 +# +# Authors: Paul E. McKenney + +T=/tmp/configinit.sh.$$ +trap 'rm -rf $T' 0 +mkdir $T + +# Capture config spec file. + +c=$1 +buildloc=$2 +builddir= +if test -n $buildloc +then + if echo $buildloc | grep -q '^O=' + then + builddir=`echo $buildloc | sed -e 's/^O=//'` + if test ! -d $builddir + then + mkdir $builddir + fi + else + echo Bad build directory: \"$builddir\" + exit 2 + fi +fi + +sed -e 's/^\(CONFIG[0-9A-Z_]*\)=.*$/grep -v "^# \1" |/' < $c > $T/u.sh +sed -e 's/^\(CONFIG[0-9A-Z_]*=\).*$/grep -v \1 |/' < $c >> $T/u.sh +grep '^grep' < $T/u.sh > $T/upd.sh +echo "cat - $c" >> $T/upd.sh +make mrproper +make $buildloc distclean > $builddir/Make.distclean 2>&1 +make $buildloc $TORTURE_DEFCONFIG > $builddir/Make.defconfig.out 2>&1 +mv $builddir/.config $builddir/.config.sav +sh $T/upd.sh < $builddir/.config.sav > $builddir/.config +cp $builddir/.config $builddir/.config.new +yes '' | make $buildloc oldconfig > $builddir/Make.modconfig.out 2>&1 + +# verify new config matches specification. +configcheck.sh $builddir/.config $c + +exit 0 diff --git a/rcutorture/bin/cpus2use.sh b/rcutorture/bin/cpus2use.sh new file mode 100755 index 0000000..abe14b7 --- /dev/null +++ b/rcutorture/bin/cpus2use.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# +# Get an estimate of how CPU-hoggy to be. +# +# Usage: cpus2use.sh +# +# 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, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2013 +# +# Authors: Paul E. McKenney + +ncpus=`grep '^processor' /proc/cpuinfo | wc -l` +idlecpus=`mpstat | tail -1 | \ + awk -v ncpus=$ncpus '{ print ncpus * ($7 + $12) / 100 }'` +awk -v ncpus=$ncpus -v idlecpus=$idlecpus < /dev/null ' +BEGIN { + cpus2use = idlecpus; + if (cpus2use < 1) + cpus2use = 1; + if (cpus2use < ncpus / 10) + cpus2use = ncpus / 10; + if (cpus2use == int(cpus2use)) + cpus2use = int(cpus2use) + else + cpus2use = int(cpus2use) + 1 + print cpus2use; +}' + diff --git a/rcutorture/bin/functions.sh b/rcutorture/bin/functions.sh new file mode 100644 index 0000000..d01b865 --- /dev/null +++ b/rcutorture/bin/functions.sh @@ -0,0 +1,223 @@ +#!/bin/bash +# +# Shell functions for the rest of the scripts. +# +# 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, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2013 +# +# Authors: Paul E. McKenney + +# bootparam_hotplug_cpu bootparam-string +# +# Returns 1 if the specified boot-parameter string tells rcutorture to +# test CPU-hotplug operations. +bootparam_hotplug_cpu () { + echo "$1" | grep -q "rcutorture\.onoff_" +} + +# checkarg --argname argtype $# arg mustmatch cannotmatch +# +# Checks the specified argument "arg" against the mustmatch and cannotmatch +# patterns. +checkarg () { + if test $3 -le 1 + then + echo $1 needs argument $2 matching \"$5\" + usage + fi + if echo "$4" | grep -q -e "$5" + then + : + else + echo $1 $2 \"$4\" must match \"$5\" + usage + fi + if echo "$4" | grep -q -e "$6" + then + echo $1 $2 \"$4\" must not match \"$6\" + usage + fi +} + +# configfrag_boot_params bootparam-string config-fragment-file +# +# Adds boot parameters from the .boot file, if any. +configfrag_boot_params () { + if test -r "$2.boot" + then + echo $1 `grep -v '^#' "$2.boot" | tr '\012' ' '` + else + echo $1 + fi +} + +# configfrag_hotplug_cpu config-fragment-file +# +# Returns 1 if the config fragment specifies hotplug CPU. +configfrag_hotplug_cpu () { + if test ! -r "$1" + then + echo Unreadable config fragment "$1" 1>&2 + exit -1 + fi + grep -q '^CONFIG_HOTPLUG_CPU=y$' "$1" +} + +# identify_boot_image qemu-cmd +# +# Returns the relative path to the kernel build image. This will be +# arch//boot/bzImage unless overridden with the TORTURE_BOOT_IMAGE +# environment variable. +identify_boot_image () { + if test -n "$TORTURE_BOOT_IMAGE" + then + echo $TORTURE_BOOT_IMAGE + else + case "$1" in + qemu-system-x86_64|qemu-system-i386) + echo arch/x86/boot/bzImage + ;; + qemu-system-ppc64) + echo arch/powerpc/boot/bzImage + ;; + *) + echo "" + ;; + esac + fi +} + +# identify_qemu builddir +# +# Returns our best guess as to which qemu command is appropriate for +# the kernel at hand. Override with the TORTURE_QEMU_CMD environment variable. +identify_qemu () { + local u="`file "$1"`" + if test -n "$TORTURE_QEMU_CMD" + then + echo $TORTURE_QEMU_CMD + elif echo $u | grep -q x86-64 + then + echo qemu-system-x86_64 + elif echo $u | grep -q "Intel 80386" + then + echo qemu-system-i386 + elif uname -a | grep -q ppc64 + then + echo qemu-system-ppc64 + else + echo Cannot figure out what qemu command to use! 1>&2 + echo file $1 output: $u + # Usually this will be one of /usr/bin/qemu-system-* + # Use TORTURE_QEMU_CMD environment variable or appropriate + # argument to top-level script. + exit 1 + fi +} + +# identify_qemu_append qemu-cmd +# +# Output arguments for the qemu "-append" string based on CPU type +# and the TORTURE_QEMU_INTERACTIVE environment variable. +identify_qemu_append () { + case "$1" in + qemu-system-x86_64|qemu-system-i386) + echo noapic selinux=0 initcall_debug debug + ;; + esac + if test -n "$TORTURE_QEMU_INTERACTIVE" + then + echo root=/dev/sda + else + echo console=ttyS0 + fi +} + +# identify_qemu_args qemu-cmd serial-file +# +# Output arguments for qemu arguments based on the TORTURE_QEMU_MAC +# and TORTURE_QEMU_INTERACTIVE environment variables. +identify_qemu_args () { + case "$1" in + qemu-system-x86_64|qemu-system-i386) + ;; + qemu-system-ppc64) + echo -enable-kvm -M pseries -cpu POWER7 -nodefaults + echo -device spapr-vscsi + if test -n "$TORTURE_QEMU_INTERACTIVE" -a -n "$TORTURE_QEMU_MAC" + then + echo -device spapr-vlan,netdev=net0,mac=$TORTURE_QEMU_MAC + echo -netdev bridge,br=br0,id=net0 + elif test -n "$TORTURE_QEMU_INTERACTIVE" + then + echo -net nic -net user + fi + ;; + esac + if test -n "$TORTURE_QEMU_INTERACTIVE" + then + echo -monitor stdio -serial pty -S + else + echo -serial file:$2 + fi +} + +# identify_qemu_vcpus +# +# Returns the number of virtual CPUs available to the aggregate of the +# guest OSes. +identify_qemu_vcpus () { + lscpu | grep '^CPU(s):' | sed -e 's/CPU(s)://' +} + +# print_bug +# +# Prints "BUG: " in red followed by remaining arguments +print_bug () { + printf '\033[031mBUG: \033[m' + echo $* +} + +# print_warning +# +# Prints "WARNING: " in yellow followed by remaining arguments +print_warning () { + printf '\033[033mWARNING: \033[m' + echo $* +} + +# specify_qemu_cpus qemu-cmd qemu-args #cpus +# +# Appends a string containing "-smp XXX" to qemu-args, unless the incoming +# qemu-args already contains "-smp". +specify_qemu_cpus () { + local nt; + + if echo $2 | grep -q -e -smp + then + echo $2 + else + case "$1" in + qemu-system-x86_64|qemu-system-i386) + echo $2 -smp $3 + ;; + qemu-system-ppc64) + nt="`lscpu | grep '^NUMA node0' | sed -e 's/^[^,]*,\([0-9]*\),.*$/\1/'`" + echo $2 -smp cores=`expr \( $3 + $nt - 1 \) / $nt`,threads=$nt + ;; + esac + fi +} diff --git a/rcutorture/bin/kvm-build.sh b/rcutorture/bin/kvm-build.sh new file mode 100755 index 0000000..7c1e56b --- /dev/null +++ b/rcutorture/bin/kvm-build.sh @@ -0,0 +1,71 @@ +#!/bin/bash +# +# Build a kvm-ready Linux kernel from the tree in the current directory. +# +# Usage: sh kvm-build.sh config-template build-dir more-configs +# +# 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, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2011 +# +# Authors: Paul E. McKenney + +config_template=${1} +if test -z "$config_template" -o ! -f "$config_template" -o ! -r "$config_template" +then + echo "kvm-build.sh :$config_template: Not a readable file" + exit 1 +fi +builddir=${2} +if test -z "$builddir" -o ! -d "$builddir" -o ! -w "$builddir" +then + echo "kvm-build.sh :$builddir: Not a writable directory, cannot build into it" + exit 1 +fi +moreconfigs=${3} +if test -z "$moreconfigs" -o ! -r "$moreconfigs" +then + echo "kvm-build.sh :$moreconfigs: Not a readable file" + exit 1 +fi + +T=/tmp/test-linux.sh.$$ +trap 'rm -rf $T' 0 +mkdir $T + +grep -v 'CONFIG_[A-Z]*_TORTURE_TEST' < ${config_template} > $T/config +cat << ___EOF___ >> $T/config +CONFIG_INITRAMFS_SOURCE="$TORTURE_INITRD" +CONFIG_VIRTIO_PCI=y +CONFIG_VIRTIO_CONSOLE=y +___EOF___ +cat $moreconfigs >> $T/config + +configinit.sh $T/config O=$builddir +retval=$? +if test $retval -gt 1 +then + exit 2 +fi +ncpus=`cpus2use.sh` +make O=$builddir -j$ncpus $TORTURE_KMAKE_ARG > $builddir/Make.out 2>&1 +retval=$? +if test $retval -ne 0 || grep "rcu[^/]*": < $builddir/Make.out | egrep -q "Stop|Error|error:|warning:" || egrep -q "Stop|Error|error:" < $builddir/Make.out +then + echo Kernel build error + egrep "Stop|Error|error:|warning:" < $builddir/Make.out + echo Run aborted. + exit 3 +fi diff --git a/rcutorture/bin/kvm-recheck-lock.sh b/rcutorture/bin/kvm-recheck-lock.sh new file mode 100755 index 0000000..7f1ff1a --- /dev/null +++ b/rcutorture/bin/kvm-recheck-lock.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# +# Analyze a given results directory for locktorture progress. +# +# Usage: sh kvm-recheck-lock.sh resdir +# +# 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, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2014 +# +# Authors: Paul E. McKenney + +i="$1" +if test -d $i +then + : +else + echo Unreadable results directory: $i + exit 1 +fi + +configfile=`echo $i | sed -e 's/^.*\///'` +ncs=`grep "Writes: Total:" $i/console.log 2> /dev/null | tail -1 | sed -e 's/^.* Total: //' -e 's/ .*$//'` +if test -z "$ncs" +then + echo "$configfile -------" +else + title="$configfile ------- $ncs acquisitions/releases" + dur=`sed -e 's/^.* locktorture.shutdown_secs=//' -e 's/ .*$//' < $i/qemu-cmd 2> /dev/null` + if test -z "$dur" + then + : + else + ncsps=`awk -v ncs=$ncs -v dur=$dur ' + BEGIN { print ncs / dur }' < /dev/null` + title="$title ($ncsps per second)" + fi + echo $title +fi diff --git a/rcutorture/bin/kvm-recheck-rcu.sh b/rcutorture/bin/kvm-recheck-rcu.sh new file mode 100755 index 0000000..307c4b9 --- /dev/null +++ b/rcutorture/bin/kvm-recheck-rcu.sh @@ -0,0 +1,51 @@ +#!/bin/bash +# +# Analyze a given results directory for rcutorture progress. +# +# Usage: sh kvm-recheck-rcu.sh resdir +# +# 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, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2014 +# +# Authors: Paul E. McKenney + +i="$1" +if test -d $i +then + : +else + echo Unreadable results directory: $i + exit 1 +fi + +configfile=`echo $i | sed -e 's/^.*\///'` +ngps=`grep ver: $i/console.log 2> /dev/null | tail -1 | sed -e 's/^.* ver: //' -e 's/ .*$//'` +if test -z "$ngps" +then + echo "$configfile -------" +else + title="$configfile ------- $ngps grace periods" + dur=`sed -e 's/^.* rcutorture.shutdown_secs=//' -e 's/ .*$//' < $i/qemu-cmd 2> /dev/null` + if test -z "$dur" + then + : + else + ngpsps=`awk -v ngps=$ngps -v dur=$dur ' + BEGIN { print ngps / dur }' < /dev/null` + title="$title ($ngpsps per second)" + fi + echo $title +fi diff --git a/rcutorture/bin/kvm-recheck.sh b/rcutorture/bin/kvm-recheck.sh new file mode 100755 index 0000000..3f6c9b7 --- /dev/null +++ b/rcutorture/bin/kvm-recheck.sh @@ -0,0 +1,69 @@ +#!/bin/bash +# +# Given the results directories for previous KVM-based torture runs, +# check the build and console output for errors. Given a directory +# containing results directories, this recursively checks them all. +# +# Usage: sh kvm-recheck.sh resdir ... +# +# 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, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2011 +# +# Authors: Paul E. McKenney + +PATH=`pwd`/tools/testing/selftests/rcutorture/bin:$PATH; export PATH +. tools/testing/selftests/rcutorture/bin/functions.sh +for rd in "$@" +do + firsttime=1 + dirs=`find $rd -name Make.defconfig.out -print | sort | sed -e 's,/[^/]*$,,' | sort -u` + for i in $dirs + do + if test -n "$firsttime" + then + firsttime="" + resdir=`echo $i | sed -e 's,/$,,' -e 's,/[^/]*$,,'` + head -1 $resdir/log + fi + TORTURE_SUITE="`cat $i/../TORTURE_SUITE`" + kvm-recheck-${TORTURE_SUITE}.sh $i + if test -f "$i/console.log" + then + configcheck.sh $i/.config $i/ConfigFragment + parse-build.sh $i/Make.out $configfile + parse-torture.sh $i/console.log $configfile + parse-console.sh $i/console.log $configfile + if test -r $i/Warnings + then + cat $i/Warnings + fi + else + if test -f "$i/qemu-cmd" + then + print_bug qemu failed + echo " $i" + elif test -f "$i/buildonly" + then + echo Build-only run, no boot/test + configcheck.sh $i/.config $i/ConfigFragment + parse-build.sh $i/Make.out $configfile + else + print_bug Build failed + echo " $i" + fi + fi + done +done diff --git a/rcutorture/bin/kvm-test-1-run.sh b/rcutorture/bin/kvm-test-1-run.sh new file mode 100755 index 0000000..0f69dcb --- /dev/null +++ b/rcutorture/bin/kvm-test-1-run.sh @@ -0,0 +1,227 @@ +#!/bin/bash +# +# Run a kvm-based test of the specified tree on the specified configs. +# Fully automated run and error checking, no graphics console. +# +# Execute this in the source tree. Do not run it as a background task +# because qemu does not seem to like that much. +# +# Usage: sh kvm-test-1-run.sh config builddir resdir minutes qemu-args boot_args +# +# qemu-args defaults to "-nographic", along with arguments specifying the +# number of CPUs and other options generated from +# the underlying CPU architecture. +# boot_args defaults to value returned by the per_version_boot_params +# shell function. +# +# Anything you specify for either qemu-args or boot_args is appended to +# the default values. The "-smp" value is deduced from the contents of +# the config fragment. +# +# More sophisticated argument parsing is clearly needed. +# +# 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, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2011 +# +# Authors: Paul E. McKenney + +grace=120 + +T=/tmp/kvm-test-1-run.sh.$$ +trap 'rm -rf $T' 0 +touch $T + +. $KVM/bin/functions.sh +. $KVPATH/ver_functions.sh + +config_template=${1} +config_dir=`echo $config_template | sed -e 's,/[^/]*$,,'` +title=`echo $config_template | sed -e 's/^.*\///'` +builddir=${2} +if test -z "$builddir" -o ! -d "$builddir" -o ! -w "$builddir" +then + echo "kvm-test-1-run.sh :$builddir: Not a writable directory, cannot build into it" + exit 1 +fi +resdir=${3} +if test -z "$resdir" -o ! -d "$resdir" -o ! -w "$resdir" +then + echo "kvm-test-1-run.sh :$resdir: Not a writable directory, cannot store results into it" + exit 1 +fi +cp $config_template $resdir/ConfigFragment +echo ' ---' `date`: Starting build +echo ' ---' Kconfig fragment at: $config_template >> $resdir/log +if test -r "$config_dir/CFcommon" +then + cat < $config_dir/CFcommon >> $T +fi +# Optimizations below this point +# CONFIG_USB=n +# CONFIG_SECURITY=n +# CONFIG_NFS_FS=n +# CONFIG_SOUND=n +# CONFIG_INPUT_JOYSTICK=n +# CONFIG_INPUT_TABLET=n +# CONFIG_INPUT_TOUCHSCREEN=n +# CONFIG_INPUT_MISC=n +# CONFIG_INPUT_MOUSE=n +# # CONFIG_NET=n # disables console access, so accept the slower build. +# CONFIG_SCSI=n +# CONFIG_ATA=n +# CONFIG_FAT_FS=n +# CONFIG_MSDOS_FS=n +# CONFIG_VFAT_FS=n +# CONFIG_ISO9660_FS=n +# CONFIG_QUOTA=n +# CONFIG_HID=n +# CONFIG_CRYPTO=n +# CONFIG_PCCARD=n +# CONFIG_PCMCIA=n +# CONFIG_CARDBUS=n +# CONFIG_YENTA=n +if kvm-build.sh $config_template $builddir $T +then + QEMU="`identify_qemu $builddir/vmlinux`" + BOOT_IMAGE="`identify_boot_image $QEMU`" + cp $builddir/Make*.out $resdir + cp $builddir/.config $resdir + if test -n "$BOOT_IMAGE" + then + cp $builddir/$BOOT_IMAGE $resdir + else + echo No identifiable boot image, not running KVM, see $resdir. + echo Do the torture scripts know about your architecture? + fi + parse-build.sh $resdir/Make.out $title + if test -f $builddir.wait + then + mv $builddir.wait $builddir.ready + fi +else + cp $builddir/Make*.out $resdir + cp $builddir/.config $resdir || : + echo Build failed, not running KVM, see $resdir. + if test -f $builddir.wait + then + mv $builddir.wait $builddir.ready + fi + exit 1 +fi +while test -f $builddir.ready +do + sleep 1 +done +minutes=$4 +seconds=$(($minutes * 60)) +qemu_args=$5 +boot_args=$6 + +cd $KVM +kstarttime=`awk 'BEGIN { print systime() }' < /dev/null` +if test -z "$TORTURE_BUILDONLY" +then + echo ' ---' `date`: Starting kernel +fi + +# Generate -smp qemu argument. +qemu_args="-nographic $qemu_args" +cpu_count=`configNR_CPUS.sh $config_template` +vcpus=`identify_qemu_vcpus` +if test $cpu_count -gt $vcpus +then + echo CPU count limited from $cpu_count to $vcpus + touch $resdir/Warnings + echo CPU count limited from $cpu_count to $vcpus >> $resdir/Warnings + cpu_count=$vcpus +fi +qemu_args="`specify_qemu_cpus "$QEMU" "$qemu_args" "$cpu_count"`" + +# Generate architecture-specific and interaction-specific qemu arguments +qemu_args="$qemu_args `identify_qemu_args "$QEMU" "$builddir/console.log"`" + +# Generate qemu -append arguments +qemu_append="`identify_qemu_append "$QEMU"`" + +# Pull in Kconfig-fragment boot parameters +boot_args="`configfrag_boot_params "$boot_args" "$config_template"`" +# Generate kernel-version-specific boot parameters +boot_args="`per_version_boot_params "$boot_args" $builddir/.config $seconds`" + +if test -n "$TORTURE_BUILDONLY" +then + echo Build-only run specified, boot/test omitted. + touch $resdir/buildonly + exit 0 +fi +echo $QEMU $qemu_args -m 512 -kernel $builddir/$BOOT_IMAGE -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd +( $QEMU $qemu_args -m 512 -kernel $builddir/$BOOT_IMAGE -append "$qemu_append $boot_args"; echo $? > $resdir/qemu-retval ) & +qemu_pid=$! +commandcompleted=0 +echo Monitoring qemu job at pid $qemu_pid +while : +do + kruntime=`awk 'BEGIN { print systime() - '"$kstarttime"' }' < /dev/null` + if kill -0 $qemu_pid > /dev/null 2>&1 + then + if test $kruntime -ge $seconds + then + break; + fi + sleep 1 + else + commandcompleted=1 + if test $kruntime -lt $seconds + then + echo Completed in $kruntime vs. $seconds >> $resdir/Warnings 2>&1 + grep "^(qemu) qemu:" $resdir/kvm-test-1-run.sh.out >> $resdir/Warnings 2>&1 + killpid="`sed -n "s/^(qemu) qemu: terminating on signal [0-9]* from pid \([0-9]*\).*$/\1/p" $resdir/Warnings`" + if test -n "$killpid" + then + echo "ps -fp $killpid" >> $resdir/Warnings 2>&1 + ps -fp $killpid >> $resdir/Warnings 2>&1 + fi + else + echo ' ---' `date`: Kernel done + fi + break + fi +done +if test $commandcompleted -eq 0 +then + echo Grace period for qemu job at pid $qemu_pid + while : + do + kruntime=`awk 'BEGIN { print systime() - '"$kstarttime"' }' < /dev/null` + if kill -0 $qemu_pid > /dev/null 2>&1 + then + : + else + break + fi + if test $kruntime -ge $((seconds + grace)) + then + echo "!!! Hang at $kruntime vs. $seconds seconds" >> $resdir/Warnings 2>&1 + kill -KILL $qemu_pid + break + fi + sleep 1 + done +fi + +cp $builddir/console.log $resdir +parse-torture.sh $resdir/console.log $title +parse-console.sh $resdir/console.log $title diff --git a/rcutorture/bin/kvm.sh b/rcutorture/bin/kvm.sh new file mode 100644 index 0000000..589e9c3 --- /dev/null +++ b/rcutorture/bin/kvm.sh @@ -0,0 +1,413 @@ +#!/bin/bash +# +# Run a series of 14 tests under KVM. These are not particularly +# well-selected or well-tuned, but are the current set. Run from the +# top level of the source tree. +# +# Edit the definitions below to set the locations of the various directories, +# as well as the test duration. +# +# Usage: sh kvm.sh [ options ] +# +# 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, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2011 +# +# Authors: Paul E. McKenney + +scriptname=$0 +args="$*" + +T=/tmp/kvm.sh.$$ +trap 'rm -rf $T' 0 +mkdir $T + +dur=30 +dryrun="" +KVM="`pwd`/tools/testing/selftests/rcutorture"; export KVM +PATH=${KVM}/bin:$PATH; export PATH +TORTURE_DEFCONFIG=defconfig +TORTURE_BOOT_IMAGE="" +TORTURE_INITRD="$KVM/initrd"; export TORTURE_INITRD +TORTURE_KMAKE_ARG="" +TORTURE_SUITE=rcu +resdir="" +configs="" +cpus=0 +ds=`date +%Y.%m.%d-%H:%M:%S` +kversion="" + +. functions.sh + +usage () { + echo "Usage: $scriptname optional arguments:" + echo " --bootargs kernel-boot-arguments" + echo " --bootimage relative-path-to-kernel-boot-image" + echo " --buildonly" + echo " --configs \"config-file list\"" + echo " --cpus N" + echo " --datestamp string" + echo " --defconfig string" + echo " --dryrun sched|script" + echo " --duration minutes" + echo " --interactive" + echo " --kmake-arg kernel-make-arguments" + echo " --kversion vN.NN" + echo " --mac nn:nn:nn:nn:nn:nn" + echo " --no-initrd" + echo " --qemu-args qemu-system-..." + echo " --qemu-cmd qemu-system-..." + echo " --results absolute-pathname" + echo " --torture rcu" + exit 1 +} + +while test $# -gt 0 +do + case "$1" in + --bootargs) + checkarg --bootargs "(list of kernel boot arguments)" "$#" "$2" '.*' '^--' + TORTURE_BOOTARGS="$2" + shift + ;; + --bootimage) + checkarg --bootimage "(relative path to kernel boot image)" "$#" "$2" '[a-zA-Z0-9][a-zA-Z0-9_]*' '^--' + TORTURE_BOOT_IMAGE="$2" + shift + ;; + --buildonly) + TORTURE_BUILDONLY=1 + ;; + --configs) + checkarg --configs "(list of config files)" "$#" "$2" '^[^/]*$' '^--' + configs="$2" + shift + ;; + --cpus) + checkarg --cpus "(number)" "$#" "$2" '^[0-9]*$' '^--' + cpus=$2 + shift + ;; + --datestamp) + checkarg --datestamp "(relative pathname)" "$#" "$2" '^[^/]*$' '^--' + ds=$2 + shift + ;; + --defconfig) + checkarg --defconfig "defconfigtype" "$#" "$2" '^[^/][^/]*$' '^--' + TORTURE_DEFCONFIG=$2 + shift + ;; + --dryrun) + checkarg --dryrun "sched|script" $# "$2" 'sched\|script' '^--' + dryrun=$2 + shift + ;; + --duration) + checkarg --duration "(minutes)" $# "$2" '^[0-9]*$' '^error' + dur=$2 + shift + ;; + --interactive) + TORTURE_QEMU_INTERACTIVE=1; export TORTURE_QEMU_INTERACTIVE + ;; + --kmake-arg) + checkarg --kmake-arg "(kernel make arguments)" $# "$2" '.*' '^error$' + TORTURE_KMAKE_ARG="$2" + shift + ;; + --kversion) + checkarg --kversion "(kernel version)" $# "$2" '^v[0-9.]*$' '^error' + kversion=$2 + shift + ;; + --mac) + checkarg --mac "(MAC address)" $# "$2" '^\([0-9a-fA-F]\{2\}:\)\{5\}[0-9a-fA-F]\{2\}$' error + TORTURE_QEMU_MAC=$2 + shift + ;; + --no-initrd) + TORTURE_INITRD=""; export TORTURE_INITRD + ;; + --qemu-args) + checkarg --qemu-args "-qemu args" $# "$2" '^-' '^error' + TORTURE_QEMU_ARG="$2" + shift + ;; + --qemu-cmd) + checkarg --qemu-cmd "(qemu-system-...)" $# "$2" 'qemu-system-' '^--' + TORTURE_QEMU_CMD="$2" + shift + ;; + --results) + checkarg --results "(absolute pathname)" "$#" "$2" '^/' '^error' + resdir=$2 + shift + ;; + --torture) + checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\)$' '^--' + TORTURE_SUITE=$2 + shift + ;; + *) + echo Unknown argument $1 + usage + ;; + esac + shift +done + +CONFIGFRAG=${KVM}/configs/${TORTURE_SUITE}; export CONFIGFRAG +KVPATH=${CONFIGFRAG}/$kversion; export KVPATH + +if test -z "$configs" +then + configs="`cat $CONFIGFRAG/$kversion/CFLIST`" +fi + +if test -z "$resdir" +then + resdir=$KVM/res +fi + +# Create a file of test-name/#cpus pairs, sorted by decreasing #cpus. +touch $T/cfgcpu +for CF in $configs +do + if test -f "$CONFIGFRAG/$kversion/$CF" + then + echo $CF `configNR_CPUS.sh $CONFIGFRAG/$kversion/$CF` >> $T/cfgcpu + else + echo "The --configs file $CF does not exist, terminating." + exit 1 + fi +done +sort -k2nr $T/cfgcpu > $T/cfgcpu.sort + +# Use a greedy bin-packing algorithm, sorting the list accordingly. +awk < $T/cfgcpu.sort > $T/cfgcpu.pack -v ncpus=$cpus ' +BEGIN { + njobs = 0; +} + +{ + # Read file of tests and corresponding required numbers of CPUs. + cf[njobs] = $1; + cpus[njobs] = $2; + njobs++; +} + +END { + alldone = 0; + batch = 0; + nc = -1; + + # Each pass through the following loop creates on test batch + # that can be executed concurrently given ncpus. Note that a + # given test that requires more than the available CPUs will run in + # their own batch. Such tests just have to make do with what + # is available. + while (nc != ncpus) { + batch++; + nc = ncpus; + + # Each pass through the following loop considers one + # test for inclusion in the current batch. + for (i = 0; i < njobs; i++) { + if (done[i]) + continue; # Already part of a batch. + if (nc >= cpus[i] || nc == ncpus) { + + # This test fits into the current batch. + done[i] = batch; + nc -= cpus[i]; + if (nc <= 0) + break; # Too-big test in its own batch. + } + } + } + + # Dump out the tests in batch order. + for (b = 1; b <= batch; b++) + for (i = 0; i < njobs; i++) + if (done[i] == b) + print cf[i], cpus[i]; +}' + +# Generate a script to execute the tests in appropriate batches. +cat << ___EOF___ > $T/script +CONFIGFRAG="$CONFIGFRAG"; export CONFIGFRAG +KVM="$KVM"; export KVM +KVPATH="$KVPATH"; export KVPATH +PATH="$PATH"; export PATH +TORTURE_BOOT_IMAGE="$TORTURE_BOOT_IMAGE"; export TORTURE_BOOT_IMAGE +TORTURE_BUILDONLY="$TORTURE_BUILDONLY"; export TORTURE_BUILDONLY +TORTURE_DEFCONFIG="$TORTURE_DEFCONFIG"; export TORTURE_DEFCONFIG +TORTURE_INITRD="$TORTURE_INITRD"; export TORTURE_INITRD +TORTURE_KMAKE_ARG="$TORTURE_KMAKE_ARG"; export TORTURE_KMAKE_ARG +TORTURE_QEMU_CMD="$TORTURE_QEMU_CMD"; export TORTURE_QEMU_CMD +TORTURE_QEMU_INTERACTIVE="$TORTURE_QEMU_INTERACTIVE"; export TORTURE_QEMU_INTERACTIVE +TORTURE_QEMU_MAC="$TORTURE_QEMU_MAC"; export TORTURE_QEMU_MAC +TORTURE_SUITE="$TORTURE_SUITE"; export TORTURE_SUITE +if ! test -e $resdir +then + mkdir -p "$resdir" || : +fi +mkdir $resdir/$ds +echo Results directory: $resdir/$ds +echo $scriptname $args +touch $resdir/$ds/log +echo $scriptname $args >> $resdir/$ds/log +echo ${TORTURE_SUITE} > $resdir/$ds/TORTURE_SUITE +pwd > $resdir/$ds/testid.txt +if test -d .git +then + git status >> $resdir/$ds/testid.txt + git rev-parse HEAD >> $resdir/$ds/testid.txt + if ! git diff HEAD > $T/git-diff 2>&1 + then + cp $T/git-diff $resdir/$ds + fi +fi +___EOF___ +awk < $T/cfgcpu.pack \ + -v CONFIGDIR="$CONFIGFRAG/$kversion/" \ + -v KVM="$KVM" \ + -v ncpus=$cpus \ + -v rd=$resdir/$ds/ \ + -v dur=$dur \ + -v TORTURE_QEMU_ARG="$TORTURE_QEMU_ARG" \ + -v TORTURE_BOOTARGS="$TORTURE_BOOTARGS" \ +'BEGIN { + i = 0; +} + +{ + cf[i] = $1; + cpus[i] = $2; + i++; +} + +# Dump out the scripting required to run one test batch. +function dump(first, pastlast) +{ + print "echo ----Start batch: `date`"; + print "echo ----Start batch: `date` >> " rd "/log"; + jn=1 + for (j = first; j < pastlast; j++) { + builddir=KVM "/b" jn + cpusr[jn] = cpus[j]; + if (cfrep[cf[j]] == "") { + cfr[jn] = cf[j]; + cfrep[cf[j]] = 1; + } else { + cfrep[cf[j]]++; + cfr[jn] = cf[j] "." cfrep[cf[j]]; + } + if (cpusr[jn] > ncpus && ncpus != 0) + ovf = "(!)"; + else + ovf = ""; + print "echo ", cfr[jn], cpusr[jn] ovf ": Starting build. `date`"; + print "echo ", cfr[jn], cpusr[jn] ovf ": Starting build. `date` >> " rd "/log"; + print "rm -f " builddir ".*"; + print "touch " builddir ".wait"; + print "mkdir " builddir " > /dev/null 2>&1 || :"; + print "mkdir " rd cfr[jn] " || :"; + print "kvm-test-1-run.sh " CONFIGDIR cf[j], builddir, rd cfr[jn], dur " \"" TORTURE_QEMU_ARG "\" \"" TORTURE_BOOTARGS "\" > " rd cfr[jn] "/kvm-test-1-run.sh.out 2>&1 &" + print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date`"; + print "echo ", cfr[jn], cpusr[jn] ovf ": Waiting for build to complete. `date` >> " rd "/log"; + print "while test -f " builddir ".wait" + print "do" + print "\tsleep 1" + print "done" + print "echo ", cfr[jn], cpusr[jn] ovf ": Build complete. `date`"; + print "echo ", cfr[jn], cpusr[jn] ovf ": Build complete. `date` >> " rd "/log"; + jn++; + } + for (j = 1; j < jn; j++) { + builddir=KVM "/b" j + print "rm -f " builddir ".ready" + print "if test -z \"$TORTURE_BUILDONLY\"" + print "then" + print "\techo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date`"; + print "\techo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date` >> " rd "/log"; + print "fi" + } + print "wait" + print "if test -z \"$TORTURE_BUILDONLY\"" + print "then" + print "\techo ---- All kernel runs complete. `date`"; + print "\techo ---- All kernel runs complete. `date` >> " rd "/log"; + print "fi" + for (j = 1; j < jn; j++) { + builddir=KVM "/b" j + print "echo ----", cfr[j], cpusr[j] ovf ": Build/run results:"; + print "echo ----", cfr[j], cpusr[j] ovf ": Build/run results: >> " rd "/log"; + print "cat " rd cfr[j] "/kvm-test-1-run.sh.out"; + print "cat " rd cfr[j] "/kvm-test-1-run.sh.out >> " rd "/log"; + } +} + +END { + njobs = i; + nc = ncpus; + first = 0; + + # Each pass through the following loop considers one test. + for (i = 0; i < njobs; i++) { + if (ncpus == 0) { + # Sequential test specified, each test its own batch. + dump(i, i + 1); + first = i; + } else if (nc < cpus[i] && i != 0) { + # Out of CPUs, dump out a batch. + dump(first, i); + first = i; + nc = ncpus; + } + # Account for the CPUs needed by the current test. + nc -= cpus[i]; + } + # Dump the last batch. + if (ncpus != 0) + dump(first, i); +}' >> $T/script + +cat << ___EOF___ >> $T/script +echo +echo +echo " --- `date` Test summary:" +echo Results directory: $resdir/$ds +kvm-recheck.sh $resdir/$ds +___EOF___ + +if test "$dryrun" = script +then + cat $T/script + exit 0 +elif test "$dryrun" = sched +then + # Extract the test run schedule from the script. + egrep 'Start batch|Starting build\.' $T/script | + grep -v ">>" | + sed -e 's/:.*$//' -e 's/^echo //' + exit 0 +else + # Not a dryrun, so run the script. + sh $T/script +fi + +# Tracing: trace_event=rcu:rcu_grace_period,rcu:rcu_future_grace_period,rcu:rcu_grace_period_init,rcu:rcu_nocb_wake,rcu:rcu_preempt_task,rcu:rcu_unlock_preempted_task,rcu:rcu_quiescent_state_report,rcu:rcu_fqs,rcu:rcu_callback,rcu:rcu_kfree_callback,rcu:rcu_batch_start,rcu:rcu_invoke_callback,rcu:rcu_invoke_kfree_callback,rcu:rcu_batch_end,rcu:rcu_torture_read,rcu:rcu_barrier diff --git a/rcutorture/bin/parse-build.sh b/rcutorture/bin/parse-build.sh new file mode 100755 index 0000000..5432309 --- /dev/null +++ b/rcutorture/bin/parse-build.sh @@ -0,0 +1,57 @@ +#!/bin/sh +# +# Check the build output from an rcutorture run for goodness. +# The "file" is a pathname on the local system, and "title" is +# a text string for error-message purposes. +# +# The file must contain kernel build output. +# +# Usage: +# sh parse-build.sh file title +# +# 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, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2011 +# +# Authors: Paul E. McKenney + +T=$1 +title=$2 + +. functions.sh + +if grep -q CC < $T +then + : +else + print_bug $title no build + exit 1 +fi + +if grep -q "error:" < $T +then + print_bug $title build errors: + grep "error:" < $T + exit 2 +fi +exit 0 + +if egrep -q "rcu[^/]*\.c.*warning:|rcu.*\.h.*warning:" < $T +then + print_warning $title build errors: + egrep "rcu[^/]*\.c.*warning:|rcu.*\.h.*warning:" < $T + exit 2 +fi +exit 0 diff --git a/rcutorture/bin/parse-console.sh b/rcutorture/bin/parse-console.sh new file mode 100755 index 0000000..4185d4c --- /dev/null +++ b/rcutorture/bin/parse-console.sh @@ -0,0 +1,41 @@ +#!/bin/sh +# +# Check the console output from an rcutorture run for oopses. +# The "file" is a pathname on the local system, and "title" is +# a text string for error-message purposes. +# +# Usage: +# sh parse-console.sh file title +# +# 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, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2011 +# +# Authors: Paul E. McKenney + +T=/tmp/abat-chk-badness.sh.$$ +trap 'rm -f $T' 0 + +file="$1" +title="$2" + +. functions.sh + +egrep 'Badness|WARNING:|Warn|BUG|===========|Call Trace:|Oops:' < $file | grep -v 'ODEBUG: ' | grep -v 'Warning: unable to open an initial console' > $T +if test -s $T +then + print_warning Assertion failure in $file $title + cat $T +fi diff --git a/rcutorture/bin/parse-torture.sh b/rcutorture/bin/parse-torture.sh new file mode 100755 index 0000000..3455560 --- /dev/null +++ b/rcutorture/bin/parse-torture.sh @@ -0,0 +1,106 @@ +#!/bin/sh +# +# Check the console output from a torture run for goodness. +# The "file" is a pathname on the local system, and "title" is +# a text string for error-message purposes. +# +# The file must contain torture output, but can be interspersed +# with other dmesg text, as in console-log output. +# +# Usage: +# sh parse-torture.sh file title +# +# 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, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2011 +# +# Authors: Paul E. McKenney + +T=/tmp/parse-torture.sh.$$ +file="$1" +title="$2" + +trap 'rm -f $T.seq' 0 + +. functions.sh + +# check for presence of torture output file. + +if test -f "$file" -a -r "$file" +then + : +else + echo $title unreadable torture output file: $file + exit 1 +fi + +# check for abject failure + +if grep -q FAILURE $file || grep -q -e '-torture.*!!!' $file +then + nerrs=`grep --binary-files=text '!!!' $file | tail -1 | awk '{for (i=NF-8;i<=NF;i++) sum+=$i; } END {print sum}'` + print_bug $title FAILURE, $nerrs instances + echo " " $url + exit +fi + +grep --binary-files=text 'torture:.*ver:' $file | grep --binary-files=text -v '(null)' | sed -e 's/^(initramfs)[^]]*] //' -e 's/^\[[^]]*] //' | +awk ' +BEGIN { + ver = 0; + badseq = 0; + } + + { + if (!badseq && ($5 + 0 != $5 || $5 <= ver)) { + badseqno1 = ver; + badseqno2 = $5; + badseqnr = NR; + badseq = 1; + } + ver = $5 + } + +END { + if (badseq) { + if (badseqno1 == badseqno2 && badseqno2 == ver) + print "GP HANG at " ver " torture stat " badseqnr; + else + print "BAD SEQ " badseqno1 ":" badseqno2 " last:" ver " version " badseqnr; + } + }' > $T.seq + +if grep -q SUCCESS $file +then + if test -s $T.seq + then + print_warning $title $title `cat $T.seq` + echo " " $file + exit 2 + fi +else + if grep -q "_HOTPLUG:" $file + then + print_warning HOTPLUG FAILURES $title `cat $T.seq` + echo " " $file + exit 3 + fi + echo $title no success message, `grep --binary-files=text 'ver:' $file | wc -l` successful version messages + if test -s $T.seq + then + print_warning $title `cat $T.seq` + fi + exit 2 +fi diff --git a/rcutorture/configs/lock/BUSTED b/rcutorture/configs/lock/BUSTED new file mode 100644 index 0000000..1d1da14 --- /dev/null +++ b/rcutorture/configs/lock/BUSTED @@ -0,0 +1,6 @@ +CONFIG_SMP=y +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y diff --git a/rcutorture/configs/lock/BUSTED.boot b/rcutorture/configs/lock/BUSTED.boot new file mode 100644 index 0000000..6386c15 --- /dev/null +++ b/rcutorture/configs/lock/BUSTED.boot @@ -0,0 +1 @@ +locktorture.torture_type=lock_busted diff --git a/rcutorture/configs/lock/CFLIST b/rcutorture/configs/lock/CFLIST new file mode 100644 index 0000000..a061b22 --- /dev/null +++ b/rcutorture/configs/lock/CFLIST @@ -0,0 +1 @@ +LOCK01 diff --git a/rcutorture/configs/lock/CFcommon b/rcutorture/configs/lock/CFcommon new file mode 100644 index 0000000..e372dc2 --- /dev/null +++ b/rcutorture/configs/lock/CFcommon @@ -0,0 +1,2 @@ +CONFIG_LOCK_TORTURE_TEST=y +CONFIG_PRINTK_TIME=y diff --git a/rcutorture/configs/lock/LOCK01 b/rcutorture/configs/lock/LOCK01 new file mode 100644 index 0000000..a9625e3 --- /dev/null +++ b/rcutorture/configs/lock/LOCK01 @@ -0,0 +1,6 @@ +CONFIG_SMP=y +CONFIG_NR_CPUS=8 +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y diff --git a/rcutorture/configs/lock/ver_functions.sh b/rcutorture/configs/lock/ver_functions.sh new file mode 100644 index 0000000..9746ea1 --- /dev/null +++ b/rcutorture/configs/lock/ver_functions.sh @@ -0,0 +1,43 @@ +#!/bin/bash +# +# Kernel-version-dependent shell functions for the rest of the scripts. +# +# 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, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2014 +# +# Authors: Paul E. McKenney + +# locktorture_param_onoff bootparam-string config-file +# +# Adds onoff locktorture module parameters to kernels having it. +locktorture_param_onoff () { + if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2" + then + echo CPU-hotplug kernel, adding locktorture onoff. 1>&2 + echo locktorture.onoff_interval=3 locktorture.onoff_holdoff=30 + fi +} + +# per_version_boot_params bootparam-string config-file seconds +# +# Adds per-version torture-module parameters to kernels supporting them. +per_version_boot_params () { + echo $1 `locktorture_param_onoff "$1" "$2"` \ + locktorture.stat_interval=15 \ + locktorture.shutdown_secs=$3 \ + locktorture.locktorture_runnable=1 \ + locktorture.verbose=1 +} diff --git a/rcutorture/configs/rcu/BUSTED b/rcutorture/configs/rcu/BUSTED new file mode 100644 index 0000000..48d8a24 --- /dev/null +++ b/rcutorture/configs/rcu/BUSTED @@ -0,0 +1,7 @@ +CONFIG_RCU_TRACE=n +CONFIG_SMP=y +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y diff --git a/rcutorture/configs/rcu/BUSTED.boot b/rcutorture/configs/rcu/BUSTED.boot new file mode 100644 index 0000000..6804f9d --- /dev/null +++ b/rcutorture/configs/rcu/BUSTED.boot @@ -0,0 +1 @@ +rcutorture.torture_type=rcu_busted diff --git a/rcutorture/configs/rcu/CFLIST b/rcutorture/configs/rcu/CFLIST new file mode 100644 index 0000000..cd3d29c --- /dev/null +++ b/rcutorture/configs/rcu/CFLIST @@ -0,0 +1,13 @@ +TREE01 +TREE02 +TREE03 +TREE04 +TREE05 +TREE06 +TREE07 +TREE08 +TREE09 +SRCU-N +SRCU-P +TINY01 +TINY02 diff --git a/rcutorture/configs/rcu/CFcommon b/rcutorture/configs/rcu/CFcommon new file mode 100644 index 0000000..d2d2a86 --- /dev/null +++ b/rcutorture/configs/rcu/CFcommon @@ -0,0 +1,2 @@ +CONFIG_RCU_TORTURE_TEST=y +CONFIG_PRINTK_TIME=y diff --git a/rcutorture/configs/rcu/SRCU-N b/rcutorture/configs/rcu/SRCU-N new file mode 100644 index 0000000..9fbb41b --- /dev/null +++ b/rcutorture/configs/rcu/SRCU-N @@ -0,0 +1,7 @@ +CONFIG_RCU_TRACE=n +CONFIG_SMP=y +CONFIG_NR_CPUS=4 +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n diff --git a/rcutorture/configs/rcu/SRCU-N.boot b/rcutorture/configs/rcu/SRCU-N.boot new file mode 100644 index 0000000..238bfe3 --- /dev/null +++ b/rcutorture/configs/rcu/SRCU-N.boot @@ -0,0 +1 @@ +rcutorture.torture_type=srcu diff --git a/rcutorture/configs/rcu/SRCU-P b/rcutorture/configs/rcu/SRCU-P new file mode 100644 index 0000000..4b6f272 --- /dev/null +++ b/rcutorture/configs/rcu/SRCU-P @@ -0,0 +1,7 @@ +CONFIG_RCU_TRACE=n +CONFIG_SMP=y +CONFIG_NR_CPUS=8 +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y diff --git a/rcutorture/configs/rcu/SRCU-P.boot b/rcutorture/configs/rcu/SRCU-P.boot new file mode 100644 index 0000000..238bfe3 --- /dev/null +++ b/rcutorture/configs/rcu/SRCU-P.boot @@ -0,0 +1 @@ +rcutorture.torture_type=srcu diff --git a/rcutorture/configs/rcu/TINY01 b/rcutorture/configs/rcu/TINY01 new file mode 100644 index 0000000..0a63e07 --- /dev/null +++ b/rcutorture/configs/rcu/TINY01 @@ -0,0 +1,12 @@ +CONFIG_SMP=n +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TINY_RCU=y +CONFIG_HZ_PERIODIC=n +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ_FULL=n +CONFIG_RCU_TRACE=n +CONFIG_DEBUG_LOCK_ALLOC=n +CONFIG_DEBUG_OBJECTS_RCU_HEAD=n +CONFIG_PREEMPT_COUNT=n diff --git a/rcutorture/configs/rcu/TINY02 b/rcutorture/configs/rcu/TINY02 new file mode 100644 index 0000000..f4feaee --- /dev/null +++ b/rcutorture/configs/rcu/TINY02 @@ -0,0 +1,12 @@ +CONFIG_SMP=n +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TINY_RCU=y +CONFIG_HZ_PERIODIC=y +CONFIG_NO_HZ_IDLE=n +CONFIG_NO_HZ_FULL=n +CONFIG_RCU_TRACE=y +CONFIG_DEBUG_LOCK_ALLOC=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=n +CONFIG_PREEMPT_COUNT=y diff --git a/rcutorture/configs/rcu/TREE01 b/rcutorture/configs/rcu/TREE01 new file mode 100644 index 0000000..063b707 --- /dev/null +++ b/rcutorture/configs/rcu/TREE01 @@ -0,0 +1,21 @@ +CONFIG_SMP=y +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_HZ_PERIODIC=n +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ_FULL=n +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_TRACE=y +CONFIG_HOTPLUG_CPU=y +CONFIG_RCU_FANOUT=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_ZERO=y +CONFIG_DEBUG_LOCK_ALLOC=n +CONFIG_RCU_CPU_STALL_INFO=n +CONFIG_RCU_CPU_STALL_VERBOSE=n +CONFIG_RCU_BOOST=n +CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/rcutorture/configs/rcu/TREE01.boot b/rcutorture/configs/rcu/TREE01.boot new file mode 100644 index 0000000..0fc8a34 --- /dev/null +++ b/rcutorture/configs/rcu/TREE01.boot @@ -0,0 +1 @@ +rcutorture.torture_type=rcu_bh diff --git a/rcutorture/configs/rcu/TREE02 b/rcutorture/configs/rcu/TREE02 new file mode 100644 index 0000000..ea119ba --- /dev/null +++ b/rcutorture/configs/rcu/TREE02 @@ -0,0 +1,24 @@ +CONFIG_SMP=y +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_HZ_PERIODIC=n +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ_FULL=n +CONFIG_RCU_FAST_NO_HZ=n +CONFIG_RCU_TRACE=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_RCU_FANOUT=3 +CONFIG_RCU_FANOUT_LEAF=3 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_RCU_NOCB_CPU=n +CONFIG_DEBUG_LOCK_ALLOC=y +CONFIG_PROVE_LOCKING=n +CONFIG_RCU_CPU_STALL_INFO=n +CONFIG_RCU_CPU_STALL_VERBOSE=y +CONFIG_RCU_BOOST=n +CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/rcutorture/configs/rcu/TREE02-T b/rcutorture/configs/rcu/TREE02-T new file mode 100644 index 0000000..19cf948 --- /dev/null +++ b/rcutorture/configs/rcu/TREE02-T @@ -0,0 +1,24 @@ +CONFIG_SMP=y +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_HZ_PERIODIC=n +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ_FULL=n +CONFIG_RCU_FAST_NO_HZ=n +CONFIG_RCU_TRACE=y +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_RCU_FANOUT=3 +CONFIG_RCU_FANOUT_LEAF=3 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_RCU_NOCB_CPU=n +CONFIG_DEBUG_LOCK_ALLOC=y +CONFIG_PROVE_LOCKING=n +CONFIG_RCU_CPU_STALL_INFO=n +CONFIG_RCU_CPU_STALL_VERBOSE=y +CONFIG_RCU_BOOST=n +CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/rcutorture/configs/rcu/TREE03 b/rcutorture/configs/rcu/TREE03 new file mode 100644 index 0000000..f4567fb --- /dev/null +++ b/rcutorture/configs/rcu/TREE03 @@ -0,0 +1,21 @@ +CONFIG_SMP=y +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_HZ_PERIODIC=y +CONFIG_NO_HZ_IDLE=n +CONFIG_NO_HZ_FULL=n +CONFIG_RCU_TRACE=y +CONFIG_HOTPLUG_CPU=y +CONFIG_RCU_FANOUT=4 +CONFIG_RCU_FANOUT_LEAF=4 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_RCU_NOCB_CPU=n +CONFIG_DEBUG_LOCK_ALLOC=n +CONFIG_RCU_CPU_STALL_INFO=n +CONFIG_RCU_CPU_STALL_VERBOSE=n +CONFIG_RCU_BOOST=y +CONFIG_RCU_BOOST_PRIO=2 +CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/rcutorture/configs/rcu/TREE04 b/rcutorture/configs/rcu/TREE04 new file mode 100644 index 0000000..0a262fb --- /dev/null +++ b/rcutorture/configs/rcu/TREE04 @@ -0,0 +1,23 @@ +CONFIG_SMP=y +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_HZ_PERIODIC=n +CONFIG_NO_HZ_IDLE=n +CONFIG_NO_HZ_FULL=y +CONFIG_NO_HZ_FULL_ALL=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_TRACE=y +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_RCU_FANOUT=2 +CONFIG_RCU_FANOUT_LEAF=2 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_RCU_NOCB_CPU=n +CONFIG_DEBUG_LOCK_ALLOC=n +CONFIG_RCU_CPU_STALL_INFO=y +CONFIG_RCU_CPU_STALL_VERBOSE=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/rcutorture/configs/rcu/TREE04.boot b/rcutorture/configs/rcu/TREE04.boot new file mode 100644 index 0000000..0fc8a34 --- /dev/null +++ b/rcutorture/configs/rcu/TREE04.boot @@ -0,0 +1 @@ +rcutorture.torture_type=rcu_bh diff --git a/rcutorture/configs/rcu/TREE05 b/rcutorture/configs/rcu/TREE05 new file mode 100644 index 0000000..3a06b97 --- /dev/null +++ b/rcutorture/configs/rcu/TREE05 @@ -0,0 +1,23 @@ +CONFIG_SMP=y +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_HZ_PERIODIC=n +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ_FULL=n +CONFIG_RCU_FAST_NO_HZ=n +CONFIG_RCU_TRACE=n +CONFIG_HOTPLUG_CPU=y +CONFIG_RCU_FANOUT=6 +CONFIG_RCU_FANOUT_LEAF=6 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_NONE=y +CONFIG_DEBUG_LOCK_ALLOC=y +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_RCU_CPU_STALL_INFO=n +CONFIG_RCU_CPU_STALL_VERBOSE=n +CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/rcutorture/configs/rcu/TREE05.boot b/rcutorture/configs/rcu/TREE05.boot new file mode 100644 index 0000000..3b42b8b --- /dev/null +++ b/rcutorture/configs/rcu/TREE05.boot @@ -0,0 +1 @@ +rcutorture.torture_type=sched diff --git a/rcutorture/configs/rcu/TREE06 b/rcutorture/configs/rcu/TREE06 new file mode 100644 index 0000000..8f084cc --- /dev/null +++ b/rcutorture/configs/rcu/TREE06 @@ -0,0 +1,24 @@ +CONFIG_SMP=y +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_HZ_PERIODIC=n +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ_FULL=n +CONFIG_RCU_FAST_NO_HZ=n +CONFIG_RCU_TRACE=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_RCU_FANOUT=6 +CONFIG_RCU_FANOUT_LEAF=6 +CONFIG_RCU_FANOUT_EXACT=y +CONFIG_RCU_NOCB_CPU=n +CONFIG_DEBUG_LOCK_ALLOC=y +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_RCU_CPU_STALL_INFO=n +CONFIG_RCU_CPU_STALL_VERBOSE=n +CONFIG_DEBUG_OBJECTS_RCU_HEAD=y diff --git a/rcutorture/configs/rcu/TREE07 b/rcutorture/configs/rcu/TREE07 new file mode 100644 index 0000000..ab62255 --- /dev/null +++ b/rcutorture/configs/rcu/TREE07 @@ -0,0 +1,22 @@ +CONFIG_SMP=y +CONFIG_NR_CPUS=16 +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_HZ_PERIODIC=n +CONFIG_NO_HZ_IDLE=n +CONFIG_NO_HZ_FULL=y +CONFIG_NO_HZ_FULL_ALL=y +CONFIG_NO_HZ_FULL_SYSIDLE=y +CONFIG_RCU_FAST_NO_HZ=n +CONFIG_RCU_TRACE=y +CONFIG_HOTPLUG_CPU=y +CONFIG_RCU_FANOUT=2 +CONFIG_RCU_FANOUT_LEAF=2 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_RCU_NOCB_CPU=n +CONFIG_DEBUG_LOCK_ALLOC=n +CONFIG_RCU_CPU_STALL_INFO=y +CONFIG_RCU_CPU_STALL_VERBOSE=n +CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/rcutorture/configs/rcu/TREE08 b/rcutorture/configs/rcu/TREE08 new file mode 100644 index 0000000..69a2e25 --- /dev/null +++ b/rcutorture/configs/rcu/TREE08 @@ -0,0 +1,24 @@ +CONFIG_SMP=y +CONFIG_NR_CPUS=16 +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_HZ_PERIODIC=n +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ_FULL=n +CONFIG_RCU_FAST_NO_HZ=n +CONFIG_RCU_TRACE=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_RCU_FANOUT=3 +CONFIG_RCU_FANOUT_EXACT=y +CONFIG_RCU_FANOUT_LEAF=2 +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_ALL=y +CONFIG_DEBUG_LOCK_ALLOC=n +CONFIG_RCU_CPU_STALL_INFO=n +CONFIG_RCU_CPU_STALL_VERBOSE=n +CONFIG_RCU_BOOST=n +CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/rcutorture/configs/rcu/TREE08-T b/rcutorture/configs/rcu/TREE08-T new file mode 100644 index 0000000..a0f32fb --- /dev/null +++ b/rcutorture/configs/rcu/TREE08-T @@ -0,0 +1,24 @@ +CONFIG_SMP=y +CONFIG_NR_CPUS=16 +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_HZ_PERIODIC=n +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ_FULL=n +CONFIG_RCU_FAST_NO_HZ=n +CONFIG_RCU_TRACE=y +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_RCU_FANOUT=3 +CONFIG_RCU_FANOUT_EXACT=y +CONFIG_RCU_FANOUT_LEAF=2 +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_ALL=y +CONFIG_DEBUG_LOCK_ALLOC=n +CONFIG_RCU_CPU_STALL_INFO=n +CONFIG_RCU_CPU_STALL_VERBOSE=n +CONFIG_RCU_BOOST=n +CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/rcutorture/configs/rcu/TREE08.boot b/rcutorture/configs/rcu/TREE08.boot new file mode 100644 index 0000000..3b42b8b --- /dev/null +++ b/rcutorture/configs/rcu/TREE08.boot @@ -0,0 +1 @@ +rcutorture.torture_type=sched diff --git a/rcutorture/configs/rcu/TREE09 b/rcutorture/configs/rcu/TREE09 new file mode 100644 index 0000000..b7a62a5 --- /dev/null +++ b/rcutorture/configs/rcu/TREE09 @@ -0,0 +1,19 @@ +CONFIG_SMP=n +CONFIG_NR_CPUS=1 +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_HZ_PERIODIC=n +CONFIG_NO_HZ_IDLE=y +CONFIG_NO_HZ_FULL=n +CONFIG_RCU_TRACE=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_RCU_NOCB_CPU=n +CONFIG_DEBUG_LOCK_ALLOC=n +CONFIG_RCU_CPU_STALL_INFO=n +CONFIG_RCU_CPU_STALL_VERBOSE=n +CONFIG_RCU_BOOST=n +CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/rcutorture/configs/rcu/v0.0/CFLIST b/rcutorture/configs/rcu/v0.0/CFLIST new file mode 100644 index 0000000..1822394 --- /dev/null +++ b/rcutorture/configs/rcu/v0.0/CFLIST @@ -0,0 +1,14 @@ +P1-S-T-NH-SD-SMP-HP +P2-2-t-nh-sd-SMP-hp +P3-3-T-nh-SD-SMP-hp +P4-A-t-NH-sd-SMP-HP +P5-U-T-NH-sd-SMP-hp +N1-S-T-NH-SD-SMP-HP +N2-2-t-nh-sd-SMP-hp +N3-3-T-nh-SD-SMP-hp +N4-A-t-NH-sd-SMP-HP +N5-U-T-NH-sd-SMP-hp +PT1-nh +PT2-NH +NT1-nh +NT3-NH diff --git a/rcutorture/configs/rcu/v0.0/N1-S-T-NH-SD-SMP-HP b/rcutorture/configs/rcu/v0.0/N1-S-T-NH-SD-SMP-HP new file mode 100644 index 0000000..d3ef873 --- /dev/null +++ b/rcutorture/configs/rcu/v0.0/N1-S-T-NH-SD-SMP-HP @@ -0,0 +1,18 @@ +CONFIG_RCU_TRACE=y +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=8 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v0.0/N2-2-t-nh-sd-SMP-hp b/rcutorture/configs/rcu/v0.0/N2-2-t-nh-sd-SMP-hp new file mode 100644 index 0000000..02e4185 --- /dev/null +++ b/rcutorture/configs/rcu/v0.0/N2-2-t-nh-sd-SMP-hp @@ -0,0 +1,20 @@ +CONFIG_RCU_TRACE=n +CONFIG_NO_HZ=n +CONFIG_SMP=y +CONFIG_RCU_FANOUT=4 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v0.0/N3-3-T-nh-SD-SMP-hp b/rcutorture/configs/rcu/v0.0/N3-3-T-nh-SD-SMP-hp new file mode 100644 index 0000000..b3100f6 --- /dev/null +++ b/rcutorture/configs/rcu/v0.0/N3-3-T-nh-SD-SMP-hp @@ -0,0 +1,22 @@ +CONFIG_RCU_TRACE=y +CONFIG_NO_HZ=n +CONFIG_SMP=y +CONFIG_RCU_FANOUT=2 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v0.0/N4-A-t-NH-sd-SMP-HP b/rcutorture/configs/rcu/v0.0/N4-A-t-NH-sd-SMP-HP new file mode 100644 index 0000000..c56b445 --- /dev/null +++ b/rcutorture/configs/rcu/v0.0/N4-A-t-NH-sd-SMP-HP @@ -0,0 +1,18 @@ +CONFIG_RCU_TRACE=n +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=6 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v0.0/N5-U-T-NH-sd-SMP-hp b/rcutorture/configs/rcu/v0.0/N5-U-T-NH-sd-SMP-hp new file mode 100644 index 0000000..90d924f --- /dev/null +++ b/rcutorture/configs/rcu/v0.0/N5-U-T-NH-sd-SMP-hp @@ -0,0 +1,22 @@ +CONFIG_RCU_TRACE=y +CONFIG_DEBUG_KERNEL=y +CONFIG_RCU_CPU_STALL_INFO=y +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=6 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=y +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v0.0/NT1-nh b/rcutorture/configs/rcu/v0.0/NT1-nh new file mode 100644 index 0000000..023f312 --- /dev/null +++ b/rcutorture/configs/rcu/v0.0/NT1-nh @@ -0,0 +1,23 @@ +#CHECK#CONFIG_TINY_RCU=y +CONFIG_RCU_TRACE=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +# +CONFIG_SMP=n +# +CONFIG_HOTPLUG_CPU=n +# +CONFIG_NO_HZ=n +# +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v0.0/NT3-NH b/rcutorture/configs/rcu/v0.0/NT3-NH new file mode 100644 index 0000000..6fd0235 --- /dev/null +++ b/rcutorture/configs/rcu/v0.0/NT3-NH @@ -0,0 +1,20 @@ +#CHECK#CONFIG_TINY_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +# +CONFIG_SMP=n +# +CONFIG_HOTPLUG_CPU=n +# +CONFIG_NO_HZ=y +# +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP b/rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP new file mode 100644 index 0000000..f72402d --- /dev/null +++ b/rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP @@ -0,0 +1,19 @@ +CONFIG_RCU_TRACE=y +CONFIG_RCU_CPU_STALL_INFO=y +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=8 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp b/rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp new file mode 100644 index 0000000..0f3b667 --- /dev/null +++ b/rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp @@ -0,0 +1,20 @@ +CONFIG_RCU_TRACE=n +CONFIG_NO_HZ=n +CONFIG_SMP=y +CONFIG_RCU_FANOUT=4 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp b/rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp new file mode 100644 index 0000000..b035e14 --- /dev/null +++ b/rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp @@ -0,0 +1,20 @@ +CONFIG_RCU_TRACE=y +CONFIG_NO_HZ=n +CONFIG_SMP=y +CONFIG_RCU_FANOUT=2 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP b/rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP new file mode 100644 index 0000000..3ccf6a9 --- /dev/null +++ b/rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP @@ -0,0 +1,22 @@ +CONFIG_RCU_TRACE=n +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=6 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_RT_MUTEXES=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_BOOST_PRIO=2 +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp b/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp new file mode 100644 index 0000000..a55c008 --- /dev/null +++ b/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp @@ -0,0 +1,27 @@ +CONFIG_RCU_TRACE=y +CONFIG_RCU_CPU_STALL_INFO=y +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=6 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=y +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=y +CONFIG_RT_MUTEXES=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_BOOST_PRIO=2 +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v0.0/PT1-nh b/rcutorture/configs/rcu/v0.0/PT1-nh new file mode 100644 index 0000000..e3361c3 --- /dev/null +++ b/rcutorture/configs/rcu/v0.0/PT1-nh @@ -0,0 +1,23 @@ +CONFIG_TINY_PREEMPT_RCU=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_BOOST_PRIO=2 +CONFIG_RCU_TRACE=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +# +CONFIG_SMP=n +# +CONFIG_HOTPLUG_CPU=n +# +CONFIG_NO_HZ=n +# +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v0.0/PT2-NH b/rcutorture/configs/rcu/v0.0/PT2-NH new file mode 100644 index 0000000..64abfc3 --- /dev/null +++ b/rcutorture/configs/rcu/v0.0/PT2-NH @@ -0,0 +1,22 @@ +CONFIG_TINY_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +# +CONFIG_SMP=n +# +CONFIG_HOTPLUG_CPU=n +# +CONFIG_NO_HZ=y +# +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v0.0/ver_functions.sh b/rcutorture/configs/rcu/v0.0/ver_functions.sh new file mode 100644 index 0000000..5ace37a --- /dev/null +++ b/rcutorture/configs/rcu/v0.0/ver_functions.sh @@ -0,0 +1,33 @@ +#!/bin/bash +# +# Kernel-version-dependent shell functions for the rest of the scripts. +# +# 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, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2013 +# +# Authors: Paul E. McKenney + +# per_version_boot_params bootparam-string config-file seconds +# +# Adds per-version torture-module parameters to kernels supporting them. +# Which old kernels do not. +per_version_boot_params () { + echo rcutorture.stat_interval=15 \ + rcutorture.shutdown_secs=$3 \ + rcutorture.rcutorture_runnable=1 \ + rcutorture.test_no_idle_hz=1 \ + rcutorture.verbose=1 +} diff --git a/rcutorture/configs/rcu/v3.12/CFLIST b/rcutorture/configs/rcu/v3.12/CFLIST new file mode 100644 index 0000000..da4cbc6 --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/CFLIST @@ -0,0 +1,17 @@ +sysidleY.2013.06.19a +sysidleN.2013.06.19a +P1-S-T-NH-SD-SMP-HP +P2-2-t-nh-sd-SMP-hp +P3-3-T-nh-SD-SMP-hp +P4-A-t-NH-sd-SMP-HP +P5-U-T-NH-sd-SMP-hp +P6---t-nh-SD-smp-hp +N1-S-T-NH-SD-SMP-HP +N2-2-t-nh-sd-SMP-hp +N3-3-T-nh-SD-SMP-hp +N4-A-t-NH-sd-SMP-HP +N5-U-T-NH-sd-SMP-hp +PT1-nh +PT2-NH +NT1-nh +NT3-NH diff --git a/rcutorture/configs/rcu/v3.12/N1-S-T-NH-SD-SMP-HP b/rcutorture/configs/rcu/v3.12/N1-S-T-NH-SD-SMP-HP new file mode 100644 index 0000000..d81e11d --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/N1-S-T-NH-SD-SMP-HP @@ -0,0 +1,19 @@ +CONFIG_RCU_TRACE=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=8 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/N2-2-t-nh-sd-SMP-hp b/rcutorture/configs/rcu/v3.12/N2-2-t-nh-sd-SMP-hp new file mode 100644 index 0000000..02e4185 --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/N2-2-t-nh-sd-SMP-hp @@ -0,0 +1,20 @@ +CONFIG_RCU_TRACE=n +CONFIG_NO_HZ=n +CONFIG_SMP=y +CONFIG_RCU_FANOUT=4 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/N3-3-T-nh-SD-SMP-hp b/rcutorture/configs/rcu/v3.12/N3-3-T-nh-SD-SMP-hp new file mode 100644 index 0000000..b3100f6 --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/N3-3-T-nh-SD-SMP-hp @@ -0,0 +1,22 @@ +CONFIG_RCU_TRACE=y +CONFIG_NO_HZ=n +CONFIG_SMP=y +CONFIG_RCU_FANOUT=2 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/N4-A-t-NH-sd-SMP-HP b/rcutorture/configs/rcu/v3.12/N4-A-t-NH-sd-SMP-HP new file mode 100644 index 0000000..c56b445 --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/N4-A-t-NH-sd-SMP-HP @@ -0,0 +1,18 @@ +CONFIG_RCU_TRACE=n +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=6 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/N5-U-T-NH-sd-SMP-hp b/rcutorture/configs/rcu/v3.12/N5-U-T-NH-sd-SMP-hp new file mode 100644 index 0000000..90d924f --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/N5-U-T-NH-sd-SMP-hp @@ -0,0 +1,22 @@ +CONFIG_RCU_TRACE=y +CONFIG_DEBUG_KERNEL=y +CONFIG_RCU_CPU_STALL_INFO=y +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=6 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=y +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/N6---t-nh-SD-smp-hp b/rcutorture/configs/rcu/v3.12/N6---t-nh-SD-smp-hp new file mode 100644 index 0000000..0ccc36d --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/N6---t-nh-SD-smp-hp @@ -0,0 +1,19 @@ +CONFIG_RCU_TRACE=n +CONFIG_NO_HZ=n +CONFIG_SMP=y +CONFIG_NR_CPUS=1 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/N7-4-T-NH-SD-SMP-HP b/rcutorture/configs/rcu/v3.12/N7-4-T-NH-SD-SMP-HP new file mode 100644 index 0000000..3f640cf --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/N7-4-T-NH-SD-SMP-HP @@ -0,0 +1,26 @@ +CONFIG_RCU_TRACE=y +CONFIG_DEBUG_KERNEL=y +CONFIG_RCU_CPU_STALL_INFO=y +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=2 +CONFIG_NR_CPUS=16 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_NONE=y +CONFIG_RCU_NOCB_CPU_ZERO=n +CONFIG_RCU_NOCB_CPU_ALL=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/N8-2-T-NH-SD-SMP-HP b/rcutorture/configs/rcu/v3.12/N8-2-T-NH-SD-SMP-HP new file mode 100644 index 0000000..285da2d --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/N8-2-T-NH-SD-SMP-HP @@ -0,0 +1,22 @@ +CONFIG_RCU_TRACE=y +CONFIG_DEBUG_KERNEL=y +CONFIG_RCU_CPU_STALL_INFO=y +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=14 +CONFIG_NR_CPUS=16 +CONFIG_RCU_FANOUT_EXACT=y +CONFIG_HOTPLUG_CPU=y +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/NT1-nh b/rcutorture/configs/rcu/v3.12/NT1-nh new file mode 100644 index 0000000..023f312 --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/NT1-nh @@ -0,0 +1,23 @@ +#CHECK#CONFIG_TINY_RCU=y +CONFIG_RCU_TRACE=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +# +CONFIG_SMP=n +# +CONFIG_HOTPLUG_CPU=n +# +CONFIG_NO_HZ=n +# +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/NT3-NH b/rcutorture/configs/rcu/v3.12/NT3-NH new file mode 100644 index 0000000..6fd0235 --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/NT3-NH @@ -0,0 +1,20 @@ +#CHECK#CONFIG_TINY_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +# +CONFIG_SMP=n +# +CONFIG_HOTPLUG_CPU=n +# +CONFIG_NO_HZ=y +# +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP b/rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP new file mode 100644 index 0000000..9647c44 --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP @@ -0,0 +1,20 @@ +CONFIG_RCU_TRACE=y +CONFIG_RCU_CPU_STALL_INFO=y +CONFIG_NO_HZ=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=8 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp b/rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp new file mode 100644 index 0000000..0f3b667 --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp @@ -0,0 +1,20 @@ +CONFIG_RCU_TRACE=n +CONFIG_NO_HZ=n +CONFIG_SMP=y +CONFIG_RCU_FANOUT=4 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp b/rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp new file mode 100644 index 0000000..b035e14 --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp @@ -0,0 +1,20 @@ +CONFIG_RCU_TRACE=y +CONFIG_NO_HZ=n +CONFIG_SMP=y +CONFIG_RCU_FANOUT=2 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP b/rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP new file mode 100644 index 0000000..3ccf6a9 --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP @@ -0,0 +1,22 @@ +CONFIG_RCU_TRACE=n +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=6 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_RT_MUTEXES=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_BOOST_PRIO=2 +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp b/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp new file mode 100644 index 0000000..a55c008 --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp @@ -0,0 +1,27 @@ +CONFIG_RCU_TRACE=y +CONFIG_RCU_CPU_STALL_INFO=y +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=6 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=y +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=y +CONFIG_RT_MUTEXES=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_BOOST_PRIO=2 +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp b/rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp new file mode 100644 index 0000000..f4c9175 --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp @@ -0,0 +1,18 @@ +CONFIG_RCU_TRACE=n +CONFIG_NO_HZ=n +CONFIG_SMP=n +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP b/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP new file mode 100644 index 0000000..77a8c5b --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP @@ -0,0 +1,30 @@ +CONFIG_RCU_TRACE=y +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=2 +CONFIG_NR_CPUS=16 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_NONE=n +CONFIG_RCU_NOCB_CPU_ZERO=n +CONFIG_RCU_NOCB_CPU_ALL=y +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_SLUB=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all b/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all new file mode 100644 index 0000000..0eecebc --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all @@ -0,0 +1,30 @@ +CONFIG_RCU_TRACE=y +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=2 +CONFIG_NR_CPUS=16 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_NONE=y +CONFIG_RCU_NOCB_CPU_ZERO=n +CONFIG_RCU_NOCB_CPU_ALL=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_SLUB=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none b/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none new file mode 100644 index 0000000..0eecebc --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none @@ -0,0 +1,30 @@ +CONFIG_RCU_TRACE=y +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=2 +CONFIG_NR_CPUS=16 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_NONE=y +CONFIG_RCU_NOCB_CPU_ZERO=n +CONFIG_RCU_NOCB_CPU_ALL=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_SLUB=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp b/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp new file mode 100644 index 0000000..588bc70 --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp @@ -0,0 +1,30 @@ +CONFIG_RCU_TRACE=y +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=2 +CONFIG_NR_CPUS=16 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=n +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_NONE=n +CONFIG_RCU_NOCB_CPU_ZERO=y +CONFIG_RCU_NOCB_CPU_ALL=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_SLUB=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/PT1-nh b/rcutorture/configs/rcu/v3.12/PT1-nh new file mode 100644 index 0000000..e3361c3 --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/PT1-nh @@ -0,0 +1,23 @@ +CONFIG_TINY_PREEMPT_RCU=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_BOOST_PRIO=2 +CONFIG_RCU_TRACE=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +# +CONFIG_SMP=n +# +CONFIG_HOTPLUG_CPU=n +# +CONFIG_NO_HZ=n +# +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.12/PT2-NH b/rcutorture/configs/rcu/v3.12/PT2-NH new file mode 100644 index 0000000..64abfc3 --- /dev/null +++ b/rcutorture/configs/rcu/v3.12/PT2-NH @@ -0,0 +1,22 @@ +CONFIG_TINY_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +# +CONFIG_SMP=n +# +CONFIG_HOTPLUG_CPU=n +# +CONFIG_NO_HZ=y +# +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.3/CFLIST b/rcutorture/configs/rcu/v3.3/CFLIST new file mode 100644 index 0000000..1822394 --- /dev/null +++ b/rcutorture/configs/rcu/v3.3/CFLIST @@ -0,0 +1,14 @@ +P1-S-T-NH-SD-SMP-HP +P2-2-t-nh-sd-SMP-hp +P3-3-T-nh-SD-SMP-hp +P4-A-t-NH-sd-SMP-HP +P5-U-T-NH-sd-SMP-hp +N1-S-T-NH-SD-SMP-HP +N2-2-t-nh-sd-SMP-hp +N3-3-T-nh-SD-SMP-hp +N4-A-t-NH-sd-SMP-HP +N5-U-T-NH-sd-SMP-hp +PT1-nh +PT2-NH +NT1-nh +NT3-NH diff --git a/rcutorture/configs/rcu/v3.3/N1-S-T-NH-SD-SMP-HP b/rcutorture/configs/rcu/v3.3/N1-S-T-NH-SD-SMP-HP new file mode 100644 index 0000000..d81e11d --- /dev/null +++ b/rcutorture/configs/rcu/v3.3/N1-S-T-NH-SD-SMP-HP @@ -0,0 +1,19 @@ +CONFIG_RCU_TRACE=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=8 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.3/N2-2-t-nh-sd-SMP-hp b/rcutorture/configs/rcu/v3.3/N2-2-t-nh-sd-SMP-hp new file mode 100644 index 0000000..02e4185 --- /dev/null +++ b/rcutorture/configs/rcu/v3.3/N2-2-t-nh-sd-SMP-hp @@ -0,0 +1,20 @@ +CONFIG_RCU_TRACE=n +CONFIG_NO_HZ=n +CONFIG_SMP=y +CONFIG_RCU_FANOUT=4 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.3/N3-3-T-nh-SD-SMP-hp b/rcutorture/configs/rcu/v3.3/N3-3-T-nh-SD-SMP-hp new file mode 100644 index 0000000..b3100f6 --- /dev/null +++ b/rcutorture/configs/rcu/v3.3/N3-3-T-nh-SD-SMP-hp @@ -0,0 +1,22 @@ +CONFIG_RCU_TRACE=y +CONFIG_NO_HZ=n +CONFIG_SMP=y +CONFIG_RCU_FANOUT=2 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.3/N4-A-t-NH-sd-SMP-HP b/rcutorture/configs/rcu/v3.3/N4-A-t-NH-sd-SMP-HP new file mode 100644 index 0000000..c56b445 --- /dev/null +++ b/rcutorture/configs/rcu/v3.3/N4-A-t-NH-sd-SMP-HP @@ -0,0 +1,18 @@ +CONFIG_RCU_TRACE=n +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=6 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.3/N5-U-T-NH-sd-SMP-hp b/rcutorture/configs/rcu/v3.3/N5-U-T-NH-sd-SMP-hp new file mode 100644 index 0000000..90d924f --- /dev/null +++ b/rcutorture/configs/rcu/v3.3/N5-U-T-NH-sd-SMP-hp @@ -0,0 +1,22 @@ +CONFIG_RCU_TRACE=y +CONFIG_DEBUG_KERNEL=y +CONFIG_RCU_CPU_STALL_INFO=y +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=6 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=y +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.3/NT1-nh b/rcutorture/configs/rcu/v3.3/NT1-nh new file mode 100644 index 0000000..023f312 --- /dev/null +++ b/rcutorture/configs/rcu/v3.3/NT1-nh @@ -0,0 +1,23 @@ +#CHECK#CONFIG_TINY_RCU=y +CONFIG_RCU_TRACE=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +# +CONFIG_SMP=n +# +CONFIG_HOTPLUG_CPU=n +# +CONFIG_NO_HZ=n +# +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.3/NT3-NH b/rcutorture/configs/rcu/v3.3/NT3-NH new file mode 100644 index 0000000..6fd0235 --- /dev/null +++ b/rcutorture/configs/rcu/v3.3/NT3-NH @@ -0,0 +1,20 @@ +#CHECK#CONFIG_TINY_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +# +CONFIG_SMP=n +# +CONFIG_HOTPLUG_CPU=n +# +CONFIG_NO_HZ=y +# +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP b/rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP new file mode 100644 index 0000000..9647c44 --- /dev/null +++ b/rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP @@ -0,0 +1,20 @@ +CONFIG_RCU_TRACE=y +CONFIG_RCU_CPU_STALL_INFO=y +CONFIG_NO_HZ=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=8 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp b/rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp new file mode 100644 index 0000000..0f3b667 --- /dev/null +++ b/rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp @@ -0,0 +1,20 @@ +CONFIG_RCU_TRACE=n +CONFIG_NO_HZ=n +CONFIG_SMP=y +CONFIG_RCU_FANOUT=4 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp b/rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp new file mode 100644 index 0000000..b035e14 --- /dev/null +++ b/rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp @@ -0,0 +1,20 @@ +CONFIG_RCU_TRACE=y +CONFIG_NO_HZ=n +CONFIG_SMP=y +CONFIG_RCU_FANOUT=2 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP b/rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP new file mode 100644 index 0000000..3ccf6a9 --- /dev/null +++ b/rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP @@ -0,0 +1,22 @@ +CONFIG_RCU_TRACE=n +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=6 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_RT_MUTEXES=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_BOOST_PRIO=2 +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp b/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp new file mode 100644 index 0000000..a55c008 --- /dev/null +++ b/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp @@ -0,0 +1,27 @@ +CONFIG_RCU_TRACE=y +CONFIG_RCU_CPU_STALL_INFO=y +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=6 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=y +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=y +CONFIG_RT_MUTEXES=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_BOOST_PRIO=2 +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.3/PT1-nh b/rcutorture/configs/rcu/v3.3/PT1-nh new file mode 100644 index 0000000..e3361c3 --- /dev/null +++ b/rcutorture/configs/rcu/v3.3/PT1-nh @@ -0,0 +1,23 @@ +CONFIG_TINY_PREEMPT_RCU=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_BOOST_PRIO=2 +CONFIG_RCU_TRACE=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +# +CONFIG_SMP=n +# +CONFIG_HOTPLUG_CPU=n +# +CONFIG_NO_HZ=n +# +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.3/PT2-NH b/rcutorture/configs/rcu/v3.3/PT2-NH new file mode 100644 index 0000000..64abfc3 --- /dev/null +++ b/rcutorture/configs/rcu/v3.3/PT2-NH @@ -0,0 +1,22 @@ +CONFIG_TINY_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +# +CONFIG_SMP=n +# +CONFIG_HOTPLUG_CPU=n +# +CONFIG_NO_HZ=y +# +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.3/ver_functions.sh b/rcutorture/configs/rcu/v3.3/ver_functions.sh new file mode 100644 index 0000000..bae5569 --- /dev/null +++ b/rcutorture/configs/rcu/v3.3/ver_functions.sh @@ -0,0 +1,44 @@ +#!/bin/bash +# +# Kernel-version-dependent shell functions for the rest of the scripts. +# +# 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, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2013 +# +# Authors: Paul E. McKenney + +# rcutorture_param_onoff bootparam-string config-file +# +# Adds onoff rcutorture module parameters to kernels having it. +rcutorture_param_onoff () { + if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2" + then + echo CPU-hotplug kernel, adding rcutorture onoff. 1>&2 + echo rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30 + fi +} + +# per_version_boot_params bootparam-string config-file seconds +# +# Adds per-version torture-module parameters to kernels supporting them. +per_version_boot_params () { + echo $1 `rcutorture_param_onoff "$1" "$2"` \ + rcutorture.stat_interval=15 \ + rcutorture.shutdown_secs=$3 \ + rcutorture.rcutorture_runnable=1 \ + rcutorture.test_no_idle_hz=1 \ + rcutorture.verbose=1 +} diff --git a/rcutorture/configs/rcu/v3.5/CFLIST b/rcutorture/configs/rcu/v3.5/CFLIST new file mode 100644 index 0000000..1822394 --- /dev/null +++ b/rcutorture/configs/rcu/v3.5/CFLIST @@ -0,0 +1,14 @@ +P1-S-T-NH-SD-SMP-HP +P2-2-t-nh-sd-SMP-hp +P3-3-T-nh-SD-SMP-hp +P4-A-t-NH-sd-SMP-HP +P5-U-T-NH-sd-SMP-hp +N1-S-T-NH-SD-SMP-HP +N2-2-t-nh-sd-SMP-hp +N3-3-T-nh-SD-SMP-hp +N4-A-t-NH-sd-SMP-HP +N5-U-T-NH-sd-SMP-hp +PT1-nh +PT2-NH +NT1-nh +NT3-NH diff --git a/rcutorture/configs/rcu/v3.5/N1-S-T-NH-SD-SMP-HP b/rcutorture/configs/rcu/v3.5/N1-S-T-NH-SD-SMP-HP new file mode 100644 index 0000000..d81e11d --- /dev/null +++ b/rcutorture/configs/rcu/v3.5/N1-S-T-NH-SD-SMP-HP @@ -0,0 +1,19 @@ +CONFIG_RCU_TRACE=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=8 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.5/N2-2-t-nh-sd-SMP-hp b/rcutorture/configs/rcu/v3.5/N2-2-t-nh-sd-SMP-hp new file mode 100644 index 0000000..02e4185 --- /dev/null +++ b/rcutorture/configs/rcu/v3.5/N2-2-t-nh-sd-SMP-hp @@ -0,0 +1,20 @@ +CONFIG_RCU_TRACE=n +CONFIG_NO_HZ=n +CONFIG_SMP=y +CONFIG_RCU_FANOUT=4 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.5/N3-3-T-nh-SD-SMP-hp b/rcutorture/configs/rcu/v3.5/N3-3-T-nh-SD-SMP-hp new file mode 100644 index 0000000..b3100f6 --- /dev/null +++ b/rcutorture/configs/rcu/v3.5/N3-3-T-nh-SD-SMP-hp @@ -0,0 +1,22 @@ +CONFIG_RCU_TRACE=y +CONFIG_NO_HZ=n +CONFIG_SMP=y +CONFIG_RCU_FANOUT=2 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.5/N4-A-t-NH-sd-SMP-HP b/rcutorture/configs/rcu/v3.5/N4-A-t-NH-sd-SMP-HP new file mode 100644 index 0000000..c56b445 --- /dev/null +++ b/rcutorture/configs/rcu/v3.5/N4-A-t-NH-sd-SMP-HP @@ -0,0 +1,18 @@ +CONFIG_RCU_TRACE=n +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=6 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.5/N5-U-T-NH-sd-SMP-hp b/rcutorture/configs/rcu/v3.5/N5-U-T-NH-sd-SMP-hp new file mode 100644 index 0000000..90d924f --- /dev/null +++ b/rcutorture/configs/rcu/v3.5/N5-U-T-NH-sd-SMP-hp @@ -0,0 +1,22 @@ +CONFIG_RCU_TRACE=y +CONFIG_DEBUG_KERNEL=y +CONFIG_RCU_CPU_STALL_INFO=y +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=6 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=y +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +#CHECK#CONFIG_TREE_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.5/NT1-nh b/rcutorture/configs/rcu/v3.5/NT1-nh new file mode 100644 index 0000000..023f312 --- /dev/null +++ b/rcutorture/configs/rcu/v3.5/NT1-nh @@ -0,0 +1,23 @@ +#CHECK#CONFIG_TINY_RCU=y +CONFIG_RCU_TRACE=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +# +CONFIG_SMP=n +# +CONFIG_HOTPLUG_CPU=n +# +CONFIG_NO_HZ=n +# +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.5/NT3-NH b/rcutorture/configs/rcu/v3.5/NT3-NH new file mode 100644 index 0000000..6fd0235 --- /dev/null +++ b/rcutorture/configs/rcu/v3.5/NT3-NH @@ -0,0 +1,20 @@ +#CHECK#CONFIG_TINY_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +# +CONFIG_SMP=n +# +CONFIG_HOTPLUG_CPU=n +# +CONFIG_NO_HZ=y +# +CONFIG_PREEMPT_NONE=y +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=n +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP b/rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP new file mode 100644 index 0000000..9647c44 --- /dev/null +++ b/rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP @@ -0,0 +1,20 @@ +CONFIG_RCU_TRACE=y +CONFIG_RCU_CPU_STALL_INFO=y +CONFIG_NO_HZ=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=8 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp b/rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp new file mode 100644 index 0000000..0f3b667 --- /dev/null +++ b/rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp @@ -0,0 +1,20 @@ +CONFIG_RCU_TRACE=n +CONFIG_NO_HZ=n +CONFIG_SMP=y +CONFIG_RCU_FANOUT=4 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp b/rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp new file mode 100644 index 0000000..b035e14 --- /dev/null +++ b/rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp @@ -0,0 +1,20 @@ +CONFIG_RCU_TRACE=y +CONFIG_NO_HZ=n +CONFIG_SMP=y +CONFIG_RCU_FANOUT=2 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP b/rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP new file mode 100644 index 0000000..3ccf6a9 --- /dev/null +++ b/rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP @@ -0,0 +1,22 @@ +CONFIG_RCU_TRACE=n +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=6 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=n +CONFIG_HOTPLUG_CPU=y +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_RT_MUTEXES=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_BOOST_PRIO=2 +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp b/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp new file mode 100644 index 0000000..a55c008 --- /dev/null +++ b/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp @@ -0,0 +1,27 @@ +CONFIG_RCU_TRACE=y +CONFIG_RCU_CPU_STALL_INFO=y +CONFIG_NO_HZ=y +CONFIG_SMP=y +CONFIG_RCU_FANOUT=6 +CONFIG_NR_CPUS=8 +CONFIG_RCU_FANOUT_EXACT=y +CONFIG_HOTPLUG_CPU=n +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +#CHECK#CONFIG_TREE_PREEMPT_RCU=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_OBJECTS=y +CONFIG_DEBUG_OBJECTS_RCU_HEAD=y +CONFIG_RT_MUTEXES=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_BOOST_PRIO=2 +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.5/PT1-nh b/rcutorture/configs/rcu/v3.5/PT1-nh new file mode 100644 index 0000000..e3361c3 --- /dev/null +++ b/rcutorture/configs/rcu/v3.5/PT1-nh @@ -0,0 +1,23 @@ +CONFIG_TINY_PREEMPT_RCU=y +CONFIG_RCU_BOOST=y +CONFIG_RCU_BOOST_PRIO=2 +CONFIG_RCU_TRACE=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +# +CONFIG_SMP=n +# +CONFIG_HOTPLUG_CPU=n +# +CONFIG_NO_HZ=n +# +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.5/PT2-NH b/rcutorture/configs/rcu/v3.5/PT2-NH new file mode 100644 index 0000000..64abfc3 --- /dev/null +++ b/rcutorture/configs/rcu/v3.5/PT2-NH @@ -0,0 +1,22 @@ +CONFIG_TINY_PREEMPT_RCU=y +CONFIG_RCU_TORTURE_TEST=m +CONFIG_MODULE_UNLOAD=y +CONFIG_SUSPEND=n +CONFIG_HIBERNATION=n +# +CONFIG_SMP=n +# +CONFIG_HOTPLUG_CPU=n +# +CONFIG_NO_HZ=y +# +CONFIG_PREEMPT_NONE=n +CONFIG_PREEMPT_VOLUNTARY=n +CONFIG_PREEMPT=y +CONFIG_PROVE_LOCKING=y +CONFIG_PROVE_RCU=y +CONFIG_SYSFS_DEPRECATED_V2=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_PRINTK_TIME=y + diff --git a/rcutorture/configs/rcu/v3.5/ver_functions.sh b/rcutorture/configs/rcu/v3.5/ver_functions.sh new file mode 100644 index 0000000..8977d8d --- /dev/null +++ b/rcutorture/configs/rcu/v3.5/ver_functions.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# +# Kernel-version-dependent shell functions for the rest of the scripts. +# +# 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, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2013 +# +# Authors: Paul E. McKenney + +# rcutorture_param_n_barrier_cbs bootparam-string +# +# Adds n_barrier_cbs rcutorture module parameter to kernels having it. +rcutorture_param_n_barrier_cbs () { + if echo $1 | grep -q "rcutorture\.n_barrier_cbs" + then + : + else + echo rcutorture.n_barrier_cbs=4 + fi +} + +# rcutorture_param_onoff bootparam-string config-file +# +# Adds onoff rcutorture module parameters to kernels having it. +rcutorture_param_onoff () { + if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2" + then + echo CPU-hotplug kernel, adding rcutorture onoff. 1>&2 + echo rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30 + fi +} + +# per_version_boot_params bootparam-string config-file seconds +# +# Adds per-version torture-module parameters to kernels supporting them. +per_version_boot_params () { + echo $1 `rcutorture_param_onoff "$1" "$2"` \ + `rcutorture_param_n_barrier_cbs "$1"` \ + rcutorture.stat_interval=15 \ + rcutorture.shutdown_secs=$3 \ + rcutorture.rcutorture_runnable=1 \ + rcutorture.test_no_idle_hz=1 \ + rcutorture.verbose=1 +} diff --git a/rcutorture/configs/rcu/ver_functions.sh b/rcutorture/configs/rcu/ver_functions.sh new file mode 100644 index 0000000..8977d8d --- /dev/null +++ b/rcutorture/configs/rcu/ver_functions.sh @@ -0,0 +1,57 @@ +#!/bin/bash +# +# Kernel-version-dependent shell functions for the rest of the scripts. +# +# 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, you can access it online at +# http://www.gnu.org/licenses/gpl-2.0.html. +# +# Copyright (C) IBM Corporation, 2013 +# +# Authors: Paul E. McKenney + +# rcutorture_param_n_barrier_cbs bootparam-string +# +# Adds n_barrier_cbs rcutorture module parameter to kernels having it. +rcutorture_param_n_barrier_cbs () { + if echo $1 | grep -q "rcutorture\.n_barrier_cbs" + then + : + else + echo rcutorture.n_barrier_cbs=4 + fi +} + +# rcutorture_param_onoff bootparam-string config-file +# +# Adds onoff rcutorture module parameters to kernels having it. +rcutorture_param_onoff () { + if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2" + then + echo CPU-hotplug kernel, adding rcutorture onoff. 1>&2 + echo rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30 + fi +} + +# per_version_boot_params bootparam-string config-file seconds +# +# Adds per-version torture-module parameters to kernels supporting them. +per_version_boot_params () { + echo $1 `rcutorture_param_onoff "$1" "$2"` \ + `rcutorture_param_n_barrier_cbs "$1"` \ + rcutorture.stat_interval=15 \ + rcutorture.shutdown_secs=$3 \ + rcutorture.rcutorture_runnable=1 \ + rcutorture.test_no_idle_hz=1 \ + rcutorture.verbose=1 +} diff --git a/rcutorture/doc/TINY_RCU.txt b/rcutorture/doc/TINY_RCU.txt new file mode 100644 index 0000000..28db67b --- /dev/null +++ b/rcutorture/doc/TINY_RCU.txt @@ -0,0 +1,40 @@ +This document gives a brief rationale for the TINY_RCU test cases. + + +Kconfig Parameters: + +CONFIG_DEBUG_LOCK_ALLOC -- Do all three and none of the three. +CONFIG_PREEMPT_COUNT +CONFIG_RCU_TRACE + +The theory here is that randconfig testing will hit the other six possible +combinations of these parameters. + + +Kconfig Parameters Ignored: + +CONFIG_DEBUG_OBJECTS_RCU_HEAD +CONFIG_PROVE_RCU + + In common code tested by TREE_RCU test cases. + +CONFIG_NO_HZ_FULL_SYSIDLE +CONFIG_RCU_NOCB_CPU +CONFIG_RCU_USER_QS + + Meaningless for TINY_RCU. + +CONFIG_RCU_STALL_COMMON +CONFIG_RCU_TORTURE_TEST + + Redundant with CONFIG_RCU_TRACE. + +CONFIG_HOTPLUG_CPU +CONFIG_PREEMPT +CONFIG_PREEMPT_RCU +CONFIG_SMP +CONFIG_TINY_RCU +CONFIG_TREE_PREEMPT_RCU +CONFIG_TREE_RCU + + All forced by CONFIG_TINY_RCU. diff --git a/rcutorture/doc/TREE_RCU-kconfig.txt b/rcutorture/doc/TREE_RCU-kconfig.txt new file mode 100644 index 0000000..3e588db --- /dev/null +++ b/rcutorture/doc/TREE_RCU-kconfig.txt @@ -0,0 +1,94 @@ +This document gives a brief rationale for the TREE_RCU-related test +cases, a group that includes TREE_PREEMPT_RCU. + + +Kconfig Parameters: + +CONFIG_DEBUG_LOCK_ALLOC -- Do three, covering CONFIG_PROVE_LOCKING & not. +CONFIG_DEBUG_OBJECTS_RCU_HEAD -- Do one. +CONFIG_HOTPLUG_CPU -- Do half. (Every second.) +CONFIG_HZ_PERIODIC -- Do one. +CONFIG_NO_HZ_IDLE -- Do those not otherwise specified. (Groups of two.) +CONFIG_NO_HZ_FULL -- Do two, one with CONFIG_NO_HZ_FULL_SYSIDLE. +CONFIG_NO_HZ_FULL_SYSIDLE -- Do one. +CONFIG_PREEMPT -- Do half. (First three and #8.) +CONFIG_PROVE_LOCKING -- Do all but two, covering CONFIG_PROVE_RCU and not. +CONFIG_PROVE_RCU -- Do all but one under CONFIG_PROVE_LOCKING. +CONFIG_RCU_BOOST -- one of TREE_PREEMPT_RCU. +CONFIG_RCU_BOOST_PRIO -- set to 2 for _BOOST testing. +CONFIG_RCU_CPU_STALL_INFO -- do one with and without _VERBOSE. +CONFIG_RCU_CPU_STALL_VERBOSE -- do one with and without _INFO. +CONFIG_RCU_FANOUT -- Cover hierarchy as currently, but overlap with others. +CONFIG_RCU_FANOUT_EXACT -- Do one. +CONFIG_RCU_FANOUT_LEAF -- Do one non-default. +CONFIG_RCU_FAST_NO_HZ -- Do one, but not with CONFIG_RCU_NOCB_CPU_ALL. +CONFIG_RCU_NOCB_CPU -- Do three, see below. +CONFIG_RCU_NOCB_CPU_ALL -- Do one. +CONFIG_RCU_NOCB_CPU_NONE -- Do one. +CONFIG_RCU_NOCB_CPU_ZERO -- Do one. +CONFIG_RCU_TRACE -- Do half. +CONFIG_SMP -- Need one !SMP for TREE_PREEMPT_RCU. +RCU-bh: Do one with PREEMPT and one with !PREEMPT. +RCU-sched: Do one with PREEMPT but not BOOST. + + +Hierarchy: + +TREE01. CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=8, CONFIG_RCU_FANOUT_EXACT=n. +TREE02. CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=3, CONFIG_RCU_FANOUT_EXACT=n, + CONFIG_RCU_FANOUT_LEAF=3. +TREE03. CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=4, CONFIG_RCU_FANOUT_EXACT=n, + CONFIG_RCU_FANOUT_LEAF=4. +TREE04. CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=2, CONFIG_RCU_FANOUT_EXACT=n, + CONFIG_RCU_FANOUT_LEAF=2. +TREE05. CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=6, CONFIG_RCU_FANOUT_EXACT=n + CONFIG_RCU_FANOUT_LEAF=6. +TREE06. CONFIG_NR_CPUS=8, CONFIG_RCU_FANOUT=6, CONFIG_RCU_FANOUT_EXACT=y + CONFIG_RCU_FANOUT_LEAF=6. +TREE07. CONFIG_NR_CPUS=16, CONFIG_RCU_FANOUT=2, CONFIG_RCU_FANOUT_EXACT=n, + CONFIG_RCU_FANOUT_LEAF=2. +TREE08. CONFIG_NR_CPUS=16, CONFIG_RCU_FANOUT=3, CONFIG_RCU_FANOUT_EXACT=y, + CONFIG_RCU_FANOUT_LEAF=2. +TREE09. CONFIG_NR_CPUS=1. + + +Kconfig Parameters Ignored: + +CONFIG_64BIT + + Used only to check CONFIG_RCU_FANOUT value, inspection suffices. + +CONFIG_NO_HZ_FULL_SYSIDLE_SMALL + + Defer until Frederic uses this. + +CONFIG_PREEMPT_COUNT +CONFIG_PREEMPT_RCU + + Redundant with CONFIG_PREEMPT, ignore. + +CONFIG_RCU_BOOST_DELAY + + Inspection suffices, ignore. + +CONFIG_RCU_CPU_STALL_TIMEOUT + + Inspection suffices, ignore. + +CONFIG_RCU_STALL_COMMON + + Implied by TREE_RCU and TREE_PREEMPT_RCU. + +CONFIG_RCU_TORTURE_TEST +CONFIG_RCU_TORTURE_TEST_RUNNABLE + + Always used in KVM testing. + +CONFIG_RCU_USER_QS + + Redundant with CONFIG_NO_HZ_FULL. + +CONFIG_TREE_PREEMPT_RCU +CONFIG_TREE_RCU + + These are controlled by CONFIG_PREEMPT. diff --git a/rcutorture/doc/initrd.txt b/rcutorture/doc/initrd.txt new file mode 100644 index 0000000..49d134c --- /dev/null +++ b/rcutorture/doc/initrd.txt @@ -0,0 +1,90 @@ +This document describes one way to create the initrd directory hierarchy +in order to allow an initrd to be built into your kernel. The trick +here is to steal the initrd file used on your Linux laptop, Ubuntu in +this case. There are probably much better ways of doing this. + +That said, here are the commands: + +------------------------------------------------------------------------ +zcat /initrd.img > /tmp/initrd.img.zcat +mkdir initrd +cd initrd +cpio -id < /tmp/initrd.img.zcat +------------------------------------------------------------------------ + +Interestingly enough, if you are running rcutorture, you don't really +need userspace in many cases. Running without userspace has the +advantage of allowing you to test your kernel independently of the +distro in place, the root-filesystem layout, and so on. To make this +happen, put the following script in the initrd's tree's "/init" file, +with 0755 mode. + +------------------------------------------------------------------------ +#!/bin/sh + +[ -d /dev ] || mkdir -m 0755 /dev +[ -d /root ] || mkdir -m 0700 /root +[ -d /sys ] || mkdir /sys +[ -d /proc ] || mkdir /proc +[ -d /tmp ] || mkdir /tmp +mkdir -p /var/lock +mount -t sysfs -o nodev,noexec,nosuid sysfs /sys +mount -t proc -o nodev,noexec,nosuid proc /proc +# Some things don't work properly without /etc/mtab. +ln -sf /proc/mounts /etc/mtab + +# Note that this only becomes /dev on the real filesystem if udev's scripts +# are used; which they will be, but it's worth pointing out +if ! mount -t devtmpfs -o mode=0755 udev /dev; then + echo "W: devtmpfs not available, falling back to tmpfs for /dev" + mount -t tmpfs -o mode=0755 udev /dev + [ -e /dev/console ] || mknod --mode=600 /dev/console c 5 1 + [ -e /dev/kmsg ] || mknod --mode=644 /dev/kmsg c 1 11 + [ -e /dev/null ] || mknod --mode=666 /dev/null c 1 3 +fi + +mkdir /dev/pts +mount -t devpts -o noexec,nosuid,gid=5,mode=0620 devpts /dev/pts || true +mount -t tmpfs -o "nosuid,size=20%,mode=0755" tmpfs /run +mkdir /run/initramfs +# compatibility symlink for the pre-oneiric locations +ln -s /run/initramfs /dev/.initramfs + +# Export relevant variables +export ROOT= +export ROOTDELAY= +export ROOTFLAGS= +export ROOTFSTYPE= +export IP= +export BOOT= +export BOOTIF= +export UBIMTD= +export break= +export init=/sbin/init +export quiet=n +export readonly=y +export rootmnt=/root +export debug= +export panic= +export blacklist= +export resume= +export resume_offset= +export recovery= + +for i in /sys/devices/system/cpu/cpu*/online +do + case $i in + '/sys/devices/system/cpu/cpu0/online') + ;; + '/sys/devices/system/cpu/cpu*/online') + ;; + *) + echo 1 > $i + ;; + esac +done + +while : +do + sleep 10 +done diff --git a/rcutorture/doc/rcu-test-image.txt b/rcutorture/doc/rcu-test-image.txt new file mode 100644 index 0000000..66efb59 --- /dev/null +++ b/rcutorture/doc/rcu-test-image.txt @@ -0,0 +1,42 @@ +This document describes one way to created the rcu-test-image file +that contains the filesystem used by the guest-OS kernel. There are +probably much better ways of doing this, and this filesystem could no +doubt be smaller. It is probably also possible to simply download +an appropriate image from any number of places. + +That said, here are the commands: + +------------------------------------------------------------------------ +dd if=/dev/zero of=rcu-test-image bs=400M count=1 +mkfs.ext3 ./rcu-test-image +sudo mount -o loop ./rcu-test-image /mnt + +# Replace "precise" below with your favorite Ubuntu release. +# Empirical evidence says this image will work for 64-bit, but... +# Note that debootstrap does take a few minutes to run. Or longer. +sudo debootstrap --verbose --arch i386 precise /mnt http://archive.ubuntu.com/ubuntu +cat << '___EOF___' | sudo dd of=/mnt/etc/fstab +# UNCONFIGURED FSTAB FOR BASE SYSTEM +# +/dev/vda / ext3 defaults 1 1 +dev /dev tmpfs rw 0 0 +tmpfs /dev/shm tmpfs defaults 0 0 +devpts /dev/pts devpts gid=5,mode=620 0 0 +sysfs /sys sysfs defaults 0 0 +proc /proc proc defaults 0 0 +___EOF___ +sudo umount /mnt +------------------------------------------------------------------------ + + +References: + + http://sripathikodi.blogspot.com/2010/02/creating-kvm-bootable-fedora-system.html + https://help.ubuntu.com/community/KVM/CreateGuests + https://help.ubuntu.com/community/JeOSVMBuilder + http://wiki.libvirt.org/page/UbuntuKVMWalkthrough + http://www.moe.co.uk/2011/01/07/pci_add_option_rom-failed-to-find-romfile-pxe-rtl8139-bin/ -- "apt-get install kvm-pxe" + http://www.landley.net/writing/rootfs-howto.html + http://en.wikipedia.org/wiki/Initrd + http://en.wikipedia.org/wiki/Cpio + http://wiki.libvirt.org/page/UbuntuKVMWalkthrough diff --git a/sysctl/Makefile b/sysctl/Makefile new file mode 100644 index 0000000..0a92ada --- /dev/null +++ b/sysctl/Makefile @@ -0,0 +1,19 @@ +# Makefile for sysctl selftests. +# Expects kernel.sysctl_writes_strict=1. + +# No binaries, but make sure arg-less "make" doesn't trigger "run_tests". +all: + +# Allow specific tests to be selected. +test_num: + @/bin/sh ./run_numerictests + +test_string: + @/bin/sh ./run_stringtests + +run_tests: all test_num test_string + +# Nothing to clean up. +clean: + +.PHONY: all run_tests clean test_num test_string diff --git a/sysctl/common_tests b/sysctl/common_tests new file mode 100644 index 0000000..17d534b --- /dev/null +++ b/sysctl/common_tests @@ -0,0 +1,109 @@ +#!/bin/sh + +TEST_FILE=$(mktemp) + +echo "== Testing sysctl behavior against ${TARGET} ==" + +set_orig() +{ + echo "${ORIG}" > "${TARGET}" +} + +set_test() +{ + echo "${TEST_STR}" > "${TARGET}" +} + +verify() +{ + local seen + seen=$(cat "$1") + if [ "${seen}" != "${TEST_STR}" ]; then + return 1 + fi + return 0 +} + +trap 'set_orig; rm -f "${TEST_FILE}"' EXIT + +rc=0 + +echo -n "Writing test file ... " +echo "${TEST_STR}" > "${TEST_FILE}" +if ! verify "${TEST_FILE}"; then + echo "FAIL" >&2 + exit 1 +else + echo "ok" +fi + +echo -n "Checking sysctl is not set to test value ... " +if verify "${TARGET}"; then + echo "FAIL" >&2 + exit 1 +else + echo "ok" +fi + +echo -n "Writing sysctl from shell ... " +set_test +if ! verify "${TARGET}"; then + echo "FAIL" >&2 + exit 1 +else + echo "ok" +fi + +echo -n "Resetting sysctl to original value ... " +set_orig +if verify "${TARGET}"; then + echo "FAIL" >&2 + exit 1 +else + echo "ok" +fi + +# Now that we've validated the sanity of "set_test" and "set_orig", +# we can use those functions to set starting states before running +# specific behavioral tests. + +echo -n "Writing entire sysctl in single write ... " +set_orig +dd if="${TEST_FILE}" of="${TARGET}" bs=4096 2>/dev/null +if ! verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 +else + echo "ok" +fi + +echo -n "Writing middle of sysctl after synchronized seek ... " +set_test +dd if="${TEST_FILE}" of="${TARGET}" bs=1 seek=1 skip=1 2>/dev/null +if ! verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 +else + echo "ok" +fi + +echo -n "Writing beyond end of sysctl ... " +set_orig +dd if="${TEST_FILE}" of="${TARGET}" bs=20 seek=2 2>/dev/null +if verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 +else + echo "ok" +fi + +echo -n "Writing sysctl with multiple long writes ... " +set_orig +(perl -e 'print "A" x 50;'; echo "${TEST_STR}") | \ + dd of="${TARGET}" bs=50 2>/dev/null +if verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 +else + echo "ok" +fi diff --git a/sysctl/run_numerictests b/sysctl/run_numerictests new file mode 100644 index 0000000..8510f93 --- /dev/null +++ b/sysctl/run_numerictests @@ -0,0 +1,10 @@ +#!/bin/sh + +SYSCTL="/proc/sys" +TARGET="${SYSCTL}/vm/swappiness" +ORIG=$(cat "${TARGET}") +TEST_STR=$(( $ORIG + 1 )) + +. ./common_tests + +exit $rc diff --git a/sysctl/run_stringtests b/sysctl/run_stringtests new file mode 100644 index 0000000..90a9293 --- /dev/null +++ b/sysctl/run_stringtests @@ -0,0 +1,77 @@ +#!/bin/sh + +SYSCTL="/proc/sys" +TARGET="${SYSCTL}/kernel/domainname" +ORIG=$(cat "${TARGET}") +TEST_STR="Testing sysctl" + +. ./common_tests + +# Only string sysctls support seeking/appending. +MAXLEN=65 + +echo -n "Writing entire sysctl in short writes ... " +set_orig +dd if="${TEST_FILE}" of="${TARGET}" bs=1 2>/dev/null +if ! verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 +else + echo "ok" +fi + +echo -n "Writing middle of sysctl after unsynchronized seek ... " +set_test +dd if="${TEST_FILE}" of="${TARGET}" bs=1 seek=1 2>/dev/null +if verify "${TARGET}"; then + echo "FAIL" >&2 + rc=1 +else + echo "ok" +fi + +echo -n "Checking sysctl maxlen is at least $MAXLEN ... " +set_orig +perl -e 'print "A" x ('"${MAXLEN}"'-2), "B";' | \ + dd of="${TARGET}" bs="${MAXLEN}" 2>/dev/null +if ! grep -q B "${TARGET}"; then + echo "FAIL" >&2 + rc=1 +else + echo "ok" +fi + +echo -n "Checking sysctl keeps original string on overflow append ... " +set_orig +perl -e 'print "A" x ('"${MAXLEN}"'-1), "B";' | \ + dd of="${TARGET}" bs=$(( MAXLEN - 1 )) 2>/dev/null +if grep -q B "${TARGET}"; then + echo "FAIL" >&2 + rc=1 +else + echo "ok" +fi + +echo -n "Checking sysctl stays NULL terminated on write ... " +set_orig +perl -e 'print "A" x ('"${MAXLEN}"'-1), "B";' | \ + dd of="${TARGET}" bs="${MAXLEN}" 2>/dev/null +if grep -q B "${TARGET}"; then + echo "FAIL" >&2 + rc=1 +else + echo "ok" +fi + +echo -n "Checking sysctl stays NULL terminated on overwrite ... " +set_orig +perl -e 'print "A" x ('"${MAXLEN}"'-1), "BB";' | \ + dd of="${TARGET}" bs=$(( $MAXLEN + 1 )) 2>/dev/null +if grep -q B "${TARGET}"; then + echo "FAIL" >&2 + rc=1 +else + echo "ok" +fi + +exit $rc diff --git a/timers/Makefile b/timers/Makefile new file mode 100644 index 0000000..eb2859f --- /dev/null +++ b/timers/Makefile @@ -0,0 +1,8 @@ +all: + gcc posix_timers.c -o posix_timers -lrt + +run_tests: all + ./posix_timers + +clean: + rm -f ./posix_timers diff --git a/timers/posix_timers.c b/timers/posix_timers.c new file mode 100644 index 0000000..41bd855 --- /dev/null +++ b/timers/posix_timers.c @@ -0,0 +1,221 @@ +/* + * Copyright (C) 2013 Red Hat, Inc., Frederic Weisbecker + * + * Licensed under the terms of the GNU GPL License version 2 + * + * Selftests for a few posix timers interface. + * + * Kernel loop code stolen from Steven Rostedt + */ + +#include +#include +#include +#include +#include +#include + +#define DELAY 2 +#define USECS_PER_SEC 1000000 + +static volatile int done; + +/* Busy loop in userspace to elapse ITIMER_VIRTUAL */ +static void user_loop(void) +{ + while (!done); +} + +/* + * Try to spend as much time as possible in kernelspace + * to elapse ITIMER_PROF. + */ +static void kernel_loop(void) +{ + void *addr = sbrk(0); + + while (!done) { + brk(addr + 4096); + brk(addr); + } +} + +/* + * Sleep until ITIMER_REAL expiration. + */ +static void idle_loop(void) +{ + pause(); +} + +static void sig_handler(int nr) +{ + done = 1; +} + +/* + * Check the expected timer expiration matches the GTOD elapsed delta since + * we armed the timer. Keep a 0.5 sec error margin due to various jitter. + */ +static int check_diff(struct timeval start, struct timeval end) +{ + long long diff; + + diff = end.tv_usec - start.tv_usec; + diff += (end.tv_sec - start.tv_sec) * USECS_PER_SEC; + + if (abs(diff - DELAY * USECS_PER_SEC) > USECS_PER_SEC / 2) { + printf("Diff too high: %lld..", diff); + return -1; + } + + return 0; +} + +static int check_itimer(int which) +{ + int err; + struct timeval start, end; + struct itimerval val = { + .it_value.tv_sec = DELAY, + }; + + printf("Check itimer "); + + if (which == ITIMER_VIRTUAL) + printf("virtual... "); + else if (which == ITIMER_PROF) + printf("prof... "); + else if (which == ITIMER_REAL) + printf("real... "); + + fflush(stdout); + + done = 0; + + if (which == ITIMER_VIRTUAL) + signal(SIGVTALRM, sig_handler); + else if (which == ITIMER_PROF) + signal(SIGPROF, sig_handler); + else if (which == ITIMER_REAL) + signal(SIGALRM, sig_handler); + + err = gettimeofday(&start, NULL); + if (err < 0) { + perror("Can't call gettimeofday()\n"); + return -1; + } + + err = setitimer(which, &val, NULL); + if (err < 0) { + perror("Can't set timer\n"); + return -1; + } + + if (which == ITIMER_VIRTUAL) + user_loop(); + else if (which == ITIMER_PROF) + kernel_loop(); + else if (which == ITIMER_REAL) + idle_loop(); + + gettimeofday(&end, NULL); + if (err < 0) { + perror("Can't call gettimeofday()\n"); + return -1; + } + + if (!check_diff(start, end)) + printf("[OK]\n"); + else + printf("[FAIL]\n"); + + return 0; +} + +static int check_timer_create(int which) +{ + int err; + timer_t id; + struct timeval start, end; + struct itimerspec val = { + .it_value.tv_sec = DELAY, + }; + + printf("Check timer_create() "); + if (which == CLOCK_THREAD_CPUTIME_ID) { + printf("per thread... "); + } else if (which == CLOCK_PROCESS_CPUTIME_ID) { + printf("per process... "); + } + fflush(stdout); + + done = 0; + err = timer_create(which, NULL, &id); + if (err < 0) { + perror("Can't create timer\n"); + return -1; + } + signal(SIGALRM, sig_handler); + + err = gettimeofday(&start, NULL); + if (err < 0) { + perror("Can't call gettimeofday()\n"); + return -1; + } + + err = timer_settime(id, 0, &val, NULL); + if (err < 0) { + perror("Can't set timer\n"); + return -1; + } + + user_loop(); + + gettimeofday(&end, NULL); + if (err < 0) { + perror("Can't call gettimeofday()\n"); + return -1; + } + + if (!check_diff(start, end)) + printf("[OK]\n"); + else + printf("[FAIL]\n"); + + return 0; +} + +int main(int argc, char **argv) +{ + int err; + + printf("Testing posix timers. False negative may happen on CPU execution \n"); + printf("based timers if other threads run on the CPU...\n"); + + if (check_itimer(ITIMER_VIRTUAL) < 0) + return -1; + + if (check_itimer(ITIMER_PROF) < 0) + return -1; + + if (check_itimer(ITIMER_REAL) < 0) + return -1; + + if (check_timer_create(CLOCK_THREAD_CPUTIME_ID) < 0) + return -1; + + /* + * It's unfortunately hard to reliably test a timer expiration + * on parallel multithread cputime. We could arm it to expire + * on DELAY * nr_threads, with nr_threads busy looping, then wait + * the normal DELAY since the time is elapsing nr_threads faster. + * But for that we need to ensure we have real physical free CPUs + * to ensure true parallelism. So test only one thread until we + * find a better solution. + */ + if (check_timer_create(CLOCK_PROCESS_CPUTIME_ID) < 0) + return -1; + + return 0; +} diff --git a/user/Makefile b/user/Makefile new file mode 100644 index 0000000..396255b --- /dev/null +++ b/user/Makefile @@ -0,0 +1,13 @@ +# Makefile for user memory selftests + +# No binaries, but make sure arg-less "make" doesn't trigger "run_tests" +all: + +run_tests: all + @if /sbin/modprobe test_user_copy ; then \ + rmmod test_user_copy; \ + echo "user_copy: ok"; \ + else \ + echo "user_copy: [FAIL]"; \ + exit 1; \ + fi diff --git a/vm/.gitignore b/vm/.gitignore new file mode 100644 index 0000000..ff1bb16 --- /dev/null +++ b/vm/.gitignore @@ -0,0 +1,4 @@ +hugepage-mmap +hugepage-shm +map_hugetlb +thuge-gen diff --git a/vm/Makefile b/vm/Makefile index 436d2e8..3f94e1a 100644 --- a/vm/Makefile +++ b/vm/Makefile @@ -2,13 +2,14 @@ CC = $(CROSS_COMPILE)gcc CFLAGS = -Wall +BINARIES = hugepage-mmap hugepage-shm map_hugetlb thuge-gen hugetlbfstest -all: hugepage-mmap hugepage-shm map_hugetlb thuge-gen +all: $(BINARIES) %: %.c $(CC) $(CFLAGS) -o $@ $^ run_tests: all - @/bin/sh ./run_vmtests || echo "vmtests: [FAIL]" + @/bin/sh ./run_vmtests || (echo "vmtests: [FAIL]"; exit 1) clean: - $(RM) hugepage-mmap hugepage-shm map_hugetlb + $(RM) $(BINARIES) diff --git a/vm/hugepage-mmap b/vm/hugepage-mmap deleted file mode 100755 index 118d5e3..0000000 Binary files a/vm/hugepage-mmap and /dev/null differ diff --git a/vm/hugepage-shm b/vm/hugepage-shm deleted file mode 100755 index 91f8e1f..0000000 Binary files a/vm/hugepage-shm and /dev/null differ diff --git a/vm/hugetlbfstest.c b/vm/hugetlbfstest.c new file mode 100644 index 0000000..ea40ff8 --- /dev/null +++ b/vm/hugetlbfstest.c @@ -0,0 +1,84 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef unsigned long long u64; + +static size_t length = 1 << 24; + +static u64 read_rss(void) +{ + char buf[4096], *s = buf; + int i, fd; + u64 rss; + + fd = open("/proc/self/statm", O_RDONLY); + assert(fd > 2); + memset(buf, 0, sizeof(buf)); + read(fd, buf, sizeof(buf) - 1); + for (i = 0; i < 1; i++) + s = strchr(s, ' ') + 1; + rss = strtoull(s, NULL, 10); + return rss << 12; /* assumes 4k pagesize */ +} + +static void do_mmap(int fd, int extra_flags, int unmap) +{ + int *p; + int flags = MAP_PRIVATE | MAP_POPULATE | extra_flags; + u64 before, after; + + before = read_rss(); + p = mmap(NULL, length, PROT_READ | PROT_WRITE, flags, fd, 0); + assert(p != MAP_FAILED || + !"mmap returned an unexpected error"); + after = read_rss(); + assert(llabs(after - before - length) < 0x40000 || + !"rss didn't grow as expected"); + if (!unmap) + return; + munmap(p, length); + after = read_rss(); + assert(llabs(after - before) < 0x40000 || + !"rss didn't shrink as expected"); +} + +static int open_file(const char *path) +{ + int fd, err; + + unlink(path); + fd = open(path, O_CREAT | O_RDWR | O_TRUNC | O_EXCL + | O_LARGEFILE | O_CLOEXEC, 0600); + assert(fd > 2); + unlink(path); + err = ftruncate(fd, length); + assert(!err); + return fd; +} + +int main(void) +{ + int hugefd, fd; + + fd = open_file("/dev/shm/hugetlbhog"); + hugefd = open_file("/hugepages/hugetlbhog"); + + system("echo 100 > /proc/sys/vm/nr_hugepages"); + do_mmap(-1, MAP_ANONYMOUS, 1); + do_mmap(fd, 0, 1); + do_mmap(-1, MAP_ANONYMOUS | MAP_HUGETLB, 1); + do_mmap(hugefd, 0, 1); + do_mmap(hugefd, MAP_HUGETLB, 1); + /* Leak the last one to test do_exit() */ + do_mmap(-1, MAP_ANONYMOUS | MAP_HUGETLB, 0); + printf("oll korrekt.\n"); + return 0; +} diff --git a/vm/map_hugetlb b/vm/map_hugetlb deleted file mode 100755 index 359d6bc..0000000 Binary files a/vm/map_hugetlb and /dev/null differ diff --git a/vm/run_vmtests b/vm/run_vmtests index 4c53cae..c87b681 100644 --- a/vm/run_vmtests +++ b/vm/run_vmtests @@ -4,6 +4,7 @@ #we need 256M, below is the size in kB needmem=262144 mnt=./huge +exitcode=0 #get pagesize and freepages from /proc/meminfo while read name size unit; do @@ -41,6 +42,7 @@ echo "--------------------" ./hugepage-mmap if [ $? -ne 0 ]; then echo "[FAIL]" + exitcode=1 else echo "[PASS]" fi @@ -55,6 +57,7 @@ echo "--------------------" ./hugepage-shm if [ $? -ne 0 ]; then echo "[FAIL]" + exitcode=1 else echo "[PASS]" fi @@ -67,6 +70,18 @@ echo "--------------------" ./map_hugetlb if [ $? -ne 0 ]; then echo "[FAIL]" + exitcode=1 +else + echo "[PASS]" +fi + +echo "--------------------" +echo "running hugetlbfstest" +echo "--------------------" +./hugetlbfstest +if [ $? -ne 0 ]; then + echo "[FAIL]" + exitcode=1 else echo "[PASS]" fi @@ -75,3 +90,4 @@ fi umount $mnt rm -rf $mnt echo $nr_hugepgs > /proc/sys/vm/nr_hugepages +exit $exitcode diff --git a/vm/thuge-gen b/vm/thuge-gen deleted file mode 100755 index f648449..0000000 Binary files a/vm/thuge-gen and /dev/null differ -- cgit v1.2.3