diff options
Diffstat (limited to 'tools/testing/selftests')
53 files changed, 2623 insertions, 346 deletions
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index e66e710cc595..36ff2e4c7b6f 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -2,8 +2,10 @@ TARGETS = breakpoints TARGETS += cpu-hotplug TARGETS += efivarfs TARGETS += kcmp +TARGETS += memfd TARGETS += memory-hotplug TARGETS += mqueue +TARGETS += mount TARGETS += net TARGETS += ptrace TARGETS += timers @@ -11,6 +13,10 @@ TARGETS += vm TARGETS += powerpc TARGETS += user TARGETS += sysctl +TARGETS += firmware + +TARGETS_HOTPLUG = cpu-hotplug +TARGETS_HOTPLUG += memory-hotplug all: for TARGET in $(TARGETS); do \ @@ -22,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/tools/testing/selftests/README.txt b/tools/testing/selftests/README.txt index 5e2faf9c55d3..2660d5ff9179 100644 --- a/tools/testing/selftests/README.txt +++ b/tools/testing/selftests/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/tools/testing/selftests/cpu-hotplug/Makefile b/tools/testing/selftests/cpu-hotplug/Makefile index 790c23a9db44..e9c28d8dc84b 100644 --- a/tools/testing/selftests/cpu-hotplug/Makefile +++ b/tools/testing/selftests/cpu-hotplug/Makefile @@ -3,4 +3,7 @@ all: run_tests: @/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/tools/testing/selftests/cpu-hotplug/on-off-test.sh b/tools/testing/selftests/cpu-hotplug/on-off-test.sh index bdde7cf428bb..98b1d6565f2c 100644 --- a/tools/testing/selftests/cpu-hotplug/on-off-test.sh +++ b/tools/testing/selftests/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) @@ -138,6 +163,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 # for cpu in `hotplaggable_offline_cpus`; do diff --git a/tools/testing/selftests/firmware/Makefile b/tools/testing/selftests/firmware/Makefile new file mode 100644 index 000000000000..e23cce0bbc3a --- /dev/null +++ b/tools/testing/selftests/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/tools/testing/selftests/firmware/fw_filesystem.sh b/tools/testing/selftests/firmware/fw_filesystem.sh new file mode 100644 index 000000000000..3fc6c10c2479 --- /dev/null +++ b/tools/testing/selftests/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/tools/testing/selftests/firmware/fw_userhelper.sh b/tools/testing/selftests/firmware/fw_userhelper.sh new file mode 100644 index 000000000000..6efbade12139 --- /dev/null +++ b/tools/testing/selftests/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/tools/testing/selftests/kcmp/kcmp_test.c b/tools/testing/selftests/kcmp/kcmp_test.c index fa4f1b37e045..dbba4084869c 100644 --- a/tools/testing/selftests/kcmp/kcmp_test.c +++ b/tools/testing/selftests/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/tools/testing/selftests/memfd/.gitignore b/tools/testing/selftests/memfd/.gitignore new file mode 100644 index 000000000000..afe87c40ac80 --- /dev/null +++ b/tools/testing/selftests/memfd/.gitignore @@ -0,0 +1,4 @@ +fuse_mnt +fuse_test +memfd_test +memfd-test-file diff --git a/tools/testing/selftests/memfd/Makefile b/tools/testing/selftests/memfd/Makefile new file mode 100644 index 000000000000..6816c491c5ff --- /dev/null +++ b/tools/testing/selftests/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/tools/testing/selftests/memfd/fuse_mnt.c b/tools/testing/selftests/memfd/fuse_mnt.c new file mode 100644 index 000000000000..feacf1280fcd --- /dev/null +++ b/tools/testing/selftests/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 <fuse.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +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/tools/testing/selftests/memfd/fuse_test.c b/tools/testing/selftests/memfd/fuse_test.c new file mode 100644 index 000000000000..67908b18f035 --- /dev/null +++ b/tools/testing/selftests/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 <errno.h> +#include <inttypes.h> +#include <limits.h> +#include <linux/falloc.h> +#include <linux/fcntl.h> +#include <linux/memfd.h> +#include <sched.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/syscall.h> +#include <sys/wait.h> +#include <unistd.h> + +#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/tools/testing/selftests/memfd/memfd_test.c b/tools/testing/selftests/memfd/memfd_test.c new file mode 100644 index 000000000000..3634c909b1b0 --- /dev/null +++ b/tools/testing/selftests/memfd/memfd_test.c @@ -0,0 +1,913 @@ +#define _GNU_SOURCE +#define __EXPORTED_HEADERS__ + +#include <errno.h> +#include <inttypes.h> +#include <limits.h> +#include <linux/falloc.h> +#include <linux/fcntl.h> +#include <linux/memfd.h> +#include <sched.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/syscall.h> +#include <unistd.h> + +#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/tools/testing/selftests/memfd/run_fuse_test.sh b/tools/testing/selftests/memfd/run_fuse_test.sh new file mode 100644 index 000000000000..69b930e1e041 --- /dev/null +++ b/tools/testing/selftests/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/tools/testing/selftests/memory-hotplug/Makefile b/tools/testing/selftests/memory-hotplug/Makefile index 058c76f5d102..d46b8d489cd2 100644 --- a/tools/testing/selftests/memory-hotplug/Makefile +++ b/tools/testing/selftests/memory-hotplug/Makefile @@ -1,6 +1,9 @@ all: run_tests: + @/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/tools/testing/selftests/memory-hotplug/on-off-test.sh b/tools/testing/selftests/memory-hotplug/on-off-test.sh index a2816f631542..6cddde0b96f8 100644 --- a/tools/testing/selftests/memory-hotplug/on-off-test.sh +++ b/tools/testing/selftests/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/tools/testing/selftests/mount/Makefile b/tools/testing/selftests/mount/Makefile new file mode 100644 index 000000000000..337d853c2b72 --- /dev/null +++ b/tools/testing/selftests/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/tools/testing/selftests/mount/unprivileged-remount-test.c b/tools/testing/selftests/mount/unprivileged-remount-test.c new file mode 100644 index 000000000000..1b3ff2fda4d0 --- /dev/null +++ b/tools/testing/selftests/mount/unprivileged-remount-test.c @@ -0,0 +1,242 @@ +#define _GNU_SOURCE +#include <sched.h> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/mount.h> +#include <sys/wait.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <grp.h> +#include <stdbool.h> +#include <stdarg.h> + +#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/tools/testing/selftests/mqueue/Makefile b/tools/testing/selftests/mqueue/Makefile index 218a122c7951..8056e2e68fa4 100644 --- a/tools/testing/selftests/mqueue/Makefile +++ b/tools/testing/selftests/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/tools/testing/selftests/mqueue/mq_open_tests.c b/tools/testing/selftests/mqueue/mq_open_tests.c index 711cc2923047..9c1a5d359055 100644 --- a/tools/testing/selftests/mqueue/mq_open_tests.c +++ b/tools/testing/selftests/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/tools/testing/selftests/mqueue/mq_perf_tests.c b/tools/testing/selftests/mqueue/mq_perf_tests.c index 2fadd4b97045..94dae65eea41 100644 --- a/tools/testing/selftests/mqueue/mq_perf_tests.c +++ b/tools/testing/selftests/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/tools/testing/selftests/powerpc/Makefile b/tools/testing/selftests/powerpc/Makefile index 54833a791a44..74a78cedce37 100644 --- a/tools/testing/selftests/powerpc/Makefile +++ b/tools/testing/selftests/powerpc/Makefile @@ -17,10 +17,10 @@ TARGETS = pmu copyloops mm tm endif -all: - @for TARGET in $(TARGETS); do \ - $(MAKE) -C $$TARGET all; \ - done; +all: $(TARGETS) + +$(TARGETS): + $(MAKE) -k -C $@ all run_tests: all @for TARGET in $(TARGETS); do \ @@ -36,4 +36,4 @@ clean: tags: find . -name '*.c' -o -name '*.h' | xargs ctags -.PHONY: all run_tests clean tags +.PHONY: all run_tests clean tags $(TARGETS) diff --git a/tools/testing/selftests/powerpc/pmu/Makefile b/tools/testing/selftests/powerpc/pmu/Makefile index b9ff0db42c79..c9f4263906a5 100644 --- a/tools/testing/selftests/powerpc/pmu/Makefile +++ b/tools/testing/selftests/powerpc/pmu/Makefile @@ -1,10 +1,12 @@ noarg: $(MAKE) -C ../ -PROGS := count_instructions -EXTRA_SOURCES := ../harness.c event.c +PROGS := count_instructions l3_bank_test per_event_excludes +EXTRA_SOURCES := ../harness.c event.c lib.c -all: $(PROGS) sub_all +SUB_TARGETS = ebb + +all: $(PROGS) $(SUB_TARGETS) $(PROGS): $(EXTRA_SOURCES) @@ -20,13 +22,8 @@ run_tests: all sub_run_tests clean: sub_clean rm -f $(PROGS) loop.o - -SUB_TARGETS = ebb - -sub_all: - @for TARGET in $(SUB_TARGETS); do \ - $(MAKE) -C $$TARGET all; \ - done; +$(SUB_TARGETS): + $(MAKE) -k -C $@ all sub_run_tests: all @for TARGET in $(SUB_TARGETS); do \ @@ -38,4 +35,4 @@ sub_clean: $(MAKE) -C $$TARGET clean; \ done; -.PHONY: all run_tests clean sub_all sub_run_tests sub_clean +.PHONY: all run_tests clean sub_run_tests sub_clean $(SUB_TARGETS) diff --git a/tools/testing/selftests/powerpc/pmu/count_instructions.c b/tools/testing/selftests/powerpc/pmu/count_instructions.c index 312b4f0fd27c..4622117b24c0 100644 --- a/tools/testing/selftests/powerpc/pmu/count_instructions.c +++ b/tools/testing/selftests/powerpc/pmu/count_instructions.c @@ -12,6 +12,7 @@ #include "event.h" #include "utils.h" +#include "lib.h" extern void thirty_two_instruction_loop(u64 loops); @@ -90,7 +91,7 @@ static u64 determine_overhead(struct event *events) return overhead; } -static int count_instructions(void) +static int test_body(void) { struct event events[2]; u64 overhead; @@ -111,17 +112,23 @@ static int count_instructions(void) overhead = determine_overhead(events); printf("Overhead of null loop: %llu instructions\n", overhead); - /* Run for 1M instructions */ - FAIL_IF(do_count_loop(events, 0x100000, overhead, true)); + /* 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 10M instructions */ - FAIL_IF(do_count_loop(events, 0xa00000, overhead, true)); + /* Run for 1Bi instructions */ + FAIL_IF(do_count_loop(events, 1000000000, overhead, true)); - /* Run for 100M instructions */ - FAIL_IF(do_count_loop(events, 0x6400000, overhead, true)); + /* Run for 16Bi instructions */ + FAIL_IF(do_count_loop(events, 16000000000, overhead, true)); - /* Run for 1G instructions */ - FAIL_IF(do_count_loop(events, 0x40000000, overhead, true)); + /* Run for 64Bi instructions */ + FAIL_IF(do_count_loop(events, 64000000000, overhead, true)); event_close(&events[0]); event_close(&events[1]); @@ -129,6 +136,11 @@ static int count_instructions(void) 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/tools/testing/selftests/powerpc/pmu/ebb/Makefile b/tools/testing/selftests/powerpc/pmu/ebb/Makefile index edbba2affc2c..3dc4332698cb 100644 --- a/tools/testing/selftests/powerpc/pmu/ebb/Makefile +++ b/tools/testing/selftests/powerpc/pmu/ebb/Makefile @@ -13,11 +13,12 @@ PROGS := reg_access_test event_attributes_test cycles_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 + 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 +$(PROGS): ../../harness.c ../event.c ../lib.c ebb.c ebb_handler.S trace.c busy_loop.S instruction_count_test: ../loop.S diff --git a/tools/testing/selftests/powerpc/pmu/ebb/busy_loop.S b/tools/testing/selftests/powerpc/pmu/ebb/busy_loop.S new file mode 100644 index 000000000000..c7e4093f1cd3 --- /dev/null +++ b/tools/testing/selftests/powerpc/pmu/ebb/busy_loop.S @@ -0,0 +1,271 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include <ppc-asm.h> + + .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/tools/testing/selftests/powerpc/pmu/ebb/cycles_with_mmcr2_test.c b/tools/testing/selftests/powerpc/pmu/ebb/cycles_with_mmcr2_test.c new file mode 100644 index 000000000000..d43029b0800c --- /dev/null +++ b/tools/testing/selftests/powerpc/pmu/ebb/cycles_with_mmcr2_test.c @@ -0,0 +1,91 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> + +#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/tools/testing/selftests/powerpc/pmu/ebb/ebb.c b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c index 1b46be94b64c..d7a72ce696b5 100644 --- a/tools/testing/selftests/powerpc/pmu/ebb/ebb.c +++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb.c @@ -224,6 +224,7 @@ void dump_ebb_hw_state(void) 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" \ @@ -233,10 +234,11 @@ void dump_ebb_hw_state(void) "PMC5 0x%016lx\n" \ "PMC6 0x%016lx\n" \ "SIAR 0x%016lx\n", - mmcr0, decode_mmcr0(mmcr0), 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)); + 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) @@ -335,257 +337,6 @@ void event_leader_ebb_init(struct event *e) e->attr.pinned = 1; } -int core_busy_loop(void) -{ - int rc; - - asm volatile ( - "li 3, 0x3030\n" - "std 3, -96(1)\n" - "li 4, 0x4040\n" - "std 4, -104(1)\n" - "li 5, 0x5050\n" - "std 5, -112(1)\n" - "li 6, 0x6060\n" - "std 6, -120(1)\n" - "li 7, 0x7070\n" - "std 7, -128(1)\n" - "li 8, 0x0808\n" - "std 8, -136(1)\n" - "li 9, 0x0909\n" - "std 9, -144(1)\n" - "li 10, 0x1010\n" - "std 10, -152(1)\n" - "li 11, 0x1111\n" - "std 11, -160(1)\n" - "li 14, 0x1414\n" - "std 14, -168(1)\n" - "li 15, 0x1515\n" - "std 15, -176(1)\n" - "li 16, 0x1616\n" - "std 16, -184(1)\n" - "li 17, 0x1717\n" - "std 17, -192(1)\n" - "li 18, 0x1818\n" - "std 18, -200(1)\n" - "li 19, 0x1919\n" - "std 19, -208(1)\n" - "li 20, 0x2020\n" - "std 20, -216(1)\n" - "li 21, 0x2121\n" - "std 21, -224(1)\n" - "li 22, 0x2222\n" - "std 22, -232(1)\n" - "li 23, 0x2323\n" - "std 23, -240(1)\n" - "li 24, 0x2424\n" - "std 24, -248(1)\n" - "li 25, 0x2525\n" - "std 25, -256(1)\n" - "li 26, 0x2626\n" - "std 26, -264(1)\n" - "li 27, 0x2727\n" - "std 27, -272(1)\n" - "li 28, 0x2828\n" - "std 28, -280(1)\n" - "li 29, 0x2929\n" - "std 29, -288(1)\n" - "li 30, 0x3030\n" - "li 31, 0x3131\n" - - "li 3, 0\n" - "0: " - "addi 3, 3, 1\n" - "cmpwi 3, 100\n" - "blt 0b\n" - - /* Return 1 (fail) unless we get through all the checks */ - "li 0, 1\n" - - /* Check none of our registers have been corrupted */ - "cmpwi 4, 0x4040\n" - "bne 1f\n" - "cmpwi 5, 0x5050\n" - "bne 1f\n" - "cmpwi 6, 0x6060\n" - "bne 1f\n" - "cmpwi 7, 0x7070\n" - "bne 1f\n" - "cmpwi 8, 0x0808\n" - "bne 1f\n" - "cmpwi 9, 0x0909\n" - "bne 1f\n" - "cmpwi 10, 0x1010\n" - "bne 1f\n" - "cmpwi 11, 0x1111\n" - "bne 1f\n" - "cmpwi 14, 0x1414\n" - "bne 1f\n" - "cmpwi 15, 0x1515\n" - "bne 1f\n" - "cmpwi 16, 0x1616\n" - "bne 1f\n" - "cmpwi 17, 0x1717\n" - "bne 1f\n" - "cmpwi 18, 0x1818\n" - "bne 1f\n" - "cmpwi 19, 0x1919\n" - "bne 1f\n" - "cmpwi 20, 0x2020\n" - "bne 1f\n" - "cmpwi 21, 0x2121\n" - "bne 1f\n" - "cmpwi 22, 0x2222\n" - "bne 1f\n" - "cmpwi 23, 0x2323\n" - "bne 1f\n" - "cmpwi 24, 0x2424\n" - "bne 1f\n" - "cmpwi 25, 0x2525\n" - "bne 1f\n" - "cmpwi 26, 0x2626\n" - "bne 1f\n" - "cmpwi 27, 0x2727\n" - "bne 1f\n" - "cmpwi 28, 0x2828\n" - "bne 1f\n" - "cmpwi 29, 0x2929\n" - "bne 1f\n" - "cmpwi 30, 0x3030\n" - "bne 1f\n" - "cmpwi 31, 0x3131\n" - "bne 1f\n" - - /* Load junk into all our registers before we reload them from the stack. */ - "li 3, 0xde\n" - "li 4, 0xad\n" - "li 5, 0xbe\n" - "li 6, 0xef\n" - "li 7, 0xde\n" - "li 8, 0xad\n" - "li 9, 0xbe\n" - "li 10, 0xef\n" - "li 11, 0xde\n" - "li 14, 0xad\n" - "li 15, 0xbe\n" - "li 16, 0xef\n" - "li 17, 0xde\n" - "li 18, 0xad\n" - "li 19, 0xbe\n" - "li 20, 0xef\n" - "li 21, 0xde\n" - "li 22, 0xad\n" - "li 23, 0xbe\n" - "li 24, 0xef\n" - "li 25, 0xde\n" - "li 26, 0xad\n" - "li 27, 0xbe\n" - "li 28, 0xef\n" - "li 29, 0xdd\n" - - "ld 3, -96(1)\n" - "cmpwi 3, 0x3030\n" - "bne 1f\n" - "ld 4, -104(1)\n" - "cmpwi 4, 0x4040\n" - "bne 1f\n" - "ld 5, -112(1)\n" - "cmpwi 5, 0x5050\n" - "bne 1f\n" - "ld 6, -120(1)\n" - "cmpwi 6, 0x6060\n" - "bne 1f\n" - "ld 7, -128(1)\n" - "cmpwi 7, 0x7070\n" - "bne 1f\n" - "ld 8, -136(1)\n" - "cmpwi 8, 0x0808\n" - "bne 1f\n" - "ld 9, -144(1)\n" - "cmpwi 9, 0x0909\n" - "bne 1f\n" - "ld 10, -152(1)\n" - "cmpwi 10, 0x1010\n" - "bne 1f\n" - "ld 11, -160(1)\n" - "cmpwi 11, 0x1111\n" - "bne 1f\n" - "ld 14, -168(1)\n" - "cmpwi 14, 0x1414\n" - "bne 1f\n" - "ld 15, -176(1)\n" - "cmpwi 15, 0x1515\n" - "bne 1f\n" - "ld 16, -184(1)\n" - "cmpwi 16, 0x1616\n" - "bne 1f\n" - "ld 17, -192(1)\n" - "cmpwi 17, 0x1717\n" - "bne 1f\n" - "ld 18, -200(1)\n" - "cmpwi 18, 0x1818\n" - "bne 1f\n" - "ld 19, -208(1)\n" - "cmpwi 19, 0x1919\n" - "bne 1f\n" - "ld 20, -216(1)\n" - "cmpwi 20, 0x2020\n" - "bne 1f\n" - "ld 21, -224(1)\n" - "cmpwi 21, 0x2121\n" - "bne 1f\n" - "ld 22, -232(1)\n" - "cmpwi 22, 0x2222\n" - "bne 1f\n" - "ld 23, -240(1)\n" - "cmpwi 23, 0x2323\n" - "bne 1f\n" - "ld 24, -248(1)\n" - "cmpwi 24, 0x2424\n" - "bne 1f\n" - "ld 25, -256(1)\n" - "cmpwi 25, 0x2525\n" - "bne 1f\n" - "ld 26, -264(1)\n" - "cmpwi 26, 0x2626\n" - "bne 1f\n" - "ld 27, -272(1)\n" - "cmpwi 27, 0x2727\n" - "bne 1f\n" - "ld 28, -280(1)\n" - "cmpwi 28, 0x2828\n" - "bne 1f\n" - "ld 29, -288(1)\n" - "cmpwi 29, 0x2929\n" - "bne 1f\n" - - /* Load 0 (success) to return */ - "li 0, 0\n" - - "1: mr %0, 0\n" - - : "=r" (rc) - : /* no inputs */ - : "3", "4", "5", "6", "7", "8", "9", "10", "11", "14", - "15", "16", "17", "18", "19", "20", "21", "22", "23", - "24", "25", "26", "27", "28", "29", "30", "31", - "memory" - ); - - return rc; -} - -int core_busy_loop_with_freeze(void) -{ - int rc; - - mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) & ~MMCR0_FC); - rc = core_busy_loop(); - mtspr(SPRN_MMCR0, mfspr(SPRN_MMCR0) | MMCR0_FC); - - return rc; -} - int ebb_child(union pipe read_pipe, union pipe write_pipe) { struct event event; diff --git a/tools/testing/selftests/powerpc/pmu/ebb/ebb.h b/tools/testing/selftests/powerpc/pmu/ebb/ebb.h index e62bde05bf78..e44eee5d97ca 100644 --- a/tools/testing/selftests/powerpc/pmu/ebb/ebb.h +++ b/tools/testing/selftests/powerpc/pmu/ebb/ebb.h @@ -70,7 +70,6 @@ int ebb_check_mmcr0(void); extern u64 sample_period; int core_busy_loop(void); -int core_busy_loop_with_freeze(void); int ebb_child(union pipe read_pipe, union pipe write_pipe); int catch_sigill(void (*func)(void)); void write_pmc1(void); diff --git a/tools/testing/selftests/powerpc/pmu/l3_bank_test.c b/tools/testing/selftests/powerpc/pmu/l3_bank_test.c new file mode 100644 index 000000000000..77472f31441e --- /dev/null +++ b/tools/testing/selftests/powerpc/pmu/l3_bank_test.c @@ -0,0 +1,48 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#include <stdio.h> +#include <stdlib.h> + +#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/tools/testing/selftests/powerpc/pmu/lib.c b/tools/testing/selftests/powerpc/pmu/lib.c index 0f6a4731d546..9768dea37bf3 100644 --- a/tools/testing/selftests/powerpc/pmu/lib.c +++ b/tools/testing/selftests/powerpc/pmu/lib.c @@ -5,10 +5,15 @@ #define _GNU_SOURCE /* For CPU_ZERO etc. */ +#include <elf.h> #include <errno.h> +#include <fcntl.h> +#include <link.h> #include <sched.h> #include <setjmp.h> #include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> #include <sys/wait.h> #include "utils.h" @@ -177,8 +182,8 @@ struct addr_range libc, vdso; int parse_proc_maps(void) { + unsigned long start, end; char execute, name[128]; - uint64_t start, end; FILE *f; int rc; @@ -250,3 +255,46 @@ out_close: 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/tools/testing/selftests/powerpc/pmu/lib.h b/tools/testing/selftests/powerpc/pmu/lib.h index ca5d72ae3be6..0f0339c8a6f6 100644 --- a/tools/testing/selftests/powerpc/pmu/lib.h +++ b/tools/testing/selftests/powerpc/pmu/lib.h @@ -29,6 +29,7 @@ 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; diff --git a/tools/testing/selftests/powerpc/pmu/per_event_excludes.c b/tools/testing/selftests/powerpc/pmu/per_event_excludes.c new file mode 100644 index 000000000000..fddbbc9cae2f --- /dev/null +++ b/tools/testing/selftests/powerpc/pmu/per_event_excludes.c @@ -0,0 +1,114 @@ +/* + * Copyright 2014, Michael Ellerman, IBM Corp. + * Licensed under GPLv2. + */ + +#define _GNU_SOURCE + +#include <elf.h> +#include <limits.h> +#include <stdio.h> +#include <stdbool.h> +#include <string.h> +#include <sys/prctl.h> + +#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/tools/testing/selftests/ptrace/peeksiginfo.c b/tools/testing/selftests/ptrace/peeksiginfo.c index d46558b1f58d..c34cd8ac8aaa 100644 --- a/tools/testing/selftests/ptrace/peeksiginfo.c +++ b/tools/testing/selftests/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/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh index ee1f6cae3d70..3f6c9b78d177 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh @@ -54,10 +54,16 @@ do 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 - echo " $i" fi done done diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh index 27e544e29510..0f69dcbf9def 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh @@ -42,6 +42,7 @@ grace=120 T=/tmp/kvm-test-1-run.sh.$$ trap 'rm -rf $T' 0 +touch $T . $KVM/bin/functions.sh . $KVPATH/ver_functions.sh @@ -131,7 +132,10 @@ boot_args=$6 cd $KVM kstarttime=`awk 'BEGIN { print systime() }' < /dev/null` -echo ' ---' `date`: Starting kernel +if test -z "$TORTURE_BUILDONLY" +then + echo ' ---' `date`: Starting kernel +fi # Generate -smp qemu argument. qemu_args="-nographic $qemu_args" @@ -157,12 +161,13 @@ 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`" -echo $QEMU $qemu_args -m 512 -kernel $builddir/$BOOT_IMAGE -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd 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 diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index 40285c58653e..589e9c38413b 100644 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh @@ -340,12 +340,18 @@ function dump(first, pastlast) for (j = 1; j < jn; j++) { builddir=KVM "/b" j print "rm -f " builddir ".ready" - print "echo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date`"; - print "echo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date` >> " rd "/log"; + 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 "echo ---- All kernel runs complete. `date`"; - print "echo ---- All kernel runs complete. `date` >> " rd "/log"; + 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:"; @@ -385,10 +391,7 @@ echo echo echo " --- `date` Test summary:" echo Results directory: $resdir/$ds -if test -z "$TORTURE_BUILDONLY" -then - kvm-recheck.sh $resdir/$ds -fi +kvm-recheck.sh $resdir/$ds ___EOF___ if test "$dryrun" = script @@ -403,7 +406,7 @@ then sed -e 's/:.*$//' -e 's/^echo //' exit 0 else - # Not a dryru, so run the script. + # Not a dryrun, so run the script. sh $T/script fi diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE01 b/tools/testing/selftests/rcutorture/configs/rcu/TREE01 index 9c827ec59a97..063b7079c621 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE01 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE01 @@ -15,7 +15,6 @@ CONFIG_RCU_FANOUT_EXACT=n CONFIG_RCU_NOCB_CPU=y CONFIG_RCU_NOCB_CPU_ZERO=y CONFIG_DEBUG_LOCK_ALLOC=n -CONFIG_PROVE_RCU_DELAY=n CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_RCU_BOOST=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE02 b/tools/testing/selftests/rcutorture/configs/rcu/TREE02 index 1a777b5f68b5..ea119ba2f7d4 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE02 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE02 @@ -18,7 +18,6 @@ CONFIG_RCU_FANOUT_EXACT=n CONFIG_RCU_NOCB_CPU=n CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=n -CONFIG_PROVE_RCU_DELAY=n CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_CPU_STALL_VERBOSE=y CONFIG_RCU_BOOST=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T b/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T index 61c8d9ce5bb2..19cf9485f48a 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T @@ -18,7 +18,6 @@ CONFIG_RCU_FANOUT_EXACT=n CONFIG_RCU_NOCB_CPU=n CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=n -CONFIG_PROVE_RCU_DELAY=n CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_CPU_STALL_VERBOSE=y CONFIG_RCU_BOOST=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE03 b/tools/testing/selftests/rcutorture/configs/rcu/TREE03 index c1f111c1561b..f4567fb3e332 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE03 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE03 @@ -14,7 +14,6 @@ CONFIG_RCU_FANOUT_LEAF=4 CONFIG_RCU_FANOUT_EXACT=n CONFIG_RCU_NOCB_CPU=n CONFIG_DEBUG_LOCK_ALLOC=n -CONFIG_PROVE_RCU_DELAY=n CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_RCU_BOOST=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 b/tools/testing/selftests/rcutorture/configs/rcu/TREE04 index 7dbd27ce17a4..0a262fbb0c12 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04 @@ -18,7 +18,6 @@ CONFIG_RCU_FANOUT_LEAF=2 CONFIG_RCU_FANOUT_EXACT=n CONFIG_RCU_NOCB_CPU=n CONFIG_DEBUG_LOCK_ALLOC=n -CONFIG_PROVE_RCU_DELAY=n CONFIG_RCU_CPU_STALL_INFO=y CONFIG_RCU_CPU_STALL_VERBOSE=y CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE05 b/tools/testing/selftests/rcutorture/configs/rcu/TREE05 index d0f32e574743..3a06b97e9a73 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE05 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE05 @@ -18,7 +18,6 @@ CONFIG_RCU_NOCB_CPU_NONE=y CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y CONFIG_PROVE_RCU=y -CONFIG_PROVE_RCU_DELAY=y CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE06 b/tools/testing/selftests/rcutorture/configs/rcu/TREE06 index 2e477dfb9c57..8f084cca91bf 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE06 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE06 @@ -19,7 +19,6 @@ CONFIG_RCU_NOCB_CPU=n CONFIG_DEBUG_LOCK_ALLOC=y CONFIG_PROVE_LOCKING=y CONFIG_PROVE_RCU=y -CONFIG_PROVE_RCU_DELAY=n CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 b/tools/testing/selftests/rcutorture/configs/rcu/TREE07 index 042f86ef362a..ab6225506909 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE07 @@ -17,7 +17,6 @@ CONFIG_RCU_FANOUT_LEAF=2 CONFIG_RCU_FANOUT_EXACT=n CONFIG_RCU_NOCB_CPU=n CONFIG_DEBUG_LOCK_ALLOC=n -CONFIG_PROVE_RCU_DELAY=n CONFIG_RCU_CPU_STALL_INFO=y CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_DEBUG_OBJECTS_RCU_HEAD=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08 b/tools/testing/selftests/rcutorture/configs/rcu/TREE08 index 3438cee1e3c5..69a2e255bf98 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE08 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08 @@ -18,7 +18,6 @@ CONFIG_RCU_FANOUT_LEAF=2 CONFIG_RCU_NOCB_CPU=y CONFIG_RCU_NOCB_CPU_ALL=y CONFIG_DEBUG_LOCK_ALLOC=n -CONFIG_PROVE_RCU_DELAY=n CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_RCU_BOOST=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T b/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T index bf4523d3e44c..a0f32fb8f17e 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T @@ -18,7 +18,6 @@ CONFIG_RCU_FANOUT_LEAF=2 CONFIG_RCU_NOCB_CPU=y CONFIG_RCU_NOCB_CPU_ALL=y CONFIG_DEBUG_LOCK_ALLOC=n -CONFIG_PROVE_RCU_DELAY=n CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_RCU_BOOST=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE09 b/tools/testing/selftests/rcutorture/configs/rcu/TREE09 index 81e4f7c0bf0b..b7a62a540ad1 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE09 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE09 @@ -13,7 +13,6 @@ CONFIG_SUSPEND=n CONFIG_HIBERNATION=n CONFIG_RCU_NOCB_CPU=n CONFIG_DEBUG_LOCK_ALLOC=n -CONFIG_PROVE_RCU_DELAY=n CONFIG_RCU_CPU_STALL_INFO=n CONFIG_RCU_CPU_STALL_VERBOSE=n CONFIG_RCU_BOOST=n diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp index ef624ce73d8e..a55c00877fe4 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp +++ b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp @@ -13,7 +13,6 @@ CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y #CHECK#CONFIG_TREE_PREEMPT_RCU=y CONFIG_DEBUG_KERNEL=y -CONFIG_PROVE_RCU_DELAY=y CONFIG_DEBUG_OBJECTS=y CONFIG_DEBUG_OBJECTS_RCU_HEAD=y CONFIG_RT_MUTEXES=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp index ef624ce73d8e..a55c00877fe4 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp @@ -13,7 +13,6 @@ CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y #CHECK#CONFIG_TREE_PREEMPT_RCU=y CONFIG_DEBUG_KERNEL=y -CONFIG_PROVE_RCU_DELAY=y CONFIG_DEBUG_OBJECTS=y CONFIG_DEBUG_OBJECTS_RCU_HEAD=y CONFIG_RT_MUTEXES=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp index ef624ce73d8e..a55c00877fe4 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp @@ -13,7 +13,6 @@ CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y #CHECK#CONFIG_TREE_PREEMPT_RCU=y CONFIG_DEBUG_KERNEL=y -CONFIG_PROVE_RCU_DELAY=y CONFIG_DEBUG_OBJECTS=y CONFIG_DEBUG_OBJECTS_RCU_HEAD=y CONFIG_RT_MUTEXES=y diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp index ef624ce73d8e..a55c00877fe4 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp +++ b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp @@ -13,7 +13,6 @@ CONFIG_PREEMPT_VOLUNTARY=n CONFIG_PREEMPT=y #CHECK#CONFIG_TREE_PREEMPT_RCU=y CONFIG_DEBUG_KERNEL=y -CONFIG_PROVE_RCU_DELAY=y CONFIG_DEBUG_OBJECTS=y CONFIG_DEBUG_OBJECTS_RCU_HEAD=y CONFIG_RT_MUTEXES=y diff --git a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt index adbb76cffb49..3e588db86a17 100644 --- a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt +++ b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt @@ -14,7 +14,6 @@ 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_PROVE_RCU_DELAY -- Do one. 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. |