From: "Dr. David Alan Gilbert" <dgilb...@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 ------------------------------------------------------------------------------ Find and fix application performance issues faster with Applications Manager Applications Manager provides deep performance insights into multiple tiers of your business applications. It resolves application problems quickly and reduces your MTTR. Get your free trial! https://ad.doubleclick.net/ddm/clk/302982198;130105516;z _______________________________________________ Strace-devel mailing list Strace-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/strace-devel