diff mbox series

[v4] syscalls: Add userfaultfd testcase

Message ID 20190319080732.30819-1-camann@suse.com
State Accepted
Delegated to: Petr Vorel
Headers show
Series [v4] syscalls: Add userfaultfd testcase | expand

Commit Message

Christian Amann March 19, 2019, 8:07 a.m. UTC
This tests the userfaultfd syscall to handle pagefault events.
It does so by registering a userfaultfd object to the address of
a memory page. In a second thread it handles the event and writes
data in the monitored memory page to indicate success.

Signed-off-by: Christian Amann <camann@suse.com>
---
 configure.ac                                       |   1 +
 include/lapi/syscalls/aarch64.in                   |   1 +
 include/lapi/syscalls/arm.in                       |   1 +
 include/lapi/syscalls/i386.in                      |   1 +
 include/lapi/syscalls/ia64.in                      |   1 +
 include/lapi/syscalls/powerpc.in                   |   1 +
 include/lapi/syscalls/powerpc64.in                 |   1 +
 include/lapi/syscalls/s390.in                      |   1 +
 include/lapi/syscalls/s390x.in                     |   1 +
 include/lapi/syscalls/sparc.in                     |   1 +
 include/lapi/syscalls/sparc64.in                   |   1 +
 include/lapi/syscalls/x86_64.in                    |   1 +
 runtest/syscalls                                   |   2 +
 testcases/kernel/syscalls/userfaultfd/.gitignore   |   1 +
 testcases/kernel/syscalls/userfaultfd/Makefile     |  15 +++
 .../kernel/syscalls/userfaultfd/userfaultfd01.c    | 125 +++++++++++++++++++++
 16 files changed, 155 insertions(+)
 create mode 100644 testcases/kernel/syscalls/userfaultfd/.gitignore
 create mode 100644 testcases/kernel/syscalls/userfaultfd/Makefile
 create mode 100644 testcases/kernel/syscalls/userfaultfd/userfaultfd01.c

Comments

Christian Amann March 19, 2019, 8:11 a.m. UTC | #1
Thanks for the feedback, so far.

This version fixes compiler warnings, renames the syscall function in
order to avoid conflicts with future glibc versions and changes
"syscall" to "syscalls" in the subject.

Regards,

Christian

