From patchwork Thu Mar 30 16:08:24 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Xu X-Patchwork-Id: 13194505 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 45DF0C761A6 for ; Thu, 30 Mar 2023 16:08:34 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id D599E900006; Thu, 30 Mar 2023 12:08:33 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id CE16E6B009D; Thu, 30 Mar 2023 12:08:33 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id B5C1C900006; Thu, 30 Mar 2023 12:08:33 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0013.hostedemail.com [216.40.44.13]) by kanga.kvack.org (Postfix) with ESMTP id A3A916B009C for ; Thu, 30 Mar 2023 12:08:33 -0400 (EDT) Received: from smtpin14.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay10.hostedemail.com (Postfix) with ESMTP id 1019EC0DFF for ; Thu, 30 Mar 2023 16:08:33 +0000 (UTC) X-FDA: 80626047306.14.B2B11A8 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by imf18.hostedemail.com (Postfix) with ESMTP id 689811C0005 for ; Thu, 30 Mar 2023 16:08:30 +0000 (UTC) Authentication-Results: imf18.hostedemail.com; dkim=pass header.d=redhat.com header.s=mimecast20190719 header.b=TnBZOkb5; spf=pass (imf18.hostedemail.com: domain of peterx@redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=peterx@redhat.com; dmarc=pass (policy=none) header.from=redhat.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1680192510; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=FYl/6yS5UtVMnAaCmSItplLGUyy4Ed+8ZQVGZ0RDCPU=; b=lEdiO5O5nrVufYmCnIb+VjxUnYxYXzvW0+GrB0xEbY+kaJzl9ssU5dC8Tqtqw6mlnYlrjG MkQHqWAPQYYOPfCuLBdPZnXFxjRypbvx+qO+qAevI8xNKa54r+JeSdcpUTtoHlYb9UJgbX xmDIY7X5aDU0KAJbKz+BAApa/CCV4Z0= ARC-Authentication-Results: i=1; imf18.hostedemail.com; dkim=pass header.d=redhat.com header.s=mimecast20190719 header.b=TnBZOkb5; spf=pass (imf18.hostedemail.com: domain of peterx@redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=peterx@redhat.com; dmarc=pass (policy=none) header.from=redhat.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1680192510; a=rsa-sha256; cv=none; b=iJos07Shk9q6O1/DcAv5Q5lRus8pcryOAj6kSOL3IElvGsSg//+Wosdd5Ie4GK/GZz8Ouc AgLtaR2bLTTC0sKRsH9/VWyU+lqkmy1LwO0+dzgbDH4tpWXNVUOPY25dNu/z7mIFGs3XdT TOFIbEBns7AyW5utRn+PpoVdJ21tvB8= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1680192509; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=FYl/6yS5UtVMnAaCmSItplLGUyy4Ed+8ZQVGZ0RDCPU=; b=TnBZOkb5kdgSSvxqdAX1HE4kVJy4ydIzeBnDngq61rhX1B6NhabKR/FZxfCWFu2CNPvm4F wSgGC7eQJJxHF5WG3iRTfH8cXQTmNHl8ZMp1uyhYkGtYDK949xVADiEi12wsC9UEziX4kb lXOtAGQF703yB+gbKY5va+YDuSuOOiE= Received: from mail-qt1-f199.google.com (mail-qt1-f199.google.com [209.85.160.199]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-448-OvBW3b_WOiypMOQcb0hajA-1; Thu, 30 Mar 2023 12:08:28 -0400 X-MC-Unique: OvBW3b_WOiypMOQcb0hajA-1 Received: by mail-qt1-f199.google.com with SMTP id a11-20020ac85b8b000000b003e3979be6abso12643637qta.12 for ; Thu, 30 Mar 2023 09:08:28 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680192508; x=1682784508; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=FYl/6yS5UtVMnAaCmSItplLGUyy4Ed+8ZQVGZ0RDCPU=; b=5+eX1qRV2gWBQjp9+j3X/qLm+ASgct+sDFCwbp/B26HrQQ8zDrXioXFXXd2QUZL6yF nHNTzyyDqriVBEEYPrZeVlPNZ83BqlklbarP8CxNTVJpGK+JGW6P4BXjfXbqAxaoHOQA bCzrCLQHIMQZ3jUB1zz/VP1sXVHGc4bmjMyU65vTbMbU5BwDQna3s4Bn3KIX7sdEhQuU 4Fj1dwdKR31IRvbGiU1eQjSuhByuIg+4lTuiywRUMcb1YWkM4MydAQ1ekY0j6NrBZpmc ulneNQep6zOh3K2BZUU6tXy7+8bja2BTOa/GTMRQ9xlDMb/aYqyeGZsELsuXesvPyaG8 Swlg== X-Gm-Message-State: AAQBX9e+z8NpeQGp+Gx4hxp+T5hWRHN1N5aZwv3lHnuV1ytJEkQPPaK+ i1u/UMCHYERVHd5LNipe8exQa62G4EQ4kcYRsABoY8NGjd3hHtWW1FS4po1J7kqcjLsLfjlT2jo bbXapYSNgdMM= X-Received: by 2002:a05:6214:300f:b0:5da:b965:1efd with SMTP id ke15-20020a056214300f00b005dab9651efdmr36932456qvb.2.1680192507596; Thu, 30 Mar 2023 09:08:27 -0700 (PDT) X-Google-Smtp-Source: AKy350bzvSc/AqAbP4HYGGuB2Ff0cVAuMuN0w5MB74cxWKB4kqee51E4nrpLgVuoA/lFvXDiP0RqlQ== X-Received: by 2002:a05:6214:300f:b0:5da:b965:1efd with SMTP id ke15-20020a056214300f00b005dab9651efdmr36932407qvb.2.1680192507098; Thu, 30 Mar 2023 09:08:27 -0700 (PDT) Received: from x1n.redhat.com (bras-base-aurron9127w-grc-40-70-52-229-124.dsl.bell.ca. [70.52.229.124]) by smtp.gmail.com with ESMTPSA id r6-20020a0cf806000000b005dd8b93457asm5582943qvn.18.2023.03.30.09.08.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 30 Mar 2023 09:08:26 -0700 (PDT) From: Peter Xu To: linux-kernel@vger.kernel.org, linux-mm@kvack.org Cc: Mike Kravetz , Mike Rapoport , Andrea Arcangeli , peterx@redhat.com, Leonardo Bras Soares Passos , Andrew Morton , David Hildenbrand , Axel Rasmussen , Nadav Amit , Zach O'Keefe Subject: [PATCH 23/29] selftests/mm: Move uffd minor test to unit test Date: Thu, 30 Mar 2023 12:08:24 -0400 Message-Id: <20230330160824.3107569-1-peterx@redhat.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230330155707.3106228-1-peterx@redhat.com> References: <20230330155707.3106228-1-peterx@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Rspamd-Queue-Id: 689811C0005 X-Stat-Signature: eskbetim5pxfc7cxmoxjaoi9sgx8aar5 X-Rspam-User: X-Rspamd-Server: rspam08 X-HE-Tag: 1680192510-56301 X-HE-Meta: U2FsdGVkX18GPSof/+XHCRerk1IxI6kEcnDVPwWreDsFdyOs3eASpdCjeIzDhHWW78x5Koz1Mbd7/w/REFQWYxIfRSC6yAs3U0p1QSiEcU6nr/J/6tbROIrK/8fjLtLIUvsRmE4+YBmH+hEz/4qLKIThDuEimU9i7j4zDA+wF9KFruFL5pdhY1LLaU6M/AMNkzemllM6IpyQbRsw0/sa3dlwkWVcZJtfjpXbFofkOdQCt7wKHCsoJ1rL/sB8zQykLg8hkWX/x8Z9I7d0kftWyi1vWmTXaibAP5BRkP/Wlb4TlTxKG7DXA8s8oYxfoZdefvg1F8L8KnuOHYoJK7JNGpbp0Tbkh7z0kIAXYEJMf9CEMbHzJqgUC3s1WS4jkLmpdQkAqPVZIqibgtTv9yi/qRNfHOl8x26AaZPcgMlRLlI6awg0+ULruoanTtQYYK+O8pawT/a8z5dh7sis4E3ybskrWlzVXo20v3LkIiGs5r5udIL2I3ofE+OmMg484/R9+rcCvCdyEaXgXyXXwbH1t7fDLQGshix5fdvM1o6bgvJYeOqM5nt673FUactDrMIatElkYC5noOXIbIBiTHL03nGjGEGxV+nmFhWN15+Du2u5mYaL4ZH3bNp3SvHkNxf1YvTlReUSLusP/0PxqoX8jxkaTFGtMcGkyrBGiepuRoxI5DiHgW2Ui6fRY9E+4dzJ6m9ZzJLiR0d2+gZCY10P30eRRAWfGadYCDJBVHae+yOvNsSvG+5Y8j4nCA3cdnKvDKsp5uUSCf2ga8VTCFXy2F20igijEAN7sy+mSDKOQGIaQpEuoj9XpymHSJwVK9aJEjLrAPMFcbCR6PrUtTLl9v2/Hg1y7nKe1ZHJrWf83hKXKH/m1N1w/CUuTlJKwjoD4y/4TMWYMtVBXJEDE2fI9129ONGFa/dY7egmKWliaPVqBfFWcsKYCi2a1ApMo1HjORAcW7HaVYsHYlYLWzx 8ZY+jlfg fN1raz18RxxcKpx3S6LC+MzyLCBvTZ3OoEJAOm4rvDKws8xlwwjX2EkZy8RNl2D50TKSJfuRPTqQcp/bfvcEppv4rtkgh7ruh/8fBkslFz85Qw70j1i+4IS0MK14wwLt/MhMpFqumVXlmgU7b2dDXa6XbrYfdDiPoXJFIPtZpLZxF95ZxuZmEZMF7AdvsJg4UkfnMVu0Gqz9Ov4zJk5JYGTKEjy0VKs7OM9/HWUOb81KDcbLXPcwn6jjzcAWbyc321/H2o0XsbjGFDAG2K3bbWCK331TBSvX6Ptol5GmvUeryENdho3Q4ugo/6C8ZGFtvupUeGwZcqjRFEuEFid2+zVAk9YRLSMK+9Sge7j0BSgb8Sjortk//637pWVby+yzxqMu1B2caXjqIuRCHeTMg1gak79PByy3gtzkiN8j5HWQGvT87cabdH5/eenvOPQBNS4E7Ad3nlQmETAPkRrRYDytlrlK9kiLe7Cueh+eOIIkkAaRlo11si22t3A== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: This moves the minor test to the new unit test. Rewrite the content check with char* opeartions to avoid fiddling with my_bcmp(). Drop global vars test_uffdio_minor and test_collapse, just assume test them always in common code for now. OTOH make this single test into five tests: - minor test on [shmem, hugetlb] with wp=false - minor test on [shmem, hugetlb] with wp=true - minor test + collapse on shmem only One thing to mention that we used to test COLLAPSE+WP but that doesn't sound right at all. It's possible it's silently broken but unnoticed because COLLAPSE is not part of the default test suite. Make the MADV_COLLAPSE test fail-able (by skip it when failing), because it's not guaranteed to success anyway. Drop a bunch of useless code after the move, because the unit test always use aligned num of pages and has nothing to do with n_cpus. Cc: Zach O'Keefe Signed-off-by: Peter Xu --- tools/testing/selftests/mm/uffd-common.c | 25 ++-- tools/testing/selftests/mm/uffd-common.h | 4 +- tools/testing/selftests/mm/uffd-stress.c | 131 +------------------ tools/testing/selftests/mm/uffd-unit-tests.c | 120 +++++++++++++++++ 4 files changed, 135 insertions(+), 145 deletions(-) diff --git a/tools/testing/selftests/mm/uffd-common.c b/tools/testing/selftests/mm/uffd-common.c index ae6b61144b53..95ad619d0df4 100644 --- a/tools/testing/selftests/mm/uffd-common.c +++ b/tools/testing/selftests/mm/uffd-common.c @@ -13,8 +13,8 @@ volatile bool test_uffdio_copy_eexist = true; unsigned long nr_cpus, nr_pages, nr_pages_per_cpu, page_size; char *area_src, *area_src_alias, *area_dst, *area_dst_alias, *area_remap; int uffd = -1, uffd_flags, finished, *pipefd, test_type; -bool map_shared, test_collapse, test_dev_userfaultfd; -bool test_uffdio_wp = true, test_uffdio_minor = false; +bool map_shared, test_dev_userfaultfd; +bool test_uffdio_wp = true; unsigned long long *count_verify; uffd_test_ops_t *uffd_test_ops; @@ -126,28 +126,27 @@ static int shmem_allocate_area(void **alloc_area, bool is_src) char *p = NULL, *p_alias = NULL; int mem_fd = uffd_mem_fd_create(bytes * 2, false); - if (test_collapse) { - p = BASE_PMD_ADDR; - if (!is_src) - /* src map + alias + interleaved hpages */ - p += 2 * (bytes + hpage_size); - p_alias = p; - p_alias += bytes; - p_alias += hpage_size; /* Prevent src/dst VMA merge */ - } + /* TODO: clean this up. Use a static addr is ugly */ + p = BASE_PMD_ADDR; + if (!is_src) + /* src map + alias + interleaved hpages */ + p += 2 * (bytes + hpage_size); + p_alias = p; + p_alias += bytes; + p_alias += hpage_size; /* Prevent src/dst VMA merge */ *alloc_area = mmap(p, bytes, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, offset); if (*alloc_area == MAP_FAILED) err("mmap of memfd failed"); - if (test_collapse && *alloc_area != p) + if (*alloc_area != p) err("mmap of memfd failed at %p", p); area_alias = mmap(p_alias, bytes, PROT_READ | PROT_WRITE, MAP_SHARED, mem_fd, offset); if (area_alias == MAP_FAILED) err("mmap of memfd alias failed"); - if (test_collapse && area_alias != p_alias) + if (area_alias != p_alias) err("mmap of anonymous memory failed at %p", p_alias); if (is_src) diff --git a/tools/testing/selftests/mm/uffd-common.h b/tools/testing/selftests/mm/uffd-common.h index 51ec75f6d0c1..16d32ddf8412 100644 --- a/tools/testing/selftests/mm/uffd-common.h +++ b/tools/testing/selftests/mm/uffd-common.h @@ -90,8 +90,8 @@ typedef struct uffd_test_ops uffd_test_ops_t; extern unsigned long nr_cpus, nr_pages, nr_pages_per_cpu, page_size; extern char *area_src, *area_src_alias, *area_dst, *area_dst_alias, *area_remap; extern int uffd, uffd_flags, finished, *pipefd, test_type; -extern bool map_shared, test_collapse, test_dev_userfaultfd; -extern bool test_uffdio_wp, test_uffdio_minor; +extern bool map_shared, test_dev_userfaultfd; +extern bool test_uffdio_wp; extern unsigned long long *count_verify; extern volatile bool test_uffdio_copy_eexist; diff --git a/tools/testing/selftests/mm/uffd-stress.c b/tools/testing/selftests/mm/uffd-stress.c index 50738a993afc..49fa61e5c54a 100644 --- a/tools/testing/selftests/mm/uffd-stress.c +++ b/tools/testing/selftests/mm/uffd-stress.c @@ -52,8 +52,6 @@ pthread_attr_t attr; #define swap(a, b) \ do { typeof(a) __tmp = (a); (a) = (b); (b) = __tmp; } while (0) -#define factor_of_2(x) ((x) ^ ((x) & ((x) - 1))) - const char *examples = "# Run anonymous memory test on 100MiB region with 99999 bounces:\n" "./userfaultfd anon 100 99999\n\n" @@ -79,8 +77,6 @@ static void usage(void) "Supported mods:\n"); fprintf(stderr, "\tsyscall - Use userfaultfd(2) (default)\n"); fprintf(stderr, "\tdev - Use /dev/userfaultfd instead of userfaultfd(2)\n"); - fprintf(stderr, "\tcollapse - Test MADV_COLLAPSE of UFFDIO_REGISTER_MODE_MINOR\n" - "memory\n"); fprintf(stderr, "\nExample test mod usage:\n"); fprintf(stderr, "# Run anonymous memory test with /dev/userfaultfd:\n"); fprintf(stderr, "./userfaultfd anon:dev 100 99999\n\n"); @@ -585,92 +581,6 @@ static int userfaultfd_sig_test(void) return userfaults != 0; } -void check_memory_contents(char *p) -{ - unsigned long i; - uint8_t expected_byte; - void *expected_page; - - if (posix_memalign(&expected_page, page_size, page_size)) - err("out of memory"); - - for (i = 0; i < nr_pages; ++i) { - expected_byte = ~((uint8_t)(i % ((uint8_t)-1))); - memset(expected_page, expected_byte, page_size); - if (my_bcmp(expected_page, p + (i * page_size), page_size)) - err("unexpected page contents after minor fault"); - } - - free(expected_page); -} - -static int userfaultfd_minor_test(void) -{ - unsigned long p; - pthread_t uffd_mon; - char c; - struct uffd_stats stats = { 0 }; - - if (!test_uffdio_minor) - return 0; - - printf("testing minor faults: "); - fflush(stdout); - - uffd_test_ctx_init(uffd_minor_feature()); - - if (uffd_register(uffd, area_dst_alias, nr_pages * page_size, - false, test_uffdio_wp, true)) - err("register failure"); - - /* - * After registering with UFFD, populate the non-UFFD-registered side of - * the shared mapping. This should *not* trigger any UFFD minor faults. - */ - for (p = 0; p < nr_pages; ++p) { - memset(area_dst + (p * page_size), p % ((uint8_t)-1), - page_size); - } - - stats.apply_wp = test_uffdio_wp; - if (pthread_create(&uffd_mon, &attr, uffd_poll_thread, &stats)) - err("uffd_poll_thread create"); - - /* - * Read each of the pages back using the UFFD-registered mapping. We - * expect that the first time we touch a page, it will result in a minor - * fault. uffd_poll_thread will resolve the fault by bit-flipping the - * page's contents, and then issuing a CONTINUE ioctl. - */ - check_memory_contents(area_dst_alias); - - if (write(pipefd[1], &c, sizeof(c)) != sizeof(c)) - err("pipe write"); - if (pthread_join(uffd_mon, NULL)) - return 1; - - uffd_stats_report(&stats, 1); - - if (test_collapse) { - printf("testing collapse of uffd memory into PMD-mapped THPs:"); - if (madvise(area_dst_alias, nr_pages * page_size, - MADV_COLLAPSE)) - err("madvise(MADV_COLLAPSE)"); - - uffd_test_ops->check_pmd_mapping(area_dst, - nr_pages * page_size / - read_pmd_pagesize()); - /* - * This won't cause uffd-fault - it purely just makes sure there - * was no corruption. - */ - check_memory_contents(area_dst_alias); - printf(" done.\n"); - } - - return stats.missing_faults != 0 || stats.minor_faults != nr_pages; -} - static int userfaultfd_stress(void) { void *area; @@ -783,7 +693,7 @@ static int userfaultfd_stress(void) } return userfaultfd_zeropage_test() || userfaultfd_sig_test() - || userfaultfd_events_test() || userfaultfd_minor_test(); + || userfaultfd_events_test(); } static void set_test_type(const char *type) @@ -798,13 +708,10 @@ static void set_test_type(const char *type) map_shared = true; test_type = TEST_HUGETLB; uffd_test_ops = &hugetlb_uffd_test_ops; - /* Minor faults require shared hugetlb; only enable here. */ - test_uffdio_minor = true; } else if (!strcmp(type, "shmem")) { map_shared = true; test_type = TEST_SHMEM; uffd_test_ops = &shmem_uffd_test_ops; - test_uffdio_minor = true; } } @@ -822,8 +729,6 @@ static void parse_test_type_arg(const char *raw_type) test_dev_userfaultfd = true; else if (!strcmp(token, "syscall")) test_dev_userfaultfd = false; - else if (!strcmp(token, "collapse")) - test_collapse = true; else err("unrecognized test mod '%s'", token); } @@ -831,9 +736,6 @@ static void parse_test_type_arg(const char *raw_type) if (!test_type) err("failed to parse test type argument: '%s'", raw_type); - if (test_collapse && test_type != TEST_SHMEM) - err("Unsupported test: %s", raw_type); - if (test_type == TEST_HUGETLB) page_size = default_huge_page_size(); else @@ -855,8 +757,6 @@ static void parse_test_type_arg(const char *raw_type) test_uffdio_wp = test_uffdio_wp && (features & UFFD_FEATURE_PAGEFAULT_FLAG_WP); - test_uffdio_minor = test_uffdio_minor && - (features & uffd_minor_feature()); close(uffd); uffd = -1; @@ -873,7 +773,6 @@ static void sigalrm(int sig) int main(int argc, char **argv) { size_t bytes; - size_t hpage_size = read_pmd_pagesize(); if (argc < 4) usage(); @@ -885,36 +784,8 @@ int main(int argc, char **argv) parse_test_type_arg(argv[1]); bytes = atol(argv[2]) * 1024 * 1024; - if (test_collapse && bytes & (hpage_size - 1)) - err("MiB must be multiple of %lu if :collapse mod set", - hpage_size >> 20); - nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); - if (test_collapse) { - /* nr_cpus must divide (bytes / page_size), otherwise, - * area allocations of (nr_pages * paze_size) won't be a - * multiple of hpage_size, even if bytes is a multiple of - * hpage_size. - * - * This means that nr_cpus must divide (N * (2 << (H-P)) - * where: - * bytes = hpage_size * N - * hpage_size = 2 << H - * page_size = 2 << P - * - * And we want to chose nr_cpus to be the largest value - * satisfying this constraint, not larger than the number - * of online CPUs. Unfortunately, prime factorization of - * N and nr_cpus may be arbitrary, so have to search for it. - * Instead, just use the highest power of 2 dividing both - * nr_cpus and (bytes / page_size). - */ - int x = factor_of_2(nr_cpus); - int y = factor_of_2(bytes / page_size); - - nr_cpus = x < y ? x : y; - } nr_pages_per_cpu = bytes / page_size / nr_cpus; if (!nr_pages_per_cpu) { _err("invalid MiB"); diff --git a/tools/testing/selftests/mm/uffd-unit-tests.c b/tools/testing/selftests/mm/uffd-unit-tests.c index bcd67bd4ec90..ecb8ba658736 100644 --- a/tools/testing/selftests/mm/uffd-unit-tests.c +++ b/tools/testing/selftests/mm/uffd-unit-tests.c @@ -332,6 +332,103 @@ static void uffd_pagemap_test(void) uffd_test_pass(); } +static void check_memory_contents(char *p) +{ + unsigned long i, j; + uint8_t expected_byte; + + for (i = 0; i < nr_pages; ++i) { + expected_byte = ~((uint8_t)(i % ((uint8_t)-1))); + for (j = 0; j < page_size; j++) { + uint8_t v = *(uint8_t *)(p + (i * page_size) + j); + if (v != expected_byte) + err("unexpected page contents"); + } + } +} + +static void uffd_minor_test_common(bool test_collapse, bool test_wp) +{ + unsigned long p; + pthread_t uffd_mon; + char c; + struct uffd_stats stats = { 0 }; + + /* + * NOTE: MADV_COLLAPSE is not yet compatible with WP, so testing + * both do not make much sense. + */ + assert(!(test_collapse && test_wp)); + + if (uffd_register(uffd, area_dst_alias, nr_pages * page_size, + /* NOTE! MADV_COLLAPSE may not work with uffd-wp */ + false, test_wp, true)) + err("register failure"); + + /* + * After registering with UFFD, populate the non-UFFD-registered side of + * the shared mapping. This should *not* trigger any UFFD minor faults. + */ + for (p = 0; p < nr_pages; ++p) + memset(area_dst + (p * page_size), p % ((uint8_t)-1), + page_size); + + stats.apply_wp = test_wp; + if (pthread_create(&uffd_mon, NULL, uffd_poll_thread, &stats)) + err("uffd_poll_thread create"); + + /* + * Read each of the pages back using the UFFD-registered mapping. We + * expect that the first time we touch a page, it will result in a minor + * fault. uffd_poll_thread will resolve the fault by bit-flipping the + * page's contents, and then issuing a CONTINUE ioctl. + */ + check_memory_contents(area_dst_alias); + + if (write(pipefd[1], &c, sizeof(c)) != sizeof(c)) + err("pipe write"); + if (pthread_join(uffd_mon, NULL)) + err("join() failed"); + + if (test_collapse) { + if (madvise(area_dst_alias, nr_pages * page_size, + MADV_COLLAPSE)) { + /* It's fine to fail for this one... */ + uffd_test_skip("MADV_COLLAPSE failed"); + return; + } + + uffd_test_ops->check_pmd_mapping(area_dst, + nr_pages * page_size / + read_pmd_pagesize()); + /* + * This won't cause uffd-fault - it purely just makes sure there + * was no corruption. + */ + check_memory_contents(area_dst_alias); + } + + if (stats.missing_faults != 0 || stats.minor_faults != nr_pages) + uffd_test_fail("stats check error"); + else + uffd_test_pass(); +} + +void uffd_minor_test(void) +{ + uffd_minor_test_common(false, false); +} + +void uffd_minor_wp_test(void) +{ + uffd_minor_test_common(false, true); +} + +void uffd_minor_collapse_test(void) +{ + uffd_minor_test_common(true, false); +} + uffd_test_case_t uffd_tests[] = { { .name = "pagemap", @@ -346,6 +443,29 @@ uffd_test_case_t uffd_tests[] = { .uffd_feature_required = UFFD_FEATURE_PAGEFAULT_FLAG_WP | UFFD_FEATURE_WP_UNPOPULATED, }, + { + .name = "minor", + .uffd_fn = uffd_minor_test, + .mem_targets = MEM_SHMEM | MEM_HUGETLB, + .uffd_feature_required = + UFFD_FEATURE_MINOR_HUGETLBFS | UFFD_FEATURE_MINOR_SHMEM, + }, + { + .name = "minor-wp", + .uffd_fn = uffd_minor_wp_test, + .mem_targets = MEM_SHMEM | MEM_HUGETLB, + .uffd_feature_required = + UFFD_FEATURE_MINOR_HUGETLBFS | UFFD_FEATURE_MINOR_SHMEM | + UFFD_FEATURE_PAGEFAULT_FLAG_WP, + }, + { + .name = "minor-collapse", + .uffd_fn = uffd_minor_collapse_test, + /* MADV_COLLAPSE only works with shmem */ + .mem_targets = MEM_SHMEM, + /* We can't test MADV_COLLAPSE, so try our luck */ + .uffd_feature_required = UFFD_FEATURE_MINOR_SHMEM, + }, }; int main(int argc, char *argv[])