selftests/mm: let uffd_handle_page_fault() take wp parameter
authorPeter Xu <peterx@redhat.com>
Wed, 12 Apr 2023 16:43:41 +0000 (12:43 -0400)
committerAndrew Morton <akpm@linux-foundation.org>
Tue, 18 Apr 2023 23:30:06 +0000 (16:30 -0700)
Make the handler optionally apply WP bit when resolving page faults for
either missing or minor page faults.  This moves towards removing global
test_uffdio_wp outside of the common code.

Link: https://lkml.kernel.org/r/20230412164341.328618-1-peterx@redhat.com
Signed-off-by: Peter Xu <peterx@redhat.com>
Cc: Axel Rasmussen <axelrasmussen@google.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: Dmitry Safonov <0x7f454c46@gmail.com>
Cc: Mike Kravetz <mike.kravetz@oracle.com>
Cc: Mike Rapoport (IBM) <rppt@kernel.org>
Cc: Zach O'Keefe <zokeefe@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
tools/testing/selftests/mm/uffd-common.c
tools/testing/selftests/mm/uffd-common.h
tools/testing/selftests/mm/uffd-stress.c

index e746405..daa2a95 100644 (file)
@@ -353,7 +353,7 @@ void wp_range(int ufd, __u64 start, __u64 len, bool wp)
                err("clear WP failed: address=0x%"PRIx64, (uint64_t)start);
 }
 
-static void continue_range(int ufd, __u64 start, __u64 len)
+static void continue_range(int ufd, __u64 start, __u64 len, bool wp)
 {
        struct uffdio_continue req;
        int ret;
@@ -361,7 +361,7 @@ static void continue_range(int ufd, __u64 start, __u64 len)
        req.range.start = start;
        req.range.len = len;
        req.mode = 0;
-       if (test_uffdio_wp)
+       if (wp)
                req.mode |= UFFDIO_CONTINUE_MODE_WP;
 
        if (ioctl(ufd, UFFDIO_CONTINUE, &req))
@@ -429,7 +429,8 @@ void uffd_handle_page_fault(struct uffd_msg *msg, struct uffd_args *args)
                                    area_dst_alias));
                for (b = 0; b < page_size; ++b)
                        area[b] = ~area[b];
