From nobody Fri Sep 25 14:31:44 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 4A7EC443C34; Fri, 11 Sep 2026 11:10:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789125019; cv=none; b=aTC7bwo0mQjea5hiAnPuqznOVfazLGMjOk2UQSWt+IzWcrFRpkIn/iD82Bb3oo8JoFB5MU8Oc0bGx5OPtncImKLWwASGGte7FlZ8Uq/+cWV75Tiwf7bJ6E8tFmIkTz0NUBdKJozOsXLTDil9oi3pcP/atptLieKKqPlXWxTgpjY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789125019; c=relaxed/simple; bh=7uLmrSIcUlqGeUcGkG2FtiBOiuFtkglH3Id+7IgETb0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=B3XsSxT4mpnRAglyhYFVaVx3ndu/KB54u5ea5Q19ZN1di/UkSwdGzZR18TuULc5e2yvVfmxe5PDBSI8RFcF4kcHi1HSCJxPQUzJvmpkLUQ4ecqUXVjR5J8X0NRVK25LJqhOuQSIucTa64Z/Xg9YuihyCwaT0CPZcodb6bGT2Yu0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=meFuv0E+; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="meFuv0E+" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id E3498143D; Fri, 11 Sep 2026 04:10:11 -0700 (PDT) Received: from a081061.blr.arm.com (a081061.arm.com [10.164.19.84]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id AF5733F59E; Fri, 11 Sep 2026 04:10:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1789125015; bh=7uLmrSIcUlqGeUcGkG2FtiBOiuFtkglH3Id+7IgETb0=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=meFuv0E+UeHasEI7seOB5zSVo5opsmJMpOKWiG9kfSUJ06LW0gFR6HYO6tD2sssag 1COt5OU6bV93hW8vx09HIWVkkUXMRxf2RHoe6oadBm/1arI+jEdsTASMZXlhIdz3WH IsB+LcgsCLq+BO1wuJD2lQ42eHi15oPQd/0R4LLQ= From: Sarthak Sharma To: Andrew Morton , David Hildenbrand Cc: Lorenzo Stoakes , "Liam R . Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Shuah Khan , Shuah Khan , Jonathan Corbet , Jason Gunthorpe , John Hubbard , Peter Xu , Leon Romanovsky , Zi Yan , Baolin Wang , Nico Pache , Ryan Roberts , Dev Jain , Barry Song , Lance Yang , Mark Brown , Anshuman Khandual , Muhammad Usama Anjum , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Sarthak Sharma Subject: [PATCH v10 1/6] selftests/mm: make file helpers return errors Date: Fri, 11 Sep 2026 16:39:45 +0530 Message-ID: <20260911110950.200240-2-sarthak.sharma@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260911110950.200240-1-sarthak.sharma@arm.com> References: <20260911110950.200240-1-sarthak.sharma@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Change read_file(), write_file(), read_num(), write_num() and write_num_ignore_einval() in vm_util.c to report failures to callers instead of exiting from the helper. Make read_file() return a negative errno on failure and 0 on success, so callers can distinguish a successful read from an I/O error. Also make read_num() reject negative and malformed values. Keep write_num_ignore_einval() silent for -EINVAL while returning other errors to its caller. Update callers to print diagnostics and fail wherever required. Modify a comment which implies write_num() uses ksft_exit_fail_msg(). Also add a helper print_file_access_error() in hugepage_settings.c to print TAP-compatible errors without a kselftest dependency. This prepares the helpers to be moved to tools/lib/mm without a kselftest dependency. Acked-by: Mike Rapoport (Microsoft) Acked-by: David Hildenbrand (Arm) Tested-by: Muhammad Usama Anjum Signed-off-by: Sarthak Sharma --- .../testing/selftests/mm/hugepage_settings.c | 98 +++++++++++--- .../selftests/mm/hugetlb-soft-offline.c | 16 ++- tools/testing/selftests/mm/khugepaged.c | 14 +- .../selftests/mm/split_huge_page_test.c | 5 +- tools/testing/selftests/mm/vm_util.c | 122 ++++++++++++------ tools/testing/selftests/mm/vm_util.h | 8 +- 6 files changed, 192 insertions(+), 71 deletions(-) diff --git a/tools/testing/selftests/mm/hugepage_settings.c b/tools/testing= /selftests/mm/hugepage_settings.c index d7917dce3aba..5bcda01ac4f6 100644 --- a/tools/testing/selftests/mm/hugepage_settings.c +++ b/tools/testing/selftests/mm/hugepage_settings.c @@ -8,6 +8,7 @@ #include #include #include +#include =20 #include "vm_util.h" #include "hugepage_settings.h" @@ -48,6 +49,11 @@ static const char * const shmem_enabled_strings[] =3D { NULL }; =20 +static void print_file_access_error(const char *path, int ret) +{ + printf("# %s: %s (%d)\n", path, strerror(-ret), -ret); +} + int thp_read_string(const char *name, const char * const strings[]) { char path[PATH_MAX]; @@ -61,8 +67,9 @@ int thp_read_string(const char *name, const char * const = strings[]) exit(EXIT_FAILURE); } =20 - if (!read_file(path, buf, sizeof(buf))) { - perror(path); + ret =3D read_file(path, buf, sizeof(buf)); + if (ret) { + print_file_access_error(path, ret); exit(EXIT_FAILURE); } =20 @@ -103,12 +110,17 @@ void thp_write_string(const char *name, const char *v= al) printf("%s: Pathname is too long\n", __func__); exit(EXIT_FAILURE); } - write_file(path, val, strlen(val) + 1); + ret =3D write_file(path, val, strlen(val) + 1); + if (ret) { + print_file_access_error(path, ret); + exit(EXIT_FAILURE); + } } =20 unsigned long thp_read_num(const char *name) { char path[PATH_MAX]; + unsigned long num; int ret; =20 ret =3D snprintf(path, PATH_MAX, THP_SYSFS "%s", name); @@ -116,7 +128,13 @@ unsigned long thp_read_num(const char *name) printf("%s: Pathname is too long\n", __func__); exit(EXIT_FAILURE); } - return read_num(path); + ret =3D read_num(path, &num); + if (ret) { + print_file_access_error(path, ret); + exit(EXIT_FAILURE); + } + + return num; } =20 void thp_write_num(const char *name, unsigned long num) @@ -129,7 +147,11 @@ void thp_write_num(const char *name, unsigned long num) printf("%s: Pathname is too long\n", __func__); exit(EXIT_FAILURE); } - write_num(path, num); + ret =3D write_num(path, num); + if (ret) { + print_file_access_error(path, ret); + exit(EXIT_FAILURE); + } } =20 void thp_read_settings(struct thp_settings *settings) @@ -157,8 +179,15 @@ void thp_read_settings(struct thp_settings *settings) .max_ptes_shared =3D thp_read_num("khugepaged/max_ptes_shared"), .pages_to_scan =3D thp_read_num("khugepaged/pages_to_scan"), }; - if (dev_queue_read_ahead_path[0]) - settings->read_ahead_kb =3D read_num(dev_queue_read_ahead_path); + if (dev_queue_read_ahead_path[0]) { + int ret =3D read_num(dev_queue_read_ahead_path, + &settings->read_ahead_kb); + + if (ret) { + print_file_access_error(dev_queue_read_ahead_path, ret); + exit(EXIT_FAILURE); + } + } =20 for (i =3D 0; i < NR_ORDERS; i++) { if (!((1 << i) & orders)) { @@ -208,8 +237,15 @@ void thp_write_settings(struct thp_settings *settings) thp_write_num("khugepaged/max_ptes_shared", khugepaged->max_ptes_shared); thp_write_num("khugepaged/pages_to_scan", khugepaged->pages_to_scan); =20 - if (dev_queue_read_ahead_path[0]) - write_num(dev_queue_read_ahead_path, settings->read_ahead_kb); + if (dev_queue_read_ahead_path[0]) { + int ret =3D write_num(dev_queue_read_ahead_path, + settings->read_ahead_kb); + + if (ret) { + print_file_access_error(dev_queue_read_ahead_path, ret); + exit(EXIT_FAILURE); + } + } =20 for (i =3D 0; i < NR_ORDERS; i++) { if (!((1 << i) & orders)) @@ -307,8 +343,15 @@ static unsigned long __thp_supported_orders(bool is_sh= mem) } =20 ret =3D read_file(path, buf, sizeof(buf)); - if (ret) - orders |=3D 1UL << i; + if (ret) { + if (ret !=3D -ENOENT) { + print_file_access_error(path, ret); + exit(EXIT_FAILURE); + } + continue; + } + + orders |=3D 1UL << i; } =20 return orders; @@ -382,8 +425,7 @@ int detect_hugetlb_page_sizes(unsigned long sizes[], in= t max) if (sscanf(entry->d_name, "hugepages-%zukB", &kb) !=3D 1) continue; sizes[count++] =3D kb * 1024; - ksft_print_msg("[INFO] detected hugetlb page size: %zu KiB\n", - kb); + printf("# [INFO] detected hugetlb page size: %zu KiB\n", kb); } closedir(dir); return count; @@ -425,28 +467,49 @@ static void hugetlb_sysfs_path(char *buf, size_t bufl= en, unsigned long hugetlb_nr_pages(unsigned long size) { char path[PATH_MAX]; + unsigned long nr; + int ret; =20 hugetlb_sysfs_path(path, sizeof(path), size, "nr_hugepages"); =20 - return read_num(path); + ret =3D read_num(path, &nr); + if (ret) { + print_file_access_error(path, ret); + exit(EXIT_FAILURE); + } + + return nr; } =20 void hugetlb_set_nr_pages(unsigned long size, unsigned long nr) { char path[PATH_MAX]; + int ret; =20 hugetlb_sysfs_path(path, sizeof(path), size, "nr_hugepages"); =20 - write_num_ignore_einval(path, nr); + ret =3D write_num_ignore_einval(path, nr); + if (ret) { + print_file_access_error(path, ret); + exit(EXIT_FAILURE); + } } =20 unsigned long hugetlb_free_pages(unsigned long size) { char path[PATH_MAX]; + unsigned long nr; + int ret; =20 hugetlb_sysfs_path(path, sizeof(path), size, "free_hugepages"); =20 - return read_num(path); + ret =3D read_num(path, &nr); + if (ret) { + print_file_access_error(path, ret); + exit(EXIT_FAILURE); + } + + return nr; } =20 static bool __hugetlb_setup(unsigned long size, unsigned long nr) @@ -502,7 +565,8 @@ unsigned long hugetlb_setup(unsigned long nr, unsigned = long sizes[], return 0; =20 if (nr_enabled > max) { - ksft_print_msg("detected %d huge page sizes, will only test %d\n", nr_en= abled, max); + printf("# detected %d huge page sizes, will only test %d\n", + nr_enabled, max); nr_enabled =3D max; } =20 diff --git a/tools/testing/selftests/mm/hugetlb-soft-offline.c b/tools/test= ing/selftests/mm/hugetlb-soft-offline.c index 4af9d3db7b5b..ffc85b958c69 100644 --- a/tools/testing/selftests/mm/hugetlb-soft-offline.c +++ b/tools/testing/selftests/mm/hugetlb-soft-offline.c @@ -85,8 +85,7 @@ static unsigned long orig_enable_soft_offline =3D -1UL; =20 /* * Runs from an atexit handler, so it must not call anything that - * exits on failure: write_num() would re-enter exit() through - * ksft_exit_fail_msg(). + * exits on failure. */ static void restore_enable_soft_offline(void) { @@ -152,7 +151,10 @@ static void test_soft_offline_common(int enable_soft_o= ffline) hugepagesize_kb =3D file_stat.f_bsize / 1024; ksft_print_msg("Hugepagesize is %ldkB\n", hugepagesize_kb); =20 - write_num(ENABLE_SOFT_OFFLINE_PATH, enable_soft_offline); + ret =3D write_num(ENABLE_SOFT_OFFLINE_PATH, enable_soft_offline); + if (ret) + ksft_exit_fail_msg("Failed to write to %s: %s\n", + ENABLE_SOFT_OFFLINE_PATH, strerror(-ret)); =20 nr_hugepages_before =3D hugetlb_nr_default_pages(); =20 @@ -189,6 +191,8 @@ static void test_soft_offline_common(int enable_soft_of= fline) =20 int main(int argc, char **argv) { + int ret; + ksft_print_header(); =20 if (!hugetlb_setup_default(8)) @@ -196,7 +200,11 @@ int main(int argc, char **argv) =20 ksft_set_plan(2); =20 - orig_enable_soft_offline =3D read_num(ENABLE_SOFT_OFFLINE_PATH); + ret =3D read_num(ENABLE_SOFT_OFFLINE_PATH, &orig_enable_soft_offline); + if (ret) + ksft_exit_fail_msg("Failed to read %s: %s\n", + ENABLE_SOFT_OFFLINE_PATH, strerror(-ret)); + atexit(restore_enable_soft_offline); =20 test_soft_offline_common(1); diff --git a/tools/testing/selftests/mm/khugepaged.c b/tools/testing/selfte= sts/mm/khugepaged.c index f82673f5f6b4..6daa22f6da2f 100644 --- a/tools/testing/selftests/mm/khugepaged.c +++ b/tools/testing/selftests/mm/khugepaged.c @@ -122,6 +122,7 @@ static void get_finfo(const char *dir) char buf[1 << 10]; char path[PATH_MAX]; char *str, *end; + int ret; =20 finfo.dir =3D dir; if (stat(finfo.dir, &path_stat)) @@ -142,8 +143,9 @@ static void get_finfo(const char *dir) major(path_stat.st_dev), minor(path_stat.st_dev)) >=3D sizeof(path)) ksft_exit_fail_msg("%s: Pathname is too long\n", __func__); - if (!read_file(path, buf, sizeof(buf))) - ksft_exit_fail_perror("read_file(uevent)"); + ret =3D read_file(path, buf, sizeof(buf)); + if (ret) + ksft_exit_fail_msg("read_file(%s): %s\n", path, strerror(-ret)); if (strstr(buf, "DEVTYPE=3Ddisk")) { /* Found it */ if (snprintf(finfo.dev_queue_read_ahead_path, @@ -324,7 +326,7 @@ static void *file_setup_area_common(int nr_hpages, enum= file_setup_ops setup) { const int open_opt =3D setup =3D=3D FILE_SETUP_READ_ONLY_FS ? O_RDONLY : = O_RDWR; const int mmap_prot =3D setup =3D=3D FILE_SETUP_READ_ONLY_FS ? PROT_READ = : (PROT_READ | PROT_WRITE); - int fd; + int fd, ret; void *p; unsigned long size; =20 @@ -362,7 +364,11 @@ static void *file_setup_area_common(int nr_hpages, enu= m file_setup_ops setup) ksft_exit_fail_perror("mmap()"); =20 /* Drop page cache */ - write_file("/proc/sys/vm/drop_caches", "3", 2); + ret =3D write_file("/proc/sys/vm/drop_caches", "3", 2); + if (ret) + ksft_exit_fail_msg("write_file(drop_caches): %s\n", + strerror(-ret)); + success("OK"); return p; } diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/test= ing/selftests/mm/split_huge_page_test.c index c01d227d7fd6..a30927514b4f 100644 --- a/tools/testing/selftests/mm/split_huge_page_test.c +++ b/tools/testing/selftests/mm/split_huge_page_test.c @@ -145,7 +145,10 @@ static void write_debugfs(const char *fmt, ...) if (ret >=3D INPUT_MAX) ksft_exit_fail_msg("%s: Debugfs input is too long\n", __func__); =20 - write_file(SPLIT_DEBUGFS, input, ret + 1); + ret =3D write_file(SPLIT_DEBUGFS, input, ret + 1); + if (ret) + ksft_exit_fail_msg("write_file(%s): %s\n", SPLIT_DEBUGFS, + strerror(-ret)); } =20 static char *allocate_zero_filled_hugepage(size_t len) diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests= /mm/vm_util.c index 80bc9f597b52..c1b8d60e519d 100644 --- a/tools/testing/selftests/mm/vm_util.c +++ b/tools/testing/selftests/mm/vm_util.c @@ -891,109 +891,149 @@ int unpoison_memory(unsigned long pfn) =20 int read_file(const char *path, char *buf, size_t buflen) { - int fd; + int fd, err; ssize_t numread; =20 fd =3D open(path, O_RDONLY); if (fd =3D=3D -1) - return 0; + return -errno; =20 numread =3D read(fd, buf, buflen - 1); if (numread < 1) { + err =3D numread ? errno : ENODATA; close(fd); - return 0; + return -err; } =20 buf[numread] =3D '\0'; close(fd); =20 - return (unsigned int) numread; + return 0; } =20 -static void __write_file(const char *path, const char *buf, size_t buflen,= bool ignore_einval) +int write_file(const char *path, const char *buf, size_t buflen) { int fd, saved_errno; ssize_t numwritten; =20 if (buflen < 2) - ksft_exit_fail_msg("Incorrect buffer len: %zu\n", buflen); + return -EINVAL; =20 fd =3D open(path, O_WRONLY); if (fd =3D=3D -1) - ksft_exit_fail_msg("%s open failed: %s\n", path, strerror(errno)); + return -errno; =20 numwritten =3D write(fd, buf, buflen - 1); saved_errno =3D errno; close(fd); - errno =3D saved_errno; - if (numwritten < 0) { - if (ignore_einval && errno =3D=3D EINVAL) - return; - ksft_exit_fail_msg("%s write(%.*s) failed: %s\n", path, (int)(buflen - 1= ), - buf, strerror(errno)); - } - if (numwritten !=3D buflen - 1) - ksft_exit_fail_msg("%s write(%.*s) is truncated, expected %zu bytes, got= %zd bytes\n", - path, (int)(buflen - 1), buf, buflen - 1, numwritten); -} =20 -void write_file(const char *path, const char *buf, size_t buflen) -{ - __write_file(path, buf, buflen, /* ignore_einval =3D */ false); + if (numwritten < 0) + return -saved_errno; + + if (numwritten !=3D (ssize_t)(buflen - 1)) + return -EIO; + + return 0; } =20 -unsigned long read_num(const char *path) +int read_num(const char *path, unsigned long *num) { + unsigned long val; + int ret; char buf[21]; + char *end; =20 - if (!read_file(path, buf, sizeof(buf))) - ksft_exit_fail_perror("read_file()"); + if (!num) + return -EINVAL; =20 - return strtoul(buf, NULL, 10); + ret =3D read_file(path, buf, sizeof(buf)); + if (ret) + return ret; + + /* Reject signs and leading whitespace that are accepted by strtoul() */ + if (buf[0] < '0' || buf[0] > '9') + return -EINVAL; + + errno =3D 0; + val =3D strtoul(buf, &end, 10); + if (errno) + return -errno; + + /* Only allow a newline after the number */ + if (*end =3D=3D '\n') + end++; + + if (*end !=3D '\0') + return -EINVAL; + + *num =3D val; + return 0; } =20 -static void __write_num(const char *path, unsigned long num, bool ignore_e= inval) +int write_num(const char *path, unsigned long num) { char buf[21]; =20 sprintf(buf, "%lu", num); - __write_file(path, buf, strlen(buf) + 1, ignore_einval); + return write_file(path, buf, strlen(buf) + 1); } =20 -void write_num(const char *path, unsigned long num) +int write_num_ignore_einval(const char *path, unsigned long num) { - return __write_num(path, num, /* ignore_einval =3D */ false); -} + int ret; =20 -void write_num_ignore_einval(const char *path, unsigned long num) -{ - return __write_num(path, num, /* ignore_einval =3D */ true); + ret =3D write_num(path, num); + return ret =3D=3D -EINVAL ? 0 : ret; } =20 static unsigned long shmall, shmmax; =20 void __shm_limits_restore(void) { - if (shmmax) - write_num("/proc/sys/kernel/shmmax", shmmax); - if (shmall) - write_num("/proc/sys/kernel/shmall", shmall); + int ret; + + if (shmmax) { + ret =3D write_num("/proc/sys/kernel/shmmax", shmmax); + if (ret < 0) + ksft_exit_fail_msg("Failed to restore shmmax: %s\n", + strerror(-ret)); + } + if (shmall) { + ret =3D write_num("/proc/sys/kernel/shmall", shmall); + if (ret < 0) + ksft_exit_fail_msg("Failed to restore shmall: %s\n", + strerror(-ret)); + } } =20 void shm_limits_prepare(unsigned long length) { unsigned long nr =3D length / psize(); unsigned long val; + int ret; + + ret =3D read_num("/proc/sys/kernel/shmmax", &val); + if (ret < 0) + ksft_exit_fail_msg("Failed to read /proc/sys/kernel/shmmax: %s\n", + strerror(-ret)); =20 - val =3D read_num("/proc/sys/kernel/shmmax"); if (val < length) { - write_num("/proc/sys/kernel/shmmax", length); + ret =3D write_num("/proc/sys/kernel/shmmax", length); + if (ret < 0) + ksft_exit_fail_msg("Failed to write %lu to /proc/sys/kernel/shmmax: %s\= n", + length, strerror(-ret)); shmmax =3D val; } =20 - val =3D read_num("/proc/sys/kernel/shmall"); + ret =3D read_num("/proc/sys/kernel/shmall", &val); + if (ret < 0) + ksft_exit_fail_msg("Failed to read /proc/sys/kernel/shmall: %s\n", + strerror(-ret)); if (val < nr) { - write_num("/proc/sys/kernel/shmall", nr); + ret =3D write_num("/proc/sys/kernel/shmall", nr); + if (ret < 0) + ksft_exit_fail_msg("Failed to write %lu to /proc/sys/kernel/shmall: %s\= n", + nr, strerror(-ret)); shmall =3D val; } } diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests= /mm/vm_util.h index 9a49af88702e..62f6f5b42649 100644 --- a/tools/testing/selftests/mm/vm_util.h +++ b/tools/testing/selftests/mm/vm_util.h @@ -166,11 +166,11 @@ int unpoison_memory(unsigned long pfn); #define PAGEMAP_PRESENT(ent) (((ent) & (1ull << 63)) !=3D 0) #define PAGEMAP_PFN(ent) ((ent) & ((1ull << 55) - 1)) =20 -void write_file(const char *path, const char *buf, size_t buflen); +int write_file(const char *path, const char *buf, size_t buflen); int read_file(const char *path, char *buf, size_t buflen); -unsigned long read_num(const char *path); -void write_num(const char *path, unsigned long num); -void write_num_ignore_einval(const char *path, unsigned long num); +int read_num(const char *path, unsigned long *num); +int write_num(const char *path, unsigned long num); +int write_num_ignore_einval(const char *path, unsigned long num); =20 void shm_limits_prepare(unsigned long length); void __shm_limits_restore(void); --=20 2.53.0 From nobody Fri Sep 25 14:31:44 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id D3CDC443C0A; Fri, 11 Sep 2026 11:10:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789125029; cv=none; b=P/jG7ipGo+q/GPLbFDJI1Y0eCbbeQGFsV0j8ynQJ/dOBA6142MMlWD20pDJo/AYTaiYQemfuzOiuooeSMoiqRThcTtp1r/DSorMxXR36QVdDCde0d9Kl4VKsNz0foQyjbMs5mLJzSAPExmMKwdjyBDbWd6tzH+pLBHi5gn4f+6M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789125029; c=relaxed/simple; bh=xF0k60TEQ8akSLlQFC4CGPrBt98AU+OSQDd7D86kcZ8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TH7TtdhKdQLP5d8I6wuhdkRVc76PZTFj3yC4UwuTPoIPrMaFmuaTaL25kN5dd7Ta2Pm20uTHpwivMY9c4HGa0i00ukfhJiDTKUmR/5MsrcufXp4qkWHZQHXOc+Z+HvLAZXEe7XlkcIUgbbrW60eKcTNrAFZXSBHZmwXkayZTd88= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=TMFDkDYX; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="TMFDkDYX" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 1CD72143D; Fri, 11 Sep 2026 04:10:20 -0700 (PDT) Received: from a081061.blr.arm.com (a081061.arm.com [10.164.19.84]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 25A383F59E; Fri, 11 Sep 2026 04:10:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1789125023; bh=xF0k60TEQ8akSLlQFC4CGPrBt98AU+OSQDd7D86kcZ8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TMFDkDYX+BNBgEfdATC448Ir4cZoeSnZ30u34WIpTqZ6lclNb0QAYrXKhbRfl7bqA 8pvy+UKS0JRTVRfIpuEAyNFRcX8h7IdVpDW4QsRm4mHnVp6WTzEiHn+sLkJKZvJzcS JI8NoFSNT4vit7wtnwmGxXiBf1fkEdfmysSAZXa4= From: Sarthak Sharma To: Andrew Morton , David Hildenbrand Cc: Lorenzo Stoakes , "Liam R . Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Shuah Khan , Shuah Khan , Jonathan Corbet , Jason Gunthorpe , John Hubbard , Peter Xu , Leon Romanovsky , Zi Yan , Baolin Wang , Nico Pache , Ryan Roberts , Dev Jain , Barry Song , Lance Yang , Mark Brown , Anshuman Khandual , Muhammad Usama Anjum , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Sarthak Sharma Subject: [PATCH v10 2/6] tools/lib/mm: add shared file helpers Date: Fri, 11 Sep 2026 16:39:46 +0530 Message-ID: <20260911110950.200240-3-sarthak.sharma@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260911110950.200240-1-sarthak.sharma@arm.com> References: <20260911110950.200240-1-sarthak.sharma@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Move read_file(), write_file(), read_num(), write_num() and write_num_ignore_einval() out of tools/testing/selftests/mm/vm_util.c into a new shared helper under tools/lib/mm/. These helpers are used by mm selftests today and will also be needed by shared hugepage helpers in subsequent patches. Move them to a generic location so they can be reused outside selftests as well. Keep the helpers exposed to mm selftests through vm_util.h by including the new shared header there, and link the new helper into the selftests/mm build. Update the explicit x86 protection_keys 32-bit and 64-bit build rules to preserve prerequisite paths, now that file_utils.c is built from tools/lib/mm. Add tools/lib/mm/ to the MEMORY MANAGEMENT - MISC entry in MAINTAINERS. Acked-by: Mike Rapoport (Microsoft) Acked-by: David Hildenbrand (Arm) Tested-by: Muhammad Usama Anjum Signed-off-by: Sarthak Sharma --- MAINTAINERS | 1 + tools/lib/mm/file_utils.c | 106 +++++++++++++++++++++++++++ tools/lib/mm/file_utils.h | 13 ++++ tools/testing/selftests/mm/Makefile | 11 +-- tools/testing/selftests/mm/vm_util.c | 97 ------------------------ tools/testing/selftests/mm/vm_util.h | 7 +- 6 files changed, 127 insertions(+), 108 deletions(-) create mode 100644 tools/lib/mm/file_utils.c create mode 100644 tools/lib/mm/file_utils.h diff --git a/MAINTAINERS b/MAINTAINERS index 35262aa3e67e..dd5374a1a3c2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17295,6 +17295,7 @@ F: mm/memory-tiers.c F: mm/page_idle.c F: mm/pgalloc-track.h F: mm/process_vm_access.c +F: tools/lib/mm/ F: tools/testing/selftests/mm/ =20 MEMORY MANAGEMENT - NUMA MEMBLOCKS AND NUMA EMULATION diff --git a/tools/lib/mm/file_utils.c b/tools/lib/mm/file_utils.c new file mode 100644 index 000000000000..9b2237e9823e --- /dev/null +++ b/tools/lib/mm/file_utils.c @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include + +#include "file_utils.h" + +int read_file(const char *path, char *buf, size_t buflen) +{ + int fd, err; + ssize_t numread; + + fd =3D open(path, O_RDONLY); + if (fd =3D=3D -1) + return -errno; + + numread =3D read(fd, buf, buflen - 1); + if (numread < 1) { + err =3D numread ? errno : ENODATA; + close(fd); + return -err; + } + + buf[numread] =3D '\0'; + close(fd); + + return 0; +} + +int write_file(const char *path, const char *buf, size_t buflen) +{ + int fd, saved_errno; + ssize_t numwritten; + + if (buflen < 2) + return -EINVAL; + + fd =3D open(path, O_WRONLY); + if (fd =3D=3D -1) + return -errno; + + numwritten =3D write(fd, buf, buflen - 1); + saved_errno =3D errno; + close(fd); + + if (numwritten < 0) + return -saved_errno; + + if (numwritten !=3D (ssize_t)(buflen - 1)) + return -EIO; + + return 0; +} + +int read_num(const char *path, unsigned long *num) +{ + unsigned long val; + int ret; + char buf[21]; + char *end; + + if (!num) + return -EINVAL; + + ret =3D read_file(path, buf, sizeof(buf)); + if (ret) + return ret; + + /* Reject signs and leading whitespace that are accepted by strtoul() */ + if (buf[0] < '0' || buf[0] > '9') + return -EINVAL; + + errno =3D 0; + val =3D strtoul(buf, &end, 10); + if (errno) + return -errno; + + /* Only allow a newline after the number */ + if (*end =3D=3D '\n') + end++; + + if (*end !=3D '\0') + return -EINVAL; + + *num =3D val; + return 0; +} + +int write_num(const char *path, unsigned long num) +{ + char buf[21]; + + sprintf(buf, "%lu", num); + return write_file(path, buf, strlen(buf) + 1); +} + +int write_num_ignore_einval(const char *path, unsigned long num) +{ + int ret; + + ret =3D write_num(path, num); + return ret =3D=3D -EINVAL ? 0 : ret; +} diff --git a/tools/lib/mm/file_utils.h b/tools/lib/mm/file_utils.h new file mode 100644 index 000000000000..50daa82c2b2b --- /dev/null +++ b/tools/lib/mm/file_utils.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __MM_FILE_UTILS_H__ +#define __MM_FILE_UTILS_H__ + +#include + +int read_file(const char *path, char *buf, size_t buflen); +int write_file(const char *path, const char *buf, size_t buflen); +int read_num(const char *path, unsigned long *num); +int write_num(const char *path, unsigned long num); +int write_num_ignore_einval(const char *path, unsigned long num); + +#endif diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/= mm/Makefile index 2d5366196e30..61d974d2cbae 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -37,7 +37,8 @@ endif # LDLIBS. MAKEFLAGS +=3D --no-builtin-rules =20 -CFLAGS =3D -Wall -O2 -I $(top_srcdir) $(EXTRA_CFLAGS) $(KHDR_INCLUDES) $(T= OOLS_INCLUDES) +CFLAGS =3D -Wall -O2 -I $(top_srcdir) -I $(top_srcdir)/tools/lib +CFLAGS +=3D $(EXTRA_CFLAGS) $(KHDR_INCLUDES) $(TOOLS_INCLUDES) CFLAGS +=3D -Wunreachable-code LDLIBS =3D -lrt -lpthread -lm =20 @@ -187,8 +188,8 @@ TEST_FILES +=3D write_hugetlb_memory.sh =20 include ../lib.mk =20 -$(TEST_GEN_PROGS): vm_util.c hugepage_settings.c -$(TEST_GEN_FILES): vm_util.c hugepage_settings.c +$(TEST_GEN_PROGS): vm_util.c hugepage_settings.c $(top_srcdir)/tools/lib/m= m/file_utils.c +$(TEST_GEN_FILES): vm_util.c hugepage_settings.c $(top_srcdir)/tools/lib/m= m/file_utils.c =20 $(OUTPUT)/uffd-stress: uffd-common.c $(OUTPUT)/uffd-unit-tests: uffd-common.c @@ -217,7 +218,7 @@ $(BINARIES_32): CFLAGS +=3D -m32 -mxsave $(BINARIES_32): LDLIBS +=3D -lrt -ldl -lm $(BINARIES_32): $(OUTPUT)/%_32: %.c $(call msg,CC,,$@) - $(Q)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(notdir $^) $(LDLIBS) -o $@ + $(Q)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $^ $(LDLIBS) -o $@ $(foreach t,$(VMTARGETS),$(eval $(call gen-target-rule-32,$(t)))) endif =20 @@ -226,7 +227,7 @@ $(BINARIES_64): CFLAGS +=3D -m64 -mxsave $(BINARIES_64): LDLIBS +=3D -lrt -ldl $(BINARIES_64): $(OUTPUT)/%_64: %.c $(call msg,CC,,$@) - $(Q)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(notdir $^) $(LDLIBS) -o $@ + $(Q)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $^ $(LDLIBS) -o $@ $(foreach t,$(VMTARGETS),$(eval $(call gen-target-rule-64,$(t)))) endif =20 diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests= /mm/vm_util.c index c1b8d60e519d..4751db798c3a 100644 --- a/tools/testing/selftests/mm/vm_util.c +++ b/tools/testing/selftests/mm/vm_util.c @@ -889,103 +889,6 @@ int unpoison_memory(unsigned long pfn) return ret > 0 ? 0 : -errno; } =20 -int read_file(const char *path, char *buf, size_t buflen) -{ - int fd, err; - ssize_t numread; - - fd =3D open(path, O_RDONLY); - if (fd =3D=3D -1) - return -errno; - - numread =3D read(fd, buf, buflen - 1); - if (numread < 1) { - err =3D numread ? errno : ENODATA; - close(fd); - return -err; - } - - buf[numread] =3D '\0'; - close(fd); - - return 0; -} - -int write_file(const char *path, const char *buf, size_t buflen) -{ - int fd, saved_errno; - ssize_t numwritten; - - if (buflen < 2) - return -EINVAL; - - fd =3D open(path, O_WRONLY); - if (fd =3D=3D -1) - return -errno; - - numwritten =3D write(fd, buf, buflen - 1); - saved_errno =3D errno; - close(fd); - - if (numwritten < 0) - return -saved_errno; - - if (numwritten !=3D (ssize_t)(buflen - 1)) - return -EIO; - - return 0; -} - -int read_num(const char *path, unsigned long *num) -{ - unsigned long val; - int ret; - char buf[21]; - char *end; - - if (!num) - return -EINVAL; - - ret =3D read_file(path, buf, sizeof(buf)); - if (ret) - return ret; - - /* Reject signs and leading whitespace that are accepted by strtoul() */ - if (buf[0] < '0' || buf[0] > '9') - return -EINVAL; - - errno =3D 0; - val =3D strtoul(buf, &end, 10); - if (errno) - return -errno; - - /* Only allow a newline after the number */ - if (*end =3D=3D '\n') - end++; - - if (*end !=3D '\0') - return -EINVAL; - - *num =3D val; - return 0; -} - -int write_num(const char *path, unsigned long num) -{ - char buf[21]; - - sprintf(buf, "%lu", num); - return write_file(path, buf, strlen(buf) + 1); -} - -int write_num_ignore_einval(const char *path, unsigned long num) -{ - int ret; - - ret =3D write_num(path, num); - return ret =3D=3D -EINVAL ? 0 : ret; -} - static unsigned long shmall, shmmax; =20 void __shm_limits_restore(void) diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests= /mm/vm_util.h index 62f6f5b42649..fe0475f2bdf2 100644 --- a/tools/testing/selftests/mm/vm_util.h +++ b/tools/testing/selftests/mm/vm_util.h @@ -8,6 +8,7 @@ #include /* _SC_PAGESIZE */ #include "kselftest.h" #include +#include =20 #define BIT_ULL(nr) (1ULL << (nr)) #define PM_SOFT_DIRTY BIT_ULL(55) @@ -166,12 +167,6 @@ int unpoison_memory(unsigned long pfn); #define PAGEMAP_PRESENT(ent) (((ent) & (1ull << 63)) !=3D 0) #define PAGEMAP_PFN(ent) ((ent) & ((1ull << 55) - 1)) =20 -int write_file(const char *path, const char *buf, size_t buflen); -int read_file(const char *path, char *buf, size_t buflen); -int read_num(const char *path, unsigned long *num); -int write_num(const char *path, unsigned long num); -int write_num_ignore_einval(const char *path, unsigned long num); - void shm_limits_prepare(unsigned long length); void __shm_limits_restore(void); =20 --=20 2.53.0 From nobody Fri Sep 25 14:31:44 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 51CC643DED4; Fri, 11 Sep 2026 11:10:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789125045; cv=none; b=oHe/QZmaCLSKjlOaKx1+WYilidMFU7AJ96ivZzQRm9KwMOMA917X+nOo52rzrTaM60Nib+huDXk19geEfQ/Yud6xbB8QDoYrOO8+6LgUTvXql/+Zn8BPfQlYSmkIfoHQCdmRIh9XRfRG6W7bL5sZEaGZOR7z9XyQxskmpJZ9tWg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789125045; c=relaxed/simple; bh=fljafABUWRaZDNDQKf2SGko8MyMWKmFnv6cTanWlJFE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mIwwk9pWyCcI2B1csUxuMxSATMeJ9teNH6C0KdmDL4qMBJC4Pm5zzPQx+0nforXCOq/EPJPU/CpmA6Bsq7OP0D+SMP7YONiGf4+BfsKcTy+JThOY6DXof8mHlbX3fMrEBqJMPe69Hr+Bpjd+6YA9OzcugqYrNx2to9KmlrPdpps= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=NFHo7aNv; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="NFHo7aNv" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 454B7143D; Fri, 11 Sep 2026 04:10:28 -0700 (PDT) Received: from a081061.blr.arm.com (a081061.arm.com [10.164.19.84]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 52A233F59E; Fri, 11 Sep 2026 04:10:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1789125031; bh=fljafABUWRaZDNDQKf2SGko8MyMWKmFnv6cTanWlJFE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=NFHo7aNvRaul99jSbewOCM5YhV8paDMFSESEM1guiazeoGMlJAw2ZlE8uny5zJPL6 VoWQdY1Cl/x3+MzA21hIudP6G/XLVXzBN/eddmUXZVoYlkGofA5dHV+9ZC7tc8QW3c Hs1szyeiHwdXp3HVpg8b0nyQ0kxKo2WOCH3ofB+s= From: Sarthak Sharma To: Andrew Morton , David Hildenbrand Cc: Lorenzo Stoakes , "Liam R . Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Shuah Khan , Shuah Khan , Jonathan Corbet , Jason Gunthorpe , John Hubbard , Peter Xu , Leon Romanovsky , Zi Yan , Baolin Wang , Nico Pache , Ryan Roberts , Dev Jain , Barry Song , Lance Yang , Mark Brown , Anshuman Khandual , Muhammad Usama Anjum , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Sarthak Sharma Subject: [PATCH v10 3/6] tools/lib/mm: move hugepage_settings out of selftests Date: Fri, 11 Sep 2026 16:39:47 +0530 Message-ID: <20260911110950.200240-4-sarthak.sharma@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260911110950.200240-1-sarthak.sharma@arm.com> References: <20260911110950.200240-1-sarthak.sharma@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Move hugepage_settings.[ch] from tools/testing/selftests/mm/ to tools/lib/mm/ so the THP and HugeTLB helpers can be shared more easily between selftests and other tools. Keep the helpers exposed to mm selftests through vm_util.h where possible, and use direct includes for files that do not include vm_util.h. Adjust the selftests/mm build to compile the moved implementation from its new location. Remove the remaining kselftest dependency by including file_utils.h directly and using EXIT_FAILURE in the signal handler. Acked-by: Mike Rapoport (Microsoft) Acked-by: David Hildenbrand (Arm) Tested-by: Muhammad Usama Anjum Signed-off-by: Sarthak Sharma --- .../{testing/selftests =3D> lib}/mm/hugepage_settings.c | 11 +++++++++-- .../{testing/selftests =3D> lib}/mm/hugepage_settings.h | 0 tools/testing/selftests/mm/Makefile | 6 ++++-- tools/testing/selftests/mm/compaction_test.c | 2 +- tools/testing/selftests/mm/cow.c | 1 - tools/testing/selftests/mm/folio_split_race_test.c | 1 - tools/testing/selftests/mm/guard-regions.c | 1 - tools/testing/selftests/mm/gup_longterm.c | 1 - tools/testing/selftests/mm/gup_test.c | 1 - tools/testing/selftests/mm/hmm-tests.c | 6 +++--- tools/testing/selftests/mm/hugetlb-madvise.c | 1 - tools/testing/selftests/mm/hugetlb-mmap.c | 1 - tools/testing/selftests/mm/hugetlb-mremap.c | 1 - tools/testing/selftests/mm/hugetlb-shm.c | 1 - tools/testing/selftests/mm/hugetlb-soft-offline.c | 2 +- tools/testing/selftests/mm/hugetlb_dio.c | 1 - tools/testing/selftests/mm/hugetlb_fault_after_madv.c | 1 - tools/testing/selftests/mm/hugetlb_madv_vs_map.c | 1 - tools/testing/selftests/mm/khugepaged.c | 1 - tools/testing/selftests/mm/ksm_tests.c | 1 - tools/testing/selftests/mm/migration.c | 2 +- tools/testing/selftests/mm/pagemap_ioctl.c | 1 - tools/testing/selftests/mm/prctl_thp_disable.c | 1 - tools/testing/selftests/mm/protection_keys.c | 2 +- tools/testing/selftests/mm/soft-dirty.c | 1 - tools/testing/selftests/mm/split_huge_page_test.c | 1 - tools/testing/selftests/mm/thuge-gen.c | 1 - tools/testing/selftests/mm/transhuge-stress.c | 1 - tools/testing/selftests/mm/uffd-common.h | 1 - tools/testing/selftests/mm/uffd-wp-mremap.c | 2 +- tools/testing/selftests/mm/va_high_addr_switch.c | 1 - tools/testing/selftests/mm/vm_util.h | 1 + 32 files changed, 22 insertions(+), 34 deletions(-) rename tools/{testing/selftests =3D> lib}/mm/hugepage_settings.c (99%) rename tools/{testing/selftests =3D> lib}/mm/hugepage_settings.h (100%) diff --git a/tools/testing/selftests/mm/hugepage_settings.c b/tools/lib/mm/= hugepage_settings.c similarity index 99% rename from tools/testing/selftests/mm/hugepage_settings.c rename to tools/lib/mm/hugepage_settings.c index 5bcda01ac4f6..abd9f7182f88 100644 --- a/tools/testing/selftests/mm/hugepage_settings.c +++ b/tools/lib/mm/hugepage_settings.c @@ -10,11 +10,16 @@ #include #include =20 -#include "vm_util.h" +#include "file_utils.h" #include "hugepage_settings.h" =20 #define THP_SYSFS "/sys/kernel/mm/transparent_hugepage/" #define MAX_SETTINGS_DEPTH 4 + +#ifndef ARRAY_SIZE +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) +#endif + static struct thp_settings settings_stack[MAX_SETTINGS_DEPTH]; static int settings_index; static struct thp_settings saved_settings; @@ -638,8 +643,10 @@ static void hugepage_restore_settings_atexit(void) =20 static void hugepage_restore_settings_sighandler(int sig) { + (void)sig; + /* exit() will invoke the hugepage_restore_settings_atexit handler. */ - exit(KSFT_FAIL); + exit(EXIT_FAILURE); } =20 void hugepage_save_settings(bool thp, bool hugetlb) diff --git a/tools/testing/selftests/mm/hugepage_settings.h b/tools/lib/mm/= hugepage_settings.h similarity index 100% rename from tools/testing/selftests/mm/hugepage_settings.h rename to tools/lib/mm/hugepage_settings.h diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/= mm/Makefile index 61d974d2cbae..7cea3228020d 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -188,8 +188,10 @@ TEST_FILES +=3D write_hugetlb_memory.sh =20 include ../lib.mk =20 -$(TEST_GEN_PROGS): vm_util.c hugepage_settings.c $(top_srcdir)/tools/lib/m= m/file_utils.c -$(TEST_GEN_FILES): vm_util.c hugepage_settings.c $(top_srcdir)/tools/lib/m= m/file_utils.c +$(TEST_GEN_PROGS): vm_util.c $(top_srcdir)/tools/lib/mm/hugepage_settings.= c \ + $(top_srcdir)/tools/lib/mm/file_utils.c +$(TEST_GEN_FILES): vm_util.c $(top_srcdir)/tools/lib/mm/hugepage_settings.= c \ + $(top_srcdir)/tools/lib/mm/file_utils.c =20 $(OUTPUT)/uffd-stress: uffd-common.c $(OUTPUT)/uffd-unit-tests: uffd-common.c diff --git a/tools/testing/selftests/mm/compaction_test.c b/tools/testing/s= elftests/mm/compaction_test.c index 30d4ace7155a..b3f5377119cb 100644 --- a/tools/testing/selftests/mm/compaction_test.c +++ b/tools/testing/selftests/mm/compaction_test.c @@ -15,9 +15,9 @@ #include #include #include +#include =20 #include "kselftest.h" -#include "hugepage_settings.h" =20 #define MAP_SIZE_MB 100 #define MAP_SIZE (MAP_SIZE_MB * 1024 * 1024) diff --git a/tools/testing/selftests/mm/cow.c b/tools/testing/selftests/mm/= cow.c index 8aa5249d9bef..3264a828575b 100644 --- a/tools/testing/selftests/mm/cow.c +++ b/tools/testing/selftests/mm/cow.c @@ -29,7 +29,6 @@ #include "../../../../mm/gup_test.h" #include "kselftest.h" #include "vm_util.h" -#include "hugepage_settings.h" =20 static size_t pagesize; static int pagemap_fd; diff --git a/tools/testing/selftests/mm/folio_split_race_test.c b/tools/tes= ting/selftests/mm/folio_split_race_test.c index 1960635a953e..e4660bf89b62 100644 --- a/tools/testing/selftests/mm/folio_split_race_test.c +++ b/tools/testing/selftests/mm/folio_split_race_test.c @@ -25,7 +25,6 @@ #include #include "vm_util.h" #include "kselftest.h" -#include "hugepage_settings.h" =20 uint64_t page_size; uint64_t pmd_pagesize; diff --git a/tools/testing/selftests/mm/guard-regions.c b/tools/testing/sel= ftests/mm/guard-regions.c index 5c8ec3ca75d7..af5cd9b30339 100644 --- a/tools/testing/selftests/mm/guard-regions.c +++ b/tools/testing/selftests/mm/guard-regions.c @@ -21,7 +21,6 @@ #include #include #include "vm_util.h" -#include "hugepage_settings.h" =20 #include "../pidfd/pidfd.h" =20 diff --git a/tools/testing/selftests/mm/gup_longterm.c b/tools/testing/self= tests/mm/gup_longterm.c index 510de93be681..c9d8b4491263 100644 --- a/tools/testing/selftests/mm/gup_longterm.c +++ b/tools/testing/selftests/mm/gup_longterm.c @@ -29,7 +29,6 @@ #include "../../../../mm/gup_test.h" #include "kselftest.h" #include "vm_util.h" -#include "hugepage_settings.h" =20 static size_t pagesize; static int nr_hugetlbsizes; diff --git a/tools/testing/selftests/mm/gup_test.c b/tools/testing/selftest= s/mm/gup_test.c index 3f841a96f870..5f44761dbec0 100644 --- a/tools/testing/selftests/mm/gup_test.c +++ b/tools/testing/selftests/mm/gup_test.c @@ -14,7 +14,6 @@ #include #include "kselftest.h" #include "vm_util.h" -#include "hugepage_settings.h" =20 #define MB (1UL << 20) =20 diff --git a/tools/testing/selftests/mm/hmm-tests.c b/tools/testing/selftes= ts/mm/hmm-tests.c index e2642eca0d02..fa1a651963fd 100644 --- a/tools/testing/selftests/mm/hmm-tests.c +++ b/tools/testing/selftests/mm/hmm-tests.c @@ -10,9 +10,6 @@ * bugs. */ =20 -#include "kselftest_harness.h" -#include "hugepage_settings.h" - #include #include #include @@ -33,6 +30,9 @@ #include #include #include +#include + +#include "kselftest_harness.h" =20 /* * This is a private UAPI to the kernel test module so it isn't exported diff --git a/tools/testing/selftests/mm/hugetlb-madvise.c b/tools/testing/s= elftests/mm/hugetlb-madvise.c index 555b4b3d1430..57cf790ca478 100644 --- a/tools/testing/selftests/mm/hugetlb-madvise.c +++ b/tools/testing/selftests/mm/hugetlb-madvise.c @@ -14,7 +14,6 @@ #include #include "vm_util.h" #include "kselftest.h" -#include "hugepage_settings.h" =20 #define MIN_FREE_PAGES 20 #define NR_HUGE_PAGES 10 /* common number of pages to map/allocate */ diff --git a/tools/testing/selftests/mm/hugetlb-mmap.c b/tools/testing/self= tests/mm/hugetlb-mmap.c index 0f2aad1b7dbd..a458becf5832 100644 --- a/tools/testing/selftests/mm/hugetlb-mmap.c +++ b/tools/testing/selftests/mm/hugetlb-mmap.c @@ -18,7 +18,6 @@ #include #include "vm_util.h" #include "kselftest.h" -#include "hugepage_settings.h" =20 #define LENGTH (256UL*1024*1024) #define PROTECTION (PROT_READ | PROT_WRITE) diff --git a/tools/testing/selftests/mm/hugetlb-mremap.c b/tools/testing/se= lftests/mm/hugetlb-mremap.c index ed3d92e862d8..9b724af66e93 100644 --- a/tools/testing/selftests/mm/hugetlb-mremap.c +++ b/tools/testing/selftests/mm/hugetlb-mremap.c @@ -26,7 +26,6 @@ #include #include "kselftest.h" #include "vm_util.h" -#include "hugepage_settings.h" =20 #define DEFAULT_LENGTH_MB 10UL #define MB_TO_BYTES(x) (x * 1024 * 1024) diff --git a/tools/testing/selftests/mm/hugetlb-shm.c b/tools/testing/selft= ests/mm/hugetlb-shm.c index 3ff7f062b7eb..f4514da49e1d 100644 --- a/tools/testing/selftests/mm/hugetlb-shm.c +++ b/tools/testing/selftests/mm/hugetlb-shm.c @@ -29,7 +29,6 @@ #include =20 #include "vm_util.h" -#include "hugepage_settings.h" =20 #define LENGTH (256UL*1024*1024) =20 diff --git a/tools/testing/selftests/mm/hugetlb-soft-offline.c b/tools/test= ing/selftests/mm/hugetlb-soft-offline.c index ffc85b958c69..d9565219378a 100644 --- a/tools/testing/selftests/mm/hugetlb-soft-offline.c +++ b/tools/testing/selftests/mm/hugetlb-soft-offline.c @@ -22,10 +22,10 @@ #include #include #include +#include =20 #include "kselftest.h" #include "vm_util.h" -#include "hugepage_settings.h" =20 #ifndef MADV_SOFT_OFFLINE #define MADV_SOFT_OFFLINE 101 diff --git a/tools/testing/selftests/mm/hugetlb_dio.c b/tools/testing/selft= ests/mm/hugetlb_dio.c index fb4600570e13..9495974eccbe 100644 --- a/tools/testing/selftests/mm/hugetlb_dio.c +++ b/tools/testing/selftests/mm/hugetlb_dio.c @@ -20,7 +20,6 @@ #include #include "vm_util.h" #include "kselftest.h" -#include "hugepage_settings.h" =20 #ifndef STATX_DIOALIGN #define STATX_DIOALIGN 0x00002000U diff --git a/tools/testing/selftests/mm/hugetlb_fault_after_madv.c b/tools/= testing/selftests/mm/hugetlb_fault_after_madv.c index 2dc158054f66..56c5a8533e9d 100644 --- a/tools/testing/selftests/mm/hugetlb_fault_after_madv.c +++ b/tools/testing/selftests/mm/hugetlb_fault_after_madv.c @@ -10,7 +10,6 @@ =20 #include "vm_util.h" #include "kselftest.h" -#include "hugepage_settings.h" =20 #define INLOOP_ITER 100 =20 diff --git a/tools/testing/selftests/mm/hugetlb_madv_vs_map.c b/tools/testi= ng/selftests/mm/hugetlb_madv_vs_map.c index f94549efcc6f..2532a42b98df 100644 --- a/tools/testing/selftests/mm/hugetlb_madv_vs_map.c +++ b/tools/testing/selftests/mm/hugetlb_madv_vs_map.c @@ -25,7 +25,6 @@ #include =20 #include "vm_util.h" -#include "hugepage_settings.h" =20 #define INLOOP_ITER 100 =20 diff --git a/tools/testing/selftests/mm/khugepaged.c b/tools/testing/selfte= sts/mm/khugepaged.c index 6daa22f6da2f..525108cace54 100644 --- a/tools/testing/selftests/mm/khugepaged.c +++ b/tools/testing/selftests/mm/khugepaged.c @@ -22,7 +22,6 @@ #include "linux/magic.h" =20 #include "vm_util.h" -#include "hugepage_settings.h" =20 #define BASE_ADDR ((void *)(1UL << 30)) static unsigned long hpage_pmd_size; diff --git a/tools/testing/selftests/mm/ksm_tests.c b/tools/testing/selftes= ts/mm/ksm_tests.c index 5fd7792a0d47..6711f4c61371 100644 --- a/tools/testing/selftests/mm/ksm_tests.c +++ b/tools/testing/selftests/mm/ksm_tests.c @@ -15,7 +15,6 @@ #include "kselftest.h" #include #include "vm_util.h" -#include "hugepage_settings.h" =20 #define KSM_SYSFS_PATH "/sys/kernel/mm/ksm/" #define KSM_FP(s) (KSM_SYSFS_PATH s) diff --git a/tools/testing/selftests/mm/migration.c b/tools/testing/selftes= ts/mm/migration.c index f19d53c69576..a35e2b57e05b 100644 --- a/tools/testing/selftests/mm/migration.c +++ b/tools/testing/selftests/mm/migration.c @@ -5,7 +5,6 @@ */ =20 #include "kselftest_harness.h" -#include "hugepage_settings.h" =20 #include #include @@ -16,6 +15,7 @@ #include #include #include + #include "vm_util.h" =20 #define TWOMEG (2<<20) diff --git a/tools/testing/selftests/mm/pagemap_ioctl.c b/tools/testing/sel= ftests/mm/pagemap_ioctl.c index d9a4fb782ecf..03898b4f6cda 100644 --- a/tools/testing/selftests/mm/pagemap_ioctl.c +++ b/tools/testing/selftests/mm/pagemap_ioctl.c @@ -24,7 +24,6 @@ =20 #include "vm_util.h" #include "kselftest.h" -#include "hugepage_settings.h" =20 #define PAGEMAP_BITS_ALL (PAGE_IS_WPALLOWED | PAGE_IS_WRITTEN | \ PAGE_IS_FILE | PAGE_IS_PRESENT | \ diff --git a/tools/testing/selftests/mm/prctl_thp_disable.c b/tools/testing= /selftests/mm/prctl_thp_disable.c index 82c6e96ea6eb..f9ec1408a6e3 100644 --- a/tools/testing/selftests/mm/prctl_thp_disable.c +++ b/tools/testing/selftests/mm/prctl_thp_disable.c @@ -14,7 +14,6 @@ #include =20 #include "kselftest_harness.h" -#include "hugepage_settings.h" #include "vm_util.h" =20 #ifndef PR_THP_DISABLE_EXCEPT_ADVISED diff --git a/tools/testing/selftests/mm/protection_keys.c b/tools/testing/s= elftests/mm/protection_keys.c index ae6e1530b354..b7882ab97683 100644 --- a/tools/testing/selftests/mm/protection_keys.c +++ b/tools/testing/selftests/mm/protection_keys.c @@ -45,8 +45,8 @@ #include #include #include +#include =20 -#include "hugepage_settings.h" #include "pkey-helpers.h" =20 u64 shadow_pkey_reg; diff --git a/tools/testing/selftests/mm/soft-dirty.c b/tools/testing/selfte= sts/mm/soft-dirty.c index 5f278913c4d7..7f649b673355 100644 --- a/tools/testing/selftests/mm/soft-dirty.c +++ b/tools/testing/selftests/mm/soft-dirty.c @@ -9,7 +9,6 @@ =20 #include "kselftest.h" #include "vm_util.h" -#include "hugepage_settings.h" =20 #define PAGEMAP_FILE_PATH "/proc/self/pagemap" #define TEST_ITERATIONS 10000 diff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/test= ing/selftests/mm/split_huge_page_test.c index a30927514b4f..68f508c9a355 100644 --- a/tools/testing/selftests/mm/split_huge_page_test.c +++ b/tools/testing/selftests/mm/split_huge_page_test.c @@ -21,7 +21,6 @@ #include #include "vm_util.h" #include "kselftest.h" -#include "hugepage_settings.h" =20 uint64_t pagesize; unsigned int pageshift; diff --git a/tools/testing/selftests/mm/thuge-gen.c b/tools/testing/selftes= ts/mm/thuge-gen.c index 50d0805b65db..a04f588df780 100644 --- a/tools/testing/selftests/mm/thuge-gen.c +++ b/tools/testing/selftests/mm/thuge-gen.c @@ -14,7 +14,6 @@ #include #include "vm_util.h" #include "kselftest.h" -#include "hugepage_settings.h" =20 #if !defined(MAP_HUGETLB) #define MAP_HUGETLB 0x40000 diff --git a/tools/testing/selftests/mm/transhuge-stress.c b/tools/testing/= selftests/mm/transhuge-stress.c index 8eb0c5630e7e..96f72898ebe0 100644 --- a/tools/testing/selftests/mm/transhuge-stress.c +++ b/tools/testing/selftests/mm/transhuge-stress.c @@ -17,7 +17,6 @@ #include #include "vm_util.h" #include "kselftest.h" -#include "hugepage_settings.h" =20 int backing_fd =3D -1; int mmap_flags =3D MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE; diff --git a/tools/testing/selftests/mm/uffd-common.h b/tools/testing/selft= ests/mm/uffd-common.h index 92a21b97f745..0723843a7626 100644 --- a/tools/testing/selftests/mm/uffd-common.h +++ b/tools/testing/selftests/mm/uffd-common.h @@ -37,7 +37,6 @@ =20 #include "kselftest.h" #include "vm_util.h" -#include "hugepage_settings.h" =20 #define UFFD_FLAGS (O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY) =20 diff --git a/tools/testing/selftests/mm/uffd-wp-mremap.c b/tools/testing/se= lftests/mm/uffd-wp-mremap.c index 572c2516e874..c48eaab8e75c 100644 --- a/tools/testing/selftests/mm/uffd-wp-mremap.c +++ b/tools/testing/selftests/mm/uffd-wp-mremap.c @@ -7,8 +7,8 @@ #include #include #include +#include #include "kselftest.h" -#include "hugepage_settings.h" #include "uffd-common.h" =20 static int pagemap_fd; diff --git a/tools/testing/selftests/mm/va_high_addr_switch.c b/tools/testi= ng/selftests/mm/va_high_addr_switch.c index e24d7ba00b44..5a354a664d1f 100644 --- a/tools/testing/selftests/mm/va_high_addr_switch.c +++ b/tools/testing/selftests/mm/va_high_addr_switch.c @@ -11,7 +11,6 @@ =20 #include "vm_util.h" #include "kselftest.h" -#include "hugepage_settings.h" =20 /* * The hint addr value is used to allocate addresses diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests= /mm/vm_util.h index fe0475f2bdf2..64a86e8a0c41 100644 --- a/tools/testing/selftests/mm/vm_util.h +++ b/tools/testing/selftests/mm/vm_util.h @@ -9,6 +9,7 @@ #include "kselftest.h" #include #include +#include =20 #define BIT_ULL(nr) (1ULL << (nr)) #define PM_SOFT_DIRTY BIT_ULL(55) --=20 2.53.0 From nobody Fri Sep 25 14:31:44 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id B3A8F43BDA9; Fri, 11 Sep 2026 11:10:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789125054; cv=none; b=KivXJhGoP5heACERqGETp2Q8KiPvGiBqMXsxLbffd3cCM2iCh/R50zDINNQyZWY1SbXl4/Qh6E2JqVayZtoNlimeWu6TWNobet4kOmHMf2wCLEjz74KsZQy7qCPSX2jF0dSQ+zCckIUfZHDjuyTKfA5PegBVqEkPhr/7budMpDc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789125054; c=relaxed/simple; bh=S4NDN/vWEtDNDxtlj2MR1Wvgbm9uPPczj9YQF4sMOig=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mBQdo/UiNiziwAe6crqn4GmFTJoTGS/28/5rov4joswnPWMmj2gEF/Qh/daljl+3wguuf9aBUbE1UkV/G26DDBvwGx2ILXPJ96mTOk2AePa/LEQj6QjVUk6EeCnwH0hIw0WTkyl1J0Rh0/30zgtCX1VUy7co2FB7ehn0IFQek38= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=Wa+hUqhQ; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="Wa+hUqhQ" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 797CC16F2; Fri, 11 Sep 2026 04:10:36 -0700 (PDT) Received: from a081061.blr.arm.com (a081061.arm.com [10.164.19.84]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 809CB3F59E; Fri, 11 Sep 2026 04:10:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1789125040; bh=S4NDN/vWEtDNDxtlj2MR1Wvgbm9uPPczj9YQF4sMOig=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Wa+hUqhQnVC86b2vxe5cYtHQWz2saEaQBQiLdhUFknHKk+Gev2OP0IxctevpmUvsO blHZJWS+IqFmAc/V1vEAb9inokkhQt2eo8RM0YFLJUpJPiIpj+qJlL8RRx2K2D5amg QzrxIKHS5DZ9yPsWcU5ERPgRDE8O607masK3JMCQ= From: Sarthak Sharma To: Andrew Morton , David Hildenbrand Cc: Lorenzo Stoakes , "Liam R . Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Shuah Khan , Shuah Khan , Jonathan Corbet , Jason Gunthorpe , John Hubbard , Peter Xu , Leon Romanovsky , Zi Yan , Baolin Wang , Nico Pache , Ryan Roberts , Dev Jain , Barry Song , Lance Yang , Mark Brown , Anshuman Khandual , Muhammad Usama Anjum , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Sarthak Sharma Subject: [PATCH v10 4/6] tools/mm: move gup_test from selftests/mm to tools/mm Date: Fri, 11 Sep 2026 16:39:48 +0530 Message-ID: <20260911110950.200240-5-sarthak.sharma@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260911110950.200240-1-sarthak.sharma@arm.com> References: <20260911110950.200240-1-sarthak.sharma@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Move tools/testing/selftests/mm/gup_test.c to tools/mm/gup_bench.c. This is the first step in separating its benchmarking and functional testing components. Later patches will make this a purely benchmarking tool and introduce a new functional selftest under selftests/mm. Include hugepage_settings.h directly instead of vm_util.h and use getpagesize() instead of psize(). Adjust the Makefiles in both locations and add gup_bench to tools/mm/.gitignore. Remove the gup_test invocations from run_vmtests.sh and update MAINTAINERS. Also remove the gup_test reference from Documentation/core-api/pin_user_pages.rst. The selftest added later in the series is standalone and does not need per command documentation here. Suggested-by: David Hildenbrand (Arm) Acked-by: Mike Rapoport (Microsoft) Acked-by: David Hildenbrand (Arm) Tested-by: Muhammad Usama Anjum Signed-off-by: Sarthak Sharma --- Documentation/core-api/pin_user_pages.rst | 9 ----- MAINTAINERS | 2 +- tools/mm/.gitignore | 1 + tools/mm/Makefile | 11 ++++-- .../mm/gup_test.c =3D> mm/gup_bench.c} | 8 ++--- tools/testing/selftests/mm/Makefile | 1 - tools/testing/selftests/mm/run_vmtests.sh | 36 ------------------- 7 files changed, 14 insertions(+), 54 deletions(-) rename tools/{testing/selftests/mm/gup_test.c =3D> mm/gup_bench.c} (97%) diff --git a/Documentation/core-api/pin_user_pages.rst b/Documentation/core= -api/pin_user_pages.rst index c16ca163b55e..e0acedbd1d48 100644 --- a/Documentation/core-api/pin_user_pages.rst +++ b/Documentation/core-api/pin_user_pages.rst @@ -226,15 +226,6 @@ will be pinned longterm, and whose data will be access= ed. =20 Unit testing =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D -This file:: - - tools/testing/selftests/mm/gup_test.c - -has the following new calls to exercise the new pin*() wrapper functions: - -* PIN_FAST_BENCHMARK (./gup_test -a) -* PIN_BASIC_TEST (./gup_test -b) - You can monitor how many total dma-pinned pages have been acquired and rel= eased since the system was booted, via two new /proc/vmstat entries: :: =20 diff --git a/MAINTAINERS b/MAINTAINERS index dd5374a1a3c2..cae3af861a7c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17187,8 +17187,8 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/gi= t/akpm/mm 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_longterm.c -F: tools/testing/selftests/mm/gup_test.c =20 MEMORY MANAGEMENT - KSM (Kernel Samepage Merging) M: Andrew Morton diff --git a/tools/mm/.gitignore b/tools/mm/.gitignore index 1446a659e540..154d740be02e 100644 --- a/tools/mm/.gitignore +++ b/tools/mm/.gitignore @@ -3,3 +3,4 @@ slabinfo page-types page_owner_sort thp_swap_allocator_test +gup_bench diff --git a/tools/mm/Makefile b/tools/mm/Makefile index 858186a6eefd..f20a32d8cc22 100644 --- a/tools/mm/Makefile +++ b/tools/mm/Makefile @@ -3,13 +3,15 @@ # include ../scripts/Makefile.include =20 -BUILD_TARGETS=3Dpage-types slabinfo page_owner_sort page_owner_filter thp_= swap_allocator_test +BUILD_TARGETS=3Dpage-types slabinfo page_owner_sort page_owner_filter +BUILD_TARGETS +=3D thp_swap_allocator_test gup_bench INSTALL_TARGETS =3D $(BUILD_TARGETS) thpmaps =20 LIB_DIR =3D ../lib/api LIBS =3D $(LIB_DIR)/libapi.a +GUP_BENCH_OBJS =3D gup_bench.c ../lib/mm/hugepage_settings.c ../lib/mm/fil= e_utils.c =20 -CFLAGS +=3D -Wall -Wextra -I../lib/ -pthread +CFLAGS +=3D -Wall -Wextra -I../lib/ -I../.. -pthread LDFLAGS +=3D $(LIBS) -pthread =20 all: $(BUILD_TARGETS) @@ -22,8 +24,11 @@ $(LIBS): %: %.c $(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) =20 +gup_bench: $(GUP_BENCH_OBJS) $(LIBS) + $(CC) $(CFLAGS) -o $@ $(GUP_BENCH_OBJS) $(LDFLAGS) + clean: - $(RM) page-types slabinfo page_owner_sort page_owner_filter thp_swap_allo= cator_test + $(RM) page-types slabinfo page_owner_sort page_owner_filter thp_swap_allo= cator_test gup_bench make -C $(LIB_DIR) clean =20 sbindir ?=3D /usr/sbin diff --git a/tools/testing/selftests/mm/gup_test.c b/tools/mm/gup_bench.c similarity index 97% rename from tools/testing/selftests/mm/gup_test.c rename to tools/mm/gup_bench.c index 5f44761dbec0..da56aa5324d3 100644 --- a/tools/testing/selftests/mm/gup_test.c +++ b/tools/mm/gup_bench.c @@ -12,8 +12,8 @@ #include #include #include -#include "kselftest.h" -#include "vm_util.h" +#include +#include "../testing/selftests/kselftest.h" =20 #define MB (1UL << 20) =20 @@ -140,7 +140,7 @@ int main(int argc, char **argv) case 'n': nr_pages =3D atoi(optarg); if (nr_pages < 0) - nr_pages =3D size / psize(); + nr_pages =3D size / getpagesize(); break; case 't': thp =3D 1; @@ -254,7 +254,7 @@ int main(int argc, char **argv) madvise(p, size, MADV_NOHUGEPAGE); =20 /* Fault them in here, from user space. */ - for (; (unsigned long)p < gup.addr + size; p +=3D psize()) + for (; (unsigned long)p < gup.addr + size; p +=3D getpagesize()) p[0] =3D 0; =20 tid =3D malloc(sizeof(pthread_t) * nthreads); diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/= mm/Makefile index 7cea3228020d..11ca9b11fef1 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -59,7 +59,6 @@ endif TEST_GEN_FILES =3D cow TEST_GEN_FILES +=3D compaction_test TEST_GEN_FILES +=3D gup_longterm -TEST_GEN_FILES +=3D gup_test TEST_GEN_FILES +=3D hmm-tests TEST_GEN_FILES +=3D hugetlb-madvise TEST_GEN_FILES +=3D hugetlb-mmap diff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/self= tests/mm/run_vmtests.sh index d09f9f6a384e..8f1e828e4f39 100755 --- a/tools/testing/selftests/mm/run_vmtests.sh +++ b/tools/testing/selftests/mm/run_vmtests.sh @@ -130,30 +130,6 @@ test_selected() { fi } =20 -run_gup_matrix() { - # -t: thp=3Don, -T: thp=3Doff, -H: hugetlb=3Don - local hugetlb_mb=3D256 - - for huge in -t -T "-H -m $hugetlb_mb"; do - # -u: gup-fast, -U: gup-basic, -a: pin-fast, -b: pin-basic, -L: pi= n-longterm - for test_cmd in -u -U -a -b -L; do - # -w: write=3D1, -W: write=3D0 - for write in -w -W; do - # -S: shared - for share in -S " "; do - # -n: How many pages to fetch together? 512 is special - # because it's default thp size (or 2M on x86), 123 to - # just test partial gup when hit a huge in whatever fo= rm - for num in "-n 1" "-n 512" "-n 123" "-n -1"; do - CATEGORY=3D"gup_test" run_test ./gup_test \ - $huge $test_cmd $write $share $num - done - done - done - done - done -} - # filter 64bit architectures ARCH64STR=3D"arm64 mips64 parisc64 ppc64 ppc64le riscv64 s390x sparc64 x86= _64" if [ -z "$ARCH" ]; then @@ -275,18 +251,6 @@ fi =20 CATEGORY=3D"mmap" run_test ./map_fixed_noreplace =20 -if $RUN_ALL; then - run_gup_matrix -else - # get_user_pages_fast() benchmark - CATEGORY=3D"gup_test" run_test ./gup_test -u -n 1 - CATEGORY=3D"gup_test" run_test ./gup_test -u -n -1 - # pin_user_pages_fast() benchmark - CATEGORY=3D"gup_test" run_test ./gup_test -a -n 1 - CATEGORY=3D"gup_test" run_test ./gup_test -a -n -1 -fi -# Dump pages 0, 19, and 4096, using pin_user_pages: -CATEGORY=3D"gup_test" run_test ./gup_test -ct -F 0x1 0 19 0x1000 CATEGORY=3D"gup_test" run_test ./gup_longterm =20 CATEGORY=3D"userfaultfd" run_test ./uffd-unit-tests --=20 2.53.0 From nobody Fri Sep 25 14:31:44 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id B17DC4483A6; Fri, 11 Sep 2026 11:10:49 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789125060; cv=none; b=iOswC1teS1DAv6mxB4TfMDO3hLAvaH9H0fI7XjIxyWT3KgZiZl5p9WwKWjd6yt/wgXhuTRpSS4XLeUytSKOJ2M/3fIjLBw3lkzkFrSxxHkPzjb6IwmkEcsiIpzatI5Irk4/QpKz7pYN3mAwRC7S9Kx0OK1hU1AWrWgfWtk0Pui8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789125060; c=relaxed/simple; bh=WzNjlswNqx8BYMXv73ri5FY2D0SBqqOIwm5TBHtFILY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ekPOmc/wZtv74dK3PBSYbSyCbcOkqJ5p36Jb8Ap0DxQb9SfqM9lTX+xZyVix3r1N5ELamSvQRrNFtM0mdsfcmUNuKym+UluveExmG/wO9zd6jyQmw9Q3HBBnC+bh+qw25feg+MTSlif7oH/4hbqRyOjEVyvDxySCmevYCG1x02A= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=sSrSB6C6; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="sSrSB6C6" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id A3392143D; Fri, 11 Sep 2026 04:10:44 -0700 (PDT) Received: from a081061.blr.arm.com (a081061.arm.com [10.164.19.84]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id AF5243F59E; Fri, 11 Sep 2026 04:10:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1789125048; bh=WzNjlswNqx8BYMXv73ri5FY2D0SBqqOIwm5TBHtFILY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sSrSB6C6dhbGILMVE5d4NRfBKce6II0R9gYOBwo5uHNuyyzaGyQ1mqTWp9hoMfsuv Ht7UF0xP2xhOGsPbrrojEC3tAdMkZgoaZO4E2zOWZtd5y7uOBrsrvP6X0j/XVmlvrt A/xD0t3N+Z+X4sYTvvFHoZubOVG8fix0Qlrg574w= From: Sarthak Sharma To: Andrew Morton , David Hildenbrand Cc: Lorenzo Stoakes , "Liam R . Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Shuah Khan , Shuah Khan , Jonathan Corbet , Jason Gunthorpe , John Hubbard , Peter Xu , Leon Romanovsky , Zi Yan , Baolin Wang , Nico Pache , Ryan Roberts , Dev Jain , Barry Song , Lance Yang , Mark Brown , Anshuman Khandual , Muhammad Usama Anjum , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Sarthak Sharma Subject: [PATCH v10 5/6] tools/mm: make gup_bench a benchmark only tool Date: Fri, 11 Sep 2026 16:39:49 +0530 Message-ID: <20260911110950.200240-6-sarthak.sharma@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260911110950.200240-1-sarthak.sharma@arm.com> References: <20260911110950.200240-1-sarthak.sharma@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Remove the functional modes (GUP_BASIC_TEST, PIN_BASIC_TEST and DUMP_USER_PAGES_TEST) from gup_bench. Drop the kselftest dependency and use normal diagnostics and exit statuses. When no arguments are supplied, run a single GUP_FAST_BENCHMARK with the existing default values. Let users select other configurations through command-line options. Report ioctl failures and handle errors without relying on assert(). Suggested-by: David Hildenbrand (Arm) Acked-by: Mike Rapoport (Microsoft) Acked-by: David Hildenbrand (Arm) Tested-by: Muhammad Usama Anjum Signed-off-by: Sarthak Sharma --- tools/mm/gup_bench.c | 183 ++++++++++++++++++------------------------- 1 file changed, 78 insertions(+), 105 deletions(-) diff --git a/tools/mm/gup_bench.c b/tools/mm/gup_bench.c index da56aa5324d3..ff6e46654681 100644 --- a/tools/mm/gup_bench.c +++ b/tools/mm/gup_bench.c @@ -10,10 +10,10 @@ #include #include #include -#include +#include +#include #include #include -#include "../testing/selftests/kselftest.h" =20 #define MB (1UL << 20) =20 @@ -37,12 +37,6 @@ static char *cmd_to_str(unsigned long cmd) return "PIN_FAST_BENCHMARK"; case PIN_LONGTERM_BENCHMARK: return "PIN_LONGTERM_BENCHMARK"; - case GUP_BASIC_TEST: - return "GUP_BASIC_TEST"; - case PIN_BASIC_TEST: - return "PIN_BASIC_TEST"; - case DUMP_USER_PAGES_TEST: - return "DUMP_USER_PAGES_TEST"; } return "Unknown command"; } @@ -52,39 +46,29 @@ void *gup_thread(void *data) struct gup_test gup =3D *(struct gup_test *)data; int i, status; =20 - /* Only report timing information on the *_BENCHMARK commands: */ - if ((cmd =3D=3D PIN_FAST_BENCHMARK) || (cmd =3D=3D GUP_FAST_BENCHMARK) || - (cmd =3D=3D PIN_LONGTERM_BENCHMARK)) { - for (i =3D 0; i < repeats; i++) { - gup.size =3D size; - status =3D ioctl(gup_fd, cmd, &gup); - if (status) - break; + for (i =3D 0; i < repeats; i++) { + gup.size =3D size; + status =3D ioctl(gup_fd, cmd, &gup); + if (status) { + int err =3D errno; =20 pthread_mutex_lock(&print_mutex); - ksft_print_msg("%s: Time: get:%lld put:%lld us", - cmd_to_str(cmd), gup.get_delta_usec, - gup.put_delta_usec); - if (gup.size !=3D size) - ksft_print_msg(", truncated (size: %lld)", gup.size); - ksft_print_msg("\n"); + fprintf(stderr, "%s ioctl failed: %s\n", cmd_to_str(cmd), + strerror(err)); pthread_mutex_unlock(&print_mutex); + return data; } - } else { - gup.size =3D size; - status =3D ioctl(gup_fd, cmd, &gup); - if (status) - goto return_; =20 pthread_mutex_lock(&print_mutex); - ksft_print_msg("%s: done\n", cmd_to_str(cmd)); + printf("%s: Time: get:%lld put:%lld us", + cmd_to_str(cmd), gup.get_delta_usec, + gup.put_delta_usec); if (gup.size !=3D size) - ksft_print_msg("Truncated (size: %lld)\n", gup.size); + printf(", truncated (size: %lld)", gup.size); + printf("\n"); pthread_mutex_unlock(&print_mutex); } =20 -return_: - ksft_test_result(!status, "ioctl status %d\n", status); return NULL; } =20 @@ -92,38 +76,21 @@ int main(int argc, char **argv) { struct gup_test gup =3D { 0 }; int filed, i, opt, nr_pages =3D 1, thp =3D -1, write =3D 1, nthreads =3D = 1, ret; - int flags =3D MAP_PRIVATE; + int flags =3D MAP_PRIVATE, started_threads =3D 0, exit_status =3D 1; char *file =3D "/dev/zero"; - bool hugetlb =3D false; + bool hugetlb =3D false, thread_error =3D false; + void *thread_result; pthread_t *tid; char *p; =20 - while ((opt =3D getopt(argc, argv, "m:r:n:F:f:abcj:tTLUuwWSHpz")) !=3D -1= ) { + while ((opt =3D getopt(argc, argv, "m:r:n:F:f:aj:tTLuwWSH")) !=3D -1) { switch (opt) { case 'a': cmd =3D PIN_FAST_BENCHMARK; break; - case 'b': - cmd =3D PIN_BASIC_TEST; - break; case 'L': cmd =3D PIN_LONGTERM_BENCHMARK; break; - case 'c': - cmd =3D DUMP_USER_PAGES_TEST; - /* - * Dump page 0 (index 1). May be overridden later, by - * user's non-option arguments. - * - * .which_pages is zero-based, so that zero can mean "do - * nothing". - */ - gup.which_pages[0] =3D 1; - break; - case 'p': - /* works only with DUMP_USER_PAGES_TEST */ - gup.test_flags |=3D GUP_TEST_FLAG_DUMP_PAGES_USE_PIN; - break; case 'F': /* strtol, so you can pass flags in hex form */ gup.gup_flags =3D strtol(optarg, 0, 0); @@ -148,9 +115,6 @@ int main(int argc, char **argv) case 'T': thp =3D 0; break; - case 'U': - cmd =3D GUP_BASIC_TEST; - break; case 'u': cmd =3D GUP_FAST_BENCHMARK; break; @@ -172,52 +136,41 @@ int main(int argc, char **argv) hugetlb =3D true; break; default: - ksft_exit_fail_msg("Wrong argument\n"); + fprintf(stderr, "Wrong argument\n"); + exit(1); } } =20 - if (optind < argc) { - int extra_arg_count =3D 0; - /* - * For example: - * - * ./gup_test -c 0 1 0x1001 - * - * ...to dump pages 0, 1, and 4097 - */ - - while ((optind < argc) && - (extra_arg_count < GUP_TEST_MAX_PAGES_TO_DUMP)) { - /* - * Do the 1-based indexing here, so that the user can - * use normal 0-based indexing on the command line. - */ - long page_index =3D strtol(argv[optind], 0, 0) + 1; - - gup.which_pages[extra_arg_count] =3D page_index; - extra_arg_count++; - optind++; - } + if (optind !=3D argc) { + fprintf(stderr, "Unexpected argument '%s'\n", argv[optind]); + exit(1); } =20 - ksft_print_header(); + if (geteuid()) { + fprintf(stderr, "Please run this test as root\n"); + exit(1); + } =20 if (hugetlb) { unsigned long hp_size =3D default_huge_page_size(); =20 - if (!hp_size) - ksft_exit_skip("HugeTLB is unavailable\n"); + if (!hp_size) { + fprintf(stderr, "Could not determine huge page size\n"); + return 1; + } =20 size =3D (size + hp_size - 1) & ~(hp_size - 1); - if (!hugetlb_setup_default(size / hp_size)) - ksft_exit_skip("Not enough huge pages\n"); + if (!hugetlb_setup_default(size / hp_size)) { + fprintf(stderr, "Not enough huge pages\n"); + return 1; + } } =20 - ksft_set_plan(nthreads); - filed =3D open(file, O_RDWR|O_CREAT, 0664); - if (filed < 0) - ksft_exit_fail_msg("Unable to open %s: %s\n", file, strerror(errno)); + if (filed < 0) { + fprintf(stderr, "Unable to open %s: %s\n", file, strerror(errno)); + return 1; + } =20 gup.nr_pages_per_call =3D nr_pages; if (write) @@ -226,26 +179,24 @@ int main(int argc, char **argv) gup_fd =3D open(GUP_TEST_FILE, O_RDWR); if (gup_fd =3D=3D -1) { switch (errno) { - case EACCES: - if (getuid()) - ksft_print_msg("Please run this test as root\n"); - break; case ENOENT: if (opendir("/sys/kernel/debug") =3D=3D NULL) - ksft_print_msg("mount debugfs at /sys/kernel/debug\n"); - ksft_print_msg("check if CONFIG_GUP_TEST is enabled in kernel config\n"= ); + fprintf(stderr, "mount debugfs at /sys/kernel/debug\n"); + fprintf(stderr, "check if CONFIG_GUP_TEST is enabled in kernel config\n= "); break; default: - ksft_print_msg("failed to open %s: %s\n", GUP_TEST_FILE, strerror(errno= )); + fprintf(stderr, "failed to open %s: %s\n", GUP_TEST_FILE, + strerror(errno)); break; } - ksft_test_result_skip("Please run this test as root\n"); - ksft_exit_pass(); + goto err_close_filed; } =20 p =3D mmap(NULL, size, PROT_READ | PROT_WRITE, flags, filed, 0); - if (p =3D=3D MAP_FAILED) - ksft_exit_fail_msg("mmap: %s\n", strerror(errno)); + if (p =3D=3D MAP_FAILED) { + fprintf(stderr, "mmap: %s\n", strerror(errno)); + goto err_close_gup_fd; + } gup.addr =3D (unsigned long)p; =20 if (thp =3D=3D 1) @@ -258,17 +209,39 @@ int main(int argc, char **argv) p[0] =3D 0; =20 tid =3D malloc(sizeof(pthread_t) * nthreads); - assert(tid); + if (!tid) { + fprintf(stderr, "Failed to allocate %d threads: %s\n", + nthreads, strerror(errno)); + goto err_unmap; + } + for (i =3D 0; i < nthreads; i++) { ret =3D pthread_create(&tid[i], NULL, gup_thread, &gup); - assert(ret =3D=3D 0); + if (ret) { + fprintf(stderr, "pthread_create failed: %s\n", strerror(ret)); + thread_error =3D true; + break; + } + started_threads++; } - for (i =3D 0; i < nthreads; i++) { - ret =3D pthread_join(tid[i], NULL); - assert(ret =3D=3D 0); + for (i =3D 0; i < started_threads; i++) { + ret =3D pthread_join(tid[i], &thread_result); + if (ret) { + fprintf(stderr, "pthread_join failed: %s\n", strerror(ret)); + thread_error =3D true; + } else if (thread_result) + thread_error =3D true; } =20 free(tid); - - ksft_exit_pass(); + if (!thread_error) + exit_status =3D 0; + +err_unmap: + munmap((void *)gup.addr, size); +err_close_gup_fd: + close(gup_fd); +err_close_filed: + close(filed); + return exit_status; } --=20 2.53.0 From nobody Fri Sep 25 14:31:44 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 7430949E136; Fri, 11 Sep 2026 11:10:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789125066; cv=none; b=tTeq7x1uCJUzUmrtPV/yN4sJYkAlQKxd1PulObtNvnOrilO7c3zUxjBHf3e/sEZvdOHxqvp0mojchghvSyni6vP/2VIhxVIi0trsYBwVITx7hh96G2ox4WOGPhHZxYtpB1oMpyxxCVQoW0bdh0Up9ufyXljUyQWxjaKpaXBcnO8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789125066; c=relaxed/simple; bh=9tmo7LnCa2gZ4wvu0gRKk4iwWl/CuwVoGBbOWdqP/EI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jLJWQO0xMZERJ39EekI7euTHadUK2R+jxdg7mcgr3s1Lu/Vk5vmFgQltDjjXeWJFiD/46pzoRuwgULhmDTdKLD3RcKlJQ+EUYlg1zYpP0Uz6TAgoNHO4kKDU4+ZcjwVB7yAwl9GU5iCNkaC3M4Yl2AKuIHJ3f9hMwGKPEWa+5YE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b=WVKHKK2C; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=arm.com header.i=@arm.com header.b="WVKHKK2C" Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id D1E1416F2; Fri, 11 Sep 2026 04:10:52 -0700 (PDT) Received: from a081061.blr.arm.com (a081061.arm.com [10.164.19.84]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id DC3523F59E; Fri, 11 Sep 2026 04:10:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1789125056; bh=9tmo7LnCa2gZ4wvu0gRKk4iwWl/CuwVoGBbOWdqP/EI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=WVKHKK2CFRceqwP6ticU/SyBU/FGoDLRCcmtzTdsI2lPWtcXGHbIWX88nv7R0yBJA scGnq6iw62DmXaezxSuhbRbvjeR+vbMnJBddDfuHJkUajBaiCTfFIK52bGgQY68vdZ 6SmcdkicYEKbBoyPttJuiYZxIhCO3JOArbrJ+CSo= From: Sarthak Sharma To: Andrew Morton , David Hildenbrand Cc: Lorenzo Stoakes , "Liam R . Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Shuah Khan , Shuah Khan , Jonathan Corbet , Jason Gunthorpe , John Hubbard , Peter Xu , Leon Romanovsky , Zi Yan , Baolin Wang , Nico Pache , Ryan Roberts , Dev Jain , Barry Song , Lance Yang , Mark Brown , Anshuman Khandual , Muhammad Usama Anjum , linux-mm@kvack.org, linux-kselftest@vger.kernel.org, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, Sarthak Sharma Subject: [PATCH v10 6/6] selftests/mm: add a GUP selftest Date: Fri, 11 Sep 2026 16:39:50 +0530 Message-ID: <20260911110950.200240-7-sarthak.sharma@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260911110950.200240-1-sarthak.sharma@arm.com> References: <20260911110950.200240-1-sarthak.sharma@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 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. Use two default hugeTLB pages and derive the mapping size from their size. This exercises GUP both within a single HugeTLB page and across a HugeTLB boundary, without reserving an excessive number of 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. Suggested-by: David Hildenbrand (Arm) Acked-by: Mike Rapoport (Microsoft) Tested-by: Muhammad Usama Anjum Signed-off-by: Sarthak Sharma Acked-by: David Hildenbrand (Arm) --- MAINTAINERS | 1 + mm/Kconfig | 19 +- tools/testing/selftests/mm/Makefile | 1 + tools/testing/selftests/mm/gup.c | 263 ++++++++++++++++++++++ tools/testing/selftests/mm/run_vmtests.sh | 1 + 5 files changed, 273 insertions(+), 12 deletions(-) create mode 100644 tools/testing/selftests/mm/gup.c diff --git a/MAINTAINERS b/MAINTAINERS index cae3af861a7c..c47e655c4111 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -17188,6 +17188,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 =20 MEMORY MANAGEMENT - KSM (Kernel Samepage Merging) diff --git a/mm/Kconfig b/mm/Kconfig index c180d40cd671..61ab1b8a2ebd 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -1291,24 +1291,19 @@ config PERCPU_STATS be used to help understand percpu memory usage. =20 config GUP_TEST - bool "Enable infrastructure for get_user_pages()-related unit tests" + bool "Enable infrastructure for get_user_pages()-related unit tests and b= enchmarks" 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. =20 - 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. =20 - 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. - - See tools/testing/selftests/mm/gup_test.c + See tools/testing/selftests/mm/gup.c and tools/mm/gup_bench.c. =20 comment "GUP_TEST needs to have DEBUG_FS enabled" depends on !GUP_TEST && !DEBUG_FS diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/= mm/Makefile index 11ca9b11fef1..9c03624fd293 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -58,6 +58,7 @@ endif =20 TEST_GEN_FILES =3D cow TEST_GEN_FILES +=3D compaction_test +TEST_GEN_FILES +=3D gup TEST_GEN_FILES +=3D gup_longterm TEST_GEN_FILES +=3D hmm-tests TEST_GEN_FILES +=3D hugetlb-madvise diff --git a/tools/testing/selftests/mm/gup.c b/tools/testing/selftests/mm/= gup.c new file mode 100644 index 000000000000..31ae38e09136 --- /dev/null +++ b/tools/testing/selftests/mm/gup.c @@ -0,0 +1,263 @@ +// SPDX-License-Identifier: GPL-2.0 +#define __SANE_USERSPACE_TYPES__ // Use ll64 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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[] =3D { 1, 512, 123, -1 }; + +#define GUP_TEST_FILE "/sys/kernel/debug/gup_test" +#define NR_HUGE_PAGES 2 + +static unsigned long hp_size; + +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 =3D false, + .hugetlb =3D false, + .write =3D true, + .shared =3D false, +}; + +FIXTURE_VARIANT_ADD(gup_test, private_read) +{ + .thp =3D false, + .hugetlb =3D false, + .write =3D false, + .shared =3D false, +}; + +FIXTURE_VARIANT_ADD(gup_test, private_write_thp) +{ + .thp =3D true, + .hugetlb =3D false, + .write =3D true, + .shared =3D false, +}; + +FIXTURE_VARIANT_ADD(gup_test, private_read_thp) +{ + .thp =3D true, + .hugetlb =3D false, + .write =3D false, + .shared =3D false, +}; + +FIXTURE_VARIANT_ADD(gup_test, private_write_hugetlb) +{ + .thp =3D false, + .hugetlb =3D true, + .write =3D true, + .shared =3D false, +}; + +FIXTURE_VARIANT_ADD(gup_test, private_read_hugetlb) +{ + .thp =3D false, + .hugetlb =3D true, + .write =3D false, + .shared =3D false, +}; + +FIXTURE_VARIANT_ADD(gup_test, shared_write) +{ + .thp =3D false, + .hugetlb =3D false, + .write =3D true, + .shared =3D true, +}; + +FIXTURE_VARIANT_ADD(gup_test, shared_read) +{ + .thp =3D false, + .hugetlb =3D false, + .write =3D false, + .shared =3D true, +}; + +FIXTURE_VARIANT_ADD(gup_test, shared_write_thp) +{ + .thp =3D true, + .hugetlb =3D false, + .write =3D true, + .shared =3D true, +}; + +FIXTURE_VARIANT_ADD(gup_test, shared_read_thp) +{ + .thp =3D true, + .hugetlb =3D false, + .write =3D false, + .shared =3D true, +}; + +FIXTURE_VARIANT_ADD(gup_test, shared_write_hugetlb) +{ + .thp =3D false, + .hugetlb =3D true, + .write =3D true, + .shared =3D true, +}; + +FIXTURE_VARIANT_ADD(gup_test, shared_read_hugetlb) +{ + .thp =3D false, + .hugetlb =3D true, + .write =3D false, + .shared =3D true, +}; + +FIXTURE_SETUP(gup_test) +{ + int mmap_flags =3D MAP_PRIVATE | MAP_ANONYMOUS; + char *p; + + self->size =3D 128 * MB; + + if (variant->hugetlb) { + if (!hp_size) + SKIP(return, "HugeTLB not available\n"); + + if (hugetlb_free_default_pages() < NR_HUGE_PAGES) + SKIP(return, "Not enough huge pages\n"); + + self->size =3D NR_HUGE_PAGES * hp_size; + mmap_flags |=3D MAP_HUGETLB; + } + + if (variant->shared) + mmap_flags =3D (mmap_flags & ~MAP_PRIVATE) | MAP_SHARED; + + /* gup_fd has to be >=3D 0. Already checked in main() */ + self->gup_fd =3D open(GUP_TEST_FILE, O_RDWR); + ASSERT_GE(self->gup_fd, 0); + + self->addr =3D mmap(NULL, self->size, PROT_READ | PROT_WRITE, + mmap_flags, -1, 0); + + ASSERT_NE(self->addr, MAP_FAILED) { + int err =3D errno; + + close(self->gup_fd); + TH_LOG("mmap failed: %s", strerror(err)); + } + + if (variant->thp) + madvise(self->addr, self->size, MADV_HUGEPAGE); + else if (!variant->hugetlb) + madvise(self->addr, self->size, MADV_NOHUGEPAGE); + + for (p =3D self->addr; (unsigned long)p < (unsigned long)self->addr + + self->size; p +=3D psize()) + p[0] =3D 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 =3D 0; i < (int)ARRAY_SIZE(nr_pages_list); i++) { + struct gup_test gup =3D { + .addr =3D (unsigned long)self->addr, + .size =3D self->size, + .nr_pages_per_call =3D nr_pages_list[i] < 0 ? + self->size / psize() : nr_pages_list[i], + .gup_flags =3D variant->write ? FOLL_WRITE : 0, + }; + + TH_LOG("nr_pages_per_call=3D%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) +{ + int fd; + + fd =3D open(GUP_TEST_FILE, O_RDWR); + if (fd =3D=3D -1) { + ksft_print_header(); + if (errno =3D=3D EACCES) + ksft_exit_skip("Please run this test as root\n"); + if (errno =3D=3D ENOENT) { + DIR *debugfs =3D opendir("/sys/kernel/debug"); + + if (!debugfs) + ksft_exit_skip("Mount debugfs at /sys/kernel/debug\n"); + 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(er= rno)); + } + close(fd); + + hp_size =3D default_huge_page_size(); + if (hp_size) + hugetlb_setup_default(NR_HUGE_PAGES); + + return test_harness_run(argc, argv); +} diff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/self= tests/mm/run_vmtests.sh index 8f1e828e4f39..ae0ab5efabae 100755 --- a/tools/testing/selftests/mm/run_vmtests.sh +++ b/tools/testing/selftests/mm/run_vmtests.sh @@ -251,6 +251,7 @@ fi =20 CATEGORY=3D"mmap" run_test ./map_fixed_noreplace =20 +CATEGORY=3D"gup_test" run_test ./gup CATEGORY=3D"gup_test" run_test ./gup_longterm =20 CATEGORY=3D"userfaultfd" run_test ./uffd-unit-tests --=20 2.53.0