Commit d93a74a9 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'linux-kselftest-4.2-rc1' of...

Merge tag 'linux-kselftest-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest

Pull kselftest update from Shuah Khan:
 "This update adds two new test suites: futex and seccomp.

  In addition, it includes fixes for bugs in timers, other tests, and
  compile framework.  It introduces new quicktest feature to enable
  users to choose to run tests that complete in a short time"

* tag 'linux-kselftest-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest:
  selftests: add quicktest support
  selftests: add seccomp suite
  selftest, x86: fix incorrect comment
  tools selftests: Fix 'clean' target with make 3.81
  selftests/futex: Add .gitignore
  kselftest: Add exit code defines
  selftests: Add futex tests to the top-level Makefile
  selftests/futex: Increment ksft pass and fail counters
  selftests/futex: Update Makefile to use lib.mk
  selftests: Add futex functional tests
  kselftests: timers: Check _ALARM clockids are supported before suspending
  kselftests: timers: Ease alarmtimer-suspend unreasonable latency value
  kselftests: timers: Increase delay between suspends in alarmtimer-suspend
  selftests/exec: do not install subdir as it is already created
  selftests/ftrace: install test.d
  selftests: copy TEST_DIRS to INSTALL_PATH
  Test compaction of mlocked memory
  selftests/mount: output WARN messages when mount test skipped
  selftests/timers: Make git ignore all binaries in timers test suite
