From: Mike Kravetz <mike.kravetz@oracle.com>
To: Andrea Arcangeli <aarcange@redhat.com>,
Andrew Morton <akpm@linux-foundation.org>,
linux-mm@kvack.org
Cc: "Dr. David Alan Gilbert" <dgilbert@redhat.com>,
Maxime Coquelin <maxime.coquelin@redhat.com>,
Mike Rapoport <rppt@linux.vnet.ibm.com>,
Alexey Perevalov <a.perevalov@samsung.com>
Subject: Re: [PATCH 2/6] userfaultfd: selftest: exercise UFFDIO_COPY/ZEROPAGE -EEXIST
Date: Wed, 2 Aug 2017 14:33:47 -0700 [thread overview]
Message-ID: <3d53f034-b129-167e-40f3-1b3534936512@oracle.com> (raw)
In-Reply-To: <20170802165145.22628-3-aarcange@redhat.com>
On 08/02/2017 09:51 AM, Andrea Arcangeli wrote:
> This will retry the UFFDIO_COPY/ZEROPAGE to verify it returns -EEXIST
> at the first invocation and then later every 10 seconds.
>
> In the filebacked MAP_SHARED case this also verifies the -EEXIST
> triggered in the filesystem pagecache insertion, if the offset in the
> file was not a hole.
>
> shmem MAP_SHARED tries to index the newly allocated pagecache in the
> radix tree before checking the pagetable so it doesn't need any
> assistance to exercise that case.
>
> hugetlbfs checks the pmd to be not none before trying to index the
> hugetlbfs page in the radix tree, so it requires to run UFFDIO_COPY
> into an alias mapping (the alternative would be to use MADV_DONTNEED
> to only zap the pagetables, but that doesn't work on hugetlbfs).
>
> Signed-off-by: Andrea Arcangeli <aarcange@redhat.com>
> ---
> tools/testing/selftests/vm/userfaultfd.c | 145 +++++++++++++++++++++++++++++--
> 1 file changed, 138 insertions(+), 7 deletions(-)
>
> diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c
> index 7db6299b2f0d..d07156de55e8 100644
> --- a/tools/testing/selftests/vm/userfaultfd.c
> +++ b/tools/testing/selftests/vm/userfaultfd.c
> @@ -67,6 +67,7 @@
> #include <pthread.h>
> #include <linux/userfaultfd.h>
> #include <setjmp.h>
> +#include <stdbool.h>
>
> #ifdef __NR_userfaultfd
>
> @@ -83,11 +84,17 @@ static int bounces;
> #define TEST_SHMEM 3
> static int test_type;
>
> +/* exercise the test_uffdio_*_eexist every ALARM_INTERVAL_SECS */
> +#define ALARM_INTERVAL_SECS 10
> +static volatile bool test_uffdio_copy_eexist = true;
> +static volatile bool test_uffdio_zeropage_eexist = true;
> +
> +static bool map_shared;
> static int huge_fd;
> static char *huge_fd_off0;
> static unsigned long long *count_verify;
> static int uffd, uffd_flags, finished, *pipefd;
> -static char *area_src, *area_dst;
> +static char *area_src, *area_src_alias, *area_dst, *area_dst_alias;
> static char *zeropage;
> pthread_attr_t attr;
>
> @@ -126,6 +133,9 @@ static void anon_allocate_area(void **alloc_area)
> }
> }
>
> +static void noop_alias_mapping(__u64 *start, size_t len, unsigned long offset)
> +{
> +}
>
> /* HugeTLB memory */
> static int hugetlb_release_pages(char *rel_area)
> @@ -146,17 +156,51 @@ static int hugetlb_release_pages(char *rel_area)
>
> static void hugetlb_allocate_area(void **alloc_area)
> {
> + void *area_alias = NULL;
> + char **alloc_area_alias;
> *alloc_area = mmap(NULL, nr_pages * page_size, PROT_READ | PROT_WRITE,
> - MAP_PRIVATE | MAP_HUGETLB, huge_fd,
> - *alloc_area == area_src ? 0 :
> - nr_pages * page_size);
> + (map_shared ? MAP_SHARED : MAP_PRIVATE) |
> + MAP_HUGETLB,
> + huge_fd, *alloc_area == area_src ? 0 :
> + nr_pages * page_size);
> if (*alloc_area == MAP_FAILED) {
> fprintf(stderr, "mmap of hugetlbfs file failed\n");
> *alloc_area = NULL;
> }
>
> - if (*alloc_area == area_src)
> + if (map_shared) {
> + area_alias = mmap(NULL, nr_pages * page_size, PROT_READ | PROT_WRITE,
> + MAP_SHARED | MAP_HUGETLB,
> + huge_fd, *alloc_area == area_src ? 0 :
> + nr_pages * page_size);
> + if (area_alias == MAP_FAILED) {
> + if (munmap(*alloc_area, nr_pages * page_size) < 0)
> + perror("hugetlb munmap"), exit(1);
> + *alloc_area = NULL;
> + return;
> + }
> + }
> + if (*alloc_area == area_src) {
> huge_fd_off0 = *alloc_area;
> + alloc_area_alias = &area_src_alias;
> + } else {
> + alloc_area_alias = &area_dst_alias;
> + }
> + if (area_alias)
> + *alloc_area_alias = area_alias;
> +}
> +
> +static void hugetlb_alias_mapping(__u64 *start, size_t len, unsigned long offset)
> +{
> + if (!map_shared)
> + return;
> + /*
> + * We can't zap just the pagetable with hugetlbfs because
> + * MADV_DONTEED won't work. So exercise -EEXIST on a alias
> + * mapping where the pagetables are not established initially,
> + * this way we'll exercise the -EEXEC at the fs level.
> + */
> + *start = (unsigned long) area_dst_alias + offset;
> }
>
> /* Shared memory */
> @@ -186,6 +230,7 @@ struct uffd_test_ops {
> unsigned long expected_ioctls;
> void (*allocate_area)(void **alloc_area);
> int (*release_pages)(char *rel_area);
> + void (*alias_mapping)(__u64 *start, size_t len, unsigned long offset);
> };
>
> #define ANON_EXPECTED_IOCTLS ((1 << _UFFDIO_WAKE) | \
> @@ -196,18 +241,21 @@ static struct uffd_test_ops anon_uffd_test_ops = {
> .expected_ioctls = ANON_EXPECTED_IOCTLS,
> .allocate_area = anon_allocate_area,
> .release_pages = anon_release_pages,
> + .alias_mapping = noop_alias_mapping,
> };
>
> static struct uffd_test_ops shmem_uffd_test_ops = {
> .expected_ioctls = ANON_EXPECTED_IOCTLS,
> .allocate_area = shmem_allocate_area,
> .release_pages = shmem_release_pages,
> + .alias_mapping = noop_alias_mapping,
> };
>
> static struct uffd_test_ops hugetlb_uffd_test_ops = {
> .expected_ioctls = UFFD_API_RANGE_IOCTLS_BASIC,
> .allocate_area = hugetlb_allocate_area,
> .release_pages = hugetlb_release_pages,
> + .alias_mapping = hugetlb_alias_mapping,
> };
>
> static struct uffd_test_ops *uffd_test_ops;
> @@ -332,6 +380,23 @@ static void *locking_thread(void *arg)
> return NULL;
> }
>
> +static void retry_copy_page(int ufd, struct uffdio_copy *uffdio_copy,
> + unsigned long offset)
> +{
> + uffd_test_ops->alias_mapping(&uffdio_copy->dst,
> + uffdio_copy->len,
> + offset);
> + if (ioctl(ufd, UFFDIO_COPY, uffdio_copy)) {
> + /* real retval in ufdio_copy.copy */
> + if (uffdio_copy->copy != -EEXIST)
> + fprintf(stderr, "UFFDIO_COPY retry error %Ld\n",
> + uffdio_copy->copy), exit(1);
> + } else {
> + fprintf(stderr, "UFFDIO_COPY retry unexpected %Ld\n",
> + uffdio_copy->copy), exit(1);
> + }
> +}
> +
> static int copy_page(int ufd, unsigned long offset)
> {
> struct uffdio_copy uffdio_copy;
> @@ -352,8 +417,13 @@ static int copy_page(int ufd, unsigned long offset)
> } else if (uffdio_copy.copy != page_size) {
> fprintf(stderr, "UFFDIO_COPY unexpected copy %Ld\n",
> uffdio_copy.copy), exit(1);
> - } else
> + } else {
> + if (test_uffdio_copy_eexist) {
> + test_uffdio_copy_eexist = false;
> + retry_copy_page(ufd, &uffdio_copy, offset);
> + }
> return 1;
> + }
> return 0;
> }
>
> @@ -692,6 +762,23 @@ static int faulting_process(int signal_test)
> return 0;
> }
>
> +static void retry_uffdio_zeropage(int ufd,
> + struct uffdio_zeropage *uffdio_zeropage,
> + unsigned long offset)
> +{
> + uffd_test_ops->alias_mapping(&uffdio_zeropage->range.start,
> + uffdio_zeropage->range.len,
> + offset);
> + if (ioctl(ufd, UFFDIO_ZEROPAGE, uffdio_zeropage)) {
> + if (uffdio_zeropage->zeropage != -EEXIST)
> + fprintf(stderr, "UFFDIO_ZEROPAGE retry error %Ld\n",
> + uffdio_zeropage->zeropage), exit(1);
> + } else {
> + fprintf(stderr, "UFFDIO_ZEROPAGE retry unexpected %Ld\n",
> + uffdio_zeropage->zeropage), exit(1);
> + }
> +}
> +
> static int uffdio_zeropage(int ufd, unsigned long offset)
> {
> struct uffdio_zeropage uffdio_zeropage;
> @@ -727,6 +814,11 @@ static int uffdio_zeropage(int ufd, unsigned long offset)
> fprintf(stderr, "UFFDIO_ZEROPAGE unexpected %Ld\n",
> uffdio_zeropage.zeropage), exit(1);
> } else
> + if (test_uffdio_zeropage_eexist) {
> + test_uffdio_zeropage_eexist = false;
> + retry_uffdio_zeropage(ufd, &uffdio_zeropage,
> + offset);
> + }
> return 1;
I think you want to add {} around those indented lines in the else
clause above. Caught by the compiler, not me.
--
Mike Kravetz
> } else {
> fprintf(stderr,
> @@ -999,6 +1091,15 @@ static int userfaultfd_stress(void)
> return 1;
> }
>
> + if (area_dst_alias) {
> + uffdio_register.range.start = (unsigned long)
> + area_dst_alias;
> + if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register)) {
> + fprintf(stderr, "register failure alias\n");
> + return 1;
> + }
> + }
> +
> /*
> * The madvise done previously isn't enough: some
> * uffd_thread could have read userfaults (one of
> @@ -1032,9 +1133,17 @@ static int userfaultfd_stress(void)
>
> /* unregister */
> if (ioctl(uffd, UFFDIO_UNREGISTER, &uffdio_register.range)) {
> - fprintf(stderr, "register failure\n");
> + fprintf(stderr, "unregister failure\n");
> return 1;
> }
> + if (area_dst_alias) {
> + uffdio_register.range.start = (unsigned long) area_dst;
> + if (ioctl(uffd, UFFDIO_UNREGISTER,
> + &uffdio_register.range)) {
> + fprintf(stderr, "unregister failure alias\n");
> + return 1;
> + }
> + }
>
> /* verification */
> if (bounces & BOUNCE_VERIFY) {
> @@ -1056,6 +1165,10 @@ static int userfaultfd_stress(void)
> area_src = area_dst;
> area_dst = tmp_area;
>
> + tmp_area = area_src_alias;
> + area_src_alias = area_dst_alias;
> + area_dst_alias = tmp_area;
> +
> printf("userfaults:");
> for (cpu = 0; cpu < nr_cpus; cpu++)
> printf(" %lu", userfaults[cpu]);
> @@ -1102,7 +1215,12 @@ static void set_test_type(const char *type)
> } else if (!strcmp(type, "hugetlb")) {
> test_type = TEST_HUGETLB;
> uffd_test_ops = &hugetlb_uffd_test_ops;
> + } else if (!strcmp(type, "hugetlb_shared")) {
> + map_shared = true;
> + test_type = TEST_HUGETLB;
> + uffd_test_ops = &hugetlb_uffd_test_ops;
> } else if (!strcmp(type, "shmem")) {
> + map_shared = true;
> test_type = TEST_SHMEM;
> uffd_test_ops = &shmem_uffd_test_ops;
> } else {
> @@ -1122,12 +1240,25 @@ static void set_test_type(const char *type)
> fprintf(stderr, "Impossible to run this test\n"), exit(2);
> }
>
> +static void sigalrm(int sig)
> +{
> + if (sig != SIGALRM)
> + abort();
> + test_uffdio_copy_eexist = true;
> + test_uffdio_zeropage_eexist = true;
> + alarm(ALARM_INTERVAL_SECS);
> +}
> +
> int main(int argc, char **argv)
> {
> if (argc < 4)
> fprintf(stderr, "Usage: <test type> <MiB> <bounces> [hugetlbfs_file]\n"),
> exit(1);
>
> + if (signal(SIGALRM, sigalrm) == SIG_ERR)
> + fprintf(stderr, "failed to arm SIGALRM"), exit(1);
> + alarm(ALARM_INTERVAL_SECS);
> +
> set_test_type(argv[1]);
>
> nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
>
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
next prev parent reply other threads:[~2017-08-02 21:33 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-08-02 16:51 [PATCH 0/6] userfaultfd updates for v4.13-rc3 Andrea Arcangeli
2017-08-02 16:51 ` [PATCH 1/6] userfaultfd: hugetlbfs: remove superfluous page unlock in VM_SHARED case Andrea Arcangeli
2017-08-02 17:12 ` Mike Kravetz
2017-08-02 16:51 ` [PATCH 2/6] userfaultfd: selftest: exercise UFFDIO_COPY/ZEROPAGE -EEXIST Andrea Arcangeli
2017-08-02 21:33 ` Mike Kravetz [this message]
2017-08-02 16:51 ` [PATCH 3/6] userfaultfd: selftest: explicit failure if the SIGBUS test failed Andrea Arcangeli
2017-08-02 16:51 ` [PATCH 4/6] userfaultfd: call userfaultfd_unmap_prep only if __split_vma succeeds Andrea Arcangeli
2017-08-02 16:51 ` [PATCH 5/6] userfaultfd: provide pid in userfault msg Andrea Arcangeli
2017-08-02 16:51 ` [PATCH 6/6] userfaultfd: provide pid in userfault msg - add feat union Andrea Arcangeli
2017-08-02 21:29 ` [PATCH 0/6] userfaultfd updates for v4.13-rc3 Andrew Morton
2017-08-02 22:27 ` Andrea Arcangeli
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=3d53f034-b129-167e-40f3-1b3534936512@oracle.com \
--to=mike.kravetz@oracle.com \
--cc=a.perevalov@samsung.com \
--cc=aarcange@redhat.com \
--cc=akpm@linux-foundation.org \
--cc=dgilbert@redhat.com \
--cc=linux-mm@kvack.org \
--cc=maxime.coquelin@redhat.com \
--cc=rppt@linux.vnet.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox