Commit 04d87731 authored by Peter Xu's avatar Peter Xu Committed by Linus Torvalds

userfaultfd: selftest: generalize read and poll

We do very similar things in read and poll modes, but we're copying the
codes around.  Share the codes properly on reading the message and
handling the page fault to make the code cleaner.  Meanwhile this solves
previous mismatch of behaviors between the two modes on that the old code:

- did not check EAGAIN case in read() mode
- ignored BOUNCE_VERIFY check in read() mode

Link: http://lkml.kernel.org/r/20180930074259.18229-3-peterx@redhat.comSigned-off-by: default avatarPeter Xu <peterx@redhat.com>
Acked-by: default avatarMike Rapoport <rppt@linux.vnet.ibm.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Mike Kravetz <mike.kravetz@oracle.com>
Cc: Jerome Glisse <jglisse@redhat.com>
Cc: Zi Yan <zi.yan@cs.rutgers.edu>
Cc: "Kirill A . Shutemov" <kirill@shutemov.name>
Cc: Shaohua Li <shli@fb.com>
Cc: Andrea Arcangeli <aarcange@redhat.com>
Cc: "Dr . David Alan Gilbert" <dgilbert@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 439de0d7
...@@ -451,6 +451,43 @@ static int copy_page(int ufd, unsigned long offset) ...@@ -451,6 +451,43 @@ static int copy_page(int ufd, unsigned long offset)
return __copy_page(ufd, offset, false); return __copy_page(ufd, offset, false);
} }
static int uffd_read_msg(int ufd, struct uffd_msg *msg)
{
int ret = read(uffd, msg, sizeof(*msg));
if (ret != sizeof(*msg)) {
if (ret < 0) {
if (errno == EAGAIN)
return 1;
else
perror("blocking read error"), exit(1);
} else {
fprintf(stderr, "short read\n"), exit(1);
}
}
return 0;
}
/* Return 1 if page fault handled by us; otherwise 0 */
static int uffd_handle_page_fault(struct uffd_msg *msg)
{
unsigned long offset;
if (msg->event != UFFD_EVENT_PAGEFAULT)
fprintf(stderr, "unexpected msg event %u\n",
msg->event), exit(1);
if (bounces & BOUNCE_VERIFY &&
msg->arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_WRITE)
fprintf(stderr, "unexpected write fault\n"), exit(1);
offset = (char *)(unsigned long)msg->arg.pagefault.address - area_dst;
offset &= ~(page_size-1);
return copy_page(uffd, offset);
}
static void *uffd_poll_thread(void *arg) static void *uffd_poll_thread(void *arg)
{ {
unsigned long cpu = (unsigned long) arg; unsigned long cpu = (unsigned long) arg;
...@@ -458,7 +495,6 @@ static void *uffd_poll_thread(void *arg) ...@@ -458,7 +495,6 @@ static void *uffd_poll_thread(void *arg)
struct uffd_msg msg; struct uffd_msg msg;
struct uffdio_register uffd_reg; struct uffdio_register uffd_reg;
int ret; int ret;
unsigned long offset;
char tmp_chr; char tmp_chr;
unsigned long userfaults = 0; unsigned long userfaults = 0;
...@@ -482,25 +518,15 @@ static void *uffd_poll_thread(void *arg) ...@@ -482,25 +518,15 @@ static void *uffd_poll_thread(void *arg)
if (!(pollfd[0].revents & POLLIN)) if (!(pollfd[0].revents & POLLIN))
fprintf(stderr, "pollfd[0].revents %d\n", fprintf(stderr, "pollfd[0].revents %d\n",
pollfd[0].revents), exit(1); pollfd[0].revents), exit(1);
ret = read(uffd, &msg, sizeof(msg)); if (uffd_read_msg(uffd, &msg))
if (ret < 0) {
if (errno == EAGAIN)
continue; continue;
perror("nonblocking read error"), exit(1);
}
switch (msg.event) { switch (msg.event) {
default: default:
fprintf(stderr, "unexpected msg event %u\n", fprintf(stderr, "unexpected msg event %u\n",
msg.event), exit(1); msg.event), exit(1);
break; break;
case UFFD_EVENT_PAGEFAULT: case UFFD_EVENT_PAGEFAULT:
if (msg.arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_WRITE) userfaults += uffd_handle_page_fault(&msg);
fprintf(stderr, "unexpected write fault\n"), exit(1);
offset = (char *)(unsigned long)msg.arg.pagefault.address -
area_dst;
offset &= ~(page_size-1);
if (copy_page(uffd, offset))
userfaults++;
break; break;
case UFFD_EVENT_FORK: case UFFD_EVENT_FORK:
close(uffd); close(uffd);
...@@ -528,8 +554,6 @@ static void *uffd_read_thread(void *arg) ...@@ -528,8 +554,6 @@ static void *uffd_read_thread(void *arg)
{ {
unsigned long *this_cpu_userfaults; unsigned long *this_cpu_userfaults;
struct uffd_msg msg; struct uffd_msg msg;
unsigned long offset;
int ret;
this_cpu_userfaults = (unsigned long *) arg; this_cpu_userfaults = (unsigned long *) arg;
*this_cpu_userfaults = 0; *this_cpu_userfaults = 0;
...@@ -538,24 +562,9 @@ static void *uffd_read_thread(void *arg) ...@@ -538,24 +562,9 @@ static void *uffd_read_thread(void *arg)
/* from here cancellation is ok */ /* from here cancellation is ok */
for (;;) { for (;;) {
ret = read(uffd, &msg, sizeof(msg)); if (uffd_read_msg(uffd, &msg))
if (ret != sizeof(msg)) { continue;
if (ret < 0) (*this_cpu_userfaults) += uffd_handle_page_fault(&msg);
perror("blocking read error"), exit(1);
else
fprintf(stderr, "short read\n"), exit(1);
}
if (msg.event != UFFD_EVENT_PAGEFAULT)
fprintf(stderr, "unexpected msg event %u\n",
msg.event), exit(1);
if (bounces & BOUNCE_VERIFY &&
msg.arg.pagefault.flags & UFFD_PAGEFAULT_FLAG_WRITE)
fprintf(stderr, "unexpected write fault\n"), exit(1);
offset = (char *)(unsigned long)msg.arg.pagefault.address -
area_dst;
offset &= ~(page_size-1);
if (copy_page(uffd, offset))
(*this_cpu_userfaults)++;
} }
return (void *)NULL; return (void *)NULL;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment