From: Andrew Morton <akpm@linux-foundation.org>
To: mm-commits@vger.kernel.org,sarthak.sharma@arm.com,akpm@linux-foundation.org
Subject: [to-be-updated] selftests-mm-add-a-gup-selftest.patch removed from -mm tree
Date: Fri, 18 Sep 2026 12:43:01 -0700 [thread overview]
Message-ID: <20260918194301.D196E1F000FF@smtp.kernel.org> (raw)
The quilt patch titled
Subject: selftests/mm: add a GUP selftest
has been removed from the -mm tree. Its filename was
selftests-mm-add-a-gup-selftest.patch
This patch was dropped because an updated version will be issued
------------------------------------------------------
From: Sarthak Sharma <sarthak.sharma@arm.com>
Subject: selftests/mm: add a GUP selftest
Date: Fri, 4 Sep 2026 18:06:31 +0530
Add a new GUP selftest which uses kselftest_harness.h. Cover 12 mapping
configurations: THP enabled, THP disabled and HugeTLB, each across
private/shared mappings and with/without FOLL_WRITE. Run 5 test cases for
every variant: get_user_pages, get_user_pages_fast, pin_user_pages,
pin_user_pages_fast and pin_user_pages_longterm.
Choose the number of default hugeTLB pages using a 256 MiB target, with a
minimum of 1 page and derive the mapping size from that number. This
avoids reserving excess memory when the hugeTLB page size is too large and
retains 128 pages for the most common case of 2MiB hugeTLB pages.
Sweep four nr_pages_per_call values for each test: 1, 512, 123 and all
pages. This preserves the coverage previously provided by
run_gup_matrix(): 12 mapping combinations x 5 GUP/PUP operations x 4 batch
sizes. In total the selftest reports 60 TAP cases and issues 240 ioctls.
Do not carry DUMP_USER_PAGES_TEST into the new selftest because its output
is written to the kernel log and the selftest does not verify that output.
Add the new gup binary to the selftests/mm build, run_vmtests.sh and
MAINTAINERS. Update mm/Kconfig to describe the benchmark and selftest
split.
Link: https://lore.kernel.org/20260904123631.198697-7-sarthak.sharma@arm.com
Signed-off-by: Sarthak Sharma <sarthak.sharma@arm.com>
Suggested-by: David Hildenbrand (Arm) <david@kernel.org>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Cc: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Barry Song <baohua@kernel.org>
Cc: Dev Jain <dev.jain@arm.com>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Lance Yang <lance.yang@linux.dev>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Mark Brown <broonie@kernel.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Nico Pache <npache@redhat.com>
Cc: Peter Xu <peterx@redhat.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Vlastimil Babka <vbabka@kernel.org>
Cc: Zi Yan <ziy@nvidia.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---
MAINTAINERS | 1
mm/Kconfig | 21 -
tools/testing/selftests/mm/Makefile | 1
tools/testing/selftests/mm/gup.c | 287 ++++++++++++++++++++
tools/testing/selftests/mm/run_vmtests.sh | 1
5 files changed, 300 insertions(+), 11 deletions(-)
--- a/MAINTAINERS~selftests-mm-add-a-gup-selftest
+++ a/MAINTAINERS
@@ -17187,6 +17187,7 @@ F: mm/gup.c
F: mm/gup_test.c
F: mm/gup_test.h
F: tools/mm/gup_bench.c
+F: tools/testing/selftests/mm/gup.c
F: tools/testing/selftests/mm/gup_longterm.c
MEMORY MANAGEMENT - KSM (Kernel Samepage Merging)
--- a/mm/Kconfig~selftests-mm-add-a-gup-selftest
+++ a/mm/Kconfig
@@ -1287,24 +1287,23 @@ config PERCPU_STATS
be used to help understand percpu memory usage.
config GUP_TEST
- bool "Enable infrastructure for get_user_pages()-related unit tests"
+ bool "Enable infrastructure for get_user_pages()-related unit tests and benchmarks"
depends on DEBUG_FS
help
Provides /sys/kernel/debug/gup_test, which in turn provides a way
- to make ioctl calls that can launch kernel-based unit tests for
- the get_user_pages*() and pin_user_pages*() family of API calls.
+ to make ioctl calls that can launch kernel-based unit tests and
+ benchmarks for the get_user_pages*() and pin_user_pages*() families
+ of API calls.
- These tests include benchmark testing of the _fast variants of
- get_user_pages*() and pin_user_pages*(), as well as smoke tests of
+ These include benchmark testing of the _fast variants of
+ get_user_pages*() and pin_user_pages*(), as well as tests of
the non-_fast variants.
- There is also a sub-test that allows running dump_page() on any
- of up to eight pages (selected by command line args) within the
- range of user-space addresses. These pages are either pinned via
- pin_user_pages*(), or pinned via get_user_pages*(), as specified
- by other command line arguments.
+ There is also a test that allows running dump_page() on any of up
+ to eight pages within the range of user-space addresses. These
+ pages are either acquired via pin_user_pages*() or get_user_pages*().
- See tools/testing/selftests/mm/gup_test.c
+ See tools/testing/selftests/mm/gup.c and tools/mm/gup_bench.c.
comment "GUP_TEST needs to have DEBUG_FS enabled"
depends on !GUP_TEST && !DEBUG_FS
diff --git a/tools/testing/selftests/mm/gup.c a/tools/testing/selftests/mm/gup.c
new file mode 100644
--- /dev/null
+++ a/tools/testing/selftests/mm/gup.c
@@ -0,0 +1,287 @@
+// SPDX-License-Identifier: GPL-2.0
+#define __SANE_USERSPACE_TYPES__ // Use ll64
+#include <fcntl.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <mm/gup_test.h>
+#include "vm_util.h"
+#include "kselftest_harness.h"
+
+#define MB (1UL << 20)
+
+/* Just the flags we need, copied from the kernel internals. */
+#define FOLL_WRITE 0x01 /* check pte is writable */
+
+/* Page counts exercising single, THP-batch, partial, and full-mapping GUP. */
+static const int nr_pages_list[] = { 1, 512, 123, -1 };
+
+#define GUP_TEST_FILE "/sys/kernel/debug/gup_test"
+#define HUGETLB_TARGET_SIZE (256 * MB)
+
+static unsigned long nr_huge_pages, hp_size;
+static bool hugetlb_setup_succeeded;
+
+FIXTURE(gup_test)
+{
+ int gup_fd;
+ char *addr;
+ unsigned long size;
+};
+
+FIXTURE_VARIANT(gup_test)
+{
+ bool thp;
+ bool hugetlb;
+ bool write;
+ bool shared;
+};
+
+FIXTURE_VARIANT_ADD(gup_test, private_write)
+{
+ .thp = false,
+ .hugetlb = false,
+ .write = true,
+ .shared = false,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, private_read)
+{
+ .thp = false,
+ .hugetlb = false,
+ .write = false,
+ .shared = false,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, private_write_thp)
+{
+ .thp = true,
+ .hugetlb = false,
+ .write = true,
+ .shared = false,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, private_read_thp)
+{
+ .thp = true,
+ .hugetlb = false,
+ .write = false,
+ .shared = false,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, private_write_hugetlb)
+{
+ .thp = false,
+ .hugetlb = true,
+ .write = true,
+ .shared = false,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, private_read_hugetlb)
+{
+ .thp = false,
+ .hugetlb = true,
+ .write = false,
+ .shared = false,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, shared_write)
+{
+ .thp = false,
+ .hugetlb = false,
+ .write = true,
+ .shared = true,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, shared_read)
+{
+ .thp = false,
+ .hugetlb = false,
+ .write = false,
+ .shared = true,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, shared_write_thp)
+{
+ .thp = true,
+ .hugetlb = false,
+ .write = true,
+ .shared = true,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, shared_read_thp)
+{
+ .thp = true,
+ .hugetlb = false,
+ .write = false,
+ .shared = true,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, shared_write_hugetlb)
+{
+ .thp = false,
+ .hugetlb = true,
+ .write = true,
+ .shared = true,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, shared_read_hugetlb)
+{
+ .thp = false,
+ .hugetlb = true,
+ .write = false,
+ .shared = true,
+};
+
+FIXTURE_SETUP(gup_test)
+{
+ int mmap_flags = MAP_PRIVATE;
+ int zero_fd;
+ char *p;
+
+ self->size = 128 * MB;
+
+ if (variant->hugetlb) {
+ if (!hp_size)
+ SKIP(return, "HugeTLB not available\n");
+
+ if (!hugetlb_setup_succeeded ||
+ hugetlb_free_default_pages() < nr_huge_pages)
+ SKIP(return, "Not enough huge pages\n");
+
+ self->size = nr_huge_pages * hp_size;
+ mmap_flags |= (MAP_HUGETLB | MAP_ANONYMOUS);
+ }
+
+ if (variant->shared)
+ mmap_flags = (mmap_flags & ~MAP_PRIVATE) | MAP_SHARED;
+
+ /* zero_fd has to be >= 0. Already checked in main() */
+ zero_fd = open("/dev/zero", O_RDWR);
+ ASSERT_GE(zero_fd, 0);
+
+ /* gup_fd has to be >= 0. Already checked in main() */
+ self->gup_fd = open(GUP_TEST_FILE, O_RDWR);
+ ASSERT_GE(self->gup_fd, 0);
+
+ self->addr = mmap(NULL, self->size, PROT_READ | PROT_WRITE,
+ mmap_flags, zero_fd, 0);
+
+ ASSERT_NE(self->addr, MAP_FAILED) {
+ int err = errno;
+
+ close(zero_fd);
+ close(self->gup_fd);
+ TH_LOG("mmap failed: %s", strerror(err));
+ }
+ close(zero_fd);
+
+ if (variant->thp)
+ madvise(self->addr, self->size, MADV_HUGEPAGE);
+ else if (!variant->hugetlb)
+ madvise(self->addr, self->size, MADV_NOHUGEPAGE);
+
+ for (p = self->addr; (unsigned long)p < (unsigned long)self->addr
+ + self->size; p += psize())
+ p[0] = 0;
+}
+
+FIXTURE_TEARDOWN(gup_test)
+{
+ munmap(self->addr, self->size);
+ close(self->gup_fd);
+}
+
+static void run_gup_cmd(struct __test_metadata *_metadata,
+ FIXTURE_DATA(gup_test) *self,
+ const FIXTURE_VARIANT(gup_test) *variant,
+ unsigned long command)
+{
+ int i;
+
+ for (i = 0; i < (int)ARRAY_SIZE(nr_pages_list); i++) {
+ struct gup_test gup = {
+ .addr = (unsigned long)self->addr,
+ .size = self->size,
+ .nr_pages_per_call = nr_pages_list[i] < 0 ?
+ self->size / psize() : nr_pages_list[i],
+ .gup_flags = variant->write ? FOLL_WRITE : 0,
+ };
+
+ TH_LOG("nr_pages_per_call=%u", gup.nr_pages_per_call);
+ ASSERT_EQ(ioctl(self->gup_fd, command, &gup), 0);
+ ASSERT_EQ(gup.size, self->size);
+ }
+}
+
+TEST_F(gup_test, get_user_pages)
+{
+ run_gup_cmd(_metadata, self, variant, GUP_BASIC_TEST);
+}
+
+TEST_F(gup_test, pin_user_pages)
+{
+ run_gup_cmd(_metadata, self, variant, PIN_BASIC_TEST);
+}
+
+TEST_F(gup_test, get_user_pages_fast)
+{
+ run_gup_cmd(_metadata, self, variant, GUP_FAST_BENCHMARK);
+}
+
+TEST_F(gup_test, pin_user_pages_fast)
+{
+ run_gup_cmd(_metadata, self, variant, PIN_FAST_BENCHMARK);
+}
+
+TEST_F(gup_test, pin_user_pages_longterm)
+{
+ run_gup_cmd(_metadata, self, variant, PIN_LONGTERM_BENCHMARK);
+}
+
+int main(int argc, char **argv)
+{
+ char *file = "/dev/zero";
+ int fd;
+
+ fd = open(file, O_RDWR);
+ if (fd < 0) {
+ ksft_print_header();
+ ksft_exit_fail_msg("Unable to open %s: %s\n", file, strerror(errno));
+ }
+ close(fd);
+
+ fd = open(GUP_TEST_FILE, O_RDWR);
+ if (fd == -1) {
+ ksft_print_header();
+ if (errno == EACCES)
+ ksft_exit_skip("Please run this test as root\n");
+ if (errno == ENOENT) {
+ DIR *debugfs = opendir("/sys/kernel/debug");
+
+ if (!debugfs) {
+ ksft_exit_skip("Mount debugfs at /sys/kernel/debug\n");
+ } else {
+ closedir(debugfs);
+ ksft_exit_skip("Check CONFIG_GUP_TEST in kernel config\n");
+ }
+ }
+ ksft_exit_fail_msg("Failed to open %s: %s\n", GUP_TEST_FILE, strerror(errno));
+ }
+ close(fd);
+
+ hp_size = default_huge_page_size();
+ if (hp_size) {
+ nr_huge_pages = HUGETLB_TARGET_SIZE / hp_size;
+ if (!nr_huge_pages)
+ nr_huge_pages = 1;
+
+ hugetlb_setup_succeeded = hugetlb_setup_default(nr_huge_pages);
+ }
+
+ return test_harness_run(argc, argv);
+}
--- a/tools/testing/selftests/mm/Makefile~selftests-mm-add-a-gup-selftest
+++ a/tools/testing/selftests/mm/Makefile
@@ -58,6 +58,7 @@ endif
TEST_GEN_FILES = cow
TEST_GEN_FILES += compaction_test
+TEST_GEN_FILES += gup
TEST_GEN_FILES += gup_longterm
TEST_GEN_FILES += hmm-tests
TEST_GEN_FILES += hugetlb-madvise
--- a/tools/testing/selftests/mm/run_vmtests.sh~selftests-mm-add-a-gup-selftest
+++ a/tools/testing/selftests/mm/run_vmtests.sh
@@ -251,6 +251,7 @@ fi
CATEGORY="mmap" run_test ./map_fixed_noreplace
+CATEGORY="gup_test" run_test ./gup
CATEGORY="gup_test" run_test ./gup_longterm
CATEGORY="userfaultfd" run_test ./uffd-unit-tests
_
Patches currently in -mm which might be from sarthak.sharma@arm.com are
mm-gup_test-report-actual-pinned-bytes.patch
mm-gup_test-safely-calculate-gup-batch-size.patch
reply other threads:[~2026-09-18 19:43 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
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=20260918194301.D196E1F000FF@smtp.kernel.org \
--to=akpm@linux-foundation.org \
--cc=mm-commits@vger.kernel.org \
--cc=sarthak.sharma@arm.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.