-               continue_range(uffd, msg->arg.pagefault.address, page_size);
+               continue_range(uffd, msg->arg.pagefault.address, page_size,
+                              args->apply_wp);
                args->minor_faults++;
        } else {
                /*
@@ -459,7 +460,7 @@ void uffd_handle_page_fault(struct uffd_msg *msg, struct uffd_args *args)
                offset = (char *)(unsigned long)msg->arg.pagefault.address - area_dst;
                offset &= ~(page_size-1);
 
-               if (copy_page(uffd, offset))
+               if (copy_page(uffd, offset, args->apply_wp))
                        args->missing_faults++;
        }
 }
@@ -555,7 +556,7 @@ static void wake_range(int ufd, unsigned long addr, unsigned long len)
                        addr), exit(1);
 }
 
-int __copy_page(int ufd, unsigned long offset, bool retry)
+int __copy_page(int ufd, unsigned long offset, bool retry, bool wp)
 {
        struct uffdio_copy uffdio_copy;
 
@@ -564,7 +565,7 @@ int __copy_page(int ufd, unsigned long offset, bool retry)
        uffdio_copy.dst = (unsigned long) area_dst + offset;
        uffdio_copy.src = (unsigned long) area_src + offset;
        uffdio_copy.len = page_size;
-       if (test_uffdio_wp)
+       if (wp)
                uffdio_copy.mode = UFFDIO_COPY_MODE_WP;
        else
                uffdio_copy.mode = 0;
@@ -587,7 +588,7 @@ int __copy_page(int ufd, unsigned long offset, bool retry)
        return 0;
 }
 
-int copy_page(int ufd, unsigned long offset)
+int copy_page(int ufd, unsigned long offset, bool wp)
 {
-       return __copy_page(ufd, offset, false);
+       return __copy_page(ufd, offset, false, wp);
 }
index f8d2ad1..0ec07d0 100644 (file)
@@ -72,6 +72,8 @@
 /* Userfaultfd test statistics */
 struct uffd_args {
        int cpu;
+       /* Whether apply wr-protects when installing pages */
+       bool apply_wp;
        unsigned long missing_faults;
        unsigned long wp_faults;
        unsigned long minor_faults;
@@ -104,8 +106,8 @@ void userfaultfd_open(uint64_t *features);
 int uffd_read_msg(int ufd, struct uffd_msg *msg);
 void wp_range(int ufd, __u64 start, __u64 len, bool wp);
 void uffd_handle_page_fault(struct uffd_msg *msg, struct uffd_args *args);
-int __copy_page(int ufd, unsigned long offset, bool retry);
-int copy_page(int ufd, unsigned long offset);
+int __copy_page(int ufd, unsigned long offset, bool retry, bool wp);
+int copy_page(int ufd, unsigned long offset, bool wp);
 void *uffd_poll_thread(void *arg);
 
 #define TEST_ANON      1
index ce7251a..747d588 100644 (file)
@@ -96,6 +96,7 @@ static void uffd_stats_reset(struct uffd_args *args, unsigned long n_cpus)
 
        for (i = 0; i < n_cpus; i++) {
                args[i].cpu = i;
+               args[i].apply_wp = test_uffdio_wp;
                args[i].missing_faults = 0;
                args[i].wp_faults = 0;
                args[i].minor_faults = 0;
@@ -155,7 +156,7 @@ static void *locking_thread(void *arg)
 
 static int copy_page_retry(int ufd, unsigned long offset)
 {
-       return __copy_page(ufd, offset, true);
+       return __copy_page(ufd, offset, true, test_uffdio_wp);
 }
 
 pthread_mutex_t uffd_read_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -308,7 +309,7 @@ static void sighndl(int sig, siginfo_t *siginfo, void *ptr)
  * This also tests UFFD_FEATURE_EVENT_FORK event along with the signal
  * feature. Using monitor thread, verify no userfault events are generated.
  */
-static int faulting_process(int signal_test)
+static int faulting_process(int signal_test, bool wp)
 {
        unsigned long nr;
        unsigned long long count;
@@ -343,7 +344,7 @@ static int faulting_process(int signal_test)
                                        if (steps == 1) {
                                                /* This is a MISSING request */
                                                steps++;
-                                               if (copy_page(uffd, offset))
+                                               if (copy_page(uffd, offset, wp))
                                                        signalled++;
                                        } else {
                                                /* This is a WP request */
@@ -507,6 +508,7 @@ static int userfaultfd_events_test(void)
                          true, test_uffdio_wp, false))
                err("register failure");
 
+       args.apply_wp = test_uffdio_wp;
        if (pthread_create(&uffd_mon, &attr, uffd_poll_thread, &args))
                err("uffd_poll_thread create");
 
@@ -515,7 +517,7 @@ static int userfaultfd_events_test(void)
                err("fork");
 
        if (!pid)
-               exit(faulting_process(0));
+               exit(faulting_process(0, test_uffdio_wp));
 
        waitpid(pid, &err, 0);
        if (err)
@@ -551,11 +553,12 @@ static int userfaultfd_sig_test(void)
                          true, test_uffdio_wp, false))
                err("register failure");
 
-       if (faulting_process(1))
+       if (faulting_process(1, test_uffdio_wp))
                err("faulting process failed");
 
        uffd_test_ops->release_pages(area_dst);
 
+       args.apply_wp = test_uffdio_wp;
        if (pthread_create(&uffd_mon, &attr, uffd_poll_thread, &args))
                err("uffd_poll_thread create");
 
@@ -564,7 +567,7 @@ static int userfaultfd_sig_test(void)
                err("fork");
 
        if (!pid)
-               exit(faulting_process(2));
+               exit(faulting_process(2, test_uffdio_wp));
 
        waitpid(pid, &err, 0);
        if (err)
@@ -628,6 +631,7 @@ static int userfaultfd_minor_test(void)
                       page_size);
        }
 
+       args.apply_wp = test_uffdio_wp;
        if (pthread_create(&uffd_mon, &attr, uffd_poll_thread, &args))
                err("uffd_poll_thread create");