From nobody Fri Sep 25 00:40:54 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id A2E194AAC72; Fri, 18 Sep 2026 11:22:57 +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=1789730580; cv=none; b=WhsM/JrBbMpevT9E52RUYJW++XWmtZeKZpzcTZlpcouegqw9awFUKAAsdSvOr4AG8tgeI2iCpksfpd3Xb0z/9AOBj7SaPlLtfPLmpqtEskMDNXU2zsJIB8Cub2hBS1u8hCklLq7oV3lVLS5wDCNoXWvGRZY1Y9EYpyirWzyEoj8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789730580; c=relaxed/simple; bh=hKA1SxNjuW9vAV8jnUyOq4aXH0ePH/0GOvQ4c1qg2OY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YFj23Scz3YwPOnlYaCSVpRk8AKE9L2yAtA9EXoEBQOd2tqTwbZFbZPOQHxWohyDIbO+xqTuJ7i+fo1YngmX5H29KhIcVXLzVWk9yjP4zU2IjCfX3dP/emaCfhHmji1eKqqiMkzz5q9CSVg0lJeckdeSdb3vrKEk4ErVMS6t6uIA= 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=hZpK6gmp; 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="hZpK6gmp" 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 7A3091596; Fri, 18 Sep 2026 04:22:53 -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 36FBB3F882; Fri, 18 Sep 2026 04:22:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1789730577; bh=hKA1SxNjuW9vAV8jnUyOq4aXH0ePH/0GOvQ4c1qg2OY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=hZpK6gmpFtLHXOrEAUOKBRTt7yTsBX8lQbGWZww+RLS7ueJYNwpKBMkTzL5cAH9yd UitLTEi2CUxkbyHnSArt8aErf4583P6aVSuXHIqpStdf+gX63J5VfuouV2Kx+ts4Id 9Cn7Uqy+i4o48cru2+IatRS1kkLTCA5arsu9NdWw= 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 v11 1/6] selftests/mm: make file helpers return errors Date: Fri, 18 Sep 2026 16:52:29 +0530 Message-ID: <20260918112234.195857-2-sarthak.sharma@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260918112234.195857-1-sarthak.sharma@arm.com> References: <20260918112234.195857-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 584054736ce9..9a63420d0744 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 unsigned long hugetlb_nr_resv_pages(unsigned long size) @@ -511,7 +574,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 00:40:54 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 25C3F4E322F; Fri, 18 Sep 2026 11:23:06 +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=1789730597; cv=none; b=Ke0uj9qOQzg3+jU738XRZNPMGlp15yrQWZouYmfd+dq29bsYNlGcvTh+KXhUHvT49raLZEh0XwL2q3+1txGMfas++vyKig/EfVM3NgTjHzIjwhCBXqZlWW+a/4viC/Bg54iKtHAie2CFssUCa9ApInYMvXn2sOR8CW2EBiRONns= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789730597; c=relaxed/simple; bh=BrhrKyOWleozRhznVBk+PWrdPljvYcLD8claL1Fr3ZI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Eqb8GQqxuHS0VuOxqO4zED9zWyoNM69yKj+Ye7x7dm4Uay5h9n8n+npC6N+jTIgzlIYSP8ZJHNaNEAOSo0EqctRp9uP08VfMes+yg9zVayEJ/7SJLI+6isoislr6LePE7CM4Hpwavy8cQjNRSkUZwmtUY/DP49C7DzUkETYyZ7g= 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=k4+XqSHz; 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="k4+XqSHz" 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 A5D6E1596; Fri, 18 Sep 2026 04:23:01 -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 9821D3F882; Fri, 18 Sep 2026 04:22:57 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1789730585; bh=BrhrKyOWleozRhznVBk+PWrdPljvYcLD8claL1Fr3ZI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=k4+XqSHzbgJWhsefqWDrZVafOC10FIw4xqWAhBwUJUY6+mrbimjmbF0QYYoTbX91k nZ5wkz0VxdpvHUgZEB4Rs1zBGI36e3Xt3ug5zT31NuI2VUAUhlooX+Ocy7UCaI/0ZR xMJnHPwvJ22jRKvMa/Zv4uF6ussASXyxmciCBr7M= 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 v11 2/6] tools/lib/mm: add shared file helpers Date: Fri, 18 Sep 2026 16:52:30 +0530 Message-ID: <20260918112234.195857-3-sarthak.sharma@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260918112234.195857-1-sarthak.sharma@arm.com> References: <20260918112234.195857-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 e4412c3d8d45..34f30d072499 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 d3e9bd67904a..c36a9a7089bb 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 @@ -184,8 +185,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 @@ -214,7 +215,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 @@ -223,7 +224,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 00:40:54 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 620EE4DD3B9; Fri, 18 Sep 2026 11:23:14 +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=1789730602; cv=none; b=HL26ABAMRC7/FHu4Z7G9Whxaep9o65m7l9yhDkbugrMEbAOr7mPnDilI/23Jat2VQQcqLneWAxVx/PDsx9USR970+F8qj44qEp/7YlgIzc0v24iWXw9qDSrvp6dTBYxnv2ZjQjOUS4wl4/aOKgqx5/q3/fa820QaoafVrQmj4SY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789730602; c=relaxed/simple; bh=AQeFAiThHabbJy74sYQtuW5pXFxkDNMyGudI0ECDWjw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=i711KJR4L7vBBwiE7XCeM5/NTwaaNDEif06/I9QvDyVNKXbFZHmk6Rwq1i8SuCpWmbHtxVxryZtQy9M+1Y2REuc4lpjjJ7qFVJ5PXDqcmGIUlEGU5bL5YFe5khTlDQ20QRGi6BhH4rRn9jynBDja4Ht3nAgzpwS48S3mkboAv24= 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=EW/3RStq; 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="EW/3RStq" 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 CDC371BF7; Fri, 18 Sep 2026 04:23:09 -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 BFD543F882; Fri, 18 Sep 2026 04:23:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1789730593; bh=AQeFAiThHabbJy74sYQtuW5pXFxkDNMyGudI0ECDWjw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=EW/3RStqtX/UTv+b5CcN0Imm0HNB6OzRv3JjwjuZb13AbDC7vIvKyrCVvSdTk6x7R eGkP6c7zm0N8hvkkR11xoSf12UTLNKGEMVbKVxmaY9F0+Up9l82bSY6jwrnNTZZGej x1pNFyvkHu4AVZxBPK9sqeIC9Lj5+lCT/dFK9f3A= 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 v11 3/6] tools/lib/mm: move hugepage_settings out of selftests Date: Fri, 18 Sep 2026 16:52:31 +0530 Message-ID: <20260918112234.195857-4-sarthak.sharma@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260918112234.195857-1-sarthak.sharma@arm.com> References: <20260918112234.195857-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 9a63420d0744..66d7d124788f 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; @@ -647,8 +652,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 c36a9a7089bb..67882e52d4ff 100644 --- a/tools/testing/selftests/mm/Makefile +++ b/tools/testing/selftests/mm/Makefile @@ -185,8 +185,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 b724d62d2b75..f7d53ea3c252 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 0f15eff1da04..1d111f42dd59 100644 --- a/tools/testing/selftests/mm/hugetlb_madv_vs_map.c +++ b/tools/testing/selftests/mm/hugetlb_madv_vs_map.c @@ -14,7 +14,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 00:40:54 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 8C0144C77BC; Fri, 18 Sep 2026 11:23:23 +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=1789730607; cv=none; b=o3P1JpaH5mhe6h25qY3fHe0kHOqIinRz7E+SIzcV9WvD9f9NUJI9us+7LNYHjusLzemyHD5r3s+6poV5yIk5AudJlSz9V0sRMX0rdZ5LlftsRLqAkQKUX2Kgy2vcQJCSSXFnpIZ0+kE0H38fqCJ/5/4iUqleWy3mf8iXf1byUo4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789730607; c=relaxed/simple; bh=ljPjjqRMMUURUiMJuppRVtMq0MGpf+iTP6VLw+3eBQw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ObbHGQuxv/3FvEzWPOOGNhoB3FTC0lT4fs/OlawBL65twW49d5udJaREhW9jwcYdIharYBoB8DyXveSCGHAkRytT3cDrL+T7R7e9uSZVr4XuBZGTcNnXL9nfiEtZbT3CN3rcXq/1zbg2NYxCS8B4e7we0V8FDO/L19wJSXLNvAE= 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=Ux7SQeid; 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="Ux7SQeid" 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 002B11596; Fri, 18 Sep 2026 04:23:18 -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 E65CC3F882; Fri, 18 Sep 2026 04:23:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1789730601; bh=ljPjjqRMMUURUiMJuppRVtMq0MGpf+iTP6VLw+3eBQw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Ux7SQeidTxEsfbH+e6zTPCtkzoa+p/qWkTKBk+NEirRq3oA7whFtpgZqMLaCnrzAh CvD7cMiCpAkYQSRTN1gkpstVGxv1J89s9lO6p/QqCi0fOYsEMAZwc8oZ2225KB9tKH 7uyq3i9PRqN06Rnz4uentqJ9+F2+ofAK2wj3OoqQ= 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 v11 4/6] tools/mm: move gup_test from selftests/mm to tools/mm Date: Fri, 18 Sep 2026 16:52:32 +0530 Message-ID: <20260918112234.195857-5-sarthak.sharma@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260918112234.195857-1-sarthak.sharma@arm.com> References: <20260918112234.195857-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 34f30d072499..b6104b7d8054 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 67882e52d4ff..d6337156111a 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 19755fb4edb9..cea59dc5707d 100755 --- a/tools/testing/selftests/mm/run_vmtests.sh +++ b/tools/testing/selftests/mm/run_vmtests.sh @@ -148,30 +148,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 @@ -293,18 +269,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 00:40:54 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 141174E3EED; Fri, 18 Sep 2026 11:23:31 +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=1789730621; cv=none; b=GMzPGjBFKWwykemrMQT0qjd0SRMOsZvb7MpRuGU+RH4B3hk7UG3TMej1s+nD5q4/lPgEkpW+UAInnzpTPya5JFfYBlUGb9K3whr2JPhpXtFr9lrbdeo5K68wnIa2SKq1PMMH64V6ZCkD+gtu6pRKCwW/1EbPNA5jZYR/LWrOOug= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789730621; c=relaxed/simple; bh=WzNjlswNqx8BYMXv73ri5FY2D0SBqqOIwm5TBHtFILY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=P0R9FjGyi6miE5ywbP2w7zofANHNAkIg3eKDAUJiB8ncsTUsBhnID8p+5ul7GSeStvoiuycpZQBipR9XWP+4d/7YvCXsKjahuEOZMfU2pQY/Ly6HX4/GwvT+WDvJPEWzYaL23/hBLFZSxkO4VqFZV1LUs1+pnSVlkzv8Uo7vIT0= 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=nVLiGBlw; 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="nVLiGBlw" 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 226231596; Fri, 18 Sep 2026 04:23:26 -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 199B63F882; Fri, 18 Sep 2026 04:23:21 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1789730609; bh=WzNjlswNqx8BYMXv73ri5FY2D0SBqqOIwm5TBHtFILY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nVLiGBlwVqr46LWCapQzGBb8EDYyB+xGO9y19/BWBfDtfvT8MjHsW6xBF8WRTGpnV s2uAvQUvTCIZYxMff/lGnjzozm8oHpDfKbOYC/QSTw/0Uk6Xwcb8rlTYRZvX5zcJR4 wD6kdxgqiFd9Ylq9wJ+kzTwDT9a4BxgdYkETDfUw= 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 v11 5/6] tools/mm: make gup_bench a benchmark only tool Date: Fri, 18 Sep 2026 16:52:33 +0530 Message-ID: <20260918112234.195857-6-sarthak.sharma@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260918112234.195857-1-sarthak.sharma@arm.com> References: <20260918112234.195857-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 00:40:54 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 709534E3222; Fri, 18 Sep 2026 11:23:39 +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=1789730623; cv=none; b=NFtYBgEHNfbVPP/xAIE2O1rUsaYeuEunHL6b844LAiNT+wTIBS1+cyJ5cIF3ZTikIMdTugEkimtYZHPypk17JiD4H4+8m4ngLFKyrP0rjbUhWXVk3uOnUeOyhTdukKybaYIV5iM986gLw1EgGDdO/+XNWY7JXDXJzIkKA5mX3cQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789730623; c=relaxed/simple; bh=Eiy/pRfgLh1eAlmrlllYweUczsrrEbMKedfGiTrN5OI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=CgO8JSABLh1GMz1M3Qj2h7M4TfuHrjOoS/DcoUgc0M1eCU3uYXLZex9vYFkBVAoOtlDnpPm4YJJtSoCtcUxpgK5imuXTR9mSM7CHOKXcWdzmctA84RkSErwnEd3w8x1IDGIYplNxad1o3lOpna2D+szDBAb64GAB8setc36GuDY= 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=D2cHoCq/; 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="D2cHoCq/" 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 4CE6D1BF7; Fri, 18 Sep 2026 04:23:34 -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 3FCAC3F882; Fri, 18 Sep 2026 04:23:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=arm.com; s=foss; t=1789730617; bh=Eiy/pRfgLh1eAlmrlllYweUczsrrEbMKedfGiTrN5OI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=D2cHoCq/arcUgYS+vPa2Qz8y8e50cVzVS1tkIg3HadRsJ0tDKWglDbvqGm36PfwrX QketPuOb41x3kVzKlUlxGsd2HrV/0S595fJpZZAkIPHheiKe6kn6rStCEYQ1gYDYap 83TgmDUZPrzWjAy+N01Ldis4UmzvgdU7JMbIBAcc= 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 v11 6/6] selftests/mm: add a GUP selftest Date: Fri, 18 Sep 2026 16:52:34 +0530 Message-ID: <20260918112234.195857-7-sarthak.sharma@arm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260918112234.195857-1-sarthak.sharma@arm.com> References: <20260918112234.195857-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) Acked-by: David Hildenbrand (Arm) Tested-by: Muhammad Usama Anjum Signed-off-by: Sarthak Sharma --- MAINTAINERS | 1 + mm/Kconfig | 19 +- tools/testing/selftests/mm/Makefile | 1 + tools/testing/selftests/mm/gup.c | 262 ++++++++++++++++++++++ tools/testing/selftests/mm/run_vmtests.sh | 1 + 5 files changed, 272 insertions(+), 12 deletions(-) create mode 100644 tools/testing/selftests/mm/gup.c diff --git a/MAINTAINERS b/MAINTAINERS index b6104b7d8054..a3aca56a4a30 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 30170a936f1f..edb4a6c0a870 100644 --- a/mm/Kconfig +++ b/mm/Kconfig @@ -1292,24 +1292,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 d6337156111a..7d69baeb93f4 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..a6a8ca47d12e --- /dev/null +++ b/tools/testing/selftests/mm/gup.c @@ -0,0 +1,262 @@ +// 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_HUGETLB_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_HUGETLB_PAGES) + SKIP(return, "Not enough huge pages\n"); + + self->size =3D NR_HUGETLB_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) +{ + const int 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_HUGETLB_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 cea59dc5707d..4cc1d1a55ebf 100755 --- a/tools/testing/selftests/mm/run_vmtests.sh +++ b/tools/testing/selftests/mm/run_vmtests.sh @@ -269,6 +269,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