parents c63f887b 2278e5ed
...@@ -8986,6 +8986,7 @@ S: Supported ...@@ -8986,6 +8986,7 @@ S: Supported
F: kernel/seccomp.c F: kernel/seccomp.c
F: include/uapi/linux/seccomp.h F: include/uapi/linux/seccomp.h
F: include/linux/seccomp.h F: include/linux/seccomp.h
F: tools/testing/selftests/seccomp/*
K: \bsecure_computing K: \bsecure_computing
K: \bTIF_SECCOMP\b K: \bTIF_SECCOMP\b
......
...@@ -4,6 +4,7 @@ TARGETS += efivarfs ...@@ -4,6 +4,7 @@ TARGETS += efivarfs
TARGETS += exec TARGETS += exec
TARGETS += firmware TARGETS += firmware
TARGETS += ftrace TARGETS += ftrace
TARGETS += futex
TARGETS += kcmp TARGETS += kcmp
TARGETS += memfd TARGETS += memfd
TARGETS += memory-hotplug TARGETS += memory-hotplug
...@@ -12,13 +13,18 @@ TARGETS += mqueue ...@@ -12,13 +13,18 @@ TARGETS += mqueue
TARGETS += net TARGETS += net
TARGETS += powerpc TARGETS += powerpc
TARGETS += ptrace TARGETS += ptrace
TARGETS += seccomp
TARGETS += size TARGETS += size
TARGETS += sysctl TARGETS += sysctl
ifneq (1, $(quicktest))
TARGETS += timers TARGETS += timers
endif
TARGETS += user TARGETS += user
TARGETS += vm TARGETS += vm
TARGETS += x86 TARGETS += x86
#Please keep the TARGETS list alphabetically sorted #Please keep the TARGETS list alphabetically sorted
# Run "make quicktest=1 run_tests" or
# "make quicktest=1 kselftest from top level Makefile
TARGETS_HOTPLUG = cpu-hotplug TARGETS_HOTPLUG = cpu-hotplug
TARGETS_HOTPLUG += memory-hotplug TARGETS_HOTPLUG += memory-hotplug
...@@ -27,7 +33,7 @@ TARGETS_HOTPLUG += memory-hotplug ...@@ -27,7 +33,7 @@ TARGETS_HOTPLUG += memory-hotplug
# Makefile to avoid test build failures when test # Makefile to avoid test build failures when test
# Makefile doesn't have explicit build rules. # Makefile doesn't have explicit build rules.
ifeq (1,$(MAKELEVEL)) ifeq (1,$(MAKELEVEL))
undefine LDFLAGS override LDFLAGS =
override MAKEFLAGS = override MAKEFLAGS =
endif endif
......
CFLAGS = -Wall CFLAGS = -Wall
BINARIES = execveat BINARIES = execveat
DEPS = execveat.symlink execveat.denatured script subdir DEPS = execveat.symlink execveat.denatured script
all: $(BINARIES) $(DEPS) all: $(BINARIES) $(DEPS)
subdir: subdir:
......
all: all:
TEST_PROGS := ftracetest TEST_PROGS := ftracetest
TEST_DIRS := test.d/
include ../lib.mk include ../lib.mk
......
SUBDIRS := functional
TEST_PROGS := run.sh
.PHONY: all clean
all:
for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done
include ../lib.mk
override define RUN_TESTS
./run.sh
endef
override define INSTALL_RULE
mkdir -p $(INSTALL_PATH)
install -t $(INSTALL_PATH) $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES)
@for SUBDIR in $(SUBDIRS); do \
$(MAKE) -C $$SUBDIR INSTALL_PATH=$(INSTALL_PATH)/$$SUBDIR install; \
done;
endef
override define EMIT_TESTS
echo "./run.sh"
endef
clean:
for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done
Futex Test
==========
Futex Test is intended to thoroughly test the Linux kernel futex system call
API.
Functional tests shall test the documented behavior of the futex operation
code under test. This includes checking for proper behavior under normal use,
odd corner cases, regression tests, and abject abuse and misuse.
Futextest will also provide example implementation of mutual exclusion
primitives. These can be used as is in user applications or can serve as
examples for system libraries. These will likely be added to either a new lib/
directory or purely as header files under include/, I'm leaning toward the
latter.
Quick Start
-----------
# make
# ./run.sh
Design and Implementation Goals
-------------------------------
o Tests should be as self contained as is practical so as to facilitate sharing
the individual tests on mailing list discussions and bug reports.
o The build system shall remain as simple as possible, avoiding any archive or
shared object building and linking.
o Where possible, any helper functions or other package-wide code shall be
implemented in header files, avoiding the need to compile intermediate object
files.
o External dependendencies shall remain as minimal as possible. Currently gcc
and glibc are the only dependencies.
o Tests return 0 for success and < 0 for failure.
Output Formatting
-----------------
Test output shall be easily parsable by both human and machine. Title and
results are printed to stdout, while intermediate ERROR or FAIL messages are
sent to stderr. Tests shall support the -c option to print PASS, FAIL, and
ERROR strings in color for easy visual parsing. Output shall conform to the
following format:
test_name: Description of the test
Arguments: arg1=val1 #units specified for clarity where appropriate
ERROR: Description of unexpected error
FAIL: Reason for test failure
# FIXME: Perhaps an " INFO: informational message" option would be
# useful here. Using -v to toggle it them on and off, as with -c.
# there may be multiple ERROR or FAIL messages
Result: (PASS|FAIL|ERROR)
Naming
------
o FIXME: decide on a sane test naming scheme. Currently the tests are named
based on the primary futex operation they test. Eventually this will become a
problem as we intend to write multiple tests which collide in this namespace.
Perhaps something like "wait-wake-1" "wait-wake-2" is adequate, leaving the
detailed description in the test source and the output.
Coding Style
------------
o The Futex Test project adheres to the coding standards set forth by Linux
kernel as defined in the Linux source Documentation/CodingStyle.
futex_requeue_pi
futex_requeue_pi_mismatched_ops
futex_requeue_pi_signal_restart
futex_wait_private_mapped_file
futex_wait_timeout
futex_wait_uninitialized_heap
futex_wait_wouldblock
INCLUDES := -I../include -I../../
CFLAGS := $(CFLAGS) -g -O2 -Wall -D_GNU_SOURCE -pthread $(INCLUDES)
LDFLAGS := $(LDFLAGS) -pthread -lrt
HEADERS := ../include/futextest.h
TARGETS := \
futex_wait_timeout \
futex_wait_wouldblock \
futex_requeue_pi \
futex_requeue_pi_signal_restart \
futex_requeue_pi_mismatched_ops \
futex_wait_uninitialized_heap \
futex_wait_private_mapped_file
TEST_PROGS := $(TARGETS) run.sh
.PHONY: all clean
all: $(TARGETS)
$(TARGETS): $(HEADERS)
include ../../lib.mk
clean:
rm -f $(TARGETS)
This diff is collapsed.
/******************************************************************************
*
* Copyright © International Business Machines Corp., 2009
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* DESCRIPTION
* 1. Block a thread using FUTEX_WAIT
* 2. Attempt to use FUTEX_CMP_REQUEUE_PI on the futex from 1.
* 3. The kernel must detect the mismatch and return -EINVAL.
*
* AUTHOR
* Darren Hart <dvhart@linux.intel.com>
*
* HISTORY
* 2009-Nov-9: Initial version by Darren Hart <dvhart@linux.intel.com>
*
*****************************************************************************/
#include <errno.h>
#include <getopt.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "futextest.h"
#include "logging.h"
futex_t f1 = FUTEX_INITIALIZER;
futex_t f2 = FUTEX_INITIALIZER;
int child_ret = 0;
void usage(char *prog)
{
printf("Usage: %s\n", prog);
printf(" -c Use color\n");
printf(" -h Display this help message\n");
printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n",
VQUIET, VCRITICAL, VINFO);
}
void *blocking_child(void *arg)
{
child_ret = futex_wait(&f1, f1, NULL, FUTEX_PRIVATE_FLAG);
if (child_ret < 0) {
child_ret = -errno;
error("futex_wait\n", errno);
}
return (void *)&child_ret;
}
int main(int argc, char *argv[])
{
int ret = RET_PASS;
pthread_t child;
int c;
while ((c = getopt(argc, argv, "chv:")) != -1) {
switch (c) {
case 'c':
log_color(1);
break;
case 'h':
usage(basename(argv[0]));
exit(0);
case 'v':
log_verbosity(atoi(optarg));
break;
default:
usage(basename(argv[0]));
exit(1);
}
}
printf("%s: Detect mismatched requeue_pi operations\n",
basename(argv[0]));
if (pthread_create(&child, NULL, blocking_child, NULL)) {
error("pthread_create\n", errno);
ret = RET_ERROR;
goto out;
}
/* Allow the child to block in the kernel. */
sleep(1);
/*
* The kernel should detect the waiter did not setup the
* q->requeue_pi_key and return -EINVAL. If it does not,
* it likely gave the lock to the child, which is now hung
* in the kernel.
*/
ret = futex_cmp_requeue_pi(&f1, f1, &f2, 1, 0, FUTEX_PRIVATE_FLAG);
if (ret < 0) {
if (errno == EINVAL) {
/*
* The kernel correctly detected the mismatched
* requeue_pi target and aborted. Wake the child with
* FUTEX_WAKE.
*/
ret = futex_wake(&f1, 1, FUTEX_PRIVATE_FLAG);
if (ret == 1) {
ret = RET_PASS;
} else if (ret < 0) {
error("futex_wake\n", errno);
ret = RET_ERROR;
} else {
error("futex_wake did not wake the child\n", 0);
ret = RET_ERROR;
}
} else {
error("futex_cmp_requeue_pi\n", errno);
ret = RET_ERROR;
}
} else if (ret > 0) {
fail("futex_cmp_requeue_pi failed to detect the mismatch\n");
ret = RET_FAIL;
} else {
error("futex_cmp_requeue_pi found no waiters\n", 0);
ret = RET_ERROR;
}
pthread_join(child, NULL);
if (!ret)
ret = child_ret;
out:
/* If the kernel crashes, we shouldn't return at all. */
print_result(ret);
return ret;
}
/******************************************************************************
*
* Copyright © International Business Machines Corp., 2006-2008
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* DESCRIPTION
* This test exercises the futex_wait_requeue_pi() signal handling both
* before and after the requeue. The first should be restarted by the
* kernel. The latter should return EWOULDBLOCK to the waiter.
*
* AUTHORS
* Darren Hart <dvhart@linux.intel.com>
*
* HISTORY
* 2008-May-5: Initial version by Darren Hart <dvhart@linux.intel.com>
*
*****************************************************************************/
#include <errno.h>
#include <getopt.h>
#include <limits.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "atomic.h"
#include "futextest.h"
#include "logging.h"
#define DELAY_US 100
futex_t f1 = FUTEX_INITIALIZER;
futex_t f2 = FUTEX_INITIALIZER;
atomic_t requeued = ATOMIC_INITIALIZER;
int waiter_ret = 0;
void usage(char *prog)
{
printf("Usage: %s\n", prog);
printf(" -c Use color\n");
printf(" -h Display this help message\n");
printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n",
VQUIET, VCRITICAL, VINFO);
}
int create_rt_thread(pthread_t *pth, void*(*func)(void *), void *arg,
int policy, int prio)
{
struct sched_param schedp;
pthread_attr_t attr;
int ret;
pthread_attr_init(&attr);
memset(&schedp, 0, sizeof(schedp));
ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
if (ret) {
error("pthread_attr_setinheritsched\n", ret);
return -1;
}
ret = pthread_attr_setschedpolicy(&attr, policy);
if (ret) {
error("pthread_attr_setschedpolicy\n", ret);
return -1;
}
schedp.sched_priority = prio;
ret = pthread_attr_setschedparam(&attr, &schedp);
if (ret) {
error("pthread_attr_setschedparam\n", ret);
return -1;
}
ret = pthread_create(pth, &attr, func, arg);
if (ret) {
error("pthread_create\n", ret);
return -1;
}
return 0;
}
void handle_signal(int signo)
{
info("signal received %s requeue\n",
requeued.val ? "after" : "prior to");
}
void *waiterfn(void *arg)
{
unsigned int old_val;
int res;
waiter_ret = RET_PASS;
info("Waiter running\n");
info("Calling FUTEX_LOCK_PI on f2=%x @ %p\n", f2, &f2);
old_val = f1;
res = futex_wait_requeue_pi(&f1, old_val, &(f2), NULL,
FUTEX_PRIVATE_FLAG);
if (!requeued.val || errno != EWOULDBLOCK) {
fail("unexpected return from futex_wait_requeue_pi: %d (%s)\n",
res, strerror(errno));
info("w2:futex: %x\n", f2);
if (!res)
futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG);
waiter_ret = RET_FAIL;
}
info("Waiter exiting with %d\n", waiter_ret);
pthread_exit(NULL);
}
int main(int argc, char *argv[])
{
unsigned int old_val;
struct sigaction sa;
pthread_t waiter;
int c, res, ret = RET_PASS;
while ((c = getopt(argc, argv, "chv:")) != -1) {
switch (c) {
case 'c':
log_color(1);
break;
case 'h':
usage(basename(argv[0]));
exit(0);
case 'v':
log_verbosity(atoi(optarg));
break;
default:
usage(basename(argv[0]));
exit(1);
}
}
printf("%s: Test signal handling during requeue_pi\n",
basename(argv[0]));
printf("\tArguments: <none>\n");
sa.sa_handler = handle_signal;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGUSR1, &sa, NULL)) {
error("sigaction\n", errno);
exit(1);
}
info("m1:f2: %x\n", f2);
info("Creating waiter\n");
res = create_rt_thread(&waiter, waiterfn, NULL, SCHED_FIFO, 1);
if (res) {
error("Creating waiting thread failed", res);
ret = RET_ERROR;
goto out;
}
info("Calling FUTEX_LOCK_PI on f2=%x @ %p\n", f2, &f2);
info("m2:f2: %x\n", f2);
futex_lock_pi(&f2, 0, 0, FUTEX_PRIVATE_FLAG);
info("m3:f2: %x\n", f2);
while (1) {
/*
* signal the waiter before requeue, waiter should automatically
* restart futex_wait_requeue_pi() in the kernel. Wait for the
* waiter to block on f1 again.
*/
info("Issuing SIGUSR1 to waiter\n");
pthread_kill(waiter, SIGUSR1);
usleep(DELAY_US);
info("Requeueing waiter via FUTEX_CMP_REQUEUE_PI\n");
old_val = f1;
res = futex_cmp_requeue_pi(&f1, old_val, &(f2), 1, 0,
FUTEX_PRIVATE_FLAG);
/*
* If res is non-zero, we either requeued the waiter or hit an
* error, break out and handle it. If it is zero, then the
* signal may have hit before the the waiter was blocked on f1.
* Try again.
*/
if (res > 0) {
atomic_set(&requeued, 1);
break;
} else if (res > 0) {
error("FUTEX_CMP_REQUEUE_PI failed\n", errno);
ret = RET_ERROR;
break;
}
}
info("m4:f2: %x\n", f2);
/*
* Signal the waiter after requeue, waiter should return from
* futex_wait_requeue_pi() with EWOULDBLOCK. Join the thread here so the
* futex_unlock_pi() can't happen before the signal wakeup is detected
* in the kernel.
*/
info("Issuing SIGUSR1 to waiter\n");
pthread_kill(waiter, SIGUSR1);
info("Waiting for waiter to return\n");
pthread_join(waiter, NULL);
info("Calling FUTEX_UNLOCK_PI on mutex=%x @ %p\n", f2, &f2);
futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG);
info("m5:f2: %x\n", f2);
out:
if (ret == RET_PASS && waiter_ret)
ret = waiter_ret;
print_result(ret);
return ret;
}
/******************************************************************************
*
* Copyright FUJITSU LIMITED 2010
* Copyright KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* DESCRIPTION
* Internally, Futex has two handling mode, anon and file. The private file
* mapping is special. At first it behave as file, but after write anything
* it behave as anon. This test is intent to test such case.
*
* AUTHOR
* KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
*
* HISTORY
* 2010-Jan-6: Initial version by KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
*
*****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <syscall.h>
#include <unistd.h>
#include <errno.h>
#include <linux/futex.h>
#include <pthread.h>
#include <libgen.h>
#include <signal.h>
#include "logging.h"
#include "futextest.h"
#define PAGE_SZ 4096
char pad[PAGE_SZ] = {1};
futex_t val = 1;
char pad2[PAGE_SZ] = {1};
#define WAKE_WAIT_US 3000000
struct timespec wait_timeout = { .tv_sec = 5, .tv_nsec = 0};
void usage(char *prog)
{
printf("Usage: %s\n", prog);
printf(" -c Use color\n");
printf(" -h Display this help message\n");
printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n",
VQUIET, VCRITICAL, VINFO);
}
void *thr_futex_wait(void *arg)
{
int ret;
info("futex wait\n");
ret = futex_wait(&val, 1, &wait_timeout, 0);
if (ret && errno != EWOULDBLOCK && errno != ETIMEDOUT) {
error("futex error.\n", errno);
print_result(RET_ERROR);
exit(RET_ERROR);
}
if (ret && errno == ETIMEDOUT)
fail("waiter timedout\n");
info("futex_wait: ret = %d, errno = %d\n", ret, errno);
return NULL;
}
int main(int argc, char **argv)
{
pthread_t thr;
int ret = RET_PASS;
int res;
int c;
while ((c = getopt(argc, argv, "chv:")) != -1) {
switch (c) {
case 'c':
log_color(1);
break;
case 'h':
usage(basename(argv[0]));
exit(0);
case 'v':
log_verbosity(atoi(optarg));
break;
default:
usage(basename(argv[0]));
exit(1);
}
}
printf("%s: Test the futex value of private file mappings in FUTEX_WAIT\n",
basename(argv[0]));
ret = pthread_create(&thr, NULL, thr_futex_wait, NULL);
if (ret < 0) {
fprintf(stderr, "pthread_create error\n");
ret = RET_ERROR;
goto out;
}
info("wait a while\n");
usleep(WAKE_WAIT_US);
val = 2;
res = futex_wake(&val, 1, 0);
info("futex_wake %d\n", res);
if (res != 1) {
fail("FUTEX_WAKE didn't find the waiting thread.\n");
ret = RET_FAIL;
}
info("join\n");
pthread_join(thr, NULL);
out:
print_result(ret);
return ret;
}
/******************************************************************************
*
* Copyright © International Business Machines Corp., 2009
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* DESCRIPTION
* Block on a futex and wait for timeout.
*
* AUTHOR
* Darren Hart <dvhart@linux.intel.com>
*
* HISTORY
* 2009-Nov-6: Initial version by Darren Hart <dvhart@linux.intel.com>
*
*****************************************************************************/
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "futextest.h"
#include "logging.h"
static long timeout_ns = 100000; /* 100us default timeout */
void usage(char *prog)
{
printf("Usage: %s\n", prog);
printf(" -c Use color\n");
printf(" -h Display this help message\n");
printf(" -t N Timeout in nanoseconds (default: 100,000)\n");
printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n",
VQUIET, VCRITICAL, VINFO);
}
int main(int argc, char *argv[])
{
futex_t f1 = FUTEX_INITIALIZER;
struct timespec to;
int res, ret = RET_PASS;
int c;
while ((c = getopt(argc, argv, "cht:v:")) != -1) {
switch (c) {
case 'c':
log_color(1);
break;
case 'h':
usage(basename(argv[0]));
exit(0);
case 't':
timeout_ns = atoi(optarg);
break;
case 'v':
log_verbosity(atoi(optarg));
break;
default:
usage(basename(argv[0]));
exit(1);
}
}
printf("%s: Block on a futex and wait for timeout\n",
basename(argv[0]));
printf("\tArguments: timeout=%ldns\n", timeout_ns);
/* initialize timeout */
to.tv_sec = 0;
to.tv_nsec = timeout_ns;
info("Calling futex_wait on f1: %u @ %p\n", f1, &f1);
res = futex_wait(&f1, f1, &to, FUTEX_PRIVATE_FLAG);
if (!res || errno != ETIMEDOUT) {
fail("futex_wait returned %d\n", ret < 0 ? errno : ret);
ret = RET_FAIL;
}
print_result(ret);
return ret;
}
/******************************************************************************
*
* Copyright FUJITSU LIMITED 2010
* Copyright KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* DESCRIPTION
* Wait on uninitialized heap. It shold be zero and FUTEX_WAIT should
* return immediately. This test is intent to test zero page handling in
* futex.
*
* AUTHOR
* KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
*
* HISTORY
* 2010-Jan-6: Initial version by KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
*
*****************************************************************************/
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <syscall.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <linux/futex.h>
#include <libgen.h>
#include "logging.h"
#include "futextest.h"
#define WAIT_US 5000000
static int child_blocked = 1;
static int child_ret;
void *buf;
void usage(char *prog)
{
printf("Usage: %s\n", prog);
printf(" -c Use color\n");
printf(" -h Display this help message\n");
printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n",
VQUIET, VCRITICAL, VINFO);
}
void *wait_thread(void *arg)
{
int res;
child_ret = RET_PASS;
res = futex_wait(buf, 1, NULL, 0);
child_blocked = 0;
if (res != 0 && errno != EWOULDBLOCK) {
error("futex failure\n", errno);
child_ret = RET_ERROR;
}
pthread_exit(NULL);
}
int main(int argc, char **argv)
{
int c, ret = RET_PASS;
long page_size;
pthread_t thr;
while ((c = getopt(argc, argv, "chv:")) != -1) {
switch (c) {
case 'c':
log_color(1);
break;
case 'h':
usage(basename(argv[0]));
exit(0);
case 'v':
log_verbosity(atoi(optarg));
break;
default:
usage(basename(argv[0]));
exit(1);
}
}
page_size = sysconf(_SC_PAGESIZE);
buf = mmap(NULL, page_size, PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
if (buf == (void *)-1) {
error("mmap\n", errno);
exit(1);
}
printf("%s: Test the uninitialized futex value in FUTEX_WAIT\n",
basename(argv[0]));
ret = pthread_create(&thr, NULL, wait_thread, NULL);
if (ret) {
error("pthread_create\n", errno);
ret = RET_ERROR;
goto out;
}
info("waiting %dus for child to return\n", WAIT_US);
usleep(WAIT_US);
ret = child_ret;
if (child_blocked) {
fail("child blocked in kernel\n");
ret = RET_FAIL;
}
out:
print_result(ret);
return ret;
}
/******************************************************************************
*
* Copyright © International Business Machines Corp., 2009
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* DESCRIPTION
* Test if FUTEX_WAIT op returns -EWOULDBLOCK if the futex value differs
* from the expected one.
*
* AUTHOR
* Gowrishankar <gowrishankar.m@in.ibm.com>
*
* HISTORY
* 2009-Nov-14: Initial version by Gowrishankar <gowrishankar.m@in.ibm.com>
*
*****************************************************************************/
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "futextest.h"
#include "logging.h"
#define timeout_ns 100000
void usage(char *prog)
{
printf("Usage: %s\n", prog);
printf(" -c Use color\n");
printf(" -h Display this help message\n");
printf(" -v L Verbosity level: %d=QUIET %d=CRITICAL %d=INFO\n",
VQUIET, VCRITICAL, VINFO);
}
int main(int argc, char *argv[])
{
struct timespec to = {.tv_sec = 0, .tv_nsec = timeout_ns};
futex_t f1 = FUTEX_INITIALIZER;
int res, ret = RET_PASS;
int c;
while ((c = getopt(argc, argv, "cht:v:")) != -1) {
switch (c) {
case 'c':
log_color(1);
break;
case 'h':
usage(basename(argv[0]));
exit(0);
case 'v':
log_verbosity(atoi(optarg));
break;
default:
usage(basename(argv[0]));
exit(1);
}
}
printf("%s: Test the unexpected futex value in FUTEX_WAIT\n",
basename(argv[0]));
info("Calling futex_wait on f1: %u @ %p with val=%u\n", f1, &f1, f1+1);
res = futex_wait(&f1, f1+1, &to, FUTEX_PRIVATE_FLAG);
if (!res || errno != EWOULDBLOCK) {
fail("futex_wait returned: %d %s\n",
res ? errno : res, res ? strerror(errno) : "");
ret = RET_FAIL;
}
print_result(ret);
return ret;
}
#!/bin/sh
###############################################################################
#
# Copyright © International Business Machines Corp., 2009
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# DESCRIPTION
# Run tests in the current directory.
#
# AUTHOR
# Darren Hart <dvhart@linux.intel.com>
#
# HISTORY
# 2009-Nov-9: Initial version by Darren Hart <dvhart@linux.intel.com>
# 2010-Jan-6: Add futex_wait_uninitialized_heap and futex_wait_private_mapped_file
# by KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
#
###############################################################################
# Test for a color capable console
if [ -z "$USE_COLOR" ]; then
tput setf 7
if [ $? -eq 0 ]; then
USE_COLOR=1
tput sgr0
fi
fi
if [ "$USE_COLOR" -eq 1 ]; then
COLOR="-c"
fi
echo
# requeue pi testing
# without timeouts
./futex_requeue_pi $COLOR
./futex_requeue_pi $COLOR -b
./futex_requeue_pi $COLOR -b -l
./futex_requeue_pi $COLOR -b -o
./futex_requeue_pi $COLOR -l
./futex_requeue_pi $COLOR -o
# with timeouts
./futex_requeue_pi $COLOR -b -l -t 5000
./futex_requeue_pi $COLOR -l -t 5000
./futex_requeue_pi $COLOR -b -l -t 500000
./futex_requeue_pi $COLOR -l -t 500000
./futex_requeue_pi $COLOR -b -t 5000
./futex_requeue_pi $COLOR -t 5000
./futex_requeue_pi $COLOR -b -t 500000
./futex_requeue_pi $COLOR -t 500000
./futex_requeue_pi $COLOR -b -o -t 5000
./futex_requeue_pi $COLOR -l -t 5000
./futex_requeue_pi $COLOR -b -o -t 500000
./futex_requeue_pi $COLOR -l -t 500000
# with long timeout
./futex_requeue_pi $COLOR -b -l -t 2000000000
./futex_requeue_pi $COLOR -l -t 2000000000
echo
./futex_requeue_pi_mismatched_ops $COLOR
echo
./futex_requeue_pi_signal_restart $COLOR
echo
./futex_wait_timeout $COLOR
echo
./futex_wait_wouldblock $COLOR
echo
./futex_wait_uninitialized_heap $COLOR
./futex_wait_private_mapped_file $COLOR
/******************************************************************************
*
* Copyright © International Business Machines Corp., 2009
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* DESCRIPTION
* GCC atomic builtin wrappers
* http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
*
* AUTHOR
* Darren Hart <dvhart@linux.intel.com>
*
* HISTORY
* 2009-Nov-17: Initial version by Darren Hart <dvhart@linux.intel.com>
*
*****************************************************************************/
#ifndef _ATOMIC_H
#define _ATOMIC_H
typedef struct {
volatile int val;
} atomic_t;
#define ATOMIC_INITIALIZER { 0 }
/**
* atomic_cmpxchg() - Atomic compare and exchange
* @uaddr: The address of the futex to be modified
* @oldval: The expected value of the futex
* @newval: The new value to try and assign the futex
*
* Return the old value of addr->val.
*/
static inline int
atomic_cmpxchg(atomic_t *addr, int oldval, int newval)
{
return __sync_val_compare_and_swap(&addr->val, oldval, newval);
}
/**
* atomic_inc() - Atomic incrememnt
* @addr: Address of the variable to increment
*
* Return the new value of addr->val.
*/
static inline int
atomic_inc(atomic_t *addr)
{
return __sync_add_and_fetch(&addr->val, 1);
}
/**
* atomic_dec() - Atomic decrement
* @addr: Address of the variable to decrement
*
* Return the new value of addr-val.
*/
static inline int
atomic_dec(atomic_t *addr)
{
return __sync_sub_and_fetch(&addr->val, 1);
}
/**
* atomic_set() - Atomic set
* @addr: Address of the variable to set
* @newval: New value for the atomic_t
*
* Return the new value of addr->val.
*/
static inline int
atomic_set(atomic_t *addr, int newval)
{
addr->val = newval;
return newval;
}
#endif
/******************************************************************************
*
* Copyright © International Business Machines Corp., 2009
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* DESCRIPTION
* Glibc independent futex library for testing kernel functionality.
*
* AUTHOR
* Darren Hart <dvhart@linux.intel.com>
*
* HISTORY
* 2009-Nov-6: Initial version by Darren Hart <dvhart@linux.intel.com>
*
*****************************************************************************/
#ifndef _FUTEXTEST_H
#define _FUTEXTEST_H
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <linux/futex.h>
typedef volatile u_int32_t futex_t;
#define FUTEX_INITIALIZER 0
/* Define the newer op codes if the system header file is not up to date. */
#ifndef FUTEX_WAIT_BITSET
#define FUTEX_WAIT_BITSET 9
#endif
#ifndef FUTEX_WAKE_BITSET
#define FUTEX_WAKE_BITSET 10
#endif
#ifndef FUTEX_WAIT_REQUEUE_PI
#define FUTEX_WAIT_REQUEUE_PI 11
#endif
#ifndef FUTEX_CMP_REQUEUE_PI
#define FUTEX_CMP_REQUEUE_PI 12
#endif
#ifndef FUTEX_WAIT_REQUEUE_PI_PRIVATE
#define FUTEX_WAIT_REQUEUE_PI_PRIVATE (FUTEX_WAIT_REQUEUE_PI | \
FUTEX_PRIVATE_FLAG)
#endif
#ifndef FUTEX_REQUEUE_PI_PRIVATE
#define FUTEX_CMP_REQUEUE_PI_PRIVATE (FUTEX_CMP_REQUEUE_PI | \
FUTEX_PRIVATE_FLAG)
#endif
/**
* futex() - SYS_futex syscall wrapper
* @uaddr: address of first futex
* @op: futex op code
* @val: typically expected value of uaddr, but varies by op
* @timeout: typically an absolute struct timespec (except where noted
* otherwise). Overloaded by some ops
* @uaddr2: address of second futex for some ops\
* @val3: varies by op
* @opflags: flags to be bitwise OR'd with op, such as FUTEX_PRIVATE_FLAG
*
* futex() is used by all the following futex op wrappers. It can also be
* used for misuse and abuse testing. Generally, the specific op wrappers
* should be used instead. It is a macro instead of an static inline function as
* some of the types over overloaded (timeout is used for nr_requeue for
* example).
*
* These argument descriptions are the defaults for all
* like-named arguments in the following wrappers except where noted below.
*/
#define futex(uaddr, op, val, timeout, uaddr2, val3, opflags) \
syscall(SYS_futex, uaddr, op | opflags, val, timeout, uaddr2, val3)
/**
* futex_wait() - block on uaddr with optional timeout
* @timeout: relative timeout
*/
static inline int
futex_wait(futex_t *uaddr, futex_t val, struct timespec *timeout, int opflags)
{
return futex(uaddr, FUTEX_WAIT, val, timeout, NULL, 0, opflags);
}
/**
* futex_wake() - wake one or more tasks blocked on uaddr
* @nr_wake: wake up to this many tasks
*/
static inline int
futex_wake(futex_t *uaddr, int nr_wake, int opflags)
{
return futex(uaddr, FUTEX_WAKE, nr_wake, NULL, NULL, 0, opflags);
}
/**
* futex_wait_bitset() - block on uaddr with bitset
* @bitset: bitset to be used with futex_wake_bitset
*/
static inline int
futex_wait_bitset(futex_t *uaddr, futex_t val, struct timespec *timeout,
u_int32_t bitset, int opflags)
{
return futex(uaddr, FUTEX_WAIT_BITSET, val, timeout, NULL, bitset,
opflags);
}
/**
* futex_wake_bitset() - wake one or more tasks blocked on uaddr with bitset
* @bitset: bitset to compare with that used in futex_wait_bitset
*/
static inline int
futex_wake_bitset(futex_t *uaddr, int nr_wake, u_int32_t bitset, int opflags)
{
return futex(uaddr, FUTEX_WAKE_BITSET, nr_wake, NULL, NULL, bitset,
opflags);
}
/**
* futex_lock_pi() - block on uaddr as a PI mutex
* @detect: whether (1) or not (0) to perform deadlock detection
*/
static inline int
futex_lock_pi(futex_t *uaddr, struct timespec *timeout, int detect,
int opflags)
{
return futex(uaddr, FUTEX_LOCK_PI, detect, timeout, NULL, 0, opflags);
}
/**
* futex_unlock_pi() - release uaddr as a PI mutex, waking the top waiter
*/
static inline int
futex_unlock_pi(futex_t *uaddr, int opflags)
{
return futex(uaddr, FUTEX_UNLOCK_PI, 0, NULL, NULL, 0, opflags);
}
/**
* futex_wake_op() - FIXME: COME UP WITH A GOOD ONE LINE DESCRIPTION
*/
static inline int
futex_wake_op(futex_t *uaddr, futex_t *uaddr2, int nr_wake, int nr_wake2,
int wake_op, int opflags)
{
return futex(uaddr, FUTEX_WAKE_OP, nr_wake, nr_wake2, uaddr2, wake_op,
opflags);
}
/**
* futex_requeue() - requeue without expected value comparison, deprecated
* @nr_wake: wake up to this many tasks
* @nr_requeue: requeue up to this many tasks
*
* Due to its inherently racy implementation, futex_requeue() is deprecated in
* favor of futex_cmp_requeue().
*/
static inline int
futex_requeue(futex_t *uaddr, futex_t *uaddr2, int nr_wake, int nr_requeue,
int opflags)
{
return futex(uaddr, FUTEX_REQUEUE, nr_wake, nr_requeue, uaddr2, 0,
opflags);
}
/**
* futex_cmp_requeue() - requeue tasks from uaddr to uaddr2
* @nr_wake: wake up to this many tasks
* @nr_requeue: requeue up to this many tasks
*/
static inline int
futex_cmp_requeue(futex_t *uaddr, futex_t val, futex_t *uaddr2, int nr_wake,
int nr_requeue, int opflags)
{
return futex(uaddr, FUTEX_CMP_REQUEUE, nr_wake, nr_requeue, uaddr2,
val, opflags);
}
/**
* futex_wait_requeue_pi() - block on uaddr and prepare to requeue to uaddr2
* @uaddr: non-PI futex source
* @uaddr2: PI futex target
*
* This is the first half of the requeue_pi mechanism. It shall always be
* paired with futex_cmp_requeue_pi().
*/
static inline int
futex_wait_requeue_pi(futex_t *uaddr, futex_t val, futex_t *uaddr2,
struct timespec *timeout, int opflags)
{
return futex(uaddr, FUTEX_WAIT_REQUEUE_PI, val, timeout, uaddr2, 0,
opflags);
}
/**
* futex_cmp_requeue_pi() - requeue tasks from uaddr to uaddr2 (PI aware)
* @uaddr: non-PI futex source
* @uaddr2: PI futex target
* @nr_wake: wake up to this many tasks
* @nr_requeue: requeue up to this many tasks
*/
static inline int
futex_cmp_requeue_pi(futex_t *uaddr, futex_t val, futex_t *uaddr2, int nr_wake,
int nr_requeue, int opflags)
{
return futex(uaddr, FUTEX_CMP_REQUEUE_PI, nr_wake, nr_requeue, uaddr2,
val, opflags);
}
/**
* futex_cmpxchg() - atomic compare and exchange
* @uaddr: The address of the futex to be modified
* @oldval: The expected value of the futex
* @newval: The new value to try and assign the futex
*
* Implement cmpxchg using gcc atomic builtins.
* http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
*
* Return the old futex value.
*/
static inline u_int32_t
futex_cmpxchg(futex_t *uaddr, u_int32_t oldval, u_int32_t newval)
{
return __sync_val_compare_and_swap(uaddr, oldval, newval);
}
/**
* futex_dec() - atomic decrement of the futex value
* @uaddr: The address of the futex to be modified
*
* Return the new futex value.
*/
static inline u_int32_t
futex_dec(futex_t *uaddr)
{
return __sync_sub_and_fetch(uaddr, 1);
}
/**
* futex_inc() - atomic increment of the futex value
* @uaddr: the address of the futex to be modified
*
* Return the new futex value.
*/
static inline u_int32_t
futex_inc(futex_t *uaddr)
{
return __sync_add_and_fetch(uaddr, 1);
}
/**
* futex_set() - atomic decrement of the futex value
* @uaddr: the address of the futex to be modified
* @newval: New value for the atomic_t
*
* Return the new futex value.
*/
static inline u_int32_t
futex_set(futex_t *uaddr, u_int32_t newval)
{
*uaddr = newval;
return newval;
}
#endif
/******************************************************************************
*
* Copyright © International Business Machines Corp., 2009
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* DESCRIPTION
* Glibc independent futex library for testing kernel functionality.
*
* AUTHOR
* Darren Hart <dvhart@linux.intel.com>
*
* HISTORY
* 2009-Nov-6: Initial version by Darren Hart <dvhart@linux.intel.com>
*
*****************************************************************************/
#ifndef _LOGGING_H
#define _LOGGING_H
#include <string.h>
#include <unistd.h>
#include <linux/futex.h>
#include "kselftest.h"
/*
* Define PASS, ERROR, and FAIL strings with and without color escape
* sequences, default to no color.
*/
#define ESC 0x1B, '['
#define BRIGHT '1'
#define GREEN '3', '2'
#define YELLOW '3', '3'
#define RED '3', '1'
#define ESCEND 'm'
#define BRIGHT_GREEN ESC, BRIGHT, ';', GREEN, ESCEND
#define BRIGHT_YELLOW ESC, BRIGHT, ';', YELLOW, ESCEND
#define BRIGHT_RED ESC, BRIGHT, ';', RED, ESCEND
#define RESET_COLOR ESC, '0', 'm'
static const char PASS_COLOR[] = {BRIGHT_GREEN, ' ', 'P', 'A', 'S', 'S',
RESET_COLOR, 0};
static const char ERROR_COLOR[] = {BRIGHT_YELLOW, 'E', 'R', 'R', 'O', 'R',
RESET_COLOR, 0};
static const char FAIL_COLOR[] = {BRIGHT_RED, ' ', 'F', 'A', 'I', 'L',
RESET_COLOR, 0};
static const char INFO_NORMAL[] = " INFO";
static const char PASS_NORMAL[] = " PASS";
static const char ERROR_NORMAL[] = "ERROR";
static const char FAIL_NORMAL[] = " FAIL";
const char *INFO = INFO_NORMAL;
const char *PASS = PASS_NORMAL;
const char *ERROR = ERROR_NORMAL;
const char *FAIL = FAIL_NORMAL;
/* Verbosity setting for INFO messages */
#define VQUIET 0
#define VCRITICAL 1
#define VINFO 2
#define VMAX VINFO
int _verbose = VCRITICAL;
/* Functional test return codes */
#define RET_PASS 0
#define RET_ERROR -1
#define RET_FAIL -2
/**
* log_color() - Use colored output for PASS, ERROR, and FAIL strings
* @use_color: use color (1) or not (0)
*/
void log_color(int use_color)
{
if (use_color) {
PASS = PASS_COLOR;
ERROR = ERROR_COLOR;
FAIL = FAIL_COLOR;
} else {
PASS = PASS_NORMAL;
ERROR = ERROR_NORMAL;
FAIL = FAIL_NORMAL;
}
}
/**
* log_verbosity() - Set verbosity of test output
* @verbose: Enable (1) verbose output or not (0)
*
* Currently setting verbose=1 will enable INFO messages and 0 will disable
* them. FAIL and ERROR messages are always displayed.
*/
void log_verbosity(int level)
{
if (level > VMAX)
level = VMAX;
else if (level < 0)
level = 0;
_verbose = level;
}
/**
* print_result() - Print standard PASS | ERROR | FAIL results
* @ret: the return value to be considered: 0 | RET_ERROR | RET_FAIL
*
* print_result() is primarily intended for functional tests.
*/
void print_result(int ret)
{
const char *result = "Unknown return code";
switch (ret) {
case RET_PASS:
ksft_inc_pass_cnt();
result = PASS;
break;
case RET_ERROR:
result = ERROR;
break;
case RET_FAIL:
ksft_inc_fail_cnt();
result = FAIL;
break;
}
printf("Result: %s\n", result);
}
/* log level macros */
#define info(message, vargs...) \
do { \
if (_verbose >= VINFO) \
fprintf(stderr, "\t%s: "message, INFO, ##vargs); \
} while (0)
#define error(message, err, args...) \
do { \
if (_verbose >= VCRITICAL) {\
if (err) \
fprintf(stderr, "\t%s: %s: "message, \
ERROR, strerror(err), ##args); \
else \
fprintf(stderr, "\t%s: "message, ERROR, ##args); \
} \
} while (0)
#define fail(message, args...) \
do { \
if (_verbose >= VCRITICAL) \
fprintf(stderr, "\t%s: "message, FAIL, ##args); \
} while (0)
#endif
#!/bin/sh
###############################################################################
#
# Copyright © International Business Machines Corp., 2009
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# DESCRIPTION
# Run all tests under the functional, performance, and stress directories.
# Format and summarize the results.
#
# AUTHOR
# Darren Hart <dvhart@linux.intel.com>
#
# HISTORY
# 2009-Nov-9: Initial version by Darren Hart <dvhart@linux.intel.com>
#
###############################################################################
# Test for a color capable shell and pass the result to the subdir scripts
USE_COLOR=0
tput setf 7
if [ $? -eq 0 ]; then
USE_COLOR=1
tput sgr0
fi
export USE_COLOR
(cd functional; ./run.sh)
...@@ -13,6 +13,13 @@ ...@@ -13,6 +13,13 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
/* define kselftest exit codes */
#define KSFT_PASS 0
#define KSFT_FAIL 1
#define KSFT_XFAIL 2
#define KSFT_XPASS 3
#define KSFT_SKIP 4
/* counters */ /* counters */
struct ksft_count { struct ksft_count {
unsigned int ksft_pass; unsigned int ksft_pass;
...@@ -40,23 +47,23 @@ static inline void ksft_print_cnts(void) ...@@ -40,23 +47,23 @@ static inline void ksft_print_cnts(void)
static inline int ksft_exit_pass(void) static inline int ksft_exit_pass(void)
{ {
exit(0); exit(KSFT_PASS);
} }
static inline int ksft_exit_fail(void) static inline int ksft_exit_fail(void)
{ {
exit(1); exit(KSFT_FAIL);
} }
static inline int ksft_exit_xfail(void) static inline int ksft_exit_xfail(void)
{ {
exit(2); exit(KSFT_XFAIL);
} }
static inline int ksft_exit_xpass(void) static inline int ksft_exit_xpass(void)
{ {
exit(3); exit(KSFT_XPASS);
} }
static inline int ksft_exit_skip(void) static inline int ksft_exit_skip(void)
{ {
exit(4); exit(KSFT_SKIP);
} }
#endif /* __KSELFTEST_H */ #endif /* __KSELFTEST_H */
...@@ -13,6 +13,9 @@ run_tests: all ...@@ -13,6 +13,9 @@ run_tests: all
define INSTALL_RULE define INSTALL_RULE
mkdir -p $(INSTALL_PATH) mkdir -p $(INSTALL_PATH)
@for TEST_DIR in $(TEST_DIRS); do\
cp -r $$TEST_DIR $(INSTALL_PATH); \
done;
install -t $(INSTALL_PATH) $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) install -t $(INSTALL_PATH) $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES)
endef endef
......
...@@ -9,7 +9,12 @@ unprivileged-remount-test: unprivileged-remount-test.c ...@@ -9,7 +9,12 @@ unprivileged-remount-test: unprivileged-remount-test.c
include ../lib.mk include ../lib.mk
TEST_PROGS := unprivileged-remount-test TEST_PROGS := unprivileged-remount-test
override RUN_TESTS := if [ -f /proc/self/uid_map ] ; then ./unprivileged-remount-test ; fi override RUN_TESTS := if [ -f /proc/self/uid_map ] ; \
then \
./unprivileged-remount-test ; \
else \
echo "WARN: No /proc/self/uid_map exist, test skipped." ; \
fi
override EMIT_TESTS := echo "$(RUN_TESTS)" override EMIT_TESTS := echo "$(RUN_TESTS)"
clean: clean:
......
TEST_PROGS := seccomp_bpf
CFLAGS += -Wl,-no-as-needed -Wall
LDFLAGS += -lpthread
all: $(TEST_PROGS)
include ../lib.mk
clean:
$(RM) $(TEST_PROGS)
This diff is collapsed.
This diff is collapsed.
alarmtimer-suspend
change_skew
clocksource-switch
inconsistency-check
leap-a-day
leapcrash
mqueue-lat
nanosleep
nsleep-lat
posix_timers
raw_skew
rtctest
set-2038
set-tai
set-timer-lat
skew_consistency
threadtest
valid-adjtimex
...@@ -57,7 +57,7 @@ static inline int ksft_exit_fail(void) ...@@ -57,7 +57,7 @@ static inline int ksft_exit_fail(void)
#define NSEC_PER_SEC 1000000000ULL #define NSEC_PER_SEC 1000000000ULL
#define UNREASONABLE_LAT (NSEC_PER_SEC * 4) /* hopefully we resume in 4secs */ #define UNREASONABLE_LAT (NSEC_PER_SEC * 5) /* hopefully we resume in 5 secs */
#define SUSPEND_SECS 15 #define SUSPEND_SECS 15
int alarmcount; int alarmcount;
...@@ -152,7 +152,11 @@ int main(void) ...@@ -152,7 +152,11 @@ int main(void)
alarm_clock_id++) { alarm_clock_id++) {
alarmcount = 0; alarmcount = 0;
timer_create(alarm_clock_id, &se, &tm1); if (timer_create(alarm_clock_id, &se, &tm1) == -1) {
printf("timer_create failled, %s unspported?\n",
clockstring(alarm_clock_id));
break;
}
clock_gettime(alarm_clock_id, &start_time); clock_gettime(alarm_clock_id, &start_time);
printf("Start time (%s): %ld:%ld\n", clockstring(alarm_clock_id), printf("Start time (%s): %ld:%ld\n", clockstring(alarm_clock_id),
...@@ -172,7 +176,7 @@ int main(void) ...@@ -172,7 +176,7 @@ int main(void)
while (alarmcount < 10) { while (alarmcount < 10) {
int ret; int ret;
sleep(1); sleep(3);
ret = system("echo mem > /sys/power/state"); ret = system("echo mem > /sys/power/state");
if (ret) if (ret)
break; break;
......
# Makefile for vm selftests # Makefile for vm selftests
CFLAGS = -Wall CFLAGS = -Wall
BINARIES = hugepage-mmap hugepage-shm map_hugetlb thuge-gen hugetlbfstest BINARIES = compaction_test
BINARIES += hugepage-mmap
BINARIES += hugepage-shm
BINARIES += hugetlbfstest
BINARIES += map_hugetlb
BINARIES += thuge-gen
BINARIES += transhuge-stress BINARIES += transhuge-stress
all: $(BINARIES) all: $(BINARIES)
......
/*
*
* A test for the patch "Allow compaction of unevictable pages".
* With this patch we should be able to allocate at least 1/4
* of RAM in huge pages. Without the patch much less is
* allocated.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#define MAP_SIZE 1048576
struct map_list {
void *map;
struct map_list *next;
};
int read_memory_info(unsigned long *memfree, unsigned long *hugepagesize)
{
char buffer[256] = {0};
char *cmd = "cat /proc/meminfo | grep -i memfree | grep -o '[0-9]*'";
FILE *cmdfile = popen(cmd, "r");
if (!(fgets(buffer, sizeof(buffer), cmdfile))) {
perror("Failed to read meminfo\n");
return -1;
}
pclose(cmdfile);
*memfree = atoll(buffer);
cmd = "cat /proc/meminfo | grep -i hugepagesize | grep -o '[0-9]*'";
cmdfile = popen(cmd, "r");
if (!(fgets(buffer, sizeof(buffer), cmdfile))) {
perror("Failed to read meminfo\n");
return -1;
}
pclose(cmdfile);
*hugepagesize = atoll(buffer);
return 0;
}
int prereq(void)
{
char allowed;
int fd;
fd = open("/proc/sys/vm/compact_unevictable_allowed",
O_RDONLY | O_NONBLOCK);
if (fd < 0) {
perror("Failed to open\n"
"/proc/sys/vm/compact_unevictable_allowed\n");
return -1;
}
if (read(fd, &allowed, sizeof(char)) != sizeof(char)) {
perror("Failed to read from\n"
"/proc/sys/vm/compact_unevictable_allowed\n");
close(fd);
return -1;
}
close(fd);
if (allowed == '1')
return 0;
return -1;
}
int check_compaction(unsigned long mem_free, unsigned int hugepage_size)
{
int fd;
int compaction_index = 0;
char initial_nr_hugepages[10] = {0};
char nr_hugepages[10] = {0};
/* We want to test with 80% of available memory. Else, OOM killer comes
in to play */
mem_free = mem_free * 0.8;
fd = open("/proc/sys/vm/nr_hugepages", O_RDWR | O_NONBLOCK);
if (fd < 0) {
perror("Failed to open /proc/sys/vm/nr_hugepages");
return -1;
}
if (read(fd, initial_nr_hugepages, sizeof(initial_nr_hugepages)) <= 0) {
perror("Failed to read from /proc/sys/vm/nr_hugepages");
goto close_fd;
}
/* Start with the initial condition of 0 huge pages*/
if (write(fd, "0", sizeof(char)) != sizeof(char)) {
perror("Failed to write to /proc/sys/vm/nr_hugepages\n");
goto close_fd;
}
lseek(fd, 0, SEEK_SET);
/* Request a large number of huge pages. The Kernel will allocate
as much as it can */
if (write(fd, "100000", (6*sizeof(char))) != (6*sizeof(char))) {
perror("Failed to write to /proc/sys/vm/nr_hugepages\n");
goto close_fd;
}
lseek(fd, 0, SEEK_SET);
if (read(fd, nr_hugepages, sizeof(nr_hugepages)) <= 0) {
perror("Failed to read from /proc/sys/vm/nr_hugepages\n");
goto close_fd;
}
/* We should have been able to request at least 1/3 rd of the memory in
huge pages */
compaction_index = mem_free/(atoi(nr_hugepages) * hugepage_size);
if (compaction_index > 3) {
printf("No of huge pages allocated = %d\n",
(atoi(nr_hugepages)));
fprintf(stderr, "ERROR: Less that 1/%d of memory is available\n"
"as huge pages\n", compaction_index);
goto close_fd;
}
printf("No of huge pages allocated = %d\n",
(atoi(nr_hugepages)));
if (write(fd, initial_nr_hugepages, sizeof(initial_nr_hugepages))
!= strlen(initial_nr_hugepages)) {
perror("Failed to write to /proc/sys/vm/nr_hugepages\n");
goto close_fd;
}
close(fd);
return 0;
close_fd:
close(fd);
printf("Not OK. Compaction test failed.");
return -1;
}
int main(int argc, char **argv)
{
struct rlimit lim;
struct map_list *list, *entry;
size_t page_size, i;
void *map = NULL;
unsigned long mem_free = 0;
unsigned long hugepage_size = 0;
unsigned long mem_fragmentable = 0;
if (prereq() != 0) {
printf("Either the sysctl compact_unevictable_allowed is not\n"
"set to 1 or couldn't read the proc file.\n"
"Skipping the test\n");
return 0;
}
lim.rlim_cur = RLIM_INFINITY;
lim.rlim_max = RLIM_INFINITY;
if (setrlimit(RLIMIT_MEMLOCK, &lim)) {
perror("Failed to set rlimit:\n");
return -1;
}
page_size = getpagesize();
list = NULL;
if (read_memory_info(&mem_free, &hugepage_size) != 0) {
printf("ERROR: Cannot read meminfo\n");
return -1;
}
mem_fragmentable = mem_free * 0.8 / 1024;
while (mem_fragmentable > 0) {
map = mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE | MAP_LOCKED, -1, 0);
if (map == MAP_FAILED)
break;
entry = malloc(sizeof(struct map_list));
if (!entry) {
munmap(map, MAP_SIZE);
break;
}
entry->map = map;
entry->next = list;
list = entry;
/* Write something (in this case the address of the map) to
* ensure that KSM can't merge the mapped pages
*/
for (i = 0; i < MAP_SIZE; i += page_size)
*(unsigned long *)(map + i) = (unsigned long)map + i;
mem_fragmentable--;
}
for (entry = list; entry != NULL; entry = entry->next) {
munmap(entry->map, MAP_SIZE);
if (!entry->next)
break;
entry = entry->next;
}
if (check_compaction(mem_free, hugepage_size) == 0)
return 0;
return -1;
}
...@@ -90,4 +90,16 @@ fi ...@@ -90,4 +90,16 @@ fi
umount $mnt umount $mnt
rm -rf $mnt rm -rf $mnt
echo $nr_hugepgs > /proc/sys/vm/nr_hugepages echo $nr_hugepgs > /proc/sys/vm/nr_hugepages
echo "-----------------------"
echo "running compaction_test"
echo "-----------------------"
./compaction_test
if [ $? -ne 0 ]; then
echo "[FAIL]"
exitcode=1
else
echo "[PASS]"
fi
exit $exitcode exit $exitcode
/* /*
* Trivial program to check that we have a valid 32-bit build environment. * Trivial program to check that we have a valid 64-bit build environment.
* Copyright (c) 2015 Andy Lutomirski * Copyright (c) 2015 Andy Lutomirski
* GPL v2 * GPL v2
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment