* Re: [PATCH 5/5] kselftest: Add exit code defines
From: Michael Ellerman @ 2015-03-27 22:59 UTC (permalink / raw)
To: Darren Hart
Cc: Linux Kernel Mailing List, Shuah Khan,
linux-api-u79uwXL29TY76Z2rM5mHXA, Ingo Molnar, Peter Zijlstra,
Thomas Gleixner, Davidlohr Bueso, KOSAKI Motohiro
In-Reply-To: <43a448183a340b61d91c711da4a75898e3ffd8f2.1427493640.git.dvhart-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
On Fri, 2015-03-27 at 15:17 -0700, Darren Hart wrote:
> Define the exit codes with KSFT_PASS and similar so tests can use these
> directly if they choose. Also enable harnesses and other tooling to use
> the defines instead of hardcoding the return codes.
+1
> diff --git a/tools/testing/selftests/kselftest.h b/tools/testing/selftests/kselftest.h
> index 572c888..ef1c80d 100644
> --- a/tools/testing/selftests/kselftest.h
> +++ b/tools/testing/selftests/kselftest.h
> @@ -13,6 +13,13 @@
> #include <stdlib.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 */
> struct ksft_count {
> unsigned int ksft_pass;
> @@ -40,23 +47,23 @@ static inline void ksft_print_cnts(void)
>
> static inline int ksft_exit_pass(void)
> {
> - exit(0);
> + exit(KSFT_PASS);
> }
Am I the only person who's bothered by the fact that these don't actually
return int?
cheers
^ permalink raw reply
* [PATCH 5/5] kselftest: Add exit code defines
From: Darren Hart @ 2015-03-27 22:17 UTC (permalink / raw)
To: Linux Kernel Mailing List
Cc: Darren Hart, Shuah Khan, linux-api, Ingo Molnar, Peter Zijlstra,
Thomas Gleixner, Davidlohr Bueso, KOSAKI Motohiro
In-Reply-To: <cover.1427493640.git.dvhart@linux.intel.com>
Define the exit codes with KSFT_PASS and similar so tests can use these
directly if they choose. Also enable harnesses and other tooling to use
the defines instead of hardcoding the return codes.
Cc: Shuah Khan <shuahkh@osg.samsung.com>
Cc: linux-api@vger.kernel.org
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: Darren Hart <dvhart@linux.intel.com>
---
tools/testing/selftests/kselftest.h | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/tools/testing/selftests/kselftest.h b/tools/testing/selftests/kselftest.h
index 572c888..ef1c80d 100644
--- a/tools/testing/selftests/kselftest.h
+++ b/tools/testing/selftests/kselftest.h
@@ -13,6 +13,13 @@
#include <stdlib.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 */
struct ksft_count {
unsigned int ksft_pass;
@@ -40,23 +47,23 @@ static inline void ksft_print_cnts(void)
static inline int ksft_exit_pass(void)
{
- exit(0);
+ exit(KSFT_PASS);
}
static inline int ksft_exit_fail(void)
{
- exit(1);
+ exit(KSFT_FAIL);
}
static inline int ksft_exit_xfail(void)
{
- exit(2);
+ exit(KSFT_XFAIL);
}
static inline int ksft_exit_xpass(void)
{
- exit(3);
+ exit(KSFT_XPASS);
}
static inline int ksft_exit_skip(void)
{
- exit(4);
+ exit(KSFT_SKIP);
}
#endif /* __KSELFTEST_H */
--
2.1.4
^ permalink raw reply related
* [PATCH 4/5] selftest: Add futex tests to the top-level Makefile
From: Darren Hart @ 2015-03-27 22:17 UTC (permalink / raw)
To: Linux Kernel Mailing List
Cc: Darren Hart, Shuah Khan, linux-api, Ingo Molnar, Peter Zijlstra,
Thomas Gleixner, Davidlohr Bueso, KOSAKI Motohiro
In-Reply-To: <cover.1427493640.git.dvhart@linux.intel.com>
Enable futex tests to be built and run with the make kselftest and
associated targets.
Most of the tests require escalated privileges. These return ERROR, and
run.sh continues.
Cc: Shuah Khan <shuahkh@osg.samsung.com>
Cc: linux-api@vger.kernel.org
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: Darren Hart <dvhart@linux.intel.com>
---
tools/testing/selftests/Makefile | 1 +
1 file changed, 1 insertion(+)
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 9af1df2..6eef08a 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -4,6 +4,7 @@ TARGETS += efivarfs
TARGETS += exec
TARGETS += firmware
TARGETS += ftrace
+TARGETS += futex
TARGETS += kcmp
TARGETS += memfd
TARGETS += memory-hotplug
--
2.1.4
^ permalink raw reply related
* [PATCH 3/5] selftest/futex: Increment ksft pass and fail counters
From: Darren Hart @ 2015-03-27 22:17 UTC (permalink / raw)
To: Linux Kernel Mailing List
Cc: Darren Hart, Shuah Khan, linux-api, Ingo Molnar, Peter Zijlstra,
Thomas Gleixner, Davidlohr Bueso, KOSAKI Motohiro
In-Reply-To: <cover.1427493640.git.dvhart@linux.intel.com>
Add kselftest.h to logging.h and increment the pass and fail counters as
part of the print_result routine which is called by all futex tests.
Cc: Shuah Khan <shuahkh@osg.samsung.com>
Cc: linux-api@vger.kernel.org
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: Darren Hart <dvhart@linux.intel.com>
---
tools/testing/selftests/futex/functional/Makefile | 2 +-
tools/testing/selftests/futex/include/logging.h | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/futex/functional/Makefile b/tools/testing/selftests/futex/functional/Makefile
index fb96927..e64d43b 100644
--- a/tools/testing/selftests/futex/functional/Makefile
+++ b/tools/testing/selftests/futex/functional/Makefile
@@ -1,4 +1,4 @@
-INCLUDES := -I../include
+INCLUDES := -I../include -I../../
CFLAGS := $(CFLAGS) -g -O2 -Wall -D_GNU_SOURCE $(INCLUDES)
LDFLAGS := $(LDFLAGS) -lpthread -lrt
diff --git a/tools/testing/selftests/futex/include/logging.h b/tools/testing/selftests/futex/include/logging.h
index 3220b90..1d0cfcd 100644
--- a/tools/testing/selftests/futex/include/logging.h
+++ b/tools/testing/selftests/futex/include/logging.h
@@ -24,6 +24,7 @@
#include <string.h>
#include <unistd.h>
#include <linux/futex.h>
+#include "kselftest.h"
/*
* Define PASS, ERROR, and FAIL strings with and without color escape
@@ -108,12 +109,14 @@ void print_result(int ret)
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;
}
--
2.1.4
^ permalink raw reply related
* [PATCH 2/5] selftest/futex: Update Makefile to use lib.mk
From: Darren Hart @ 2015-03-27 22:17 UTC (permalink / raw)
To: Linux Kernel Mailing List
Cc: Darren Hart, Shuah Khan, linux-api, Ingo Molnar, Peter Zijlstra,
Thomas Gleixner, Davidlohr Bueso, KOSAKI Motohiro
In-Reply-To: <cover.1427493640.git.dvhart@linux.intel.com>
Adapt the futextest Makefiles to use lib.mk macros for RUN_TESTS and
EMIT_TESTS. For now, we reuse the run.sh mechanism provided by
futextest. This doesn't provide the standard selftests: [PASS|FAIL]
format, but the tests provide very similar output already.
This results in the run_kselftest.sh script for futexes including a
single line: ./run.sh
Cc: Shuah Khan <shuahkh@osg.samsung.com>
Cc: linux-api@vger.kernel.org
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Davidlohr Bueso <dave@stgolabs.net>
Cc: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Signed-off-by: Darren Hart <dvhart@linux.intel.com>
---
tools/testing/selftests/futex/Makefile | 21 +++++++++++++++++++++
tools/testing/selftests/futex/functional/Makefile | 4 ++++
2 files changed, 25 insertions(+)
diff --git a/tools/testing/selftests/futex/Makefile b/tools/testing/selftests/futex/Makefile
index 8629187..6a17529 100644
--- a/tools/testing/selftests/futex/Makefile
+++ b/tools/testing/selftests/futex/Makefile
@@ -1,8 +1,29 @@
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
diff --git a/tools/testing/selftests/futex/functional/Makefile b/tools/testing/selftests/futex/functional/Makefile
index 6ecb42c..fb96927 100644
--- a/tools/testing/selftests/futex/functional/Makefile
+++ b/tools/testing/selftests/futex/functional/Makefile
@@ -12,10 +12,14 @@ TARGETS := \
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)
--
2.1.4
^ permalink raw reply related
* [PATCH 1/5] selftests: Add futex functional tests
From: Darren Hart @ 2015-03-27 22:17 UTC (permalink / raw)
To: Linux Kernel Mailing List
Cc: Darren Hart, Shuah Khan, linux-api-u79uwXL29TY76Z2rM5mHXA,
Ingo Molnar, Peter Zijlstra, Thomas Gleixner, Davidlohr Bueso,
KOSAKI Motohiro
In-Reply-To: <cover.1427493640.git.dvhart-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
The futextest testsuite [1] provides functional, stress, and
performance tests for the various futex op codes. Those tests will be of
more use to futex developers if they are included with the kernel
source.
Copy the core infrastructure and the functional tests into selftests.
Remove reference to the performance and stress tests from the
contributed sources.
Remove the Free Software Foundation address paragraph from all
contributed files to avoid checkpatch complaints.
A future effort will explore moving the performance and stress tests
into the kernel.
1. http://git.kernel.org/cgit/linux/kernel/git/dvhart/futextest.git
Cc: Shuah Khan <shuahkh-JPH+aEBZ4P+UEJcrhfAQsw@public.gmane.org>
Cc: linux-api-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Cc: Ingo Molnar <mingo-X9Un+BFzKDI@public.gmane.org>
Cc: Peter Zijlstra <peterz-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>
Cc: Thomas Gleixner <tglx-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org>
Cc: Davidlohr Bueso <dave-h16yJtLeMjHk1uMJSBkQmQ@public.gmane.org>
Cc: KOSAKI Motohiro <kosaki.motohiro-+CUm20s59erQFUHtdCDX3A@public.gmane.org>
Signed-off-by: Darren Hart <dvhart-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
tools/testing/selftests/futex/Makefile | 8 +
tools/testing/selftests/futex/README | 62 ++++
tools/testing/selftests/futex/functional/Makefile | 21 ++
.../selftests/futex/functional/futex_requeue_pi.c | 402 +++++++++++++++++++++
.../functional/futex_requeue_pi_mismatched_ops.c | 136 +++++++
.../functional/futex_requeue_pi_signal_restart.c | 220 +++++++++++
.../functional/futex_wait_private_mapped_file.c | 126 +++++++
.../futex/functional/futex_wait_timeout.c | 85 +++++
.../functional/futex_wait_uninitialized_heap.c | 124 +++++++
.../futex/functional/futex_wait_wouldblock.c | 79 ++++
tools/testing/selftests/futex/functional/run.sh | 79 ++++
tools/testing/selftests/futex/include/atomic.h | 83 +++++
tools/testing/selftests/futex/include/futextest.h | 266 ++++++++++++++
tools/testing/selftests/futex/include/logging.h | 147 ++++++++
tools/testing/selftests/futex/run.sh | 33 ++
15 files changed, 1871 insertions(+)
create mode 100644 tools/testing/selftests/futex/Makefile
create mode 100644 tools/testing/selftests/futex/README
create mode 100644 tools/testing/selftests/futex/functional/Makefile
create mode 100644 tools/testing/selftests/futex/functional/futex_requeue_pi.c
create mode 100644 tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c
create mode 100644 tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c
create mode 100644 tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c
create mode 100644 tools/testing/selftests/futex/functional/futex_wait_timeout.c
create mode 100644 tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c
create mode 100644 tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
create mode 100755 tools/testing/selftests/futex/functional/run.sh
create mode 100644 tools/testing/selftests/futex/include/atomic.h
create mode 100644 tools/testing/selftests/futex/include/futextest.h
create mode 100644 tools/testing/selftests/futex/include/logging.h
create mode 100755 tools/testing/selftests/futex/run.sh
diff --git a/tools/testing/selftests/futex/Makefile b/tools/testing/selftests/futex/Makefile
new file mode 100644
index 0000000..8629187
--- /dev/null
+++ b/tools/testing/selftests/futex/Makefile
@@ -0,0 +1,8 @@
+SUBDIRS := functional
+
+.PHONY: all clean
+all:
+ for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done
+
+clean:
+ for DIR in $(SUBDIRS); do $(MAKE) -C $$DIR $@ ; done
diff --git a/tools/testing/selftests/futex/README b/tools/testing/selftests/futex/README
new file mode 100644
index 0000000..3224a04
--- /dev/null
+++ b/tools/testing/selftests/futex/README
@@ -0,0 +1,62 @@
+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.
diff --git a/tools/testing/selftests/futex/functional/Makefile b/tools/testing/selftests/futex/functional/Makefile
new file mode 100644
index 0000000..6ecb42c
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/Makefile
@@ -0,0 +1,21 @@
+INCLUDES := -I../include
+CFLAGS := $(CFLAGS) -g -O2 -Wall -D_GNU_SOURCE $(INCLUDES)
+LDFLAGS := $(LDFLAGS) -lpthread -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
+
+.PHONY: all clean
+all: $(TARGETS)
+
+$(TARGETS): $(HEADERS)
+
+clean:
+ rm -f $(TARGETS)
diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi.c b/tools/testing/selftests/futex/functional/futex_requeue_pi.c
new file mode 100644
index 0000000..fbeb9f7
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_requeue_pi.c
@@ -0,0 +1,402 @@
+/******************************************************************************
+ *
+ * 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 excercises the futex syscall op codes needed for requeuing
+ * priority inheritance aware POSIX condition variables and mutexes.
+ *
+ * AUTHORS
+ * Sripathi Kodi <sripathik-xthvdsQ13ZrQT0dZR+AlfA@public.gmane.org>
+ * Darren Hart <dvhart-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
+ *
+ * HISTORY
+ * 2008-Jan-13: Initial version by Sripathi Kodi <sripathik-rWuWpvqGGmM@public.gmane.orgm.com>
+ * 2009-Nov-6: futex test adaptation by Darren Hart <dvhart@linux.intel.com>
+ *
+ *****************************************************************************/
+
+#include <errno.h>
+#include <limits.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include "atomic.h"
+#include "futextest.h"
+#include "logging.h"
+
+#define MAX_WAKE_ITERS 1000
+#define THREAD_MAX 10
+#define SIGNAL_PERIOD_US 100
+
+atomic_t waiters_blocked = ATOMIC_INITIALIZER;
+atomic_t waiters_woken = ATOMIC_INITIALIZER;
+
+futex_t f1 = FUTEX_INITIALIZER;
+futex_t f2 = FUTEX_INITIALIZER;
+futex_t wake_complete = FUTEX_INITIALIZER;
+
+/* Test options default to 0 */
+static long timeout_ns;
+static int broadcast;
+static int owner;
+static int locked;
+
+typedef struct {
+ long id;
+ struct timespec *timeout;
+ int lock;
+ int ret;
+} thread_arg_t;
+#define THREAD_ARG_INITIALIZER { 0, NULL, 0, 0 }
+
+void usage(char *prog)
+{
+ printf("Usage: %s\n", prog);
+ printf(" -b Broadcast wakeup (all waiters)\n");
+ printf(" -c Use color\n");
+ printf(" -h Display this help message\n");
+ printf(" -l Lock the pi futex across requeue\n");
+ printf(" -o Use a third party pi futex owner during requeue (cancels -l)\n");
+ printf(" -t N Timeout in nanoseconds (default: 0)\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)
+{
+ int ret;
+ struct sched_param schedp;
+ pthread_attr_t attr;
+
+ pthread_attr_init(&attr);
+ memset(&schedp, 0, sizeof(schedp));
+
+ if ((ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) != 0) {
+ error("pthread_attr_setinheritsched\n", ret);
+ return -1;
+ }
+
+ if ((ret = pthread_attr_setschedpolicy(&attr, policy)) != 0) {
+ error("pthread_attr_setschedpolicy\n", ret);
+ return -1;
+ }
+
+ schedp.sched_priority = prio;
+ if ((ret = pthread_attr_setschedparam(&attr, &schedp)) != 0) {
+ error("pthread_attr_setschedparam\n", ret);
+ return -1;
+ }
+
+ if ((ret = pthread_create(pth, &attr, func, arg)) != 0) {
+ error("pthread_create\n", ret);
+ return -1;
+ }
+ return 0;
+}
+
+
+void *waiterfn(void *arg)
+{
+ thread_arg_t *args = (thread_arg_t *)arg;
+ futex_t old_val;
+
+ info("Waiter %ld: running\n", args->id);
+ /* Each thread sleeps for a different amount of time
+ * This is to avoid races, because we don't lock the
+ * external mutex here */
+ usleep(1000 * (long)args->id);
+
+ old_val = f1;
+ atomic_inc(&waiters_blocked);
+ info("Calling futex_wait_requeue_pi: %p (%u) -> %p\n",
+ &f1, f1, &f2);
+ args->ret = futex_wait_requeue_pi(&f1, old_val, &f2, args->timeout,
+ FUTEX_PRIVATE_FLAG);
+
+ info("waiter %ld woke with %d %s\n", args->id, args->ret,
+ args->ret < 0 ? strerror(errno) : "");
+ atomic_inc(&waiters_woken);
+ if (args->ret < 0) {
+ if (args->timeout && errno == ETIMEDOUT)
+ args->ret = 0;
+ else {
+ args->ret = RET_ERROR;
+ error("futex_wait_requeue_pi\n", errno);
+ }
+ futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG);
+ }
+ futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG);
+
+ info("Waiter %ld: exiting with %d\n", args->id, args->ret);
+ pthread_exit((void *)&args->ret);
+}
+
+void *broadcast_wakerfn(void *arg)
+{
+ thread_arg_t *args = (thread_arg_t *)arg;
+ int nr_requeue = INT_MAX;
+ int task_count = 0;
+ futex_t old_val;
+ int nr_wake = 1;
+ int i = 0;
+
+ info("Waker: waiting for waiters to block\n");
+ while (waiters_blocked.val < THREAD_MAX)
+ usleep(1000);
+ usleep(1000);
+
+ info("Waker: Calling broadcast\n");
+ if (args->lock) {
+ info("Calling FUTEX_LOCK_PI on mutex=%x @ %p\n", f2, &f2);
+ futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG);
+ }
+ continue_requeue:
+ old_val = f1;
+ args->ret = futex_cmp_requeue_pi(&f1, old_val, &f2, nr_wake, nr_requeue,
+ FUTEX_PRIVATE_FLAG);
+ if (args->ret < 0) {
+ args->ret = RET_ERROR;
+ error("FUTEX_CMP_REQUEUE_PI failed\n", errno);
+ } else if (++i < MAX_WAKE_ITERS) {
+ task_count += args->ret;
+ if (task_count < THREAD_MAX - waiters_woken.val)
+ goto continue_requeue;
+ } else {
+ error("max broadcast iterations (%d) reached with %d/%d tasks woken or requeued\n",
+ 0, MAX_WAKE_ITERS, task_count, THREAD_MAX);
+ args->ret = RET_ERROR;
+ }
+
+ futex_wake(&wake_complete, 1, FUTEX_PRIVATE_FLAG);
+
+ if (args->lock)
+ futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG);
+
+ if (args->ret > 0)
+ args->ret = task_count;
+
+ info("Waker: exiting with %d\n", args->ret);
+ pthread_exit((void *)&args->ret);
+}
+
+void *signal_wakerfn(void *arg)
+{
+ thread_arg_t *args = (thread_arg_t *)arg;
+ unsigned int old_val;
+ int nr_requeue = 0;
+ int task_count = 0;
+ int nr_wake = 1;
+ int i = 0;
+
+ info("Waker: waiting for waiters to block\n");
+ while (waiters_blocked.val < THREAD_MAX)
+ usleep(1000);
+ usleep(1000);
+
+ while (task_count < THREAD_MAX && waiters_woken.val < THREAD_MAX) {
+ info("task_count: %d, waiters_woken: %d\n",
+ task_count, waiters_woken.val);
+ if (args->lock) {
+ info("Calling FUTEX_LOCK_PI on mutex=%x @ %p\n",
+ f2, &f2);
+ futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG);
+ }
+ info("Waker: Calling signal\n");
+ /* cond_signal */
+ old_val = f1;
+ args->ret = futex_cmp_requeue_pi(&f1, old_val, &f2,
+ nr_wake, nr_requeue,
+ FUTEX_PRIVATE_FLAG);
+ if (args->ret < 0)
+ args->ret = -errno;
+ info("futex: %x\n", f2);
+ if (args->lock) {
+ info("Calling FUTEX_UNLOCK_PI on mutex=%x @ %p\n",
+ f2, &f2);
+ futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG);
+ }
+ info("futex: %x\n", f2);
+ if (args->ret < 0) {
+ error("FUTEX_CMP_REQUEUE_PI failed\n", errno);
+ args->ret = RET_ERROR;
+ break;
+ }
+
+ task_count += args->ret;
+ usleep(SIGNAL_PERIOD_US);
+ i++;
+ /* we have to loop at least THREAD_MAX times */
+ if (i > MAX_WAKE_ITERS + THREAD_MAX) {
+ error("max signaling iterations (%d) reached, giving up on pending waiters.\n",
+ 0, MAX_WAKE_ITERS + THREAD_MAX);
+ args->ret = RET_ERROR;
+ break;
+ }
+ }
+
+ futex_wake(&wake_complete, 1, FUTEX_PRIVATE_FLAG);
+
+ if (args->ret >= 0)
+ args->ret = task_count;
+
+ info("Waker: exiting with %d\n", args->ret);
+ info("Waker: waiters_woken: %d\n", waiters_woken.val);
+ pthread_exit((void *)&args->ret);
+}
+
+void *third_party_blocker(void *arg)
+{
+ thread_arg_t *args = (thread_arg_t *)arg;
+ int ret2 = 0;
+
+ if ((args->ret = futex_lock_pi(&f2, NULL, 0, FUTEX_PRIVATE_FLAG)))
+ goto out;
+ args->ret = futex_wait(&wake_complete, wake_complete, NULL,
+ FUTEX_PRIVATE_FLAG);
+ ret2 = futex_unlock_pi(&f2, FUTEX_PRIVATE_FLAG);
+
+ out:
+ if (args->ret || ret2) {
+ error("third_party_blocker() futex error", 0);
+ args->ret = RET_ERROR;
+ }
+
+ pthread_exit((void *)&args->ret);
+}
+
+int unit_test(int broadcast, long lock, int third_party_owner, long timeout_ns)
+{
+ void *(*wakerfn)(void *) = signal_wakerfn;
+ thread_arg_t blocker_arg = THREAD_ARG_INITIALIZER;
+ thread_arg_t waker_arg = THREAD_ARG_INITIALIZER;
+ pthread_t waiter[THREAD_MAX], waker, blocker;
+ struct timespec ts, *tsp = NULL;
+ thread_arg_t args[THREAD_MAX];
+ int *waiter_ret;
+ int i, ret = RET_PASS;
+
+ if (timeout_ns) {
+ time_t secs;
+
+ info("timeout_ns = %ld\n", timeout_ns);
+ ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+ secs = (ts.tv_nsec + timeout_ns) / 1000000000;
+ ts.tv_nsec = ((int64_t)ts.tv_nsec + timeout_ns) % 1000000000;
+ ts.tv_sec += secs;
+ info("ts.tv_sec = %ld\n", ts.tv_sec);
+ info("ts.tv_nsec = %ld\n", ts.tv_nsec);
+ tsp = &ts;
+ }
+
+ if (broadcast)
+ wakerfn = broadcast_wakerfn;
+
+ if (third_party_owner) {
+ if (create_rt_thread(&blocker, third_party_blocker,
+ (void *)&blocker_arg, SCHED_FIFO, 1)) {
+ error("Creating third party blocker thread failed\n",
+ errno);
+ ret = RET_ERROR;
+ goto out;
+ }
+ }
+
+ atomic_set(&waiters_woken, 0);
+ for (i = 0; i < THREAD_MAX; i++) {
+ args[i].id = i;
+ args[i].timeout = tsp;
+ info("Starting thread %d\n", i);
+ if (create_rt_thread(&waiter[i], waiterfn, (void *)&args[i],
+ SCHED_FIFO, 1)) {
+ error("Creating waiting thread failed\n", errno);
+ ret = RET_ERROR;
+ goto out;
+ }
+ }
+ waker_arg.lock = lock;
+ if (create_rt_thread(&waker, wakerfn, (void *)&waker_arg,
+ SCHED_FIFO, 1)) {
+ error("Creating waker thread failed\n", errno);
+ ret = RET_ERROR;
+ goto out;
+ }
+
+ /* Wait for threads to finish */
+ /* Store the first error or failure encountered in waiter_ret */
+ waiter_ret = &args[0].ret;
+ for (i = 0; i < THREAD_MAX; i++)
+ pthread_join(waiter[i], *waiter_ret ? NULL : (void **)&waiter_ret);
+
+ if (third_party_owner)
+ pthread_join(blocker, NULL);
+ pthread_join(waker, NULL);
+
+out:
+ if (!ret) {
+ if (*waiter_ret)
+ ret = *waiter_ret;
+ else if (waker_arg.ret < 0)
+ ret = waker_arg.ret;
+ else if (blocker_arg.ret)
+ ret = blocker_arg.ret;
+ }
+
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ int c, ret;
+
+ while ((c = getopt(argc, argv, "bchlot:v:")) != -1) {
+ switch (c) {
+ case 'b':
+ broadcast = 1;
+ break;
+ case 'c':
+ log_color(1);
+ break;
+ case 'h':
+ usage(basename(argv[0]));
+ exit(0);
+ case 'l':
+ locked = 1;
+ break;
+ case 'o':
+ owner = 1;
+ locked = 0;
+ break;
+ case 't':
+ timeout_ns = atoi(optarg);
+ break;
+ case 'v':
+ log_verbosity(atoi(optarg));
+ break;
+ default:
+ usage(basename(argv[0]));
+ exit(1);
+ }
+ }
+
+ printf("%s: Test requeue functionality\n", basename(argv[0]));
+ printf("\tArguments: broadcast=%d locked=%d owner=%d timeout=%ldns\n",
+ broadcast, locked, owner, timeout_ns);
+
+ /*
+ * FIXME: unit_test is obsolete now that we parse options and the
+ * various style of runs are done by run.sh - simplify the code and move
+ * unit_test into main()
+ */
+ ret = unit_test(broadcast, locked, owner, timeout_ns);
+
+ print_result(ret);
+ return ret;
+}
diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c b/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c
new file mode 100644
index 0000000..4bf8fc9
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c
@@ -0,0 +1,136 @@
+/******************************************************************************
+ *
+ * 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-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
+ *
+ * HISTORY
+ * 2009-Nov-9: Initial version by Darren Hart <dvhart-VuQAYsv1560/9W2qTSuDoA@public.gmane.org.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;
+}
diff --git a/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c b/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c
new file mode 100644
index 0000000..6cb2a6a
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c
@@ -0,0 +1,220 @@
+/******************************************************************************
+ *
+ * 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-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
+ *
+ * HISTORY
+ * 2008-May-5: Initial version by Darren Hart <dvhart-VuQAYsv1560/9W2qTSuDoA@public.gmane.org.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;
+
+typedef struct struct_waiter_arg {
+ long id;
+ struct timespec *timeout;
+} waiter_arg_t;
+
+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)
+{
+ int ret;
+ struct sched_param schedp;
+ pthread_attr_t attr;
+
+ pthread_attr_init(&attr);
+ memset(&schedp, 0, sizeof(schedp));
+
+ if ((ret = pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED)) != 0) {
+ error("pthread_attr_setinheritsched\n", ret);
+ return -1;
+ }
+
+ if ((ret = pthread_attr_setschedpolicy(&attr, policy)) != 0) {
+ error("pthread_attr_setschedpolicy\n", ret);
+ return -1;
+ }
+
+ schedp.sched_priority = prio;
+ if ((ret = pthread_attr_setschedparam(&attr, &schedp)) != 0) {
+ error("pthread_attr_setschedparam\n", ret);
+ return -1;
+ }
+
+ if ((ret = pthread_create(pth, &attr, func, arg)) != 0) {
+ 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");
+ if ((res = create_rt_thread(&waiter, waiterfn, NULL, SCHED_FIFO, 1))) {
+ 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;
+}
diff --git a/tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c b/tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c
new file mode 100644
index 0000000..cdd54b9
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c
@@ -0,0 +1,126 @@
+/******************************************************************************
+ *
+ * Copyright FUJITSU LIMITED 2010
+ * Copyright KOSAKI Motohiro <kosaki.motohiro-+CUm20s59erQFUHtdCDX3A@public.gmane.org>
+ *
+ * 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-+CUm20s59erQFUHtdCDX3A@public.gmane.org>
+ *
+ * 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;
+}
diff --git a/tools/testing/selftests/futex/functional/futex_wait_timeout.c b/tools/testing/selftests/futex/functional/futex_wait_timeout.c
new file mode 100644
index 0000000..95c2d28
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_wait_timeout.c
@@ -0,0 +1,85 @@
+/******************************************************************************
+ *
+ * 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-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
+ *
+ * HISTORY
+ * 2009-Nov-6: Initial version by Darren Hart <dvhart-VuQAYsv1560/9W2qTSuDoA@public.gmane.org.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;
+}
diff --git a/tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c b/tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c
new file mode 100644
index 0000000..db077ae
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c
@@ -0,0 +1,124 @@
+/******************************************************************************
+ *
+ * Copyright FUJITSU LIMITED 2010
+ * Copyright KOSAKI Motohiro <kosaki.motohiro-+CUm20s59erQFUHtdCDX3A@public.gmane.org>
+ *
+ * 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-+CUm20s59erQFUHtdCDX3A@public.gmane.org>
+ *
+ * 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);
+
+ if (child_blocked) {
+ fail("child blocked in kernel\n");
+ ret = RET_FAIL;
+ } else {
+ ret = child_ret;
+ }
+
+ out:
+ print_result(ret);
+ return ret;
+}
diff --git a/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
new file mode 100644
index 0000000..b6b0274
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
@@ -0,0 +1,79 @@
+/******************************************************************************
+ *
+ * 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-xthvdsQ13ZrQT0dZR+AlfA@public.gmane.org>
+ *
+ * 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;
+}
diff --git a/tools/testing/selftests/futex/functional/run.sh b/tools/testing/selftests/futex/functional/run.sh
new file mode 100755
index 0000000..e87dbe2
--- /dev/null
+++ b/tools/testing/selftests/futex/functional/run.sh
@@ -0,0 +1,79 @@
+#!/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-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
+#
+# HISTORY
+# 2009-Nov-9: Initial version by Darren Hart <dvhart-VuQAYsv1562uYJLRA6qg5Q@public.gmane.orgcom>
+# 2010-Jan-6: Add futex_wait_uninitialized_heap and futex_wait_private_mapped_file
+# by KOSAKI Motohiro <kosaki.motohiro-+CUm20s59erQFUHtdCDX3A@public.gmane.org>
+#
+###############################################################################
+
+# 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
diff --git a/tools/testing/selftests/futex/include/atomic.h b/tools/testing/selftests/futex/include/atomic.h
new file mode 100644
index 0000000..f861da3
--- /dev/null
+++ b/tools/testing/selftests/futex/include/atomic.h
@@ -0,0 +1,83 @@
+/******************************************************************************
+ *
+ * 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-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
+ *
+ * HISTORY
+ * 2009-Nov-17: Initial version by Darren Hart <dvhart-VuQAYsv1563N0uC3ymp8PA@public.gmane.orgl.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
diff --git a/tools/testing/selftests/futex/include/futextest.h b/tools/testing/selftests/futex/include/futextest.h
new file mode 100644
index 0000000..7b4bbab
--- /dev/null
+++ b/tools/testing/selftests/futex/include/futextest.h
@@ -0,0 +1,266 @@
+/******************************************************************************
+ *
+ * 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-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
+ *
+ * HISTORY
+ * 2009-Nov-6: Initial version by Darren Hart <dvhart-VuQAYsv1560/9W2qTSuDoA@public.gmane.org.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
diff --git a/tools/testing/selftests/futex/include/logging.h b/tools/testing/selftests/futex/include/logging.h
new file mode 100644
index 0000000..3220b90
--- /dev/null
+++ b/tools/testing/selftests/futex/include/logging.h
@@ -0,0 +1,147 @@
+/******************************************************************************
+ *
+ * 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-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
+ *
+ * HISTORY
+ * 2009-Nov-6: Initial version by Darren Hart <dvhart-VuQAYsv1560/9W2qTSuDoA@public.gmane.org.com>
+ *
+ *****************************************************************************/
+
+#ifndef _LOGGING_H
+#define _LOGGING_H
+
+#include <string.h>
+#include <unistd.h>
+#include <linux/futex.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";
+char *INFO = INFO_NORMAL;
+char *PASS = PASS_NORMAL;
+char *ERROR = ERROR_NORMAL;
+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)
+{
+ char *result = "Unknown return code";
+
+ switch (ret) {
+ case RET_PASS:
+ result = PASS;
+ break;
+ case RET_ERROR:
+ result = ERROR;
+ break;
+ case RET_FAIL:
+ 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
diff --git a/tools/testing/selftests/futex/run.sh b/tools/testing/selftests/futex/run.sh
new file mode 100755
index 0000000..4126312
--- /dev/null
+++ b/tools/testing/selftests/futex/run.sh
@@ -0,0 +1,33 @@
+#!/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-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
+#
+# HISTORY
+# 2009-Nov-9: Initial version by Darren Hart <dvhart-VuQAYsv1562uYJLRA6qg5Q@public.gmane.orgcom>
+#
+###############################################################################
+
+# 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)
--
2.1.4
^ permalink raw reply related
* [GIT PULL] selftest: Add futex functional tests
From: Darren Hart @ 2015-03-27 22:17 UTC (permalink / raw)
To: Linux Kernel Mailing List
Cc: Shuah Khan, linux-api-u79uwXL29TY76Z2rM5mHXA, Ingo Molnar,
Peter Zijlstra, Thomas Gleixner, Davidlohr Bueso, KOSAKI Motohiro,
Darren Hart
Hi Shuah,
This series begins the process of migrating my futextest tests into kselftest.
I've started with only the functional tests, as the performance and stress may
not be appropriate for kselftest as they stand.
I cleaned up various complaints from checkpatch, but I ignored others that would
require significant rework of the testcases, such as not using volatile and not
creating new typedefs.
The patches will follow, but I'm providing a pull request for your convenience
as well.
The following changes since commit 0b63accf87225b5eb7e52814c374cf02d733d4bb:
tools, update rtctest.c to verify passage of time (2015-03-24 22:02:59 -0600)
are available in the git repository at:
git://git.infradead.org/users/dvhart/linux.git futextest
Darren Hart (5):
selftests: Add futex functional tests
selftest/futex: Update Makefile to use lib.mk
selftest/futex: Increment ksft pass and fail counters
selftest: Add futex tests to the top-level Makefile
kselftest: Add exit code defines
tools/testing/selftests/Makefile | 1 +
tools/testing/selftests/futex/Makefile | 29 ++
tools/testing/selftests/futex/README | 62 ++++
tools/testing/selftests/futex/functional/Makefile | 25 ++
.../selftests/futex/functional/futex_requeue_pi.c | 402 +++++++++++++++++++++
.../functional/futex_requeue_pi_mismatched_ops.c | 136 +++++++
.../functional/futex_requeue_pi_signal_restart.c | 220 +++++++++++
.../functional/futex_wait_private_mapped_file.c | 126 +++++++
.../futex/functional/futex_wait_timeout.c | 85 +++++
.../functional/futex_wait_uninitialized_heap.c | 124 +++++++
.../futex/functional/futex_wait_wouldblock.c | 79 ++++
tools/testing/selftests/futex/functional/run.sh | 79 ++++
tools/testing/selftests/futex/include/atomic.h | 83 +++++
tools/testing/selftests/futex/include/futextest.h | 266 ++++++++++++++
tools/testing/selftests/futex/include/logging.h | 150 ++++++++
tools/testing/selftests/futex/run.sh | 33 ++
tools/testing/selftests/kselftest.h | 17 +-
17 files changed, 1912 insertions(+), 5 deletions(-)
create mode 100644 tools/testing/selftests/futex/Makefile
create mode 100644 tools/testing/selftests/futex/README
create mode 100644 tools/testing/selftests/futex/functional/Makefile
create mode 100644 tools/testing/selftests/futex/functional/futex_requeue_pi.c
create mode 100644 tools/testing/selftests/futex/functional/futex_requeue_pi_mismatched_ops.c
create mode 100644 tools/testing/selftests/futex/functional/futex_requeue_pi_signal_restart.c
create mode 100644 tools/testing/selftests/futex/functional/futex_wait_private_mapped_file.c
create mode 100644 tools/testing/selftests/futex/functional/futex_wait_timeout.c
create mode 100644 tools/testing/selftests/futex/functional/futex_wait_uninitialized_heap.c
create mode 100644 tools/testing/selftests/futex/functional/futex_wait_wouldblock.c
create mode 100755 tools/testing/selftests/futex/functional/run.sh
create mode 100644 tools/testing/selftests/futex/include/atomic.h
create mode 100644 tools/testing/selftests/futex/include/futextest.h
create mode 100644 tools/testing/selftests/futex/include/logging.h
create mode 100755 tools/testing/selftests/futex/run.sh
--
2.1.4
^ permalink raw reply
* [PATCH 3/3] Documentation/ABI: Update sysfs-driver-toshiba_acpi entry
From: Azael Avalos @ 2015-03-27 21:10 UTC (permalink / raw)
To: Darren Hart, platform-driver-x86, linux-kernel, linux-api; +Cc: Azael Avalos
This patch updates the sysfs-driver-toshiba_acpi entry, adding the
missing entries for USB Sleep functions.
And also, while at the neighborhood, fix some typos and add a note
that some features require a reboot.
Signed-off-by: Azael Avalos <coproscefalo@gmail.com>
---
.../ABI/testing/sysfs-driver-toshiba_acpi | 93 +++++++++++++++++++---
1 file changed, 80 insertions(+), 13 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-driver-toshiba_acpi b/Documentation/ABI/testing/sysfs-driver-toshiba_acpi
index ca9c71a..eed922e 100644
--- a/Documentation/ABI/testing/sysfs-driver-toshiba_acpi
+++ b/Documentation/ABI/testing/sysfs-driver-toshiba_acpi
@@ -8,9 +8,11 @@ Description: This file controls the keyboard backlight operation mode, valid
* 0x2 -> AUTO (also called TIMER)
* 0x8 -> ON
* 0x10 -> OFF
- Note that the kernel 3.16 onwards this file accepts all listed
+ Note that from kernel 3.16 onwards this file accepts all listed
parameters, kernel 3.15 only accepts the first two (FN-Z and
AUTO).
+ Also note that toggling this value on type 1 devices, requires
+ a reboot for changes to take effect.
Users: KToshiba
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/kbd_backlight_timeout
@@ -67,15 +69,72 @@ Description: This file shows the current keyboard backlight type,
* 2 -> Type 2, supporting modes TIMER, ON and OFF
Users: KToshiba
+What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/usb_sleep_charge
+Date: January 23, 2015
+KernelVersion: 4.0
+Contact: Azael Avalos <coproscefalo@gmail.com>
+Description: This file controls the USB Sleep & Charge charging mode, which
+ can be:
+ * 0 -> Disabled (0x00)
+ * 1 -> Alternate (0x09)
+ * 2 -> Auto (0x21)
+ * 3 -> Typical (0x11)
+ Note that from kernel 4.1 onwards this file accepts all listed
+ values, kernel 4.0 only supports the first three.
+ Note that this feature only works when connected to power, if
+ you want to use it under battery, see the entry named
+ "sleep_functions_on_battery"
+Users: KToshiba
+
+What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/sleep_functions_on_battery
+Date: January 23, 2015
+KernelVersion: 4.0
+Contact: Azael Avalos <coproscefalo@gmail.com>
+Description: This file controls the USB Sleep Functions under battery, and
+ set the level at which point they will be disabled, accepted
+ values can be:
+ * 0 -> Disabled
+ * 1-100 -> Battery level to disable sleep functions
+ Currently it prints two values, the first one indicates if the
+ feature is enabled or disabled, while the second one shows the
+ current battery level set.
+ Note that when the value is set to disabled, the sleep function
+ will only work when connected to power.
+Users: KToshiba
+
+What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/usb_rapid_charge
+Date: January 23, 2015
+KernelVersion: 4.0
+Contact: Azael Avalos <coproscefalo@gmail.com>
+Description: This file controls the USB Rapid Charge state, which can be:
+ * 0 -> Disabled
+ * 1 -> Enabled
+ Note that toggling this value requires a reboot for changes to
+ take effect.
+Users: KToshiba
+
+What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/usb_sleep_music
+Date: January 23, 2015
+KernelVersion: 4.0
+Contact: Azael Avalos <coproscefalo@gmail.com>
+Description: This file controls the Sleep & Music state, which values can be:
+ * 0 -> Disabled
+ * 1 -> Enabled
+ Note that this feature only works when connected to power, if
+ you want to use it under battery, see the entry named
+ "sleep_functions_on_battery"
+Users: KToshiba
+
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/version
-Date: February, 2015
-KernelVersion: 3.20
+Date: February 12, 2015
+KernelVersion: 4.0
Contact: Azael Avalos <coproscefalo@gmail.com>
Description: This file shows the current version of the driver
+Users: KToshiba
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/fan
-Date: February, 2015
-KernelVersion: 3.20
+Date: February 12, 2015
+KernelVersion: 4.0
Contact: Azael Avalos <coproscefalo@gmail.com>
Description: This file controls the state of the internal fan, valid
values are:
@@ -83,8 +142,8 @@ Description: This file controls the state of the internal fan, valid
* 1 -> ON
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/kbd_function_keys
-Date: February, 2015
-KernelVersion: 3.20
+Date: February 12, 2015
+KernelVersion: 4.0
Contact: Azael Avalos <coproscefalo@gmail.com>
Description: This file controls the Special Functions (hotkeys) operation
mode, valid values are:
@@ -94,21 +153,29 @@ Description: This file controls the Special Functions (hotkeys) operation
and the hotkeys are accessed via FN-F{1-12}.
In the "Special Functions" mode, the F{1-12} keys trigger the
hotkey and the F{1-12} keys are accessed via FN-F{1-12}.
+ Note that toggling this value requires a reboot for changes to
+ take effect.
+Users: KToshiba
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/panel_power_on
-Date: February, 2015
-KernelVersion: 3.20
+Date: February 12, 2015
+KernelVersion: 4.0
Contact: Azael Avalos <coproscefalo@gmail.com>
Description: This file controls whether the laptop should turn ON whenever
the LID is opened, valid values are:
* 0 -> Disabled
* 1 -> Enabled
+ Note that toggling this value requires a reboot for changes to
+ take effect.
+Users: KToshiba
What: /sys/devices/LNXSYSTM:00/LNXSYBUS:00/TOS{1900,620{0,7,8}}:00/usb_three
-Date: February, 2015
-KernelVersion: 3.20
+Date: February 12, 2015
+KernelVersion: 4.0
Contact: Azael Avalos <coproscefalo@gmail.com>
-Description: This file controls whether the USB 3 functionality, valid
- values are:
+Description: This file controls the USB 3 functionality, valid values are:
* 0 -> Disabled (Acts as a regular USB 2)
* 1 -> Enabled (Full USB 3 functionality)
+ Note that toggling this value requires a reboot for changes to
+ take effect.
+Users: KToshiba
--
2.2.2
^ permalink raw reply related
* Re: [PATCH 3/5] of: overlay: Master enable switch
From: Pantelis Antoniou @ 2015-03-27 18:25 UTC (permalink / raw)
To: Rob Herring
Cc: Grant Likely, Andrew Morton, Matt Porter, Koen Kooi,
Guenter Roeck, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-api@vger.kernel.org
In-Reply-To: <CAL_JsqKZZW=Vq9Mry9H0yjnv=TW8P=xzyX3EjQP+B15U0roaBA@mail.gmail.com>
Hi Rob,
> On Mar 24, 2015, at 22:25 , Rob Herring <robherring2@gmail.com> wrote:
>
> On Tue, Mar 17, 2015 at 3:30 PM, Pantelis Antoniou
> <pantelis.antoniou@konsulko.com> wrote:
>> Implement a throw once master enable switch to protect against any
>> further overlay applications if the administrator desires so.
>
> sysfs documentation?
>
OK, coming up.
>> Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
>> ---
>> drivers/of/overlay.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++-
>> 1 file changed, 65 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
>> index f17f5ef..6688797 100644
>> --- a/drivers/of/overlay.c
>> +++ b/drivers/of/overlay.c
>> @@ -21,6 +21,7 @@
>> #include <linux/err.h>
>> #include <linux/idr.h>
>> #include <linux/sysfs.h>
>> +#include <linux/atomic.h>
>>
>> #include "of_private.h"
>>
>> @@ -55,6 +56,9 @@ struct of_overlay {
>> struct kobject kobj;
>> };
>>
>> +/* master enable switch; once set to 0 can't be re-enabled */
>> +static atomic_t ov_enable = ATOMIC_INIT(1);
>> +
>> static int of_overlay_apply_one(struct of_overlay *ov,
>> struct device_node *target, const struct device_node *overlay);
>>
>> @@ -345,6 +349,60 @@ static struct kobj_type of_overlay_ktype = {
>>
>> static struct kset *ov_kset;
>>
>> +static ssize_t enable_read(struct file *filp, struct kobject *kobj,
>> + struct bin_attribute *bin_attr, char *buf,
>> + loff_t offset, size_t count)
>> +{
>> + char tbuf[3];
>> +
>> + if (offset < 0)
>> + return -EINVAL;
>> +
>> + if (offset >= sizeof(tbuf))
>> + return 0;
>> +
>> + if (count > sizeof(tbuf) - offset)
>> + count = sizeof(tbuf) - offset;
>> +
>> + /* fill in temp */
>> + tbuf[0] = '0' + atomic_read(&ov_enable);
>> + tbuf[1] = '\n';
>> + tbuf[2] = '\0';
>> +
>> + /* copy to buffer */
>> + memcpy(buf, tbuf + offset, count);
>> +
>> + return count;
>> +}
>> +
>> +static ssize_t enable_write(struct file *filp, struct kobject *kobj,
>> + struct bin_attribute *bin_attr, char *buf,
>> + loff_t off, size_t count)
>> +{
>> + int new_enable;
>> +
>> + if (off != 0 || (buf[0] != '0' && buf[1] != '1'))
>
> Is buf[1] correct here?
>
Nope.
>> + return -EINVAL;
>> +
>> + new_enable = buf[0] - '0';
>> + if (new_enable != 0 && new_enable != 1)
>
> Make unsigned just "if (new_enable > 1)”.
>
OK.
>> + return -EINVAL;
>> +
>> + /* NOP for same value */
>> + if (new_enable == atomic_read(&ov_enable))
>> + return count;
>> +
>> + /* if we've disabled it, no going back */
>> + if (atomic_read(&ov_enable) == 0)
>> + return -EPERM;
>> +
>> + atomic_set(&ov_enable, new_enable);
>> + return count;
>> +}
>> +
>> +/* just a single char + '\n' + '\0' */
>> +static BIN_ATTR_RW(enable, 3);
>> +
>> /**
>> * of_overlay_create() - Create and apply an overlay
>> * @tree: Device node containing all the overlays
>> @@ -360,6 +418,10 @@ int of_overlay_create(struct device_node *tree)
>> struct of_overlay *ov;
>> int err, id;
>>
>> + /* administratively disabled */
>> + if (!atomic_read(&ov_enable))
>> + return -EPERM;
>> +
>> /* allocate the overlay structure */
>> ov = kzalloc(sizeof(*ov), GFP_KERNEL);
>> if (ov == NULL)
>> @@ -596,5 +658,7 @@ int of_overlay_init(void)
>> if (!ov_kset)
>> return -ENOMEM;
>>
>> - return 0;
>> + rc = sysfs_create_bin_file(&ov_kset->kobj, &bin_attr_enable);
>> + WARN(rc, "%s: error adding enable attribute\n", __func__);
>> + return rc;
>> }
>> --
>> 1.7.12
Regards
— Pantelis
^ permalink raw reply
* Re: [PATCH 1/5] of: unittest: overlay: Keep track of created overlays
From: Pantelis Antoniou @ 2015-03-27 18:24 UTC (permalink / raw)
To: Rob Herring
Cc: Grant Likely, Andrew Morton, Matt Porter, Koen Kooi,
Guenter Roeck, devicetree@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-api@vger.kernel.org
In-Reply-To: <CAL_JsqKjGb5coH9aDPoSm63YV+E7d+A_VpzgA8W2iSuQ4ViAaw@mail.gmail.com>
Hi Rob,
> On Mar 24, 2015, at 21:53 , Rob Herring <robherring2@gmail.com> wrote:
>
> On Tue, Mar 17, 2015 at 3:30 PM, Pantelis Antoniou
> <pantelis.antoniou@konsulko.com> wrote:
>> During the course of the overlay selftests some of them remain
>> applied. While this does not pose a real problem, make sure you track
>> them and destroy them at the end of the test.
>
> This is going to need to be rebased on my tree as there has been some
> selftest->unitest renaming.
>
Ok, will do so first thing next week.
> Rob
>
Regards
— Pantelis
>>
>> Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
>> ---
>> drivers/of/unittest.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++
>> 1 file changed, 62 insertions(+)
>>
>> diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
>> index 4e60682..c711534 100644
>> --- a/drivers/of/unittest.c
>> +++ b/drivers/of/unittest.c
>> @@ -23,6 +23,8 @@
>> #include <linux/i2c.h>
>> #include <linux/i2c-mux.h>
>>
>> +#include <linux/bitops.h>
>> +
>> #include "of_private.h"
>>
>> static struct selftest_results {
>> @@ -1115,6 +1117,59 @@ static const char *overlay_path(int nr)
>>
>> static const char *bus_path = "/testcase-data/overlay-node/test-bus";
>>
>> +/* it is guaranteed that overlay ids are assigned in sequence */
>> +#define MAX_SELFTEST_OVERLAYS 256
>> +static unsigned long overlay_id_bits[BITS_TO_LONGS(MAX_SELFTEST_OVERLAYS)];
>> +static int overlay_first_id = -1;
>> +
>> +static void of_selftest_track_overlay(int id)
>> +{
>> + if (overlay_first_id < 0)
>> + overlay_first_id = id;
>> + id -= overlay_first_id;
>> +
>> + /* we shouldn't need that many */
>> + BUG_ON(id >= MAX_SELFTEST_OVERLAYS);
>> + overlay_id_bits[BIT_WORD(id)] |= BIT_MASK(id);
>> +}
>> +
>> +static void of_selftest_untrack_overlay(int id)
>> +{
>> + if (overlay_first_id < 0)
>> + return;
>> + id -= overlay_first_id;
>> + BUG_ON(id >= MAX_SELFTEST_OVERLAYS);
>> + overlay_id_bits[BIT_WORD(id)] &= ~BIT_MASK(id);
>> +}
>> +
>> +static void of_selftest_destroy_tracked_overlays(void)
>> +{
>> + int id, ret, defers;
>> +
>> + if (overlay_first_id < 0)
>> + return;
>> +
>> + /* try until no defers */
>> + do {
>> + defers = 0;
>> + /* remove in reverse order */
>> + for (id = MAX_SELFTEST_OVERLAYS - 1; id >= 0; id--) {
>> + if (!(overlay_id_bits[BIT_WORD(id)] & BIT_MASK(id)))
>> + continue;
>> +
>> + ret = of_overlay_destroy(id + overlay_first_id);
>> + if (ret != 0) {
>> + defers++;
>> + pr_warn("%s: overlay destroy failed for #%d\n",
>> + __func__, id + overlay_first_id);
>> + continue;
>> + }
>> +
>> + overlay_id_bits[BIT_WORD(id)] &= ~BIT_MASK(id);
>> + }
>> + } while (defers > 0);
>> +}
>> +
>> static int of_selftest_apply_overlay(int selftest_nr, int overlay_nr,
>> int *overlay_id)
>> {
>> @@ -1136,6 +1191,7 @@ static int of_selftest_apply_overlay(int selftest_nr, int overlay_nr,
>> goto out;
>> }
>> id = ret;
>> + of_selftest_track_overlay(id);
>>
>> ret = 0;
>>
>> @@ -1349,6 +1405,7 @@ static void of_selftest_overlay_6(void)
>> return;
>> }
>> ov_id[i] = ret;
>> + of_selftest_track_overlay(ov_id[i]);
>> }
>>
>> for (i = 0; i < 2; i++) {
>> @@ -1373,6 +1430,7 @@ static void of_selftest_overlay_6(void)
>> PDEV_OVERLAY));
>> return;
>> }
>> + of_selftest_untrack_overlay(ov_id[i]);
>> }
>>
>> for (i = 0; i < 2; i++) {
>> @@ -1417,6 +1475,7 @@ static void of_selftest_overlay_8(void)
>> return;
>> }
>> ov_id[i] = ret;
>> + of_selftest_track_overlay(ov_id[i]);
>> }
>>
>> /* now try to remove first overlay (it should fail) */
>> @@ -1439,6 +1498,7 @@ static void of_selftest_overlay_8(void)
>> PDEV_OVERLAY));
>> return;
>> }
>> + of_selftest_untrack_overlay(ov_id[i]);
>> }
>>
>> selftest(1, "overlay test %d passed\n", 8);
>> @@ -1861,6 +1921,8 @@ static void __init of_selftest_overlay(void)
>> of_selftest_overlay_i2c_cleanup();
>> #endif
>>
>> + of_selftest_destroy_tracked_overlays();
>> +
>> out:
>> of_node_put(bus_np);
>> }
>> --
>> 1.7.12
^ permalink raw reply
* Re: [PATCH v2 3/4] mm, shmem: Add shmem resident memory accounting
From: Konstantin Khlebnikov @ 2015-03-27 17:09 UTC (permalink / raw)
To: Vlastimil Babka, linux-mm, Jerome Marchand
Cc: linux-kernel, Andrew Morton, linux-doc, Hugh Dickins,
Michal Hocko, Kirill A. Shutemov, Cyrill Gorcunov, Randy Dunlap,
linux-s390, Martin Schwidefsky, Heiko Carstens, Peter Zijlstra,
Paul Mackerras, Arnaldo Carvalho de Melo, Oleg Nesterov,
Linux API
In-Reply-To: <1427474441-17708-4-git-send-email-vbabka@suse.cz>
On 27.03.2015 19:40, Vlastimil Babka wrote:
> From: Jerome Marchand <jmarchan@redhat.com>
>
> Currently looking at /proc/<pid>/status or statm, there is no way to
> distinguish shmem pages from pages mapped to a regular file (shmem
> pages are mapped to /dev/zero), even though their implication in
> actual memory use is quite different.
> This patch adds MM_SHMEMPAGES counter to mm_rss_stat to account for
> shmem pages instead of MM_FILEPAGES.
>
> Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
> Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
> ---
> --- a/include/linux/mm_types.h
> +++ b/include/linux/mm_types.h
> @@ -327,9 +327,12 @@ struct core_state {
> };
>
> enum {
> - MM_FILEPAGES,
> - MM_ANONPAGES,
> - MM_SWAPENTS,
> + MM_FILEPAGES, /* Resident file mapping pages */
> + MM_ANONPAGES, /* Resident anonymous pages */
> + MM_SWAPENTS, /* Anonymous swap entries */
> +#ifdef CONFIG_SHMEM
> + MM_SHMEMPAGES, /* Resident shared memory pages */
> +#endif
I prefer to keep that counter unconditionally:
kernel has MM_SWAPENTS even without CONFIG_SWAP.
> NR_MM_COUNTERS
> };
>
^ permalink raw reply
* Re: [PATCH v7 0/5] vfs: Non-blockling buffered fs read (page cache only)
From: Andrew Morton @ 2015-03-27 17:04 UTC (permalink / raw)
To: Milosz Tanski
Cc: LKML, Christoph Hellwig, linux-fsdevel@vger.kernel.org,
linux-aio@kvack.org, Mel Gorman, Volker Lendecke, Tejun Heo,
Jeff Moyer, Theodore Ts'o, Al Viro, Linux API,
Michael Kerrisk, linux-arch, Dave Chinner
In-Reply-To: <CANP1eJEbDusq_Gda35dGKiacC+2tbvb_bQEEHpi6PmgnNoWDFw@mail.gmail.com>
On Fri, 27 Mar 2015 11:21:26 -0400 Milosz Tanski <milosz@adfin.com> wrote:
> On Thu, Mar 26, 2015 at 11:28 PM, Andrew Morton
> <akpm@linux-foundation.org> wrote:
> > On Mon, 16 Mar 2015 14:27:10 -0400 Milosz Tanski <milosz@adfin.com> wrote:
> >
> >> This patchset introduces two new syscalls preadv2 and pwritev2. They are the
> >> same syscalls as preadv and pwrite but with a flag argument. Additionally,
> >> preadv2 implements an extra RWF_NONBLOCK flag.
> >
> > I still don't understand why pwritev() exists. We discussed this last
> > time but it seems nothing has changed. I'm not seeing here an adequate
> > description of why it exists nor a justification for its addition.
>
> In the "Forward Looking" section there's a description of why we want
> pwritev2 and what we're doing to do with it in the future. The goal is
> to have two additional flags for those calls RWF_DSYNC and
> RWF_NONBLOCK. As Christop mentioned modern network filesystem
> protocols have per operation sync flags. And there's use cases for
> guaranteeing of write dirtying pages without triggering a writeout.
>
> The consensus from our discussion at LSF fs tack was 1) that both
> preadv and pwritev should have flags to begin with, inline with the
> API syscall design guidelines 2) if we're adding preadv2 we should add
> a matching pwritev2 3) especially that we plan on introducing further
> flags to preadv in the near future.
mm... I don't think we should be adding placeholders to the kernel API
to support code which hasn't been written, tested, reviewed, merged,
etc. It's possible none of this will ever happen and we end up with a
syscall nobody needs or uses. Plus it's always possible that during
this development we decide the pwrite2() interface needs alteration but
it's too late.
What would be the downside of deferring pwrite2() until it's all
implemented?
> >
> > Also, why are we adding new syscalls instead of using O_NONBLOCK? I
> > think this might have been discussed before, but the changelogs haven't
> > been updated to reflect it - please do so.
>
> In a much earlier patch series we already had the discussion on why we
> can't use O_NONBLOCK for regular files. It comes down to that it
> breaks some userspace applications. Link for further reference to the
> thread:
>
> https://lkml.org/lkml/2014/9/22/294
> http://thread.gmane.org/gmane.linux.kernel.aio.general/4242
>
> I will include the background in the next patchset.
Cool, thanks.
> >
> >> The RWF_NONBLOCK flag in preadv2 introduces an ability to perform a
> >> non-blocking read from regular files in buffered IO mode. This works by only
> >> for those filesystems that have data in the page cache.
> >>
> >> We discussed these changes at this year's LSF/MM summit in Boston. More details
> >> on the Samba use case, the numbers, and presentation is available at this link:
> >> https://lists.samba.org/archive/samba-technical/2015-March/106290.html
> >
> > https://drive.google.com/file/d/0B3maCn0jCvYncndGbXJKbGlhejQ/view?usp=sharing
> > talks about "sync" but I can't find a description of what this actually
> > is. It appears to perform better than anything else?
>
> Sync is the samba mode where we do not use threadpool just service the
> IO request in the network thread. In a single client case if
> everything is in the page cache we are aiming to be as close in
> latency as sync. The reason it isn't is because the threadpool path in
> samba has some additional over head. I did bring it up to the Samba
> folks on their technical mailing list, they can investigate it further
> if they want it.
>
> It's impractical to use Sync anywhere we have modern SMB3 clients that
> can multiplex > 100 operations over a single connection. Head-of-line
> blocking would kill performance, why we need the threadpool. With the
> threadpool we increase the mean (and tail) latency even if the data is
> handy and we can answer it right away.
OK, all makes sense.
> >
> >> Background:
> >>
> >> Using a threadpool to emulate non-blocking operations on regular buffered
> >> files is a common pattern today (samba, libuv, etc...) Applications split the
> >> work between network bound threads (epoll) and IO threadpool. Not every
> >> application can use sendfile syscall (TLS / post-processing).
> >>
> >> This common pattern leads to increased request latency. Latency can be due to
> >> additional synchronization between the threads or fast (cached data) request
> >> stuck behind slow request (large / uncached data).
> >>
> >> The preadv2 syscall with RWF_NONBLOCK lets userspace applications bypass
> >> enqueuing operation in the threadpool if it's already available in the
> >> pagecache.
> >
> > A thing which bugs me about pread2() is that it is specifically
> > tailored to applications which are able to use a partial read result.
> > ie, by sending it over the network.
> >
> > But it is not very useful for the class of applications which require
> > that the entire read be completed before they can proceed with using
> > the data. Such applications will have to run pread2(), see the short
> > result, save away the partial data, perform some IO then fetch the
> > remaining data then proceed. By this time, the original partially read
> > data may have fallen out of CPU cache (or we're on a different CPU) and
> > the data will need to be fetched into cache a second time.
> >
> > Such applications would be better served if they were able to query for
> > pagecache presence _before_ doing the big copy_to_user(), so they can
> > ensure that all the data is in pagecache before copying it in. ie:
> > fincore(), perhaps supported by a synchronous POSIX_FADV_WILLNEED.
> >
> > And of course fincore could be used by Samba etc to avoid blocking on
> > reads. It wouldn't perform quite as well as pread2(), but I bet it's
> > good enough.
>
> The RWF_NONBLOCK is aimed primarily at network applications. Some of
> them can send a partial result down the network, and then they can
> enqueue the rest in the threadpool. For applications that need the
> whole value, they clearly have to wait to read in the rest, but it's
> behavior that are opting into.
Right. But these applications would prefer "all or nothing" behaviour.
They can get that with fincore()+pread() but they can't get it with
pread2(). Because pread2() takes the two separate concepts of "are
these pages in cache" and "copy these pages to me" and joins them
together in a single operation.
> >
> > Bottom line: with pread2() there's still a need for fincore(), but with
> > fincore() there probably isn't a need for pread2().
>
> I see fincore() and preadv2() with RWF_NONBLOCK as tangential
> syscalls. You can implement a poor man's RWF_NONBLOCK in userspace
> with fincore() but not all of us are fine with it's racy nature or
> requiring 2 syscalls in the best case.
I find this to be too handwavy to be able to process it, sorry.
- WHY is the raciness unacceptable? If 0.0001% of pread2() calls
inadvertently block, what problem does this cause? 0.01%? Details
please, lots of them.
- Yes, 2 syscalls is more expensive. But
a) we don't know *how* expensive. It might be negligible.
b) bear in mind that this patchset is adding minor additional overhead
to every linux application that does read(). To benefit the teeny
teeny minority of apps which use pread2().
btw, that overhead might be slightly reduced by doing
- if (iocb->ki_rwflags & RWF_NONBLOCK)
+ if (unlikely(iocb->ki_rwflags & RWF_NONBLOCK))
return -EAGAIN;
in the appropriate places.
^ permalink raw reply
* [RFC 00/39] Richacls (2)
From: Andreas Gruenbacher @ 2015-03-27 16:49 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-nfs-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA,
samba-technical-w/Ol4Ecudpl8XjKLYN78aQ, Steve French,
linux-security-module-u79uwXL29TY76Z2rM5mHXA
Hello,
here is an update to the richacl patch queue. The changes since the last
posting (https://lwn.net/Articles/634870/) include:
* The ACL4_ and ACE4_ prefixes used for various richacl flags were renamed
to RICHACL_ and RICHACE_. The flag values are still identical with NFSv4
for flags that exist in NFSv4.
* The code is now uid/gid namespace aware.
* The nfs server now uses richacls as its internal acl representation;
struct nfs4_acl is gone. On the underlying file system, it uses either POSIX
ACLs or richacls depending on what that file system supports.
* The nfs client now exports NFSv4 acls as richacls in the "system.richacl"
attribute instead of the nfs-specific "system.nfs4_acl" attribute, just like
local file systems.
Note that the richacl xattr format has changed from the previous version and is
incompatible.
The git version is available here:
git://git.kernel.org/pub/scm/linux/kernel/git/agruen/linux-richacl.git \
richacl-2015-03-27
For comparison, the previous version is available here:
git://git.kernel.org/pub/scm/linux/kernel/git/agruen/linux-richacl.git \
richacl-2015-02-26
Things still to be done, or which I'm not entirely happy with:
* We may need to add back support for the "system.nfs4_acl" attribute
on nfs mounts for backwards compatible. Is anyone actually using that
attribute?
* While richacls do support Automatic Inheritance, the nfs client and server
don't because they don't support the NFSv4.1 "dacl" attribute yet (see RFC
5661).
* The nfs server performs some access checking on its own before calling into
the vfs which is rersponsible for the actual access checking (see where it
calls inode_permission()). With the additional MAY_ flags introduced in
this patch queue, the nfsd access checks may now be too restrictive in some
cases; I have yet to figure out how to deal with this.
* It would make sense for CIFS to expose Windows ACLs as richacls as well.
Steve maybe?
* The base_acl code is still rather ugly.
* It would be nice if the MAY_DELETE_SELF flag could override the sticky
directory check as it did in the previous version of this patch queue. I
couldn't come up with a clean way of achieving that, though.
Andreas Gruenbacher (37):
vfs: Minor documentation fix
uapi: Remove kernel internal declaration
vfs: Shrink struct posix_acl
vfs: Add IS_ACL() and IS_RICHACL() tests
vfs: Add MAY_CREATE_FILE and MAY_CREATE_DIR permission flags
vfs: Add MAY_DELETE_SELF and MAY_DELETE_CHILD permission flags
vfs: Make the inode passed to inode_change_ok non-const
vfs: Add permission flags for setting file attributes
richacl: In-memory representation and helper functions
richacl: Permission mapping functions
richacl: Compute maximum file masks from an acl
richacl: Update the file masks in chmod()
richacl: Permission check algorithm
vfs: Cache base_acl objects in inodes
vfs: Cache richacl in struct inode
richacl: Create-time inheritance
richacl: Check if an acl is equivalent to a file mode
richacl: Automatic Inheritance
richacl: xattr mapping functions
vfs: Add richacl permission checking
richacl: acl editing helper functions
richacl: Move everyone@ aces down the acl
richacl: Propagate everyone@ permissions to other aces
richacl: Isolate the owner and group classes
richacl: Apply the file masks to a richacl
richacl: Create richacl from mode values
richacl: Create acl with masks applied in richacl_from_mode()
nfsd: Remove dead declarations
nfsd: Keep list of acls to dispose of in compoundargs
nfsd: Use richacls as internal acl representation
nfsd: Add richacl support
nfs/sunrpc: No more encode and decode function pointer casting
nfs/sunrpc: Return status code from encode functions
nfs3: Return posix acl encode errors
nfs: Remove unused xdr page offsets in getacl/setacl arguments
rpc: Allow to demand-allocate pages to encode into
nfs: Add richacl support
Aneesh Kumar K.V (2):
ext4: Add richacl support
ext4: Add richacl feature flag
Documentation/filesystems/porting | 8 +-
Documentation/filesystems/vfs.txt | 3 +
drivers/staging/lustre/lustre/llite/llite_lib.c | 2 +-
fs/Kconfig | 9 +
fs/Makefile | 3 +
fs/attr.c | 81 ++-
fs/ext4/Kconfig | 15 +
fs/ext4/Makefile | 1 +
fs/ext4/acl.c | 7 +-
fs/ext4/acl.h | 12 +-
fs/ext4/ext4.h | 6 +-
fs/ext4/file.c | 6 +-
fs/ext4/ialloc.c | 7 +-
fs/ext4/inode.c | 10 +-
fs/ext4/namei.c | 11 +-
fs/ext4/richacl.c | 211 ++++++
fs/ext4/richacl.h | 47 ++
fs/ext4/super.c | 41 +-
fs/ext4/xattr.c | 6 +
fs/ext4/xattr.h | 1 +
fs/f2fs/acl.c | 4 +-
fs/inode.c | 15 +-
fs/lockd/clnt4xdr.c | 58 +-
fs/lockd/clntxdr.c | 58 +-
fs/lockd/mon.c | 26 +-
fs/namei.c | 108 ++-
fs/nfs/inode.c | 2 +-
fs/nfs/mount_clnt.c | 24 +-
fs/nfs/nfs2xdr.c | 115 ++--
fs/nfs/nfs3xdr.c | 225 ++++---
fs/nfs/nfs4proc.c | 335 +++++-----
fs/nfs/nfs4xdr.c | 699 ++++++++++++++------
fs/nfs/super.c | 4 +-
fs/nfs_common/Makefile | 1 +
fs/nfs_common/nfs4acl.c | 41 ++
fs/nfsd/Kconfig | 1 +
fs/nfsd/acl.h | 24 +-
fs/nfsd/nfs4acl.c | 467 ++++++-------
fs/nfsd/nfs4callback.c | 29 +-
fs/nfsd/nfs4proc.c | 17 +-
fs/nfsd/nfs4xdr.c | 103 +--
fs/nfsd/xdr4.h | 12 +-
fs/posix_acl.c | 31 +-
fs/richacl_base.c | 549 ++++++++++++++++
fs/richacl_compat.c | 835 ++++++++++++++++++++++++
fs/richacl_inode.c | 195 ++++++
fs/richacl_xattr.c | 210 ++++++
fs/xattr.c | 34 +-
include/linux/fs.h | 47 +-
include/linux/nfs4.h | 16 -
include/linux/nfs4acl.h | 7 +
include/linux/nfs_fs.h | 2 +-
include/linux/nfs_fs_sb.h | 2 +
include/linux/nfs_xdr.h | 8 +-
include/linux/posix_acl.h | 12 +-
include/linux/richacl.h | 330 ++++++++++
include/linux/richacl_compat.h | 40 ++
include/linux/richacl_xattr.h | 52 ++
include/linux/sunrpc/xdr.h | 5 +-
include/uapi/linux/fs.h | 3 +-
include/uapi/linux/nfs4.h | 7 -
include/uapi/linux/xattr.h | 2 +
net/sunrpc/auth.c | 7 +-
net/sunrpc/auth_gss/gss_rpc_upcall.c | 4 +-
net/sunrpc/auth_gss/gss_rpc_xdr.c | 11 +-
net/sunrpc/auth_gss/gss_rpc_xdr.h | 8 +-
net/sunrpc/clnt.c | 5 +-
net/sunrpc/rpcb_clnt.c | 57 +-
net/sunrpc/xdr.c | 8 +
69 files changed, 4283 insertions(+), 1059 deletions(-)
create mode 100644 fs/ext4/richacl.c
create mode 100644 fs/ext4/richacl.h
create mode 100644 fs/nfs_common/nfs4acl.c
create mode 100644 fs/richacl_base.c
create mode 100644 fs/richacl_compat.c
create mode 100644 fs/richacl_inode.c
create mode 100644 fs/richacl_xattr.c
create mode 100644 include/linux/nfs4acl.h
create mode 100644 include/linux/richacl.h
create mode 100644 include/linux/richacl_compat.h
create mode 100644 include/linux/richacl_xattr.h
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] Add preadv2/pwritev2 documentation.
From: Andrew Morton @ 2015-03-27 16:49 UTC (permalink / raw)
To: Milosz Tanski
Cc: linux-kernel, Christoph Hellwig, linux-fsdevel, linux-aio,
Mel Gorman, Volker Lendecke, Tejun Heo, Jeff Moyer,
Theodore Ts'o, Al Viro, linux-api, Michael Kerrisk,
linux-arch, Dave Chinner
In-Reply-To: <1426530746-32222-1-git-send-email-milosz@adfin.com>
On Mon, 16 Mar 2015 14:32:26 -0400 Milosz Tanski <milosz@adfin.com> wrote:
> +.BR pwritev2 ()
> can also fail for the same reasons as
> .BR lseek (2).
> -Additionally, the following error is defined:
> +Additionally, the following errors are defined:
> +.TP
> +.B EAGAIN
> +The operation would block. This is possible if the file descriptor \fIfd\fP refers to a socket and has been marked nonblocking
> +.RB ( O_NONBLOCK ),
> +or the operation is a
> +.BR preadv2
> +and the \fIflags\fP argument is set to
> +.BR RWF_NONBLOCK.
Can you please expand on this to describe the circumstances in which
pread2() returns -EAGAIN? Let's fix up the short-read confusion.
And let's have a think about EAGAIN vs EWOULDBLOCK.
^ permalink raw reply
* Re: [PATCH v7 0/5] vfs: Non-blockling buffered fs read (page cache only)
From: Milosz Tanski @ 2015-03-27 16:45 UTC (permalink / raw)
To: Andrew Morton
Cc: Jeremy Allison, Christoph Hellwig, LKML,
linux-fsdevel@vger.kernel.org, linux-aio@kvack.org, Mel Gorman,
Volker Lendecke, Tejun Heo, Jeff Moyer, Theodore Ts'o,
Al Viro, Linux API, Michael Kerrisk, linux-arch, Dave Chinner
In-Reply-To: <20150327093046.53c2769a.akpm@linux-foundation.org>
On Fri, Mar 27, 2015 at 12:30 PM, Andrew Morton
<akpm@linux-foundation.org> wrote:
> On Fri, 27 Mar 2015 08:58:54 -0700 Jeremy Allison <jra@samba.org> wrote:
>
>> On Fri, Mar 27, 2015 at 02:01:59AM -0700, Andrew Morton wrote:
>> > On Fri, 27 Mar 2015 01:48:33 -0700 Christoph Hellwig <hch@infradead.org> wrote:
>> >
>> > > On Fri, Mar 27, 2015 at 01:35:16AM -0700, Andrew Morton wrote:
>> > > > fincore() doesn't have to be ugly. Please address the design issues I
>> > > > raised. How is pread2() useful to the class of applications which
>> > > > cannot proceed until all data is available?
>> > >
>> > > It actually makes them work correctly? preadv2( ..., DONTWAIT) will
>> > > return -EGAIN, which causes them to bounce to the threadpool where
>> > > they call preadv(...).
>> >
>> > (I assume you mean RWF_NONBLOCK)
>> >
>> > That isn't how pread2() works. If the leading one or more pages are
>> > uptodate, pread2() will return a partial read. Now what? Either the
>> > application reads the same data a second time via the worker thread
>> > (dumb, but it will usually be a rare case)
>>
>> The problem with the above is that we can't tell the difference
>> between pread2() returning a short read because the pages are not
>> in cache, or because someone truncated the file. So we need some
>> way to differentiate this.
>>
>> My preference from userspace would be for pread2() to return
>> EAGAIN if *all* the data requested is not available (where
>> 'all' can be less than the size requested if the file has
>> been truncated in the meantime).
>>
>> ...
>>
>> The thing I want to avoid is the case where
>> ret < size_wanted means only part of the file
>> is in cache.
>
> From my reading of the code, pread2() will return -EAGAIN only when it
> copied zero bytes to userspace. ie, the very first page wasn't in
> cache. If pread2() does copy some data to userspace then it will
> return the amount of data copied. This is traditional read()
> behaviour.
>
> Maybe there's some other code somewhere in the patch which converts
> that short read into -EAGAIN, dunno - the changelogs don't appear to
> mention it and the manpage update is ambiguous about this.
>
> But from an interface perspective the behaviour you're asking for is
> insane, frankly - if the kernel copied out 8k of data then pread2()
> should return 8k. Otherwise there's no way for userspace to know that
> the 8k copy actually happened and we have just wasted a great pile of
> CPU doing a pointless memcpy.
>
> I expect that this situation (first part in cache, latter part not in
> cache) is rare - for reasonably small requests the common cases will be
> "all cached" and "nothing cached". So perhaps the best approach here
> is for samba to add special handling for the short read, to work out
> the reason for its occurrence.
>
> Alternatively we could add another flag to pread2() to select this
> "throw away my data and return -EAGAIN" behaviour. Presumably
> implemented with an i_size check, but it's gonna be racy.
>
>
>
> I take it from your comments that nobody has actually wired up pread2()
> into samba yet? That's a bit disturbing, because if we later want to
> go and change something like this short-read behaviour, we're screwed -
> it's a non back-compat userspace-visible change.
Volker and did wired so we can use Samba as a test / use case. The
change we made was quick and dirty 9 lines of code, if you exclude the
syscall boiler plate. In fact, right now it does the stupid thing of
throwing away the partial result and enqueing in the threadpool if it
doesn't get the whole block. Volker agreed that was as much as we need
to do to get the numbers and we'll make a proper patch once it's in
upstream.
Patch to samba at end of email for reference.
>
>
> And a note on cosmetics: why are we using EAGAIN here rather than
> EWOULDBLOCK? They have the same numerical value, but EWOULDBLOCK is a
> better name - EAGAIN says "run it again", but that won't work.
You're right. I will fix this.
diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c
index 5634cc0..90348d8 100644
--- a/source3/modules/vfs_default.c
+++ b/source3/modules/vfs_default.c
@@ -34,6 +34,29 @@
#include "lib/util/tevent_ntstatus.h"
#include "lib/sys_rw.h"
+#include <pthread.h>
+
+#define __NR_preadv2 322
+#define __NR_pwritev2 323
+#define RWF_NONBLOCK 1
+
+#define LO_HI_LONG(val) \
+ (off_t) val, \
+ (off_t) ((((uint64_t) (val)) >> (sizeof (long) * 4)) >>
(sizeof (long) * 4))
+
+static inline
+int preadv2(int fd, const struct iovec *iov, int iovcnt, off_t
offset, int flags)
+{
+ return syscall(__NR_preadv2, fd, iov, iovcnt,
LO_HI_LONG(offset), flags);
+}
+
+static inline
+int pread2(int fd, void *data, size_t len, off_t offset, int flags)
+{
+ struct iovec iov = { data, len };
+ return preadv2(fd, &iov, 1, offset, flags);
+}
+
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_VFS
@@ -718,6 +741,7 @@ static struct tevent_req
*vfswrap_pread_send(struct vfs_handle_struct *handle,
struct tevent_req *req;
struct vfswrap_asys_state *state;
int ret;
+ ssize_t nread;
req = tevent_req_create(mem_ctx, &state, struct vfswrap_asys_state);
if (req == NULL) {
@@ -730,6 +754,14 @@ static struct tevent_req
*vfswrap_pread_send(struct vfs_handle_struct *handle,
state->asys_ctx = handle->conn->sconn->asys_ctx;
state->req = req;
+ nread = pread2(fsp->fh->fd, data, n, offset, RWF_NONBLOCK);
+ // TODO: partial reads
+ if (nread == n) {
+ state->ret = nread;
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+ }
+
SMBPROFILE_BYTES_ASYNC_START(syscall_asys_pread, profile_p,
state->profile_bytes, n);
ret = asys_pread(state->asys_ctx, fsp->fh->fd, data, n, offset, req);
^ permalink raw reply related
* [PATCH v2 4/4] mm, procfs: Display VmAnon, VmFile and VmShm in /proc/pid/status
From: Vlastimil Babka @ 2015-03-27 16:40 UTC (permalink / raw)
To: linux-mm, Jerome Marchand
Cc: linux-kernel, Andrew Morton, linux-doc, Hugh Dickins,
Michal Hocko, Kirill A. Shutemov, Cyrill Gorcunov, Randy Dunlap,
linux-s390, Martin Schwidefsky, Heiko Carstens, Peter Zijlstra,
Paul Mackerras, Arnaldo Carvalho de Melo, Oleg Nesterov,
Linux API, Konstantin Khlebnikov, Vlastimil Babka
In-Reply-To: <1427474441-17708-1-git-send-email-vbabka@suse.cz>
From: Jerome Marchand <jmarchan@redhat.com>
It's currently inconvenient to retrieve MM_ANONPAGES value from status
and statm files and there is no way to separate MM_FILEPAGES and
MM_SHMEMPAGES. Add VmAnon, VmFile and VmShm lines in /proc/<pid>/status
to solve these issues.
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
---
Documentation/filesystems/proc.txt | 10 +++++++++-
fs/proc/task_mmu.c | 13 +++++++++++--
2 files changed, 20 insertions(+), 3 deletions(-)
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 8b30543..c777adb 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -168,6 +168,9 @@ read the file /proc/PID/status:
VmLck: 0 kB
VmHWM: 476 kB
VmRSS: 476 kB
+ VmAnon: 352 kB
+ VmFile: 120 kB
+ VmShm: 4 kB
VmData: 156 kB
VmStk: 88 kB
VmExe: 68 kB
@@ -224,7 +227,12 @@ Table 1-2: Contents of the status files (as of 2.6.30-rc7)
VmSize total program size
VmLck locked memory size
VmHWM peak resident set size ("high water mark")
- VmRSS size of memory portions
+ VmRSS size of memory portions. It contains the three
+ following parts (VmRSS = VmAnon + VmFile + VmShm)
+ VmAnon size of resident anonymous memory
+ VmFile size of resident file mappings
+ VmShm size of resident shmem memory (includes SysV shm,
+ mapping of tmpfs and shared anonymous mappings)
VmData size of data, stack, and text segments
VmStk size of data, stack, and text segments
VmExe size of text segment
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index e86e137..1eeacd3 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -22,7 +22,7 @@
void task_mem(struct seq_file *m, struct mm_struct *mm)
{
- unsigned long data, text, lib, swap, ptes, pmds;
+ unsigned long data, text, lib, swap, ptes, pmds, anon, file, shmem;
unsigned long hiwater_vm, total_vm, hiwater_rss, total_rss;
/*
@@ -39,6 +39,9 @@ void task_mem(struct seq_file *m, struct mm_struct *mm)
if (hiwater_rss < mm->hiwater_rss)
hiwater_rss = mm->hiwater_rss;
+ anon = get_mm_counter(mm, MM_ANONPAGES);
+ file = get_mm_counter(mm, MM_FILEPAGES);
+ shmem = get_mm_counter_shmem(mm);
data = mm->total_vm - mm->shared_vm - mm->stack_vm;
text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK)) >> 10;
lib = (mm->exec_vm << (PAGE_SHIFT-10)) - text;
@@ -52,6 +55,9 @@ void task_mem(struct seq_file *m, struct mm_struct *mm)
"VmPin:\t%8lu kB\n"
"VmHWM:\t%8lu kB\n"
"VmRSS:\t%8lu kB\n"
+ "VmAnon:\t%8lu kB\n"
+ "VmFile:\t%8lu kB\n"
+ "VmShm:\t%8lu kB\n"
"VmData:\t%8lu kB\n"
"VmStk:\t%8lu kB\n"
"VmExe:\t%8lu kB\n"
@@ -65,6 +71,9 @@ void task_mem(struct seq_file *m, struct mm_struct *mm)
mm->pinned_vm << (PAGE_SHIFT-10),
hiwater_rss << (PAGE_SHIFT-10),
total_rss << (PAGE_SHIFT-10),
+ anon << (PAGE_SHIFT-10),
+ file << (PAGE_SHIFT-10),
+ shmem << (PAGE_SHIFT-10),
data << (PAGE_SHIFT-10),
mm->stack_vm << (PAGE_SHIFT-10), text, lib,
ptes >> 10,
@@ -82,7 +91,7 @@ unsigned long task_statm(struct mm_struct *mm,
unsigned long *data, unsigned long *resident)
{
*shared = get_mm_counter(mm, MM_FILEPAGES) +
- get_mm_counter(mm, MM_SHMEMPAGES);
+ get_mm_counter_shmem(mm);
*text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK))
>> PAGE_SHIFT;
*data = mm->total_vm - mm->shared_vm;
--
2.1.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
* [PATCH v2 3/4] mm, shmem: Add shmem resident memory accounting
From: Vlastimil Babka @ 2015-03-27 16:40 UTC (permalink / raw)
To: linux-mm, Jerome Marchand
Cc: linux-kernel, Andrew Morton, linux-doc, Hugh Dickins,
Michal Hocko, Kirill A. Shutemov, Cyrill Gorcunov, Randy Dunlap,
linux-s390, Martin Schwidefsky, Heiko Carstens, Peter Zijlstra,
Paul Mackerras, Arnaldo Carvalho de Melo, Oleg Nesterov,
Linux API, Konstantin Khlebnikov, Vlastimil Babka
In-Reply-To: <1427474441-17708-1-git-send-email-vbabka@suse.cz>
From: Jerome Marchand <jmarchan@redhat.com>
Currently looking at /proc/<pid>/status or statm, there is no way to
distinguish shmem pages from pages mapped to a regular file (shmem
pages are mapped to /dev/zero), even though their implication in
actual memory use is quite different.
This patch adds MM_SHMEMPAGES counter to mm_rss_stat to account for
shmem pages instead of MM_FILEPAGES.
Signed-off-by: Jerome Marchand <jmarchan@redhat.com>
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
---
arch/s390/mm/pgtable.c | 5 +----
fs/proc/task_mmu.c | 3 ++-
include/linux/mm.h | 28 ++++++++++++++++++++++++++++
include/linux/mm_types.h | 9 ++++++---
kernel/events/uprobes.c | 2 +-
mm/memory.c | 30 ++++++++++--------------------
mm/oom_kill.c | 5 +++--
mm/rmap.c | 15 ++++-----------
8 files changed, 55 insertions(+), 42 deletions(-)
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index b2c1542..5bffd5d 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -617,10 +617,7 @@ static void gmap_zap_swap_entry(swp_entry_t entry, struct mm_struct *mm)
else if (is_migration_entry(entry)) {
struct page *page = migration_entry_to_page(entry);
- if (PageAnon(page))
- dec_mm_counter(mm, MM_ANONPAGES);
- else
- dec_mm_counter(mm, MM_FILEPAGES);
+ dec_mm_counter(mm, mm_counter(page));
}
free_swap_and_cache(entry);
}
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 1b271ec..e86e137 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -81,7 +81,8 @@ unsigned long task_statm(struct mm_struct *mm,
unsigned long *shared, unsigned long *text,
unsigned long *data, unsigned long *resident)
{
- *shared = get_mm_counter(mm, MM_FILEPAGES);
+ *shared = get_mm_counter(mm, MM_FILEPAGES) +
+ get_mm_counter(mm, MM_SHMEMPAGES);
*text = (PAGE_ALIGN(mm->end_code) - (mm->start_code & PAGE_MASK))
>> PAGE_SHIFT;
*data = mm->total_vm - mm->shared_vm;
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 47a9392..adfbb5b 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1364,6 +1364,16 @@ static inline unsigned long get_mm_counter(struct mm_struct *mm, int member)
return (unsigned long)val;
}
+/* A wrapper for the CONFIG_SHMEM dependent counter */
+static inline unsigned long get_mm_counter_shmem(struct mm_struct *mm)
+{
+#ifdef CONFIG_SHMEM
+ return get_mm_counter(mm, MM_SHMEMPAGES);
+#else
+ return 0;
+#endif
+}
+
static inline void add_mm_counter(struct mm_struct *mm, int member, long value)
{
atomic_long_add(value, &mm->rss_stat.count[member]);
@@ -1379,9 +1389,27 @@ static inline void dec_mm_counter(struct mm_struct *mm, int member)
atomic_long_dec(&mm->rss_stat.count[member]);
}
+/* Optimized variant when page is already known not to be PageAnon */
+static inline int mm_counter_file(struct page *page)
+{
+#ifdef CONFIG_SHMEM
+ if (PageSwapBacked(page))
+ return MM_SHMEMPAGES;
+#endif
+ return MM_FILEPAGES;
+}
+
+static inline int mm_counter(struct page *page)
+{
+ if (PageAnon(page))
+ return MM_ANONPAGES;
+ return mm_counter_file(page);
+}
+
static inline unsigned long get_mm_rss(struct mm_struct *mm)
{
return get_mm_counter(mm, MM_FILEPAGES) +
+ get_mm_counter_shmem(mm) +
get_mm_counter(mm, MM_ANONPAGES);
}
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 199a03a..d3c2372 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -327,9 +327,12 @@ struct core_state {
};
enum {
- MM_FILEPAGES,
- MM_ANONPAGES,
- MM_SWAPENTS,
+ MM_FILEPAGES, /* Resident file mapping pages */
+ MM_ANONPAGES, /* Resident anonymous pages */
+ MM_SWAPENTS, /* Anonymous swap entries */
+#ifdef CONFIG_SHMEM
+ MM_SHMEMPAGES, /* Resident shared memory pages */
+#endif
NR_MM_COUNTERS
};
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index cb346f2..0a08fdd 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -188,7 +188,7 @@ static int __replace_page(struct vm_area_struct *vma, unsigned long addr,
lru_cache_add_active_or_unevictable(kpage, vma);
if (!PageAnon(page)) {
- dec_mm_counter(mm, MM_FILEPAGES);
+ dec_mm_counter(mm, mm_counter_file(page));
inc_mm_counter(mm, MM_ANONPAGES);
}
diff --git a/mm/memory.c b/mm/memory.c
index 411144f..db66400 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -832,10 +832,7 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
} else if (is_migration_entry(entry)) {
page = migration_entry_to_page(entry);
- if (PageAnon(page))
- rss[MM_ANONPAGES]++;
- else
- rss[MM_FILEPAGES]++;
+ rss[mm_counter(page)]++;
if (is_write_migration_entry(entry) &&
is_cow_mapping(vm_flags)) {
@@ -874,10 +871,7 @@ copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
if (page) {
get_page(page);
page_dup_rmap(page);
- if (PageAnon(page))
- rss[MM_ANONPAGES]++;
- else
- rss[MM_FILEPAGES]++;
+ rss[mm_counter(page)]++;
}
out_set_pte:
@@ -1113,9 +1107,8 @@ again:
tlb_remove_tlb_entry(tlb, pte, addr);
if (unlikely(!page))
continue;
- if (PageAnon(page))
- rss[MM_ANONPAGES]--;
- else {
+
+ if (!PageAnon(page)) {
if (pte_dirty(ptent)) {
force_flush = 1;
set_page_dirty(page);
@@ -1123,8 +1116,8 @@ again:
if (pte_young(ptent) &&
likely(!(vma->vm_flags & VM_SEQ_READ)))
mark_page_accessed(page);
- rss[MM_FILEPAGES]--;
}
+ rss[mm_counter(page)]--;
page_remove_rmap(page);
if (unlikely(page_mapcount(page) < 0))
print_bad_pte(vma, addr, ptent, page);
@@ -1146,11 +1139,7 @@ again:
struct page *page;
page = migration_entry_to_page(entry);
-
- if (PageAnon(page))
- rss[MM_ANONPAGES]--;
- else
- rss[MM_FILEPAGES]--;
+ rss[mm_counter(page)]--;
}
if (unlikely(!free_swap_and_cache(entry)))
print_bad_pte(vma, addr, ptent, NULL);
@@ -1460,7 +1449,7 @@ static int insert_page(struct vm_area_struct *vma, unsigned long addr,
/* Ok, finally just insert the thing.. */
get_page(page);
- inc_mm_counter_fast(mm, MM_FILEPAGES);
+ inc_mm_counter_fast(mm, mm_counter_file(page));
page_add_file_rmap(page);
set_pte_at(mm, addr, pte, mk_pte(page, prot));
@@ -2174,7 +2163,8 @@ gotten:
if (likely(pte_same(*page_table, orig_pte))) {
if (old_page) {
if (!PageAnon(old_page)) {
- dec_mm_counter_fast(mm, MM_FILEPAGES);
+ dec_mm_counter_fast(mm,
+ mm_counter_file(old_page));
inc_mm_counter_fast(mm, MM_ANONPAGES);
}
} else
@@ -2703,7 +2693,7 @@ void do_set_pte(struct vm_area_struct *vma, unsigned long address,
inc_mm_counter_fast(vma->vm_mm, MM_ANONPAGES);
page_add_new_anon_rmap(page, vma, address);
} else {
- inc_mm_counter_fast(vma->vm_mm, MM_FILEPAGES);
+ inc_mm_counter_fast(vma->vm_mm, mm_counter_file(page));
page_add_file_rmap(page);
}
set_pte_at(vma->vm_mm, address, pte, entry);
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 642f38c..a5ee3a2 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -573,10 +573,11 @@ void oom_kill_process(struct task_struct *p, gfp_t gfp_mask, int order,
/* mm cannot safely be dereferenced after task_unlock(victim) */
mm = victim->mm;
mark_tsk_oom_victim(victim);
- pr_err("Killed process %d (%s) total-vm:%lukB, anon-rss:%lukB, file-rss:%lukB\n",
+ pr_err("Killed process %d (%s) total-vm:%lukB, anon-rss:%lukB, file-rss:%lukB, shmem-rss:%lukB\n",
task_pid_nr(victim), victim->comm, K(victim->mm->total_vm),
K(get_mm_counter(victim->mm, MM_ANONPAGES)),
- K(get_mm_counter(victim->mm, MM_FILEPAGES)));
+ K(get_mm_counter(victim->mm, MM_FILEPAGES)),
+ K(get_mm_counter_shmem(victim->mm)));
task_unlock(victim);
/*
diff --git a/mm/rmap.c b/mm/rmap.c
index 5e3e090..e3c4392 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1216,12 +1216,8 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
update_hiwater_rss(mm);
if (PageHWPoison(page) && !(flags & TTU_IGNORE_HWPOISON)) {
- if (!PageHuge(page)) {
- if (PageAnon(page))
- dec_mm_counter(mm, MM_ANONPAGES);
- else
- dec_mm_counter(mm, MM_FILEPAGES);
- }
+ if (!PageHuge(page))
+ dec_mm_counter(mm, mm_counter(page));
set_pte_at(mm, address, pte,
swp_entry_to_pte(make_hwpoison_entry(page)));
} else if (pte_unused(pteval)) {
@@ -1230,10 +1226,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
* interest anymore. Simply discard the pte, vmscan
* will take care of the rest.
*/
- if (PageAnon(page))
- dec_mm_counter(mm, MM_ANONPAGES);
- else
- dec_mm_counter(mm, MM_FILEPAGES);
+ dec_mm_counter(mm, mm_counter(page));
} else if (PageAnon(page)) {
swp_entry_t entry = { .val = page_private(page) };
pte_t swp_pte;
@@ -1276,7 +1269,7 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma,
entry = make_migration_entry(page, pte_write(pteval));
set_pte_at(mm, address, pte, swp_entry_to_pte(entry));
} else
- dec_mm_counter(mm, MM_FILEPAGES);
+ dec_mm_counter(mm, mm_counter_file(page));
page_remove_rmap(page);
page_cache_release(page);
--
2.1.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
* [PATCH v2 2/4] mm, proc: account for shmem swap in /proc/pid/smaps
From: Vlastimil Babka @ 2015-03-27 16:40 UTC (permalink / raw)
To: linux-mm, Jerome Marchand
Cc: linux-kernel, Andrew Morton, linux-doc, Hugh Dickins,
Michal Hocko, Kirill A. Shutemov, Cyrill Gorcunov, Randy Dunlap,
linux-s390, Martin Schwidefsky, Heiko Carstens, Peter Zijlstra,
Paul Mackerras, Arnaldo Carvalho de Melo, Oleg Nesterov,
Linux API, Konstantin Khlebnikov, Vlastimil Babka
In-Reply-To: <1427474441-17708-1-git-send-email-vbabka@suse.cz>
Currently, /proc/pid/smaps will always show "Swap: 0 kB" for shmem-backed
mappings, even if the mapped portion does contain pages that were swapped out.
This is because unlike private anonymous mappings, shmem does not change pte
to swap entry, but pte_none when swapping the page out. In the smaps page
walk, such page thus looks like it was never faulted in.
This patch changes smaps_pte_entry() to determine the swap status for such
pte_none entries for shmem mappings, similarly to how mincore_page() does it.
Swapped out pages are thus accounted for.
The accounting is arguably still not as precise as for private anonymous
mappings, since now we will count also pages that the process in question never
accessed, but only another process populated them and then let them become
swapped out. I believe it is still less confusing and subtle than not showing
any swap usage by shmem mappings at all. Also, swapped out pages only becomee a
performance issue for future accesses, and we cannot predict those for neither
kind of mapping.
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
---
Documentation/filesystems/proc.txt | 3 ++-
fs/proc/task_mmu.c | 38 +++++++++++++++++++++++++++
include/linux/shmem_fs.h | 6 +++++
mm/shmem.c | 54 ++++++++++++++++++++++++++++++++++++++
4 files changed, 100 insertions(+), 1 deletion(-)
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index d4f56ec..8b30543 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -437,7 +437,8 @@ indicates the amount of memory currently marked as referenced or accessed.
a mapping associated with a file may contain anonymous pages: when MAP_PRIVATE
and a page is modified, the file page is replaced by a private anonymous copy.
"Swap" shows how much would-be-anonymous memory is also used, but out on
-swap.
+swap. For shmem mappings, "Swap" shows how much of the mapped portion of the
+underlying shmem object is on swap.
"VmFlags" field deserves a separate description. This member represents the kernel
flags associated with the particular virtual memory area in two letter encoded
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 6dee68d..1b271ec 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -13,6 +13,7 @@
#include <linux/swap.h>
#include <linux/swapops.h>
#include <linux/mmu_notifier.h>
+#include <linux/shmem_fs.h>
#include <asm/elf.h>
#include <asm/uaccess.h>
@@ -610,6 +611,41 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma)
seq_putc(m, '\n');
}
+#if defined(CONFIG_SHMEM) && defined(CONFIG_SWAP)
+static unsigned long smaps_shmem_swap(struct vm_area_struct *vma)
+{
+ struct inode *inode;
+ unsigned long swapped;
+ pgoff_t start, end;
+
+ if (!vma->vm_file)
+ return 0;
+
+ inode = file_inode(vma->vm_file);
+
+ if (!shmem_mapping(inode->i_mapping))
+ return 0;
+
+ swapped = shmem_swap_usage(inode);
+
+ if (swapped == 0)
+ return 0;
+
+ if (vma->vm_end - vma->vm_start >= inode->i_size)
+ return swapped;
+
+ start = linear_page_index(vma, vma->vm_start);
+ end = linear_page_index(vma, vma->vm_end);
+
+ return shmem_partial_swap_usage(inode->i_mapping, start, end);
+}
+#else
+static unsigned long smaps_shmem_swap(struct vm_area_struct *vma)
+{
+ return 0;
+}
+#endif
+
static int show_smap(struct seq_file *m, void *v, int is_pid)
{
struct vm_area_struct *vma = v;
@@ -624,6 +660,8 @@ static int show_smap(struct seq_file *m, void *v, int is_pid)
/* mmap_sem is held in m_start */
walk_page_vma(vma, &smaps_walk);
+ mss.swap += smaps_shmem_swap(vma);
+
show_map_vma(m, vma, is_pid);
seq_printf(m,
diff --git a/include/linux/shmem_fs.h b/include/linux/shmem_fs.h
index 50777b5..12519e4 100644
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -60,6 +60,12 @@ extern struct page *shmem_read_mapping_page_gfp(struct address_space *mapping,
extern void shmem_truncate_range(struct inode *inode, loff_t start, loff_t end);
extern int shmem_unuse(swp_entry_t entry, struct page *page);
+#ifdef CONFIG_SWAP
+extern unsigned long shmem_swap_usage(struct inode *inode);
+extern unsigned long shmem_partial_swap_usage(struct address_space *mapping,
+ pgoff_t start, pgoff_t end);
+#endif
+
static inline struct page *shmem_read_mapping_page(
struct address_space *mapping, pgoff_t index)
{
diff --git a/mm/shmem.c b/mm/shmem.c
index cf2d0ca..f8ebd23 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -357,6 +357,60 @@ static int shmem_free_swap(struct address_space *mapping,
return 0;
}
+#ifdef CONFIG_SWAP
+unsigned long shmem_swap_usage(struct inode *inode)
+{
+ struct shmem_inode_info *info = SHMEM_I(inode);
+ unsigned long swapped;
+
+ spin_lock(&info->lock);
+ swapped = info->swapped;
+ spin_unlock(&info->lock);
+
+ return swapped << PAGE_SHIFT;
+}
+
+unsigned long shmem_partial_swap_usage(struct address_space *mapping,
+ pgoff_t start, pgoff_t end)
+{
+ struct radix_tree_iter iter;
+ void **slot;
+ struct page *page;
+ unsigned long swapped = 0;
+
+ rcu_read_lock();
+
+restart:
+ radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, start) {
+ if (iter.index >= end)
+ break;
+
+ page = radix_tree_deref_slot(slot);
+
+ /*
+ * This should only be possible to happen at index 0, so we
+ * don't need to reset the counter, nor do we risk infinite
+ * restarts.
+ */
+ if (radix_tree_deref_retry(page))
+ goto restart;
+
+ if (radix_tree_exceptional_entry(page))
+ swapped++;
+
+ if (need_resched()) {
+ cond_resched_rcu();
+ start = iter.index + 1;
+ goto restart;
+ }
+ }
+
+ rcu_read_unlock();
+
+ return swapped << PAGE_SHIFT;
+}
+#endif
+
/*
* SysV IPC SHM_UNLOCK restore Unevictable pages to their evictable lists.
*/
--
2.1.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
* [PATCH v2 1/4] mm, documentation: clarify /proc/pid/status VmSwap limitations
From: Vlastimil Babka @ 2015-03-27 16:40 UTC (permalink / raw)
To: linux-mm, Jerome Marchand
Cc: linux-kernel, Andrew Morton, linux-doc, Hugh Dickins,
Michal Hocko, Kirill A. Shutemov, Cyrill Gorcunov, Randy Dunlap,
linux-s390, Martin Schwidefsky, Heiko Carstens, Peter Zijlstra,
Paul Mackerras, Arnaldo Carvalho de Melo, Oleg Nesterov,
Linux API, Konstantin Khlebnikov, Vlastimil Babka
In-Reply-To: <1427474441-17708-1-git-send-email-vbabka@suse.cz>
The documentation for /proc/pid/status does not mention that the value of
VmSwap counts only swapped out anonymous private pages and not shmem. This is
not obvious, so document this limitation.
Signed-off-by: Vlastimil Babka <vbabka@suse.cz>
---
Documentation/filesystems/proc.txt | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index a07ba61..d4f56ec 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -231,6 +231,8 @@ Table 1-2: Contents of the status files (as of 2.6.30-rc7)
VmLib size of shared library code
VmPTE size of page table entries
VmSwap size of swap usage (the number of referred swapents)
+ by anonymous private data (shmem swap usage is not
+ included)
Threads number of threads
SigQ number of signals queued/max. number for queue
SigPnd bitmap of pending signals for the thread
--
2.1.4
^ permalink raw reply related
* [PATCH v2 0/4] enhance shmem process and swap accounting
From: Vlastimil Babka @ 2015-03-27 16:40 UTC (permalink / raw)
To: linux-mm, Jerome Marchand
Cc: linux-kernel, Andrew Morton, linux-doc, Hugh Dickins,
Michal Hocko, Kirill A. Shutemov, Cyrill Gorcunov, Randy Dunlap,
linux-s390, Martin Schwidefsky, Heiko Carstens, Peter Zijlstra,
Paul Mackerras, Arnaldo Carvalho de Melo, Oleg Nesterov,
Linux API, Konstantin Khlebnikov, Vlastimil Babka
Changes since v1:
o In Patch 2, rely on SHMEM_I(inode)->swapped if possible, and fallback to
radix tree iterator on partially mapped shmem objects, i.e. decouple shmem
swap usage determination from the page walk, for performance reasons.
Thanks to Jerome and Konstantin for the tips.
The downside is that mm/shmem.c had to be touched.
This series is based on Jerome Marchand's [1] so let me quote the first
paragraph from there:
There are several shortcomings with the accounting of shared memory
(sysV shm, shared anonymous mapping, mapping to a tmpfs file). The
values in /proc/<pid>/status and statm don't allow to distinguish
between shmem memory and a shared mapping to a regular file, even
though theirs implication on memory usage are quite different: at
reclaim, file mapping can be dropped or write back on disk while shmem
needs a place in swap. As for shmem pages that are swapped-out or in
swap cache, they aren't accounted at all.
The original motivation for myself is that a customer found (IMHO rightfully)
confusing that e.g. top output for process swap usage is unreliable with
respect to swapped out shmem pages, which are not accounted for.
The fundamental difference between private anonymous and shmem pages is that
the latter has PTE's converted to pte_none, and not swapents. As such, they are
not accounted to the number of swapents visible e.g. in /proc/pid/status VmSwap
row. It might be theoretically possible to use swapents when swapping out shmem
(without extra cost, as one has to change all mappers anyway), and on swap in
only convert the swapent for the faulting process, leaving swapents in other
processes until they also fault (so again no extra cost). But I don't know how
many assumptions this would break, and it would be too disruptive change for a
relatively small benefit.
Instead, my approach is to document the limitation of VmSwap, and provide means
to determine the swap usage for shmem areas for those who are interested and
willing to pay the price, using /proc/pid/smaps. Because outside of ipcs, I
don't think it's possible to currently to determine the usage at all. The
previous patchset [1] did introduce new shmem-specific fields into smaps
output, and functions to determine the values. I take a simpler approach,
noting that smaps output already has a "Swap: X kB" line, where currently X ==
0 always for shmem areas. I think we can just consider this a bug and provide
the proper value by consulting the radix tree, as e.g. mincore_page() does. In the
patch changelog I explain why this is also not perfect (and cannot be without
swapents), but still arguably much better than showing a 0.
The last two patches are adapted from Jerome's patchset and provide a VmRSS
breakdown to VmAnon, VmFile and VmShm in /proc/pid/status. Hugh noted that
this is a welcome addition, and I agree that it might help e.g. debugging
process memory usage at albeit non-zero, but still rather low cost of extra
per-mm counter and some page flag checks. I updated these patches to 4.0-rc1,
made them respect !CONFIG_SHMEM so that tiny systems don't pay the cost, and
optimized the page flag checking somewhat.
[1] http://lwn.net/Articles/611966/
Jerome Marchand (2):
mm, shmem: Add shmem resident memory accounting
mm, procfs: Display VmAnon, VmFile and VmShm in /proc/pid/status
Vlastimil Babka (2):
mm, documentation: clarify /proc/pid/status VmSwap limitations
mm, proc: account for shmem swap in /proc/pid/smaps
Documentation/filesystems/proc.txt | 15 +++++++++--
arch/s390/mm/pgtable.c | 5 +---
fs/proc/task_mmu.c | 52 ++++++++++++++++++++++++++++++++++--
include/linux/mm.h | 28 ++++++++++++++++++++
include/linux/mm_types.h | 9 ++++---
include/linux/shmem_fs.h | 6 +++++
kernel/events/uprobes.c | 2 +-
mm/memory.c | 30 +++++++--------------
mm/oom_kill.c | 5 ++--
mm/rmap.c | 15 +++--------
mm/shmem.c | 54 ++++++++++++++++++++++++++++++++++++++
11 files changed, 176 insertions(+), 45 deletions(-)
--
2.1.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH v7 0/5] vfs: Non-blockling buffered fs read (page cache only)
From: Andrew Morton @ 2015-03-27 16:39 UTC (permalink / raw)
To: Jeremy Allison, Christoph Hellwig, Milosz Tanski, linux-kernel,
linux-fsdevel, linux-aio, Mel Gorman, Volker Lendecke, Tejun Heo,
Jeff Moyer, Theodore Ts'o, Al Viro, linux-api,
Michael Kerrisk, linux-arch, Dave Chinner
In-Reply-To: <20150327093046.53c2769a.akpm@linux-foundation.org>
On Fri, 27 Mar 2015 09:30:46 -0700 Andrew Morton <akpm@linux-foundation.org> wrote:
> I expect that this situation (first part in cache, latter part not in
> cache) is rare - for reasonably small requests the common cases will be
> "all cached" and "nothing cached". So perhaps the best approach here
> is for samba to add special handling for the short read, to work out
> the reason for its occurrence.
>
> Alternatively we could add another flag to pread2() to select this
> "throw away my data and return -EAGAIN" behaviour. Presumably
> implemented with an i_size check, but it's gonna be racy.
Here's a better way:
nr_read = pread2(buf, len);
if (nr_read < len)
nr_read += pread(buf + nr_read, len - nr_read);
if (nr_read < len)
we_hit_eof();
^ permalink raw reply
* Re: [PATCH v7 0/5] vfs: Non-blockling buffered fs read (page cache only)
From: Jeremy Allison @ 2015-03-27 16:39 UTC (permalink / raw)
To: Andrew Morton
Cc: Jeremy Allison, Christoph Hellwig, Milosz Tanski, linux-kernel,
linux-fsdevel, linux-aio, Mel Gorman, Volker Lendecke, Tejun Heo,
Jeff Moyer, Theodore Ts'o, Al Viro, linux-api,
Michael Kerrisk, linux-arch, Dave Chinner
In-Reply-To: <20150327093046.53c2769a.akpm@linux-foundation.org>
On Fri, Mar 27, 2015 at 09:30:46AM -0700, Andrew Morton wrote:
>
> But from an interface perspective the behaviour you're asking for is
> insane, frankly - if the kernel copied out 8k of data then pread2()
> should return 8k. Otherwise there's no way for userspace to know that
> the 8k copy actually happened and we have just wasted a great pile of
> CPU doing a pointless memcpy.
Why would it do the copy in the first place if we asked (for example)
for 16k, but only 8k was available ? Just return EAGAIN and have
done with it.
> I expect that this situation (first part in cache, latter part not in
> cache) is rare - for reasonably small requests the common cases will be
> "all cached" and "nothing cached". So perhaps the best approach here
> is for samba to add special handling for the short read, to work out
> the reason for its occurrence.
We can do that, but as Volker says this is a very hot code path.
> I take it from your comments that nobody has actually wired up pread2()
> into samba yet? That's a bit disturbing, because if we later want to
> go and change something like this short-read behaviour, we're screwed -
> it's a non back-compat userspace-visible change.
It's been done as a test, so the code exists and has run (and improved
perforamance as I recall). Not much point commiting it without kernel
support :-).
> And a note on cosmetics: why are we using EAGAIN here rather than
> EWOULDBLOCK? They have the same numerical value, but EWOULDBLOCK is a
> better name - EAGAIN says "run it again", but that won't work.
Sounds good to me !
--
To unsubscribe, send a message with 'unsubscribe linux-aio' in
the body to majordomo@kvack.org. For more info on Linux AIO,
see: http://www.kvack.org/aio/
Don't email: <a href=mailto:"aart@kvack.org">aart@kvack.org</a>
^ permalink raw reply
* Re: [PATCH v7 0/5] vfs: Non-blockling buffered fs read (page cache only)
From: Milosz Tanski @ 2015-03-27 16:38 UTC (permalink / raw)
To: Jeremy Allison
Cc: Andrew Morton, Christoph Hellwig, LKML,
linux-fsdevel@vger.kernel.org, linux-aio@kvack.org, Mel Gorman,
Volker Lendecke, Tejun Heo, Jeff Moyer, Theodore Ts'o,
Al Viro, Linux API, Michael Kerrisk, linux-arch, Dave Chinner
In-Reply-To: <20150327155854.GA5548@samba2>
On Fri, Mar 27, 2015 at 11:58 AM, Jeremy Allison <jra@samba.org> wrote:
> On Fri, Mar 27, 2015 at 02:01:59AM -0700, Andrew Morton wrote:
>> On Fri, 27 Mar 2015 01:48:33 -0700 Christoph Hellwig <hch@infradead.org> wrote:
>>
>> > On Fri, Mar 27, 2015 at 01:35:16AM -0700, Andrew Morton wrote:
>> > > fincore() doesn't have to be ugly. Please address the design issues I
>> > > raised. How is pread2() useful to the class of applications which
>> > > cannot proceed until all data is available?
>> >
>> > It actually makes them work correctly? preadv2( ..., DONTWAIT) will
>> > return -EGAIN, which causes them to bounce to the threadpool where
>> > they call preadv(...).
>>
>> (I assume you mean RWF_NONBLOCK)
>>
>> That isn't how pread2() works. If the leading one or more pages are
>> uptodate, pread2() will return a partial read. Now what? Either the
>> application reads the same data a second time via the worker thread
>> (dumb, but it will usually be a rare case)
>
> The problem with the above is that we can't tell the difference
> between pread2() returning a short read because the pages are not
> in cache, or because someone truncated the file. So we need some
> way to differentiate this.
>
> My preference from userspace would be for pread2() to return
> EAGAIN if *all* the data requested is not available (where
> 'all' can be less than the size requested if the file has
> been truncated in the meantime).
>
> So:
>
> ret = pread2(fd, buf, size_wanted, RWF_NONBLOCK)
>
> if (ret == -1) {
> if (errno == EAGAIN) {
> goto threadpool...
> }
> .. real error..
> }
>
> if (ret == size_wanted) {
> .. normal read, file not truncated...
> }
>
> if (ret < size_wanted) {
> .. file was truncated..
> }
>
> The thing I want to avoid is the case where
> ret < size_wanted means only part of the file
> is in cache.
I very much like the short read behavior. It lets you overlap some CPU
work partial data (like TLS and then sticking it network output
buffer) with waiting for the test of the data (enequed in the thread
pool).
Short reads are the current behavior, if you call preadv2 a second
time around at EOF it'll return 0 instead of EWOULDBLOCK today. I
actually test for this in the preadv2 test in xfstest here:
https://github.com/mtanski/xfstests/commit/688db24c292999c81ee17caf2b61fe8cf7bb3cd6#diff-114416ea98ce29dde3b5b3d145afbd2bR81.
There's one caveat, that it's possible to get EWOULDBLOCK when reading
at end of file if the file metadata is not paged in.
--
Milosz Tanski
CTO
16 East 34th Street, 15th floor
New York, NY 10016
p: 646-253-9055
e: milosz@adfin.com
--
To unsubscribe, send a message with 'unsubscribe linux-aio' in
the body to majordomo@kvack.org. For more info on Linux AIO,
see: http://www.kvack.org/aio/
Don't email: <a href=mailto:"aart@kvack.org">aart@kvack.org</a>
^ permalink raw reply
* Re: [PATCH v7 0/5] vfs: Non-blockling buffered fs read (page cache only)
From: Andrew Morton @ 2015-03-27 16:30 UTC (permalink / raw)
To: Jeremy Allison
Cc: Christoph Hellwig, Milosz Tanski,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-fsdevel-u79uwXL29TY76Z2rM5mHXA,
linux-aio-Bw31MaZKKs3YtjvyW6yDsg, Mel Gorman, Volker Lendecke,
Tejun Heo, Jeff Moyer, Theodore Ts'o, Al Viro,
linux-api-u79uwXL29TY76Z2rM5mHXA, Michael Kerrisk,
linux-arch-u79uwXL29TY76Z2rM5mHXA, Dave Chinner
In-Reply-To: <20150327155854.GA5548@samba2>
On Fri, 27 Mar 2015 08:58:54 -0700 Jeremy Allison <jra-eUNUBHrolfbYtjvyW6yDsg@public.gmane.org> wrote:
> On Fri, Mar 27, 2015 at 02:01:59AM -0700, Andrew Morton wrote:
> > On Fri, 27 Mar 2015 01:48:33 -0700 Christoph Hellwig <hch-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org> wrote:
> >
> > > On Fri, Mar 27, 2015 at 01:35:16AM -0700, Andrew Morton wrote:
> > > > fincore() doesn't have to be ugly. Please address the design issues I
> > > > raised. How is pread2() useful to the class of applications which
> > > > cannot proceed until all data is available?
> > >
> > > It actually makes them work correctly? preadv2( ..., DONTWAIT) will
> > > return -EGAIN, which causes them to bounce to the threadpool where
> > > they call preadv(...).
> >
> > (I assume you mean RWF_NONBLOCK)
> >
> > That isn't how pread2() works. If the leading one or more pages are
> > uptodate, pread2() will return a partial read. Now what? Either the
> > application reads the same data a second time via the worker thread
> > (dumb, but it will usually be a rare case)
>
> The problem with the above is that we can't tell the difference
> between pread2() returning a short read because the pages are not
> in cache, or because someone truncated the file. So we need some
> way to differentiate this.
>
> My preference from userspace would be for pread2() to return
> EAGAIN if *all* the data requested is not available (where
> 'all' can be less than the size requested if the file has
> been truncated in the meantime).
>
> ...
>
> The thing I want to avoid is the case where
> ret < size_wanted means only part of the file
> is in cache.
>From my reading of the code, pread2() will return -EAGAIN only when it
copied zero bytes to userspace. ie, the very first page wasn't in
cache. If pread2() does copy some data to userspace then it will
return the amount of data copied. This is traditional read()
behaviour.
Maybe there's some other code somewhere in the patch which converts
that short read into -EAGAIN, dunno - the changelogs don't appear to
mention it and the manpage update is ambiguous about this.
But from an interface perspective the behaviour you're asking for is
insane, frankly - if the kernel copied out 8k of data then pread2()
should return 8k. Otherwise there's no way for userspace to know that
the 8k copy actually happened and we have just wasted a great pile of
CPU doing a pointless memcpy.
I expect that this situation (first part in cache, latter part not in
cache) is rare - for reasonably small requests the common cases will be
"all cached" and "nothing cached". So perhaps the best approach here
is for samba to add special handling for the short read, to work out
the reason for its occurrence.
Alternatively we could add another flag to pread2() to select this
"throw away my data and return -EAGAIN" behaviour. Presumably
implemented with an i_size check, but it's gonna be racy.
I take it from your comments that nobody has actually wired up pread2()
into samba yet? That's a bit disturbing, because if we later want to
go and change something like this short-read behaviour, we're screwed -
it's a non back-compat userspace-visible change.
And a note on cosmetics: why are we using EAGAIN here rather than
EWOULDBLOCK? They have the same numerical value, but EWOULDBLOCK is a
better name - EAGAIN says "run it again", but that won't work.
^ permalink raw reply
* Re: [PATCH net-next] tc: bpf: generalize pedit action
From: Alexei Starovoitov @ 2015-03-27 16:01 UTC (permalink / raw)
To: Daniel Borkmann, David S. Miller
Cc: Jiri Pirko, Jamal Hadi Salim, linux-api, netdev
In-Reply-To: <55153425.2070502@iogearbox.net>
On 3/27/15 3:42 AM, Daniel Borkmann wrote:
> On 03/27/2015 03:53 AM, Alexei Starovoitov wrote:
>> existing TC action 'pedit' can munge any bits of the packet.
>> Generalize it for use in bpf programs attached as cls_bpf and act_bpf via
>> bpf_skb_store_bytes() helper function.
>>
>> Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
>
> I like it.
>
>> pedit is limited to 32-bit masked rewrites. Here let it be flexible.
>>
>> ptr = skb_header_pointer(skb, offset, len, buf);
>> memcpy(ptr, from, len);
>> if (ptr == buf)
>> skb_store_bits(skb, offset, ptr, len);
>>
>> ^^ logic is the same as in pedit.
>> shifts, mask, invert style of rewrite is easily done by the program.
>> Just like arbitrary parsing of the packet and applying rewrites on
>> demand.
> ...
>> +static u64 bpf_skb_store_bytes(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5)
>> +{
>> + struct sk_buff *skb = (struct sk_buff *) (long) r1;
>> + unsigned int offset = (unsigned int) r2;
>> + void *from = (void *) (long) r3;
>> + unsigned int len = (unsigned int) r4;
>> + char buf[16];
>> + void *ptr;
>> +
>> + /* bpf verifier guarantees that:
>> + * 'from' pointer points to bpf program stack
>> + * 'len' bytes of it were initialized
>> + * 'len' > 0
>> + * 'skb' is a valid pointer to 'struct sk_buff'
>> + *
>> + * so check for invalid 'offset' and too large 'len'
>> + */
>> + if (offset > 0xffff || len > sizeof(buf))
>> + return -EFAULT;
>
> Could you elaborate on the hard-coded 0xffff? Hm, perhaps better u16, or
> do you see any issues with wrong widening?
0xffff is the maximum packet size, of course.
Beyond basic sanity the above two conditions check for overflow
of offset+len automatically.
u16 won't work, since all the following functions are taking 'int' or
'unsigned int'. These checks are done first to make there are no wrap
arounds or other subtleties. Especially since skb_copy_bits is quite
complex inside.
> This check should probably be also unlikely().
I thought about it as well, but decided against it, since we don't
use likley/unlikely in skb_header_pointer, skb_copy_bits and others.
Better to be consistent.
> Ok, the sizeof(buf) could still be increased in future if truly necessary.
yes. correct.
I've decided to go small first and extend if necessary.
>> + if (skb_cloned(skb) && !skb_clone_writable(skb, offset + len))
>> + return -EFAULT;
>> +
>> + ptr = skb_header_pointer(skb, offset, len, buf);
>> + if (unlikely(!ptr))
>> + return -EFAULT;
>> +
>> + skb_postpull_rcsum(skb, ptr, len);
>> +
>> + memcpy(ptr, from, len);
>> +
>> + if (ptr == buf)
>> + /* skb_store_bits cannot return -EFAULT here */
>> + skb_store_bits(skb, offset, ptr, len);
>> +
>> + if (skb->ip_summed == CHECKSUM_COMPLETE)
>> + skb->csum = csum_add(skb->csum, csum_partial(ptr, len, 0));
>
> For egress, I think that CHECKSUM_PARTIAL does not need to be dealt
> with since the skb length doesn't change. Do you see an issue when
> cls_bpf/act_bpf would be attached to the ingress qdisc?
Well, this patch is packet writer only.
The checksum helpers and support for CHECKSUM_PARTIAL (similar to
TP_STATUS_CSUMNOTREADY) are coming in the future patches.
They should be independent. Otherwise this simple writer function
would need to special case different offsets and tons of other
checks. Keep it simple principle.
> I was also thinking if it's worth it to split off the csum correction
> as a separate function if there are not too big performance implications?
yep. performance will suffer if we split it. Better to leave it as-is.
> That way, an action may also allow to intentionally test corruption of
> a part of the skb data together with the recent prandom function.
This writer can do that already, but it keeps skb->csum correct.
If you suggestion is to test corruption of skb->csum, then I don't
see why we would want that.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox