From patchwork Wed Apr 12 16:43:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Peter Xu X-Patchwork-Id: 13209361 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 86C48C7619A for ; Wed, 12 Apr 2023 16:44:14 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 2172090000B; Wed, 12 Apr 2023 12:44:14 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 1C708900003; Wed, 12 Apr 2023 12:44:14 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 0676090000B; Wed, 12 Apr 2023 12:44:14 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0016.hostedemail.com [216.40.44.16]) by kanga.kvack.org (Postfix) with ESMTP id E6ABE900003 for ; Wed, 12 Apr 2023 12:44:13 -0400 (EDT) Received: from smtpin11.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay02.hostedemail.com (Postfix) with ESMTP id 9CC42120165 for ; Wed, 12 Apr 2023 16:44:13 +0000 (UTC) X-FDA: 80673311586.11.D54724A Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by imf17.hostedemail.com (Postfix) with ESMTP id 5E3294000E for ; Wed, 12 Apr 2023 16:44:11 +0000 (UTC) Authentication-Results: imf17.hostedemail.com; dkim=pass header.d=redhat.com header.s=mimecast20190719 header.b=hiuASNIH; spf=pass (imf17.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=1681317851; a=rsa-sha256; cv=none; b=w35CEntMbnucmEJrwz2BVMpeOnWp+IQlX/3WsCjaKGP8JovEH4VI6EIg5TT00oPIMkyL9B fG08fHZec+9gs7PRJhYUai96QV+BhHxlQzIRxkReT1r6J1lrhpuyYBT4l58ZQ3D/fha2GP xc7EJVWX+BczYf4ghwKDyGHcqbvbqcs= ARC-Authentication-Results: i=1; imf17.hostedemail.com; dkim=pass header.d=redhat.com header.s=mimecast20190719 header.b=hiuASNIH; spf=pass (imf17.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=1681317851; 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=DGYE1DDdeK4+pcxB+E5dvgvlIGHgCfc4atHqaHYPYpQ=; b=PB6t6J+S7ECS0OxmAzGX/v7j9dEGOfzBfrWaoTBHnob5XLNJVIjZpYMJZM9kwdjOyXzWSE BN0DrShqNe2fD0UV46qt6Q7hc4/iQ1kbgBoHKWIkDYCU3TIkboUobaDx0AVxC6TDCXZUOS WW4WgV6X80U4U2ehWYJ/F8msunUfcDA= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1681317850; 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=DGYE1DDdeK4+pcxB+E5dvgvlIGHgCfc4atHqaHYPYpQ=; b=hiuASNIHfT9zs295GjkQywf2neMTv83SWeaDH8sV/iIItfE/6mCjRilV3oz/xoDY7DNvvN CL3c4IXaYgfg0lfOX1rlioJi3/U83tyG58MK+R50xZH41tDl7u6WpXFHXyWyxEL1S4NvAN mfOzhj3b+etIwVY2ChS7yD+HtbI8wxk= Received: from mail-qk1-f198.google.com (mail-qk1-f198.google.com [209.85.222.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-672-o-R8E_0WPTSPC3u5PBe6vA-1; Wed, 12 Apr 2023 12:44:02 -0400 X-MC-Unique: o-R8E_0WPTSPC3u5PBe6vA-1 Received: by mail-qk1-f198.google.com with SMTP id af79cd13be357-74a904f38f3so86468485a.1 for ; Wed, 12 Apr 2023 09:44:02 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1681317841; x=1683909841; 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=DGYE1DDdeK4+pcxB+E5dvgvlIGHgCfc4atHqaHYPYpQ=; b=I2xbxyP1pSlP0Z70e48tTJ1598LW9Km+XyzAj304oa6jT+Tu06wF5S1bV3jssQEVoE bHulGckpZjqYINRS3cvD7UkvC6IOmMNxI/ezyYxdYdvxyyrw8lN8PG4dlhO49yF69qo/ w0cDlml98tMDOEONALPplUdgkpHrUj3fJrGxzKoqR1CUoLtilblkzB9OxTSBURspfn+q 4VBFDEYEsELepjaPXScW0dpqhe9GhfzfPDWlthZcNTX4RpVhsvKP0rYNd6NfchdDDeFE 4mlgS0XUE9TXiL6VI507hcnTc1umxDqmSalQxXJoQD9KelZQsGAydsn/Z34RgwEKopCx M6LA== X-Gm-Message-State: AAQBX9fIpJxu8OzndliKEGfFSVWqpWXHll8rEPTv3CdyarOUFEngCHV6 gJhz+CsGGwjBdPYrck+ikzXCP+Vhc1SrNv1Y2jjjzZ92r1dFgAojru/Vx2V2B1GjFeg63I8vFCy qEg5ObiKyIilAvDLHD7U= X-Received: by 2002:a05:6214:528e:b0:5a5:e941:f33d with SMTP id kj14-20020a056214528e00b005a5e941f33dmr4706425qvb.3.1681317840862; Wed, 12 Apr 2023 09:44:00 -0700 (PDT) X-Google-Smtp-Source: AKy350ZjRI108S/AEWKqmkwW7425E04im1RHPeYTESzVUXReVKQDc9FypzgLpo/HuPpxAL+w9pWXmQ== X-Received: by 2002:a05:6214:528e:b0:5a5:e941:f33d with SMTP id kj14-20020a056214528e00b005a5e941f33dmr4706400qvb.3.1681317840523; Wed, 12 Apr 2023 09:44:00 -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 o191-20020a3741c8000000b0074abe1e1457sm777268qka.76.2023.04.12.09.43.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 12 Apr 2023 09:43:59 -0700 (PDT) From: Peter Xu To: linux-kernel@vger.kernel.org, linux-mm@kvack.org Cc: David Hildenbrand , Andrew Morton , Leonardo Bras Soares Passos , peterx@redhat.com, Andrea Arcangeli , Nadav Amit , Mike Rapoport , Axel Rasmussen , Mike Kravetz , Zach O'Keefe Subject: [PATCH v2 24/31] selftests/mm: Move uffd minor test to unit test Date: Wed, 12 Apr 2023 12:43:57 -0400 Message-Id: <20230412164357.328779-1-peterx@redhat.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: <20230412163922.327282-1-peterx@redhat.com> References: <20230412163922.327282-1-peterx@redhat.com> MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Rspam-User: X-Rspamd-Queue-Id: 5E3294000E X-Rspamd-Server: rspam01 X-Stat-Signature: d6oed1c1pcy8zdhukezkksegmb71zrat X-HE-Tag: 1681317851-708085 X-HE-Meta: U2FsdGVkX18XgagL9R15+AG7pc23uo2z8Ezm8bfa5scv0kt5EB1yXYAiFZ3mezfW4PgyCgZDO+UllX8yEhR54lTJ5RuSPMvrZQhsPYd48MEIR3yuWVISfnj2qaMh6DUdG2wR1pMfAIagO/3DsHud7PydKWp7mxz0WjwGEEH4T4fedKbkNkfdo5WAaAltqZicGnrRQdB8t/6fnlBGlLGolnQN0fIk7VJZUgR6YD5GEL1tuduTfX58fOyFSPh9UfROqDI2aKLZ9XdOZnMEFr5Jc7RVU3vLr5vudPit8ejJj70mp/qeaDW4XynWZYrYvPwH0lVV3CyW8BkC8aSFuDf+bSTvRjZ4yp0RaWEM8GMEvgdYHOVxJb2W2Wy/gE0LEispCy5q5LeEdVLXKGLYzkNlzPX/mtcolrRf7DU7NeLVmIr9V8iSbcEqUctaJeKNuayV5XuxaGJOd4u4/7s7CP/sNvVHY9liHHde452IyN953kLiPgoF/XyTFHO0g3yYs+Xs5yuOp9Lys9glD41DaIc/1KOPDgiOOHju86kngNeiDuNrqaL2vnj5Of3qeifSOVJm5AyUq2p7Nz2EMM92dpAoeYZ4Cln31WiC8AD9NiuaPxIFtFO/Pr8mN19KxKJmsH+jHmbs6otYYGhsuawdusptKN3G9/+vQq04+G3Oe2bui8C6QM646OZG8WWyk+34MwB9uO6Nu0qHqbxN6yumhWga1mPKrVbVbgAYXiOhddjgJvuRnacAII+ZgTVJeOYwvDHaSAl87tqa5hpn5kLLrKKpY1eSDW6MqLAjyj5fpwdVN+GOHKJcQmDu6rZHmoWPmzwPyJbEZ866/vFlaCvof4gRw/8s/vG2rJOdNUJubfhZGEi7jx9D5/dm6cMgp+biKwKWcNOAoO1iY6j4qtdulvjcH3h8t+vFczgdECSXrqWyXpnu+8FAxLKIu8aO9jgI0qZ/LqhL/pJ/XzYO+GdpY25 Kwdiyx1f Rc4dC6TXmOiWtv1aRsKr1Q3UDQuRN5KOtdokWUbEHA8eeW/7zDP9KJjm06iptau9FQ15sLfC9ilv+XHAqyiWi16OoVgk0rQawVwVNpiE2b/nR9K+6DVL6UDvT0rC8ozu8BeL+iOBx4nvyXLmHi2ItgxCOSOFmLHzmY+4i/S8Yn3W+FE/qXijLdHweRnqHgPxNAoDSWUDlHHs3bGG9SC9UnJbqUWctT/BNttPveXE8wg+gASUvcaALM6ysddkIPJvwIvoSJ/xFKmmB/U/6tAOj5RVhqvkZC92heinmuq+jAFX6/329DvhOtMTGeIZKOy17Wr4h+RxZ6tI9O3+fAy1RVPAOd3QLau74Q3lVvs+UQRxAWs6a17ImwwxfZtNfSPQ0FddHEdL76kMXfKfr1aLTQ+DnlVJamtamfaF5G+/7QXwQfdsIf10JmpIwEHNLXUNXmEP63gnzHZWF7MB/B6QZkxrEBUpw3Cu8UJxD/ZZENc/zHE/vU5Ey6p93tA== 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 bc6c5c38d6dd..12ac84712a38 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; @@ -128,15 +128,14 @@ 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); @@ -144,7 +143,7 @@ static int shmem_allocate_area(void **alloc_area, bool is_src) *alloc_area = NULL; return -errno; } - 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, @@ -154,7 +153,7 @@ static int shmem_allocate_area(void **alloc_area, bool is_src) *alloc_area = NULL; return -errno; } - 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 9479a0649d7f..4bd5915cf5b4 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 61d025d87bf2..f9322bbaf825 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"); @@ -584,92 +580,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_args args = { 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); - } - - args.apply_wp = test_uffdio_wp; - if (pthread_create(&uffd_mon, &attr, uffd_poll_thread, &args)) - 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(&args, 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 args.missing_faults != 0 || args.minor_faults != nr_pages; -} - static int userfaultfd_stress(void) { void *area; @@ -782,7 +692,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) @@ -797,13 +707,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; } } @@ -821,8 +728,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); } @@ -830,9 +735,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 @@ -854,8 +756,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; @@ -872,7 +772,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(); @@ -884,36 +783,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 4690c95a9420..cba04608bdb0 100644 --- a/tools/testing/selftests/mm/uffd-unit-tests.c +++ b/tools/testing/selftests/mm/uffd-unit-tests.c @@ -329,6 +329,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_args args = { 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); + + args.apply_wp = test_wp; + if (pthread_create(&uffd_mon, NULL, uffd_poll_thread, &args)) + 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 (args.missing_faults != 0 || args.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", @@ -343,6 +440,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[])