On 19/03/2019 09:07, Christian Amann wrote:
> This tests the userfaultfd syscall to handle pagefault events.
> It does so by registering a userfaultfd object to the address of
> a memory page. In a second thread it handles the event and writes
> data in the monitored memory page to indicate success.
>
> Signed-off-by: Christian Amann <camann@suse.com>
> ---
>  configure.ac                                       |   1 +
>  include/lapi/syscalls/aarch64.in                   |   1 +
>  include/lapi/syscalls/arm.in                       |   1 +
>  include/lapi/syscalls/i386.in                      |   1 +
>  include/lapi/syscalls/ia64.in                      |   1 +
>  include/lapi/syscalls/powerpc.in                   |   1 +
>  include/lapi/syscalls/powerpc64.in                 |   1 +
>  include/lapi/syscalls/s390.in                      |   1 +
>  include/lapi/syscalls/s390x.in                     |   1 +
>  include/lapi/syscalls/sparc.in                     |   1 +
>  include/lapi/syscalls/sparc64.in                   |   1 +
>  include/lapi/syscalls/x86_64.in                    |   1 +
>  runtest/syscalls                                   |   2 +
>  testcases/kernel/syscalls/userfaultfd/.gitignore   |   1 +
>  testcases/kernel/syscalls/userfaultfd/Makefile     |  15 +++
>  .../kernel/syscalls/userfaultfd/userfaultfd01.c    | 125 +++++++++++++++++++++
>  16 files changed, 155 insertions(+)
>  create mode 100644 testcases/kernel/syscalls/userfaultfd/.gitignore
>  create mode 100644 testcases/kernel/syscalls/userfaultfd/Makefile
>  create mode 100644 testcases/kernel/syscalls/userfaultfd/userfaultfd01.c
>
> diff --git a/configure.ac b/configure.ac
> index e002c248e..523ab7d87 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -46,6 +46,7 @@ AC_CHECK_HEADERS([ \
>      linux/mempolicy.h \
>      linux/module.h \
>      linux/netlink.h \
> +    linux/userfaultfd.h \
>      mm.h \
>      netinet/sctp.h \
>      pthread.h \
> diff --git a/include/lapi/syscalls/aarch64.in b/include/lapi/syscalls/aarch64.in
> index 7ce148524..177dd0115 100644
> --- a/include/lapi/syscalls/aarch64.in
> +++ b/include/lapi/syscalls/aarch64.in
> @@ -258,6 +258,7 @@ process_vm_writev 271
>  kcmp 272
>  getrandom 278
>  memfd_create 279
> +userfaultfd 282
>  membarrier 283
>  execveat 281
>  mlock2 284
> diff --git a/include/lapi/syscalls/arm.in b/include/lapi/syscalls/arm.in
> index 22c76d4f0..f4adedb2c 100644
> --- a/include/lapi/syscalls/arm.in
> +++ b/include/lapi/syscalls/arm.in
> @@ -343,6 +343,7 @@ renameat2 (__NR_SYSCALL_BASE+382)
>  getrandom (__NR_SYSCALL_BASE+384)
>  memfd_create (__NR_SYSCALL_BASE+385)
>  execveat (__NR_SYSCALL_BASE+387)
> +userfaultfd (__NR_SYSCALL_BASE+388)
>  membarrier (__NR_SYSCALL_BASE+389)
>  mlock2 (__NR_SYSCALL_BASE+390)
>  copy_file_range (__NR_SYSCALL_BASE+391)
> diff --git a/include/lapi/syscalls/i386.in b/include/lapi/syscalls/i386.in
> index 7e485aebf..af5254f77 100644
> --- a/include/lapi/syscalls/i386.in
> +++ b/include/lapi/syscalls/i386.in
> @@ -341,6 +341,7 @@ renameat2 354
>  getrandom 355
>  memfd_create 356
>  execveat 358
> +userfaultfd 374
>  membarrier 375
>  mlock2 376
>  copy_file_range 377
> diff --git a/include/lapi/syscalls/ia64.in b/include/lapi/syscalls/ia64.in
> index 7c9a0ead6..c0aeed08b 100644
> --- a/include/lapi/syscalls/ia64.in
> +++ b/include/lapi/syscalls/ia64.in
> @@ -298,6 +298,7 @@ process_vm_writev 1333
>  renameat2 1338
>  getrandom 1339
>  memfd_create 1340
> +userfaultfd 1343
>  membarrier 1344
>  execveat 1342
>  mlock2 1346
> diff --git a/include/lapi/syscalls/powerpc.in b/include/lapi/syscalls/powerpc.in
> index fc1f89945..6b6be58a7 100644
> --- a/include/lapi/syscalls/powerpc.in
> +++ b/include/lapi/syscalls/powerpc.in
> @@ -347,6 +347,7 @@ sched_getattr 356
>  renameat2 357
>  getrandom 359
>  memfd_create 360
> +userfaultfd 364
>  membarrier 365
>  execveat 362
>  mlock2 378
> diff --git a/include/lapi/syscalls/powerpc64.in b/include/lapi/syscalls/powerpc64.in
> index fc1f89945..6b6be58a7 100644
> --- a/include/lapi/syscalls/powerpc64.in
> +++ b/include/lapi/syscalls/powerpc64.in
> @@ -347,6 +347,7 @@ sched_getattr 356
>  renameat2 357
>  getrandom 359
>  memfd_create 360
> +userfaultfd 364
>  membarrier 365
>  execveat 362
>  mlock2 378
> diff --git a/include/lapi/syscalls/s390.in b/include/lapi/syscalls/s390.in
> index 6d0c895fa..2a2ffe223 100644
> --- a/include/lapi/syscalls/s390.in
> +++ b/include/lapi/syscalls/s390.in
> @@ -331,6 +331,7 @@ sched_getattr 346
>  renameat2 347
>  getrandom 349
>  memfd_create 350
> +userfaultfd 355
>  membarrier 356
>  execveat 354
>  mlock2 374
> diff --git a/include/lapi/syscalls/s390x.in b/include/lapi/syscalls/s390x.in
> index 8105b5598..4c36ce17c 100644
> --- a/include/lapi/syscalls/s390x.in
> +++ b/include/lapi/syscalls/s390x.in
> @@ -330,6 +330,7 @@ sched_getattr 346
>  renameat2 347
>  getrandom 349
>  memfd_create 350
> +userfaultfd 355
>  membarrier 356
>  execveat 354
>  mlock2 374
> diff --git a/include/lapi/syscalls/sparc.in b/include/lapi/syscalls/sparc.in
> index 20a21a9ce..20dc37b01 100644
> --- a/include/lapi/syscalls/sparc.in
> +++ b/include/lapi/syscalls/sparc.in
> @@ -337,6 +337,7 @@ renameat2 345
>  getrandom 347
>  memfd_create 348
>  membarrier 351
> +userfaultfd 352
>  execveat 350
>  mlock2 356
>  copy_file_range 357
> diff --git a/include/lapi/syscalls/sparc64.in b/include/lapi/syscalls/sparc64.in
> index 36ab39420..c100b8e3e 100644
> --- a/include/lapi/syscalls/sparc64.in
> +++ b/include/lapi/syscalls/sparc64.in
> @@ -313,6 +313,7 @@ renameat2 345
>  getrandom 347
>  memfd_create 348
>  membarrier 351
> +userfaultfd 352
>  execveat 350
>  mlock2 356
>  copy_file_range 357
> diff --git a/include/lapi/syscalls/x86_64.in b/include/lapi/syscalls/x86_64.in
> index 6aa9d12a8..87849e5c0 100644
> --- a/include/lapi/syscalls/x86_64.in
> +++ b/include/lapi/syscalls/x86_64.in
> @@ -308,6 +308,7 @@ renameat2 316
>  getrandom 318
>  memfd_create 319
>  execveat 322
> +userfaultfd 323
>  membarrier 324
>  mlock2 325
>  copy_file_range 326
> diff --git a/runtest/syscalls b/runtest/syscalls
> index 03b613c07..89f4b5097 100644
> --- a/runtest/syscalls
> +++ b/runtest/syscalls
> @@ -1465,6 +1465,8 @@ umount2_01 umount2_01
>  umount2_02 umount2_02
>  umount2_03 umount2_03
>  
> +userfaultfd01 userfaultfd01
> +
>  ustat01 ustat01
>  ustat02 ustat02
>  
> diff --git a/testcases/kernel/syscalls/userfaultfd/.gitignore b/testcases/kernel/syscalls/userfaultfd/.gitignore
> new file mode 100644
> index 000000000..d819a2a7c
> --- /dev/null
> +++ b/testcases/kernel/syscalls/userfaultfd/.gitignore
> @@ -0,0 +1 @@
> +/userfaultfd01
> diff --git a/testcases/kernel/syscalls/userfaultfd/Makefile b/testcases/kernel/syscalls/userfaultfd/Makefile
> new file mode 100644
> index 000000000..33fe59e5b
> --- /dev/null
> +++ b/testcases/kernel/syscalls/userfaultfd/Makefile
> @@ -0,0 +1,15 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +#
> +#   Copyright (c) 2019 SUSE LLC
> +#
> +#   Author: Christian Amann <camann@suse.com>
> +#
> +
> +top_srcdir		?= ../../../..
> +
> +include $(top_srcdir)/include/mk/testcases.mk
> +
> +include $(top_srcdir)/include/mk/generic_leaf_target.mk
> +
> +userfaultfd01: CFLAGS += -pthread
> +
> diff --git a/testcases/kernel/syscalls/userfaultfd/userfaultfd01.c b/testcases/kernel/syscalls/userfaultfd/userfaultfd01.c
> new file mode 100644
> index 000000000..bb8395e7f
> --- /dev/null
> +++ b/testcases/kernel/syscalls/userfaultfd/userfaultfd01.c
> @@ -0,0 +1,125 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) 2019 SUSE LLC
> + *
> + * Author: Christian Amann <camann@suse.com>
> + *
> + */
> +
> +/*
> + * Test userfaultfd
> + *
> + * Force a pagefault event and handle it using userfaultfd
> + * from a different thread
> + *
> + */
> +
> +#include "tst_test.h"
> +#include "tst_safe_macros.h"
> +#include "tst_safe_pthread.h"
> +#include "lapi/syscalls.h"
> +#include <poll.h>
> +
> +#ifdef HAVE_LINUX_USERFAULTFD_H
> +#include <linux/userfaultfd.h>
> +
> +static int page_size;
> +static char *page;
> +static void *copy_page;
> +static int uffd;
> +
> +static int sys_userfaultfd(int flags)
> +{
> +	return tst_syscall(__NR_userfaultfd, flags);
> +}
> +
> +static void set_pages(void)
> +{
> +	page_size = sysconf(_SC_PAGE_SIZE);
> +	page = SAFE_MMAP(NULL, page_size, PROT_READ | PROT_WRITE,
> +			MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> +	copy_page = SAFE_MMAP(NULL, page_size, PROT_READ | PROT_WRITE,
> +			MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> +}
> +
> +static void handle_thread(void)
> +{
> +	static struct uffd_msg msg;
> +	struct uffdio_copy uffdio_copy;
> +
> +	struct pollfd pollfd;
> +	int nready;
> +
> +	pollfd.fd = uffd;
> +	pollfd.events = POLLIN;
> +	nready = poll(&pollfd, 1, -1);
> +	if (nready == -1)
> +		tst_brk(TBROK | TERRNO,
> +				"Error on poll");
> +
> +	SAFE_READ(1, uffd, &msg, sizeof(msg));
> +
> +	if (msg.event != UFFD_EVENT_PAGEFAULT)
> +		tst_brk(TBROK | TERRNO,
> +				"Received unexpected UFFD_EVENT");
> +
> +	memset(copy_page, 'X', page_size);
> +
> +	uffdio_copy.src = (unsigned long) copy_page;
> +
> +	uffdio_copy.dst = (unsigned long) msg.arg.pagefault.address
> +			& ~(page_size - 1);
> +	uffdio_copy.len = page_size;
> +	uffdio_copy.mode = 0;
> +	uffdio_copy.copy = 0;
> +	SAFE_IOCTL(uffd, UFFDIO_COPY, &uffdio_copy);
> +
> +	close(uffd);
> +}
> +
> +static void run(void)
> +{
> +	pthread_t thr;
> +	struct uffdio_api uffdio_api;
> +	struct uffdio_register uffdio_register;
> +
> +	set_pages();
> +
> +	uffd = sys_userfaultfd(O_CLOEXEC | O_NONBLOCK);
> +
> +	if (uffd == -1)
> +		tst_brk(TBROK | TERRNO,
> +			"Could not create userfault file descriptor");
> +
> +	uffdio_api.api = UFFD_API;
> +	uffdio_api.features = 0;
> +	SAFE_IOCTL(uffd, UFFDIO_API, &uffdio_api);
> +
> +	uffdio_register.range.start = (unsigned long) page;
> +	uffdio_register.range.len = page_size;
> +	uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
> +
> +	SAFE_IOCTL(uffd, UFFDIO_REGISTER, &uffdio_register);
> +
> +	SAFE_PTHREAD_CREATE(&thr, NULL,
> +			(void * (*)(void *)) handle_thread, NULL);
> +
> +	char c = page[0xf];
> +
> +	if (c == 'X')
> +		tst_res(TPASS, "Pagefault handled!");
> +	else
> +		tst_res(TFAIL, "Pagefault not handled!");
> +
> +	SAFE_PTHREAD_JOIN(thr, NULL);
> +}
> +
> +static struct tst_test test = {
> +	.test_all = run,
> +	.min_kver = "4.3",
> +	.timeout = 20
> +};
> +
> +#else
> +	TST_TEST_TCONF("This system does not provide userfaultfd support");
> +#endif
Petr Vorel March 25, 2019, 1:37 p.m. UTC | #2
Hi Christian,

> Thanks for the feedback, so far.

> This version fixes compiler warnings, renames the syscall function in
> order to avoid conflicts with future glibc versions and changes
> "syscall" to "syscalls" in the subject.

Thanks for your work. Accepted with minor changes (functional change was to
include config.h before using HAVE_LINUX_USERFAULTFD_H).

Kind regards,
Petr


diff --git testcases/kernel/syscalls/userfaultfd/userfaultfd01.c testcases/kernel/syscalls/userfaultfd/userfaultfd01.c
index bb8395e7f..a5e142209 100644
--- testcases/kernel/syscalls/userfaultfd/userfaultfd01.c
+++ testcases/kernel/syscalls/userfaultfd/userfaultfd01.c
@@ -1,27 +1,24 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
  * Copyright (c) 2019 SUSE LLC
- *
  * Author: Christian Amann <camann@suse.com>
  *
- */
-
-/*
  * Test userfaultfd
  *
  * Force a pagefault event and handle it using userfaultfd
  * from a different thread
- *
  */
 
+#include "config.h"
 #include "tst_test.h"
-#include "tst_safe_macros.h"
-#include "tst_safe_pthread.h"
-#include "lapi/syscalls.h"
-#include <poll.h>
 
 #ifdef HAVE_LINUX_USERFAULTFD_H
 #include <linux/userfaultfd.h>
+#include <poll.h>
+
+#include "tst_safe_macros.h"
+#include "tst_safe_pthread.h"
+#include "lapi/syscalls.h"
 
 static int page_size;
 static char *page;
diff mbox series

Patch

diff --git a/configure.ac b/configure.ac
index e002c248e..523ab7d87 100644
--- a/configure.ac
+++ b/configure.ac
@@ -46,6 +46,7 @@  AC_CHECK_HEADERS([ \
     linux/mempolicy.h \
     linux/module.h \
     linux/netlink.h \
+    linux/userfaultfd.h \
     mm.h \
     netinet/sctp.h \
     pthread.h \
diff --git a/include/lapi/syscalls/aarch64.in b/include/lapi/syscalls/aarch64.in
index 7ce148524..177dd0115 100644
--- a/include/lapi/syscalls/aarch64.in
+++ b/include/lapi/syscalls/aarch64.in
@@ -258,6 +258,7 @@  process_vm_writev 271
 kcmp 272
 getrandom 278
 memfd_create 279
+userfaultfd 282
 membarrier 283
 execveat 281
 mlock2 284
diff --git a/include/lapi/syscalls/arm.in b/include/lapi/syscalls/arm.in
index 22c76d4f0..f4adedb2c 100644
--- a/include/lapi/syscalls/arm.in
+++ b/include/lapi/syscalls/arm.in
@@ -343,6 +343,7 @@  renameat2 (__NR_SYSCALL_BASE+382)
 getrandom (__NR_SYSCALL_BASE+384)
 memfd_create (__NR_SYSCALL_BASE+385)
 execveat (__NR_SYSCALL_BASE+387)
+userfaultfd (__NR_SYSCALL_BASE+388)
 membarrier (__NR_SYSCALL_BASE+389)
 mlock2 (__NR_SYSCALL_BASE+390)
 copy_file_range (__NR_SYSCALL_BASE+391)
diff --git a/include/lapi/syscalls/i386.in b/include/lapi/syscalls/i386.in
index 7e485aebf..af5254f77 100644
--- a/include/lapi/syscalls/i386.in
+++ b/include/lapi/syscalls/i386.in
@@ -341,6 +341,7 @@  renameat2 354
 getrandom 355
 memfd_create 356
 execveat 358
+userfaultfd 374
 membarrier 375
 mlock2 376
 copy_file_range 377
diff --git a/include/lapi/syscalls/ia64.in b/include/lapi/syscalls/ia64.in
index 7c9a0ead6..c0aeed08b 100644
--- a/include/lapi/syscalls/ia64.in
+++ b/include/lapi/syscalls/ia64.in
@@ -298,6 +298,7 @@  process_vm_writev 1333
 renameat2 1338
 getrandom 1339
 memfd_create 1340
+userfaultfd 1343
 membarrier 1344
 execveat 1342
 mlock2 1346
diff --git a/include/lapi/syscalls/powerpc.in b/include/lapi/syscalls/powerpc.in
index fc1f89945..6b6be58a7 100644
--- a/include/lapi/syscalls/powerpc.in
+++ b/include/lapi/syscalls/powerpc.in
@@ -347,6 +347,7 @@  sched_getattr 356
 renameat2 357
 getrandom 359
 memfd_create 360
+userfaultfd 364
 membarrier 365
 execveat 362
 mlock2 378
diff --git a/include/lapi/syscalls/powerpc64.in b/include/lapi/syscalls/powerpc64.in
index fc1f89945..6b6be58a7 100644
--- a/include/lapi/syscalls/powerpc64.in
+++ b/include/lapi/syscalls/powerpc64.in
@@ -347,6 +347,7 @@  sched_getattr 356
 renameat2 357
 getrandom 359
 memfd_create 360
+userfaultfd 364
 membarrier 365
 execveat 362
 mlock2 378
diff --git a/include/lapi/syscalls/s390.in b/include/lapi/syscalls/s390.in
index 6d0c895fa..2a2ffe223 100644
--- a/include/lapi/syscalls/s390.in
+++ b/include/lapi/syscalls/s390.in
@@ -331,6 +331,7 @@  sched_getattr 346
 renameat2 347
 getrandom 349
 memfd_create 350
+userfaultfd 355
 membarrier 356
 execveat 354
 mlock2 374
diff --git a/include/lapi/syscalls/s390x.in b/include/lapi/syscalls/s390x.in
index 8105b5598..4c36ce17c 100644
--- a/include/lapi/syscalls/s390x.in
+++ b/include/lapi/syscalls/s390x.in
@@ -330,6 +330,7 @@  sched_getattr 346
 renameat2 347
 getrandom 349
 memfd_create 350
+userfaultfd 355
 membarrier 356
 execveat 354
 mlock2 374
diff --git a/include/lapi/syscalls/sparc.in b/include/lapi/syscalls/sparc.in
index 20a21a9ce..20dc37b01 100644
--- a/include/lapi/syscalls/sparc.in
+++ b/include/lapi/syscalls/sparc.in
@@ -337,6 +337,7 @@  renameat2 345
 getrandom 347
 memfd_create 348
 membarrier 351
+userfaultfd 352
 execveat 350
 mlock2 356
 copy_file_range 357
diff --git a/include/lapi/syscalls/sparc64.in b/include/lapi/syscalls/sparc64.in
index 36ab39420..c100b8e3e 100644
--- a/include/lapi/syscalls/sparc64.in
+++ b/include/lapi/syscalls/sparc64.in
@@ -313,6 +313,7 @@  renameat2 345
 getrandom 347
 memfd_create 348
 membarrier 351
+userfaultfd 352
 execveat 350
 mlock2 356
 copy_file_range 357
diff --git a/include/lapi/syscalls/x86_64.in b/include/lapi/syscalls/x86_64.in
index 6aa9d12a8..87849e5c0 100644
--- a/include/lapi/syscalls/x86_64.in
+++ b/include/lapi/syscalls/x86_64.in
@@ -308,6 +308,7 @@  renameat2 316
 getrandom 318
 memfd_create 319
 execveat 322
+userfaultfd 323
 membarrier 324
 mlock2 325
 copy_file_range 326
diff --git a/runtest/syscalls b/runtest/syscalls
index 03b613c07..89f4b5097 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -1465,6 +1465,8 @@  umount2_01 umount2_01
 umount2_02 umount2_02
 umount2_03 umount2_03
 
+userfaultfd01 userfaultfd01
+
 ustat01 ustat01
 ustat02 ustat02
 
diff --git a/testcases/kernel/syscalls/userfaultfd/.gitignore b/testcases/kernel/syscalls/userfaultfd/.gitignore
new file mode 100644
index 000000000..d819a2a7c
--- /dev/null
+++ b/testcases/kernel/syscalls/userfaultfd/.gitignore
@@ -0,0 +1 @@ 
+/userfaultfd01
diff --git a/testcases/kernel/syscalls/userfaultfd/Makefile b/testcases/kernel/syscalls/userfaultfd/Makefile
new file mode 100644
index 000000000..33fe59e5b
--- /dev/null
+++ b/testcases/kernel/syscalls/userfaultfd/Makefile
@@ -0,0 +1,15 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+#
+#   Copyright (c) 2019 SUSE LLC
+#
+#   Author: Christian Amann <camann@suse.com>
+#
+
+top_srcdir		?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
+
+userfaultfd01: CFLAGS += -pthread
+
diff --git a/testcases/kernel/syscalls/userfaultfd/userfaultfd01.c b/testcases/kernel/syscalls/userfaultfd/userfaultfd01.c
new file mode 100644
index 000000000..bb8395e7f
--- /dev/null
+++ b/testcases/kernel/syscalls/userfaultfd/userfaultfd01.c
@@ -0,0 +1,125 @@ 
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 SUSE LLC
+ *
+ * Author: Christian Amann <camann@suse.com>
+ *
+ */
+
+/*
+ * Test userfaultfd
+ *
+ * Force a pagefault event and handle it using userfaultfd
+ * from a different thread
+ *
+ */
+
+#include "tst_test.h"
+#include "tst_safe_macros.h"
+#include "tst_safe_pthread.h"
+#include "lapi/syscalls.h"
+#include <poll.h>
+
+#ifdef HAVE_LINUX_USERFAULTFD_H
+#include <linux/userfaultfd.h>
+
+static int page_size;
+static char *page;
+static void *copy_page;
+static int uffd;
+
+static int sys_userfaultfd(int flags)
+{
+	return tst_syscall(__NR_userfaultfd, flags);
+}
+
+static void set_pages(void)
+{
+	page_size = sysconf(_SC_PAGE_SIZE);
+	page = SAFE_MMAP(NULL, page_size, PROT_READ | PROT_WRITE,
+			MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+	copy_page = SAFE_MMAP(NULL, page_size, PROT_READ | PROT_WRITE,
+			MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+}
+
+static void handle_thread(void)
+{
+	static struct uffd_msg msg;
+	struct uffdio_copy uffdio_copy;
+
+	struct pollfd pollfd;
+	int nready;
+
+	pollfd.fd = uffd;
+	pollfd.events = POLLIN;
+	nready = poll(&pollfd, 1, -1);
+	if (nready == -1)
+		tst_brk(TBROK | TERRNO,
+				"Error on poll");
+
+	SAFE_READ(1, uffd, &msg, sizeof(msg));
+
+	if (msg.event != UFFD_EVENT_PAGEFAULT)
+		tst_brk(TBROK | TERRNO,
+				"Received unexpected UFFD_EVENT");
+
+	memset(copy_page, 'X', page_size);
+
+	uffdio_copy.src = (unsigned long) copy_page;
+
+	uffdio_copy.dst = (unsigned long) msg.arg.pagefault.address
+			& ~(page_size - 1);
+	uffdio_copy.len = page_size;
+	uffdio_copy.mode = 0;
+	uffdio_copy.copy = 0;
+	SAFE_IOCTL(uffd, UFFDIO_COPY, &uffdio_copy);
+
+	close(uffd);
+}
+
+static void run(void)
+{
+	pthread_t thr;
+	struct uffdio_api uffdio_api;
+	struct uffdio_register uffdio_register;
+
+	set_pages();
+
+	uffd = sys_userfaultfd(O_CLOEXEC | O_NONBLOCK);
+
+	if (uffd == -1)
+		tst_brk(TBROK | TERRNO,
+			"Could not create userfault file descriptor");
+
+	uffdio_api.api = UFFD_API;
+	uffdio_api.features = 0;
+	SAFE_IOCTL(uffd, UFFDIO_API, &uffdio_api);
+
+	uffdio_register.range.start = (unsigned long) page;
+	uffdio_register.range.len = page_size;
+	uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;
+
+	SAFE_IOCTL(uffd, UFFDIO_REGISTER, &uffdio_register);
+
+	SAFE_PTHREAD_CREATE(&thr, NULL,
+			(void * (*)(void *)) handle_thread, NULL);
+
+	char c = page[0xf];
+
+	if (c == 'X')
+		tst_res(TPASS, "Pagefault handled!");
+	else
+		tst_res(TFAIL, "Pagefault not handled!");
+
+	SAFE_PTHREAD_JOIN(thr, NULL);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.min_kver = "4.3",
+	.timeout = 20
+};
+
+#else
+	TST_TEST_TCONF("This system does not provide userfaultfd support");
+#endif