[PATCH 2/2] userfaultfd: Add ioctl tests
Dr. David Alan Gilbert (git)
dgilbert at redhat.com
Fri May 6 11:08:41 UTC 2016
From: "Dr. David Alan Gilbert" <dgilbert at redhat.com>
* tests/userfaultfd.c: Add test
* tests/userfaultfd.test: Call test
---
tests/userfaultfd.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++-
tests/userfaultfd.test | 2 +-
2 files changed, 177 insertions(+), 4 deletions(-)
diff --git a/tests/userfaultfd.c b/tests/userfaultfd.c
index 5747a2a..9410fe4 100644
--- a/tests/userfaultfd.c
+++ b/tests/userfaultfd.c
@@ -26,7 +26,11 @@
*/
#include "tests.h"
+#include <assert.h>
#include <fcntl.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <string.h>
#include <sys/syscall.h>
#if defined __NR_userfaultfd && defined O_CLOEXEC
@@ -34,12 +38,181 @@
# include <stdio.h>
# include <unistd.h>
+#ifdef HAVE_LINUX_USERFAULTFD_H
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <linux/ioctl.h>
+#include <linux/userfaultfd.h>
+#endif
+
+void
+ioctl_test(int fd)
+{
+#ifdef HAVE_LINUX_USERFAULTFD_H
+ int rc;
+ size_t pagesize = getpagesize();
+
+ /* ---- API ---- */
+ struct uffdio_api api_struct;
+ /* With a bad fd */
+ memset(&api_struct, 0, sizeof(api_struct));
+ rc = ioctl(-1, UFFDIO_API, &api_struct);
+ printf("ioctl(-1, UFFDIO_API, {api=0, features=0, "
+ "features.out=0, ioctls=0"
+ "}) = %d %s (%m)\n", rc, errno2name());
+ /* With a bad pointer */
+ rc = ioctl(fd, UFFDIO_API, NULL);
+ printf("ioctl(%d, UFFDIO_API, NULL) = %d %s (%m)\n",
+ fd, rc, errno2name());
+ /* Normal call */
+ api_struct.api = UFFD_API;
+ api_struct.features = 0;
+ rc = ioctl(fd, UFFDIO_API, &api_struct);
+ printf("ioctl(%d, UFFDIO_API, {api=0xaa, features=0, "
+ "features.out=%#" PRIx64 ", " "ioctls=1<<_UFFDIO_REGISTER|"
+ "1<<_UFFDIO_UNREGISTER|1<<_UFFDIO_API",
+ fd, (uint64_t)api_struct.features);
+ api_struct.ioctls &= ~(1ull<<_UFFDIO_REGISTER|
+ 1ull<<_UFFDIO_UNREGISTER|
+ 1ull<<_UFFDIO_API);
+ if (api_struct.ioctls)
+ printf("|%#" PRIx64, (uint64_t)api_struct.ioctls);
+ printf("}) = %d\n", rc);
+
+ /* For the rest of the tests we need some anonymous memory */
+ void *area1 = mmap(NULL, pagesize, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS,
+ -1, 0);
+ assert(area1);
+ void *area2 = mmap(NULL, pagesize, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS,
+ -1, 0);
+ assert(area2);
+ madvise(area2, pagesize, MADV_DONTNEED);
+ *(char *)area1 = 42;
+
+ /* ---- REGISTER ---- */
+ struct uffdio_register register_struct;
+ memset(®ister_struct, 0, sizeof(register_struct));
+
+ rc = ioctl(-1, UFFDIO_REGISTER, ®ister_struct);
+ printf("ioctl(-1, UFFDIO_REGISTER, {range={start=0, len=0}, "
+ "mode=0, ioctls=0}) = %d %s (%m)\n",
+ rc, errno2name());
+
+ rc = ioctl(fd, UFFDIO_REGISTER, NULL);
+ printf("ioctl(%d, UFFDIO_REGISTER, NULL) = %d %s (%m)\n",
+ fd, rc, errno2name());
+
+ register_struct.range.start = (uint64_t)(uintptr_t)area2;
+ register_struct.range.len = pagesize;
+ register_struct.mode = UFFDIO_REGISTER_MODE_MISSING;
+ rc = ioctl(fd, UFFDIO_REGISTER, ®ister_struct);
+ printf("ioctl(%d, UFFDIO_REGISTER, {range={start=%p, len=%#zx}, "
+ "mode=UFFDIO_REGISTER_MODE_MISSING, ioctls="
+ "1<<_UFFDIO_WAKE|1<<_UFFDIO_COPY|1<<_UFFDIO_ZEROPAGE",
+ fd, area2, pagesize);
+ register_struct.ioctls &= ~(1ull<<_UFFDIO_WAKE|
+ 1ull<<_UFFDIO_COPY|
+ 1ull<<_UFFDIO_ZEROPAGE);
+ if (register_struct.ioctls)
+ printf("|%#" PRIx64, (uint64_t)register_struct.ioctls);
+ printf("}) = %d\n", rc);
+
+ /* With area2 registered we can now do the atomic copies onto it
+ * but be careful not to access it in any other way otherwise
+ * userfaultfd will cause us to stall.
+ */
+ /* ---- COPY ---- */
+ struct uffdio_copy copy_struct;
+
+ memset(©_struct, 0, sizeof(copy_struct));
+ rc = ioctl(-1, UFFDIO_COPY, ©_struct);
+ printf("ioctl(-1, UFFDIO_COPY, {dst=0, src=0, len=0, mode=0"
+ ", copy=0}) = %d %s (%m)\n",
+ rc, errno2name());
+
+ rc = ioctl(fd, UFFDIO_COPY, NULL);
+ printf("ioctl(%d, UFFDIO_COPY, NULL) = %d %s (%m)\n",
+ fd, rc, errno2name());
+
+ copy_struct.dst = (uint64_t)(uintptr_t)area2;
+ copy_struct.src = (uint64_t)(uintptr_t)area1;
+ copy_struct.len = pagesize;
+ copy_struct.mode = UFFDIO_COPY_MODE_DONTWAKE;
+ rc = ioctl(fd, UFFDIO_COPY, ©_struct);
+ printf("ioctl(%d, UFFDIO_COPY, {dst=%p, src=%p, len=%#zx,"
+ " mode=UFFDIO_COPY_MODE_DONTWAKE, copy=%#zx}) = %d\n",
+ fd, area2, area1, pagesize, pagesize, rc);
+
+ /* ---- ZEROPAGE ---- */
+ struct uffdio_zeropage zero_struct;
+ madvise(area2, pagesize, MADV_DONTNEED);
+
+ memset(&zero_struct, 0, sizeof(zero_struct));
+ rc = ioctl(-1, UFFDIO_ZEROPAGE, &zero_struct);
+ printf("ioctl(-1, UFFDIO_ZEROPAGE, {range={start=0, len=0}, mode=0"
+ ", zeropage=0}) = %d %s (%m)\n",
+ rc, errno2name());
+
+ rc = ioctl(fd, UFFDIO_ZEROPAGE, NULL);
+ printf("ioctl(%d, UFFDIO_ZEROPAGE, NULL) = %d %s (%m)\n",
+ fd, rc, errno2name());
+
+ zero_struct.range.start = (uint64_t)(uintptr_t)area2;
+ zero_struct.range.len = pagesize;
+ zero_struct.mode = UFFDIO_ZEROPAGE_MODE_DONTWAKE;
+ rc = ioctl(fd, UFFDIO_ZEROPAGE, &zero_struct);
+ printf("ioctl(%d, UFFDIO_ZEROPAGE, {range={start=%p, len=%#zx},"
+ " mode=UFFDIO_ZEROPAGE_MODE_DONTWAKE, zeropage=%#zx}) = %d\n",
+ fd, area2, pagesize, pagesize, rc);
+
+ /* ---- WAKE ---- */
+ struct uffdio_range range_struct;
+ memset(&range_struct, 0, sizeof(range_struct));
+
+ rc = ioctl(-1, UFFDIO_WAKE, &range_struct);
+ printf("ioctl(-1, UFFDIO_WAKE, {start=0, len=0}) = %d %s (%m)\n",
+ rc, errno2name());
+
+ rc = ioctl(fd, UFFDIO_WAKE, NULL);
+ printf("ioctl(%d, UFFDIO_WAKE, NULL) = %d %s (%m)\n",
+ fd, rc, errno2name());
+
+ range_struct.start = (uint64_t)(uintptr_t)area2;
+ range_struct.len = pagesize;
+ rc = ioctl(fd, UFFDIO_WAKE, &range_struct);
+ printf("ioctl(%d, UFFDIO_WAKE, {start=%p, len=%#zx}) = %d\n",
+ fd, area2, pagesize, rc);
+
+ /* ---- UNREGISTER ---- */
+ memset(&range_struct, 0, sizeof(range_struct));
+
+ rc = ioctl(-1, UFFDIO_UNREGISTER, &range_struct);
+ printf("ioctl(-1, UFFDIO_UNREGISTER, {start=0, len=0}) = %d %s (%m)\n",
+ rc, errno2name());
+
+ rc = ioctl(fd, UFFDIO_UNREGISTER, NULL);
+ printf("ioctl(%d, UFFDIO_UNREGISTER, NULL) = %d %s (%m)\n",
+ fd, rc, errno2name());
+
+ range_struct.start = (uint64_t)(uintptr_t)area2;
+ range_struct.len = pagesize;
+ rc = ioctl(fd, UFFDIO_UNREGISTER, &range_struct);
+ printf("ioctl(%d, UFFDIO_UNREGISTER, {start=%p, len=%#zx}) = %d\n",
+ fd, area2, pagesize, rc);
+
+#endif
+}
+
int
main(void)
{
- long rc = syscall(__NR_userfaultfd, 1 | O_NONBLOCK | O_CLOEXEC);
- printf("userfaultfd(O_NONBLOCK|O_CLOEXEC|0x1) = %ld %s (%m)\n",
- rc, errno2name());
+ int fd = syscall(__NR_userfaultfd, O_NONBLOCK | O_CLOEXEC);
+ printf("userfaultfd(O_NONBLOCK|O_CLOEXEC) = %d\n",
+ fd);
+ if (fd != -1)
+ ioctl_test(fd);
puts("+++ exited with 0 +++");
return 0;
}
diff --git a/tests/userfaultfd.test b/tests/userfaultfd.test
index af8b6fb..ccf4e44 100755
--- a/tests/userfaultfd.test
+++ b/tests/userfaultfd.test
@@ -3,4 +3,4 @@
# Check userfaultfd syscall decoding.
. "${srcdir=.}/init.sh"
-run_strace_match_diff -a38
+run_strace_match_diff -a1 -e trace=ioctl,userfaultfd
--
2.5.5
More information about the Strace-devel
mailing list