| Seq | Timestamp | Type | Name | Duration |
|---|---|---|---|---|
| 0/0 | 2026/09/11 12:46 | flow | patch-triage |
0mArgs:null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"KMSANReasoning": "",
"NeedsKMSAN": false,
"Reasoning": "The patch modifies only userspace tools and selftests (tools/lib/mm/, tools/mm/, tools/testing/selftests/mm/), documentation (Documentation/core-api/pin_user_pages.rst), MAINTAINERS, and Kconfig help text (mm/Kconfig). No compiled kernel C logic is affected.",
"WorthFuzzing": false
} |
| 1/1 | 2026/09/11 12:46 | action | read-patch-diff |
0mArgs:null Results: {
"PatchDiff": "commit 8130d75271d743a2b21dbcb4a6b365ba04f740d4\nAuthor: syz-cluster \u003ctriage@syzkaller.com\u003e\nDate: Fri Sep 11 12:46:57 2026 +0000\n\n syz-cluster: applied patch under review\n\ndiff --git a/Documentation/core-api/pin_user_pages.rst b/Documentation/core-api/pin_user_pages.rst\nindex c16ca163b55e3..e0acedbd1d486 100644\n--- a/Documentation/core-api/pin_user_pages.rst\n+++ b/Documentation/core-api/pin_user_pages.rst\n@@ -226,15 +226,6 @@ will be pinned longterm, and whose data will be accessed.\n \n Unit testing\n ============\n-This file::\n-\n- tools/testing/selftests/mm/gup_test.c\n-\n-has the following new calls to exercise the new pin*() wrapper functions:\n-\n-* PIN_FAST_BENCHMARK (./gup_test -a)\n-* PIN_BASIC_TEST (./gup_test -b)\n-\n You can monitor how many total dma-pinned pages have been acquired and released\n since the system was booted, via two new /proc/vmstat entries: ::\n \ndiff --git a/MAINTAINERS b/MAINTAINERS\nindex 35262aa3e67ef..c47e655c41112 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -17187,8 +17187,9 @@ T:\tgit git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm\n F:\tmm/gup.c\n F:\tmm/gup_test.c\n F:\tmm/gup_test.h\n+F:\ttools/mm/gup_bench.c\n+F:\ttools/testing/selftests/mm/gup.c\n F:\ttools/testing/selftests/mm/gup_longterm.c\n-F:\ttools/testing/selftests/mm/gup_test.c\n \n MEMORY MANAGEMENT - KSM (Kernel Samepage Merging)\n M:\tAndrew Morton \u003cakpm@linux-foundation.org\u003e\n@@ -17295,6 +17296,7 @@ F:\tmm/memory-tiers.c\n F:\tmm/page_idle.c\n F:\tmm/pgalloc-track.h\n F:\tmm/process_vm_access.c\n+F:\ttools/lib/mm/\n F:\ttools/testing/selftests/mm/\n \n MEMORY MANAGEMENT - NUMA MEMBLOCKS AND NUMA EMULATION\ndiff --git a/mm/Kconfig b/mm/Kconfig\nindex c180d40cd6712..61ab1b8a2ebdf 100644\n--- a/mm/Kconfig\n+++ b/mm/Kconfig\n@@ -1291,24 +1291,19 @@ config PERCPU_STATS\n \t be used to help understand percpu memory usage.\n \n config GUP_TEST\n-\tbool \"Enable infrastructure for get_user_pages()-related unit tests\"\n+\tbool \"Enable infrastructure for get_user_pages()-related unit tests and benchmarks\"\n \tdepends on DEBUG_FS\n \thelp\n \t Provides /sys/kernel/debug/gup_test, which in turn provides a way\n-\t to make ioctl calls that can launch kernel-based unit tests for\n-\t the get_user_pages*() and pin_user_pages*() family of API calls.\n+\t to make ioctl calls that can launch kernel-based unit tests and\n+\t benchmarks for the get_user_pages*() and pin_user_pages*() families\n+\t of API calls.\n \n-\t These tests include benchmark testing of the _fast variants of\n-\t get_user_pages*() and pin_user_pages*(), as well as smoke tests of\n+\t These include benchmark testing of the _fast variants of\n+\t get_user_pages*() and pin_user_pages*(), as well as tests of\n \t the non-_fast variants.\n \n-\t There is also a sub-test that allows running dump_page() on any\n-\t of up to eight pages (selected by command line args) within the\n-\t range of user-space addresses. These pages are either pinned via\n-\t pin_user_pages*(), or pinned via get_user_pages*(), as specified\n-\t by other command line arguments.\n-\n-\t See tools/testing/selftests/mm/gup_test.c\n+\t See tools/testing/selftests/mm/gup.c and tools/mm/gup_bench.c.\n \n comment \"GUP_TEST needs to have DEBUG_FS enabled\"\n \tdepends on !GUP_TEST \u0026\u0026 !DEBUG_FS\ndiff --git a/tools/lib/mm/file_utils.c b/tools/lib/mm/file_utils.c\nnew file mode 100644\nindex 0000000000000..9b2237e9823e9\n--- /dev/null\n+++ b/tools/lib/mm/file_utils.c\n@@ -0,0 +1,106 @@\n+// SPDX-License-Identifier: GPL-2.0\n+#include \u003cerrno.h\u003e\n+#include \u003cfcntl.h\u003e\n+#include \u003cstdio.h\u003e\n+#include \u003cstdlib.h\u003e\n+#include \u003cstring.h\u003e\n+#include \u003cunistd.h\u003e\n+\n+#include \"file_utils.h\"\n+\n+int read_file(const char *path, char *buf, size_t buflen)\n+{\n+\tint fd, err;\n+\tssize_t numread;\n+\n+\tfd = open(path, O_RDONLY);\n+\tif (fd == -1)\n+\t\treturn -errno;\n+\n+\tnumread = read(fd, buf, buflen - 1);\n+\tif (numread \u003c 1) {\n+\t\terr = numread ? errno : ENODATA;\n+\t\tclose(fd);\n+\t\treturn -err;\n+\t}\n+\n+\tbuf[numread] = '\\0';\n+\tclose(fd);\n+\n+\treturn 0;\n+}\n+\n+int write_file(const char *path, const char *buf, size_t buflen)\n+{\n+\tint fd, saved_errno;\n+\tssize_t numwritten;\n+\n+\tif (buflen \u003c 2)\n+\t\treturn -EINVAL;\n+\n+\tfd = open(path, O_WRONLY);\n+\tif (fd == -1)\n+\t\treturn -errno;\n+\n+\tnumwritten = write(fd, buf, buflen - 1);\n+\tsaved_errno = errno;\n+\tclose(fd);\n+\n+\tif (numwritten \u003c 0)\n+\t\treturn -saved_errno;\n+\n+\tif (numwritten != (ssize_t)(buflen - 1))\n+\t\treturn -EIO;\n+\n+\treturn 0;\n+}\n+\n+int read_num(const char *path, unsigned long *num)\n+{\n+\tunsigned long val;\n+\tint ret;\n+\tchar buf[21];\n+\tchar *end;\n+\n+\tif (!num)\n+\t\treturn -EINVAL;\n+\n+\tret = read_file(path, buf, sizeof(buf));\n+\tif (ret)\n+\t\treturn ret;\n+\n+\t/* Reject signs and leading whitespace that are accepted by strtoul() */\n+\tif (buf[0] \u003c '0' || buf[0] \u003e '9')\n+\t\treturn -EINVAL;\n+\n+\terrno = 0;\n+\tval = strtoul(buf, \u0026end, 10);\n+\tif (errno)\n+\t\treturn -errno;\n+\n+\t/* Only allow a newline after the number */\n+\tif (*end == '\\n')\n+\t\tend++;\n+\n+\tif (*end != '\\0')\n+\t\treturn -EINVAL;\n+\n+\t*num = val;\n+\treturn 0;\n+}\n+\n+int write_num(const char *path, unsigned long num)\n+{\n+\tchar buf[21];\n+\n+\tsprintf(buf, \"%lu\", num);\n+\treturn write_file(path, buf, strlen(buf) + 1);\n+}\n+\n+int write_num_ignore_einval(const char *path, unsigned long num)\n+{\n+\tint ret;\n+\n+\tret = write_num(path, num);\n+\treturn ret == -EINVAL ? 0 : ret;\n+}\ndiff --git a/tools/lib/mm/file_utils.h b/tools/lib/mm/file_utils.h\nnew file mode 100644\nindex 0000000000000..50daa82c2b2b4\n--- /dev/null\n+++ b/tools/lib/mm/file_utils.h\n@@ -0,0 +1,13 @@\n+/* SPDX-License-Identifier: GPL-2.0 */\n+#ifndef __MM_FILE_UTILS_H__\n+#define __MM_FILE_UTILS_H__\n+\n+#include \u003cstddef.h\u003e\n+\n+int read_file(const char *path, char *buf, size_t buflen);\n+int write_file(const char *path, const char *buf, size_t buflen);\n+int read_num(const char *path, unsigned long *num);\n+int write_num(const char *path, unsigned long num);\n+int write_num_ignore_einval(const char *path, unsigned long num);\n+\n+#endif\ndiff --git a/tools/testing/selftests/mm/hugepage_settings.c b/tools/lib/mm/hugepage_settings.c\nsimilarity index 87%\nrename from tools/testing/selftests/mm/hugepage_settings.c\nrename to tools/lib/mm/hugepage_settings.c\nindex d7917dce3abac..abd9f7182f88f 100644\n--- a/tools/testing/selftests/mm/hugepage_settings.c\n+++ b/tools/lib/mm/hugepage_settings.c\n@@ -8,12 +8,18 @@\n #include \u003cstdlib.h\u003e\n #include \u003cstring.h\u003e\n #include \u003cunistd.h\u003e\n+#include \u003cerrno.h\u003e\n \n-#include \"vm_util.h\"\n+#include \"file_utils.h\"\n #include \"hugepage_settings.h\"\n \n #define THP_SYSFS \"/sys/kernel/mm/transparent_hugepage/\"\n #define MAX_SETTINGS_DEPTH 4\n+\n+#ifndef ARRAY_SIZE\n+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))\n+#endif\n+\n static struct thp_settings settings_stack[MAX_SETTINGS_DEPTH];\n static int settings_index;\n static struct thp_settings saved_settings;\n@@ -48,6 +54,11 @@ static const char * const shmem_enabled_strings[] = {\n \tNULL\n };\n \n+static void print_file_access_error(const char *path, int ret)\n+{\n+\tprintf(\"# %s: %s (%d)\\n\", path, strerror(-ret), -ret);\n+}\n+\n int thp_read_string(const char *name, const char * const strings[])\n {\n \tchar path[PATH_MAX];\n@@ -61,8 +72,9 @@ int thp_read_string(const char *name, const char * const strings[])\n \t\texit(EXIT_FAILURE);\n \t}\n \n-\tif (!read_file(path, buf, sizeof(buf))) {\n-\t\tperror(path);\n+\tret = read_file(path, buf, sizeof(buf));\n+\tif (ret) {\n+\t\tprint_file_access_error(path, ret);\n \t\texit(EXIT_FAILURE);\n \t}\n \n@@ -103,12 +115,17 @@ void thp_write_string(const char *name, const char *val)\n \t\tprintf(\"%s: Pathname is too long\\n\", __func__);\n \t\texit(EXIT_FAILURE);\n \t}\n-\twrite_file(path, val, strlen(val) + 1);\n+\tret = write_file(path, val, strlen(val) + 1);\n+\tif (ret) {\n+\t\tprint_file_access_error(path, ret);\n+\t\texit(EXIT_FAILURE);\n+\t}\n }\n \n unsigned long thp_read_num(const char *name)\n {\n \tchar path[PATH_MAX];\n+\tunsigned long num;\n \tint ret;\n \n \tret = snprintf(path, PATH_MAX, THP_SYSFS \"%s\", name);\n@@ -116,7 +133,13 @@ unsigned long thp_read_num(const char *name)\n \t\tprintf(\"%s: Pathname is too long\\n\", __func__);\n \t\texit(EXIT_FAILURE);\n \t}\n-\treturn read_num(path);\n+\tret = read_num(path, \u0026num);\n+\tif (ret) {\n+\t\tprint_file_access_error(path, ret);\n+\t\texit(EXIT_FAILURE);\n+\t}\n+\n+\treturn num;\n }\n \n void thp_write_num(const char *name, unsigned long num)\n@@ -129,7 +152,11 @@ void thp_write_num(const char *name, unsigned long num)\n \t\tprintf(\"%s: Pathname is too long\\n\", __func__);\n \t\texit(EXIT_FAILURE);\n \t}\n-\twrite_num(path, num);\n+\tret = write_num(path, num);\n+\tif (ret) {\n+\t\tprint_file_access_error(path, ret);\n+\t\texit(EXIT_FAILURE);\n+\t}\n }\n \n void thp_read_settings(struct thp_settings *settings)\n@@ -157,8 +184,15 @@ void thp_read_settings(struct thp_settings *settings)\n \t\t.max_ptes_shared = thp_read_num(\"khugepaged/max_ptes_shared\"),\n \t\t.pages_to_scan = thp_read_num(\"khugepaged/pages_to_scan\"),\n \t};\n-\tif (dev_queue_read_ahead_path[0])\n-\t\tsettings-\u003eread_ahead_kb = read_num(dev_queue_read_ahead_path);\n+\tif (dev_queue_read_ahead_path[0]) {\n+\t\tint ret = read_num(dev_queue_read_ahead_path,\n+\t\t\t\t \u0026settings-\u003eread_ahead_kb);\n+\n+\t\tif (ret) {\n+\t\t\tprint_file_access_error(dev_queue_read_ahead_path, ret);\n+\t\t\texit(EXIT_FAILURE);\n+\t\t}\n+\t}\n \n \tfor (i = 0; i \u003c NR_ORDERS; i++) {\n \t\tif (!((1 \u003c\u003c i) \u0026 orders)) {\n@@ -208,8 +242,15 @@ void thp_write_settings(struct thp_settings *settings)\n \tthp_write_num(\"khugepaged/max_ptes_shared\", khugepaged-\u003emax_ptes_shared);\n \tthp_write_num(\"khugepaged/pages_to_scan\", khugepaged-\u003epages_to_scan);\n \n-\tif (dev_queue_read_ahead_path[0])\n-\t\twrite_num(dev_queue_read_ahead_path, settings-\u003eread_ahead_kb);\n+\tif (dev_queue_read_ahead_path[0]) {\n+\t\tint ret = write_num(dev_queue_read_ahead_path,\n+\t\t\t\t settings-\u003eread_ahead_kb);\n+\n+\t\tif (ret) {\n+\t\t\tprint_file_access_error(dev_queue_read_ahead_path, ret);\n+\t\t\texit(EXIT_FAILURE);\n+\t\t}\n+\t}\n \n \tfor (i = 0; i \u003c NR_ORDERS; i++) {\n \t\tif (!((1 \u003c\u003c i) \u0026 orders))\n@@ -307,8 +348,15 @@ static unsigned long __thp_supported_orders(bool is_shmem)\n \t\t}\n \n \t\tret = read_file(path, buf, sizeof(buf));\n-\t\tif (ret)\n-\t\t\torders |= 1UL \u003c\u003c i;\n+\t\tif (ret) {\n+\t\t\tif (ret != -ENOENT) {\n+\t\t\t\tprint_file_access_error(path, ret);\n+\t\t\t\texit(EXIT_FAILURE);\n+\t\t\t}\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\torders |= 1UL \u003c\u003c i;\n \t}\n \n \treturn orders;\n@@ -382,8 +430,7 @@ int detect_hugetlb_page_sizes(unsigned long sizes[], int max)\n \t\tif (sscanf(entry-\u003ed_name, \"hugepages-%zukB\", \u0026kb) != 1)\n \t\t\tcontinue;\n \t\tsizes[count++] = kb * 1024;\n-\t\tksft_print_msg(\"[INFO] detected hugetlb page size: %zu KiB\\n\",\n-\t\t\t kb);\n+\t\tprintf(\"# [INFO] detected hugetlb page size: %zu KiB\\n\", kb);\n \t}\n \tclosedir(dir);\n \treturn count;\n@@ -425,28 +472,49 @@ static void hugetlb_sysfs_path(char *buf, size_t buflen,\n unsigned long hugetlb_nr_pages(unsigned long size)\n {\n \tchar path[PATH_MAX];\n+\tunsigned long nr;\n+\tint ret;\n \n \thugetlb_sysfs_path(path, sizeof(path), size, \"nr_hugepages\");\n \n-\treturn read_num(path);\n+\tret = read_num(path, \u0026nr);\n+\tif (ret) {\n+\t\tprint_file_access_error(path, ret);\n+\t\texit(EXIT_FAILURE);\n+\t}\n+\n+\treturn nr;\n }\n \n void hugetlb_set_nr_pages(unsigned long size, unsigned long nr)\n {\n \tchar path[PATH_MAX];\n+\tint ret;\n \n \thugetlb_sysfs_path(path, sizeof(path), size, \"nr_hugepages\");\n \n-\twrite_num_ignore_einval(path, nr);\n+\tret = write_num_ignore_einval(path, nr);\n+\tif (ret) {\n+\t\tprint_file_access_error(path, ret);\n+\t\texit(EXIT_FAILURE);\n+\t}\n }\n \n unsigned long hugetlb_free_pages(unsigned long size)\n {\n \tchar path[PATH_MAX];\n+\tunsigned long nr;\n+\tint ret;\n \n \thugetlb_sysfs_path(path, sizeof(path), size, \"free_hugepages\");\n \n-\treturn read_num(path);\n+\tret = read_num(path, \u0026nr);\n+\tif (ret) {\n+\t\tprint_file_access_error(path, ret);\n+\t\texit(EXIT_FAILURE);\n+\t}\n+\n+\treturn nr;\n }\n \n static bool __hugetlb_setup(unsigned long size, unsigned long nr)\n@@ -502,7 +570,8 @@ unsigned long hugetlb_setup(unsigned long nr, unsigned long sizes[],\n \t\treturn 0;\n \n \tif (nr_enabled \u003e max) {\n-\t\tksft_print_msg(\"detected %d huge page sizes, will only test %d\\n\", nr_enabled, max);\n+\t\tprintf(\"# detected %d huge page sizes, will only test %d\\n\",\n+\t\t nr_enabled, max);\n \t\tnr_enabled = max;\n \t}\n \n@@ -574,8 +643,10 @@ static void hugepage_restore_settings_atexit(void)\n \n static void hugepage_restore_settings_sighandler(int sig)\n {\n+\t(void)sig;\n+\n \t/* exit() will invoke the hugepage_restore_settings_atexit handler. */\n-\texit(KSFT_FAIL);\n+\texit(EXIT_FAILURE);\n }\n \n void hugepage_save_settings(bool thp, bool hugetlb)\ndiff --git a/tools/testing/selftests/mm/hugepage_settings.h b/tools/lib/mm/hugepage_settings.h\nsimilarity index 100%\nrename from tools/testing/selftests/mm/hugepage_settings.h\nrename to tools/lib/mm/hugepage_settings.h\ndiff --git a/tools/mm/.gitignore b/tools/mm/.gitignore\nindex 1446a659e5408..154d740be02e8 100644\n--- a/tools/mm/.gitignore\n+++ b/tools/mm/.gitignore\n@@ -3,3 +3,4 @@ slabinfo\n page-types\n page_owner_sort\n thp_swap_allocator_test\n+gup_bench\ndiff --git a/tools/mm/Makefile b/tools/mm/Makefile\nindex 858186a6eefdb..f20a32d8cc22e 100644\n--- a/tools/mm/Makefile\n+++ b/tools/mm/Makefile\n@@ -3,13 +3,15 @@\n #\n include ../scripts/Makefile.include\n \n-BUILD_TARGETS=page-types slabinfo page_owner_sort page_owner_filter thp_swap_allocator_test\n+BUILD_TARGETS=page-types slabinfo page_owner_sort page_owner_filter\n+BUILD_TARGETS += thp_swap_allocator_test gup_bench\n INSTALL_TARGETS = $(BUILD_TARGETS) thpmaps\n \n LIB_DIR = ../lib/api\n LIBS = $(LIB_DIR)/libapi.a\n+GUP_BENCH_OBJS = gup_bench.c ../lib/mm/hugepage_settings.c ../lib/mm/file_utils.c\n \n-CFLAGS += -Wall -Wextra -I../lib/ -pthread\n+CFLAGS += -Wall -Wextra -I../lib/ -I../.. -pthread\n LDFLAGS += $(LIBS) -pthread\n \n all: $(BUILD_TARGETS)\n@@ -22,8 +24,11 @@ $(LIBS):\n %: %.c\n \t$(CC) $(CFLAGS) -o $@ $\u003c $(LDFLAGS)\n \n+gup_bench: $(GUP_BENCH_OBJS) $(LIBS)\n+\t$(CC) $(CFLAGS) -o $@ $(GUP_BENCH_OBJS) $(LDFLAGS)\n+\n clean:\n-\t$(RM) page-types slabinfo page_owner_sort page_owner_filter thp_swap_allocator_test\n+\t$(RM) page-types slabinfo page_owner_sort page_owner_filter thp_swap_allocator_test gup_bench\n \tmake -C $(LIB_DIR) clean\n \n sbindir ?= /usr/sbin\ndiff --git a/tools/testing/selftests/mm/gup_test.c b/tools/mm/gup_bench.c\nsimilarity index 50%\nrename from tools/testing/selftests/mm/gup_test.c\nrename to tools/mm/gup_bench.c\nindex 3f841a96f8706..ff6e466546813 100644\n--- a/tools/testing/selftests/mm/gup_test.c\n+++ b/tools/mm/gup_bench.c\n@@ -10,11 +10,10 @@\n #include \u003csys/stat.h\u003e\n #include \u003csys/types.h\u003e\n #include \u003cpthread.h\u003e\n-#include \u003cassert.h\u003e\n+#include \u003cstdbool.h\u003e\n+#include \u003cstring.h\u003e\n #include \u003cmm/gup_test.h\u003e\n-#include \"kselftest.h\"\n-#include \"vm_util.h\"\n-#include \"hugepage_settings.h\"\n+#include \u003cmm/hugepage_settings.h\u003e\n \n #define MB (1UL \u003c\u003c 20)\n \n@@ -38,12 +37,6 @@ static char *cmd_to_str(unsigned long cmd)\n \t\treturn \"PIN_FAST_BENCHMARK\";\n \tcase PIN_LONGTERM_BENCHMARK:\n \t\treturn \"PIN_LONGTERM_BENCHMARK\";\n-\tcase GUP_BASIC_TEST:\n-\t\treturn \"GUP_BASIC_TEST\";\n-\tcase PIN_BASIC_TEST:\n-\t\treturn \"PIN_BASIC_TEST\";\n-\tcase DUMP_USER_PAGES_TEST:\n-\t\treturn \"DUMP_USER_PAGES_TEST\";\n \t}\n \treturn \"Unknown command\";\n }\n@@ -53,39 +46,29 @@ void *gup_thread(void *data)\n \tstruct gup_test gup = *(struct gup_test *)data;\n \tint i, status;\n \n-\t/* Only report timing information on the *_BENCHMARK commands: */\n-\tif ((cmd == PIN_FAST_BENCHMARK) || (cmd == GUP_FAST_BENCHMARK) ||\n-\t (cmd == PIN_LONGTERM_BENCHMARK)) {\n-\t\tfor (i = 0; i \u003c repeats; i++) {\n-\t\t\tgup.size = size;\n-\t\t\tstatus = ioctl(gup_fd, cmd, \u0026gup);\n-\t\t\tif (status)\n-\t\t\t\tbreak;\n+\tfor (i = 0; i \u003c repeats; i++) {\n+\t\tgup.size = size;\n+\t\tstatus = ioctl(gup_fd, cmd, \u0026gup);\n+\t\tif (status) {\n+\t\t\tint err = errno;\n \n \t\t\tpthread_mutex_lock(\u0026print_mutex);\n-\t\t\tksft_print_msg(\"%s: Time: get:%lld put:%lld us\",\n-\t\t\t\t cmd_to_str(cmd), gup.get_delta_usec,\n-\t\t\t\t gup.put_delta_usec);\n-\t\t\tif (gup.size != size)\n-\t\t\t\tksft_print_msg(\", truncated (size: %lld)\", gup.size);\n-\t\t\tksft_print_msg(\"\\n\");\n+\t\t\tfprintf(stderr, \"%s ioctl failed: %s\\n\", cmd_to_str(cmd),\n+\t\t\t\tstrerror(err));\n \t\t\tpthread_mutex_unlock(\u0026print_mutex);\n+\t\t\treturn data;\n \t\t}\n-\t} else {\n-\t\tgup.size = size;\n-\t\tstatus = ioctl(gup_fd, cmd, \u0026gup);\n-\t\tif (status)\n-\t\t\tgoto return_;\n \n \t\tpthread_mutex_lock(\u0026print_mutex);\n-\t\tksft_print_msg(\"%s: done\\n\", cmd_to_str(cmd));\n+\t\tprintf(\"%s: Time: get:%lld put:%lld us\",\n+\t\t\tcmd_to_str(cmd), gup.get_delta_usec,\n+\t\t\tgup.put_delta_usec);\n \t\tif (gup.size != size)\n-\t\t\tksft_print_msg(\"Truncated (size: %lld)\\n\", gup.size);\n+\t\t\tprintf(\", truncated (size: %lld)\", gup.size);\n+\t\tprintf(\"\\n\");\n \t\tpthread_mutex_unlock(\u0026print_mutex);\n \t}\n \n-return_:\n-\tksft_test_result(!status, \"ioctl status %d\\n\", status);\n \treturn NULL;\n }\n \n@@ -93,38 +76,21 @@ int main(int argc, char **argv)\n {\n \tstruct gup_test gup = { 0 };\n \tint filed, i, opt, nr_pages = 1, thp = -1, write = 1, nthreads = 1, ret;\n-\tint flags = MAP_PRIVATE;\n+\tint flags = MAP_PRIVATE, started_threads = 0, exit_status = 1;\n \tchar *file = \"/dev/zero\";\n-\tbool hugetlb = false;\n+\tbool hugetlb = false, thread_error = false;\n+\tvoid *thread_result;\n \tpthread_t *tid;\n \tchar *p;\n \n-\twhile ((opt = getopt(argc, argv, \"m:r:n:F:f:abcj:tTLUuwWSHpz\")) != -1) {\n+\twhile ((opt = getopt(argc, argv, \"m:r:n:F:f:aj:tTLuwWSH\")) != -1) {\n \t\tswitch (opt) {\n \t\tcase 'a':\n \t\t\tcmd = PIN_FAST_BENCHMARK;\n \t\t\tbreak;\n-\t\tcase 'b':\n-\t\t\tcmd = PIN_BASIC_TEST;\n-\t\t\tbreak;\n \t\tcase 'L':\n \t\t\tcmd = PIN_LONGTERM_BENCHMARK;\n \t\t\tbreak;\n-\t\tcase 'c':\n-\t\t\tcmd = DUMP_USER_PAGES_TEST;\n-\t\t\t/*\n-\t\t\t * Dump page 0 (index 1). May be overridden later, by\n-\t\t\t * user's non-option arguments.\n-\t\t\t *\n-\t\t\t * .which_pages is zero-based, so that zero can mean \"do\n-\t\t\t * nothing\".\n-\t\t\t */\n-\t\t\tgup.which_pages[0] = 1;\n-\t\t\tbreak;\n-\t\tcase 'p':\n-\t\t\t/* works only with DUMP_USER_PAGES_TEST */\n-\t\t\tgup.test_flags |= GUP_TEST_FLAG_DUMP_PAGES_USE_PIN;\n-\t\t\tbreak;\n \t\tcase 'F':\n \t\t\t/* strtol, so you can pass flags in hex form */\n \t\t\tgup.gup_flags = strtol(optarg, 0, 0);\n@@ -141,7 +107,7 @@ int main(int argc, char **argv)\n \t\tcase 'n':\n \t\t\tnr_pages = atoi(optarg);\n \t\t\tif (nr_pages \u003c 0)\n-\t\t\t\tnr_pages = size / psize();\n+\t\t\t\tnr_pages = size / getpagesize();\n \t\t\tbreak;\n \t\tcase 't':\n \t\t\tthp = 1;\n@@ -149,9 +115,6 @@ int main(int argc, char **argv)\n \t\tcase 'T':\n \t\t\tthp = 0;\n \t\t\tbreak;\n-\t\tcase 'U':\n-\t\t\tcmd = GUP_BASIC_TEST;\n-\t\t\tbreak;\n \t\tcase 'u':\n \t\t\tcmd = GUP_FAST_BENCHMARK;\n \t\t\tbreak;\n@@ -173,52 +136,41 @@ int main(int argc, char **argv)\n \t\t\thugetlb = true;\n \t\t\tbreak;\n \t\tdefault:\n-\t\t\tksft_exit_fail_msg(\"Wrong argument\\n\");\n+\t\t\tfprintf(stderr, \"Wrong argument\\n\");\n+\t\t\texit(1);\n \t\t}\n \t}\n \n-\tif (optind \u003c argc) {\n-\t\tint extra_arg_count = 0;\n-\t\t/*\n-\t\t * For example:\n-\t\t *\n-\t\t * ./gup_test -c 0 1 0x1001\n-\t\t *\n-\t\t * ...to dump pages 0, 1, and 4097\n-\t\t */\n-\n-\t\twhile ((optind \u003c argc) \u0026\u0026\n-\t\t (extra_arg_count \u003c GUP_TEST_MAX_PAGES_TO_DUMP)) {\n-\t\t\t/*\n-\t\t\t * Do the 1-based indexing here, so that the user can\n-\t\t\t * use normal 0-based indexing on the command line.\n-\t\t\t */\n-\t\t\tlong page_index = strtol(argv[optind], 0, 0) + 1;\n-\n-\t\t\tgup.which_pages[extra_arg_count] = page_index;\n-\t\t\textra_arg_count++;\n-\t\t\toptind++;\n-\t\t}\n+\tif (optind != argc) {\n+\t\tfprintf(stderr, \"Unexpected argument '%s'\\n\", argv[optind]);\n+\t\texit(1);\n \t}\n \n-\tksft_print_header();\n+\tif (geteuid()) {\n+\t\tfprintf(stderr, \"Please run this test as root\\n\");\n+\t\texit(1);\n+\t}\n \n \tif (hugetlb) {\n \t\tunsigned long hp_size = default_huge_page_size();\n \n-\t\tif (!hp_size)\n-\t\t\tksft_exit_skip(\"HugeTLB is unavailable\\n\");\n+\t\tif (!hp_size) {\n+\t\t\tfprintf(stderr, \"Could not determine huge page size\\n\");\n+\t\t\treturn 1;\n+\t\t}\n \n \t\tsize = (size + hp_size - 1) \u0026 ~(hp_size - 1);\n-\t\tif (!hugetlb_setup_default(size / hp_size))\n-\t\t\tksft_exit_skip(\"Not enough huge pages\\n\");\n+\t\tif (!hugetlb_setup_default(size / hp_size)) {\n+\t\t\tfprintf(stderr, \"Not enough huge pages\\n\");\n+\t\t\treturn 1;\n+\t\t}\n \t}\n \n-\tksft_set_plan(nthreads);\n-\n \tfiled = open(file, O_RDWR|O_CREAT, 0664);\n-\tif (filed \u003c 0)\n-\t\tksft_exit_fail_msg(\"Unable to open %s: %s\\n\", file, strerror(errno));\n+\tif (filed \u003c 0) {\n+\t\tfprintf(stderr, \"Unable to open %s: %s\\n\", file, strerror(errno));\n+\t\treturn 1;\n+\t}\n \n \tgup.nr_pages_per_call = nr_pages;\n \tif (write)\n@@ -227,26 +179,24 @@ int main(int argc, char **argv)\n \tgup_fd = open(GUP_TEST_FILE, O_RDWR);\n \tif (gup_fd == -1) {\n \t\tswitch (errno) {\n-\t\tcase EACCES:\n-\t\t\tif (getuid())\n-\t\t\t\tksft_print_msg(\"Please run this test as root\\n\");\n-\t\t\tbreak;\n \t\tcase ENOENT:\n \t\t\tif (opendir(\"/sys/kernel/debug\") == NULL)\n-\t\t\t\tksft_print_msg(\"mount debugfs at /sys/kernel/debug\\n\");\n-\t\t\tksft_print_msg(\"check if CONFIG_GUP_TEST is enabled in kernel config\\n\");\n+\t\t\t\tfprintf(stderr, \"mount debugfs at /sys/kernel/debug\\n\");\n+\t\t\tfprintf(stderr, \"check if CONFIG_GUP_TEST is enabled in kernel config\\n\");\n \t\t\tbreak;\n \t\tdefault:\n-\t\t\tksft_print_msg(\"failed to open %s: %s\\n\", GUP_TEST_FILE, strerror(errno));\n+\t\t\tfprintf(stderr, \"failed to open %s: %s\\n\", GUP_TEST_FILE,\n+\t\t\t\tstrerror(errno));\n \t\t\tbreak;\n \t\t}\n-\t\tksft_test_result_skip(\"Please run this test as root\\n\");\n-\t\tksft_exit_pass();\n+\t\tgoto err_close_filed;\n \t}\n \n \tp = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, filed, 0);\n-\tif (p == MAP_FAILED)\n-\t\tksft_exit_fail_msg(\"mmap: %s\\n\", strerror(errno));\n+\tif (p == MAP_FAILED) {\n+\t\tfprintf(stderr, \"mmap: %s\\n\", strerror(errno));\n+\t\tgoto err_close_gup_fd;\n+\t}\n \tgup.addr = (unsigned long)p;\n \n \tif (thp == 1)\n@@ -255,21 +205,43 @@ int main(int argc, char **argv)\n \t\tmadvise(p, size, MADV_NOHUGEPAGE);\n \n \t/* Fault them in here, from user space. */\n-\tfor (; (unsigned long)p \u003c gup.addr + size; p += psize())\n+\tfor (; (unsigned long)p \u003c gup.addr + size; p += getpagesize())\n \t\tp[0] = 0;\n \n \ttid = malloc(sizeof(pthread_t) * nthreads);\n-\tassert(tid);\n+\tif (!tid) {\n+\t\tfprintf(stderr, \"Failed to allocate %d threads: %s\\n\",\n+\t\t\tnthreads, strerror(errno));\n+\t\tgoto err_unmap;\n+\t}\n+\n \tfor (i = 0; i \u003c nthreads; i++) {\n \t\tret = pthread_create(\u0026tid[i], NULL, gup_thread, \u0026gup);\n-\t\tassert(ret == 0);\n+\t\tif (ret) {\n+\t\t\tfprintf(stderr, \"pthread_create failed: %s\\n\", strerror(ret));\n+\t\t\tthread_error = true;\n+\t\t\tbreak;\n+\t\t}\n+\t\tstarted_threads++;\n \t}\n-\tfor (i = 0; i \u003c nthreads; i++) {\n-\t\tret = pthread_join(tid[i], NULL);\n-\t\tassert(ret == 0);\n+\tfor (i = 0; i \u003c started_threads; i++) {\n+\t\tret = pthread_join(tid[i], \u0026thread_result);\n+\t\tif (ret) {\n+\t\t\tfprintf(stderr, \"pthread_join failed: %s\\n\", strerror(ret));\n+\t\t\tthread_error = true;\n+\t\t} else if (thread_result)\n+\t\t\tthread_error = true;\n \t}\n \n \tfree(tid);\n-\n-\tksft_exit_pass();\n+\tif (!thread_error)\n+\t\texit_status = 0;\n+\n+err_unmap:\n+\tmunmap((void *)gup.addr, size);\n+err_close_gup_fd:\n+\tclose(gup_fd);\n+err_close_filed:\n+\tclose(filed);\n+\treturn exit_status;\n }\ndiff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile\nindex 2d5366196e309..9c03624fd2936 100644\n--- a/tools/testing/selftests/mm/Makefile\n+++ b/tools/testing/selftests/mm/Makefile\n@@ -37,7 +37,8 @@ endif\n # LDLIBS.\n MAKEFLAGS += --no-builtin-rules\n \n-CFLAGS = -Wall -O2 -I $(top_srcdir) $(EXTRA_CFLAGS) $(KHDR_INCLUDES) $(TOOLS_INCLUDES)\n+CFLAGS = -Wall -O2 -I $(top_srcdir) -I $(top_srcdir)/tools/lib\n+CFLAGS += $(EXTRA_CFLAGS) $(KHDR_INCLUDES) $(TOOLS_INCLUDES)\n CFLAGS += -Wunreachable-code\n LDLIBS = -lrt -lpthread -lm\n \n@@ -57,8 +58,8 @@ endif\n \n TEST_GEN_FILES = cow\n TEST_GEN_FILES += compaction_test\n+TEST_GEN_FILES += gup\n TEST_GEN_FILES += gup_longterm\n-TEST_GEN_FILES += gup_test\n TEST_GEN_FILES += hmm-tests\n TEST_GEN_FILES += hugetlb-madvise\n TEST_GEN_FILES += hugetlb-mmap\n@@ -187,8 +188,10 @@ TEST_FILES += write_hugetlb_memory.sh\n \n include ../lib.mk\n \n-$(TEST_GEN_PROGS): vm_util.c hugepage_settings.c\n-$(TEST_GEN_FILES): vm_util.c hugepage_settings.c\n+$(TEST_GEN_PROGS): vm_util.c $(top_srcdir)/tools/lib/mm/hugepage_settings.c \\\n+\t\t $(top_srcdir)/tools/lib/mm/file_utils.c\n+$(TEST_GEN_FILES): vm_util.c $(top_srcdir)/tools/lib/mm/hugepage_settings.c \\\n+\t\t $(top_srcdir)/tools/lib/mm/file_utils.c\n \n $(OUTPUT)/uffd-stress: uffd-common.c\n $(OUTPUT)/uffd-unit-tests: uffd-common.c\n@@ -217,7 +220,7 @@ $(BINARIES_32): CFLAGS += -m32 -mxsave\n $(BINARIES_32): LDLIBS += -lrt -ldl -lm\n $(BINARIES_32): $(OUTPUT)/%_32: %.c\n \t$(call msg,CC,,$@)\n-\t$(Q)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(notdir $^) $(LDLIBS) -o $@\n+\t$(Q)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $^ $(LDLIBS) -o $@\n $(foreach t,$(VMTARGETS),$(eval $(call gen-target-rule-32,$(t))))\n endif\n \n@@ -226,7 +229,7 @@ $(BINARIES_64): CFLAGS += -m64 -mxsave\n $(BINARIES_64): LDLIBS += -lrt -ldl\n $(BINARIES_64): $(OUTPUT)/%_64: %.c\n \t$(call msg,CC,,$@)\n-\t$(Q)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $(notdir $^) $(LDLIBS) -o $@\n+\t$(Q)$(CC) $(CFLAGS) $(EXTRA_CFLAGS) $^ $(LDLIBS) -o $@\n $(foreach t,$(VMTARGETS),$(eval $(call gen-target-rule-64,$(t))))\n endif\n \ndiff --git a/tools/testing/selftests/mm/compaction_test.c b/tools/testing/selftests/mm/compaction_test.c\nindex 30d4ace7155ae..b3f5377119cb8 100644\n--- a/tools/testing/selftests/mm/compaction_test.c\n+++ b/tools/testing/selftests/mm/compaction_test.c\n@@ -15,9 +15,9 @@\n #include \u003cerrno.h\u003e\n #include \u003cunistd.h\u003e\n #include \u003cstring.h\u003e\n+#include \u003cmm/hugepage_settings.h\u003e\n \n #include \"kselftest.h\"\n-#include \"hugepage_settings.h\"\n \n #define MAP_SIZE_MB\t100\n #define MAP_SIZE\t(MAP_SIZE_MB * 1024 * 1024)\ndiff --git a/tools/testing/selftests/mm/cow.c b/tools/testing/selftests/mm/cow.c\nindex 8aa5249d9bef6..3264a828575bd 100644\n--- a/tools/testing/selftests/mm/cow.c\n+++ b/tools/testing/selftests/mm/cow.c\n@@ -29,7 +29,6 @@\n #include \"../../../../mm/gup_test.h\"\n #include \"kselftest.h\"\n #include \"vm_util.h\"\n-#include \"hugepage_settings.h\"\n \n static size_t pagesize;\n static int pagemap_fd;\ndiff --git a/tools/testing/selftests/mm/folio_split_race_test.c b/tools/testing/selftests/mm/folio_split_race_test.c\nindex 1960635a953eb..e4660bf89b624 100644\n--- a/tools/testing/selftests/mm/folio_split_race_test.c\n+++ b/tools/testing/selftests/mm/folio_split_race_test.c\n@@ -25,7 +25,6 @@\n #include \u003cunistd.h\u003e\n #include \"vm_util.h\"\n #include \"kselftest.h\"\n-#include \"hugepage_settings.h\"\n \n uint64_t page_size;\n uint64_t pmd_pagesize;\ndiff --git a/tools/testing/selftests/mm/guard-regions.c b/tools/testing/selftests/mm/guard-regions.c\nindex 5c8ec3ca75d7d..af5cd9b303395 100644\n--- a/tools/testing/selftests/mm/guard-regions.c\n+++ b/tools/testing/selftests/mm/guard-regions.c\n@@ -21,7 +21,6 @@\n #include \u003csys/uio.h\u003e\n #include \u003cunistd.h\u003e\n #include \"vm_util.h\"\n-#include \"hugepage_settings.h\"\n \n #include \"../pidfd/pidfd.h\"\n \ndiff --git a/tools/testing/selftests/mm/gup.c b/tools/testing/selftests/mm/gup.c\nnew file mode 100644\nindex 0000000000000..31ae38e09136d\n--- /dev/null\n+++ b/tools/testing/selftests/mm/gup.c\n@@ -0,0 +1,263 @@\n+// SPDX-License-Identifier: GPL-2.0\n+#define __SANE_USERSPACE_TYPES__ // Use ll64\n+#include \u003cfcntl.h\u003e\n+#include \u003cerrno.h\u003e\n+#include \u003cstdbool.h\u003e\n+#include \u003cstring.h\u003e\n+#include \u003cunistd.h\u003e\n+#include \u003cdirent.h\u003e\n+#include \u003csys/ioctl.h\u003e\n+#include \u003csys/mman.h\u003e\n+#include \u003cmm/gup_test.h\u003e\n+#include \"vm_util.h\"\n+#include \"kselftest_harness.h\"\n+\n+#define MB (1UL \u003c\u003c 20)\n+\n+/* Just the flags we need, copied from the kernel internals. */\n+#define FOLL_WRITE\t0x01\t/* check pte is writable */\n+\n+/* Page counts exercising single, THP-batch, partial, and full-mapping GUP. */\n+static const int nr_pages_list[] = { 1, 512, 123, -1 };\n+\n+#define GUP_TEST_FILE \"/sys/kernel/debug/gup_test\"\n+#define NR_HUGE_PAGES 2\n+\n+static unsigned long hp_size;\n+\n+FIXTURE(gup_test)\n+{\n+\tint gup_fd;\n+\tchar *addr;\n+\tunsigned long size;\n+};\n+\n+FIXTURE_VARIANT(gup_test)\n+{\n+\tbool thp;\n+\tbool hugetlb;\n+\tbool write;\n+\tbool shared;\n+};\n+\n+FIXTURE_VARIANT_ADD(gup_test, private_write)\n+{\n+\t.thp = false,\n+\t.hugetlb = false,\n+\t.write = true,\n+\t.shared = false,\n+};\n+\n+FIXTURE_VARIANT_ADD(gup_test, private_read)\n+{\n+\t.thp = false,\n+\t.hugetlb = false,\n+\t.write = false,\n+\t.shared = false,\n+};\n+\n+FIXTURE_VARIANT_ADD(gup_test, private_write_thp)\n+{\n+\t.thp = true,\n+\t.hugetlb = false,\n+\t.write = true,\n+\t.shared = false,\n+};\n+\n+FIXTURE_VARIANT_ADD(gup_test, private_read_thp)\n+{\n+\t.thp = true,\n+\t.hugetlb = false,\n+\t.write = false,\n+\t.shared = false,\n+};\n+\n+FIXTURE_VARIANT_ADD(gup_test, private_write_hugetlb)\n+{\n+\t.thp = false,\n+\t.hugetlb = true,\n+\t.write = true,\n+\t.shared = false,\n+};\n+\n+FIXTURE_VARIANT_ADD(gup_test, private_read_hugetlb)\n+{\n+\t.thp = false,\n+\t.hugetlb = true,\n+\t.write = false,\n+\t.shared = false,\n+};\n+\n+FIXTURE_VARIANT_ADD(gup_test, shared_write)\n+{\n+\t.thp = false,\n+\t.hugetlb = false,\n+\t.write = true,\n+\t.shared = true,\n+};\n+\n+FIXTURE_VARIANT_ADD(gup_test, shared_read)\n+{\n+\t.thp = false,\n+\t.hugetlb = false,\n+\t.write = false,\n+\t.shared = true,\n+};\n+\n+FIXTURE_VARIANT_ADD(gup_test, shared_write_thp)\n+{\n+\t.thp = true,\n+\t.hugetlb = false,\n+\t.write = true,\n+\t.shared = true,\n+};\n+\n+FIXTURE_VARIANT_ADD(gup_test, shared_read_thp)\n+{\n+\t.thp = true,\n+\t.hugetlb = false,\n+\t.write = false,\n+\t.shared = true,\n+};\n+\n+FIXTURE_VARIANT_ADD(gup_test, shared_write_hugetlb)\n+{\n+\t.thp = false,\n+\t.hugetlb = true,\n+\t.write = true,\n+\t.shared = true,\n+};\n+\n+FIXTURE_VARIANT_ADD(gup_test, shared_read_hugetlb)\n+{\n+\t.thp = false,\n+\t.hugetlb = true,\n+\t.write = false,\n+\t.shared = true,\n+};\n+\n+FIXTURE_SETUP(gup_test)\n+{\n+\tint mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;\n+\tchar *p;\n+\n+\tself-\u003esize = 128 * MB;\n+\n+\tif (variant-\u003ehugetlb) {\n+\t\tif (!hp_size)\n+\t\t\tSKIP(return, \"HugeTLB not available\\n\");\n+\n+\t\tif (hugetlb_free_default_pages() \u003c NR_HUGE_PAGES)\n+\t\t\tSKIP(return, \"Not enough huge pages\\n\");\n+\n+\t\tself-\u003esize = NR_HUGE_PAGES * hp_size;\n+\t\tmmap_flags |= MAP_HUGETLB;\n+\t}\n+\n+\tif (variant-\u003eshared)\n+\t\tmmap_flags = (mmap_flags \u0026 ~MAP_PRIVATE) | MAP_SHARED;\n+\n+\t/* gup_fd has to be \u003e= 0. Already checked in main() */\n+\tself-\u003egup_fd = open(GUP_TEST_FILE, O_RDWR);\n+\tASSERT_GE(self-\u003egup_fd, 0);\n+\n+\tself-\u003eaddr = mmap(NULL, self-\u003esize, PROT_READ | PROT_WRITE,\n+\t\t\t mmap_flags, -1, 0);\n+\n+\tASSERT_NE(self-\u003eaddr, MAP_FAILED) {\n+\t\tint err = errno;\n+\n+\t\tclose(self-\u003egup_fd);\n+\t\tTH_LOG(\"mmap failed: %s\", strerror(err));\n+\t}\n+\n+\tif (variant-\u003ethp)\n+\t\tmadvise(self-\u003eaddr, self-\u003esize, MADV_HUGEPAGE);\n+\telse if (!variant-\u003ehugetlb)\n+\t\tmadvise(self-\u003eaddr, self-\u003esize, MADV_NOHUGEPAGE);\n+\n+\tfor (p = self-\u003eaddr; (unsigned long)p \u003c (unsigned long)self-\u003eaddr\n+\t\t\t+ self-\u003esize; p += psize())\n+\t\tp[0] = 0;\n+}\n+\n+FIXTURE_TEARDOWN(gup_test)\n+{\n+\tmunmap(self-\u003eaddr, self-\u003esize);\n+\tclose(self-\u003egup_fd);\n+}\n+\n+static void run_gup_cmd(struct __test_metadata *_metadata,\n+\t\t\t FIXTURE_DATA(gup_test) *self,\n+\t\t\t const FIXTURE_VARIANT(gup_test) *variant,\n+\t\t\t unsigned long command)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i \u003c (int)ARRAY_SIZE(nr_pages_list); i++) {\n+\t\tstruct gup_test gup = {\n+\t\t\t.addr = (unsigned long)self-\u003eaddr,\n+\t\t\t.size = self-\u003esize,\n+\t\t\t.nr_pages_per_call = nr_pages_list[i] \u003c 0 ?\n+\t\t\t\tself-\u003esize / psize() : nr_pages_list[i],\n+\t\t\t.gup_flags = variant-\u003ewrite ? FOLL_WRITE : 0,\n+\t\t};\n+\n+\t\tTH_LOG(\"nr_pages_per_call=%u\", gup.nr_pages_per_call);\n+\t\tASSERT_EQ(ioctl(self-\u003egup_fd, command, \u0026gup), 0);\n+\t\tASSERT_EQ(gup.size, self-\u003esize);\n+\t}\n+}\n+\n+TEST_F(gup_test, get_user_pages)\n+{\n+\trun_gup_cmd(_metadata, self, variant, GUP_BASIC_TEST);\n+}\n+\n+TEST_F(gup_test, pin_user_pages)\n+{\n+\trun_gup_cmd(_metadata, self, variant, PIN_BASIC_TEST);\n+}\n+\n+TEST_F(gup_test, get_user_pages_fast)\n+{\n+\trun_gup_cmd(_metadata, self, variant, GUP_FAST_BENCHMARK);\n+}\n+\n+TEST_F(gup_test, pin_user_pages_fast)\n+{\n+\trun_gup_cmd(_metadata, self, variant, PIN_FAST_BENCHMARK);\n+}\n+\n+TEST_F(gup_test, pin_user_pages_longterm)\n+{\n+\trun_gup_cmd(_metadata, self, variant, PIN_LONGTERM_BENCHMARK);\n+}\n+\n+int main(int argc, char **argv)\n+{\n+\tint fd;\n+\n+\tfd = open(GUP_TEST_FILE, O_RDWR);\n+\tif (fd == -1) {\n+\t\tksft_print_header();\n+\t\tif (errno == EACCES)\n+\t\t\tksft_exit_skip(\"Please run this test as root\\n\");\n+\t\tif (errno == ENOENT) {\n+\t\t\tDIR *debugfs = opendir(\"/sys/kernel/debug\");\n+\n+\t\t\tif (!debugfs)\n+\t\t\t\tksft_exit_skip(\"Mount debugfs at /sys/kernel/debug\\n\");\n+\t\t\tclosedir(debugfs);\n+\t\t\tksft_exit_skip(\"Check CONFIG_GUP_TEST in kernel config\\n\");\n+\t\t}\n+\t\tksft_exit_fail_msg(\"Failed to open %s: %s\\n\", GUP_TEST_FILE, strerror(errno));\n+\t}\n+\tclose(fd);\n+\n+\thp_size = default_huge_page_size();\n+\tif (hp_size)\n+\t\thugetlb_setup_default(NR_HUGE_PAGES);\n+\n+\treturn test_harness_run(argc, argv);\n+}\ndiff --git a/tools/testing/selftests/mm/gup_longterm.c b/tools/testing/selftests/mm/gup_longterm.c\nindex 510de93be6814..c9d8b44912638 100644\n--- a/tools/testing/selftests/mm/gup_longterm.c\n+++ b/tools/testing/selftests/mm/gup_longterm.c\n@@ -29,7 +29,6 @@\n #include \"../../../../mm/gup_test.h\"\n #include \"kselftest.h\"\n #include \"vm_util.h\"\n-#include \"hugepage_settings.h\"\n \n static size_t pagesize;\n static int nr_hugetlbsizes;\ndiff --git a/tools/testing/selftests/mm/hmm-tests.c b/tools/testing/selftests/mm/hmm-tests.c\nindex e2642eca0d02b..fa1a651963fd0 100644\n--- a/tools/testing/selftests/mm/hmm-tests.c\n+++ b/tools/testing/selftests/mm/hmm-tests.c\n@@ -10,9 +10,6 @@\n * bugs.\n */\n \n-#include \"kselftest_harness.h\"\n-#include \"hugepage_settings.h\"\n-\n #include \u003cerrno.h\u003e\n #include \u003cfcntl.h\u003e\n #include \u003cstdio.h\u003e\n@@ -33,6 +30,9 @@\n #include \u003csys/eventfd.h\u003e\n #include \u003clinux/userfaultfd.h\u003e\n #include \u003cpoll.h\u003e\n+#include \u003cmm/hugepage_settings.h\u003e\n+\n+#include \"kselftest_harness.h\"\n \n /*\n * This is a private UAPI to the kernel test module so it isn't exported\ndiff --git a/tools/testing/selftests/mm/hugetlb-madvise.c b/tools/testing/selftests/mm/hugetlb-madvise.c\nindex 555b4b3d14307..57cf790ca478d 100644\n--- a/tools/testing/selftests/mm/hugetlb-madvise.c\n+++ b/tools/testing/selftests/mm/hugetlb-madvise.c\n@@ -14,7 +14,6 @@\n #include \u003cfcntl.h\u003e\n #include \"vm_util.h\"\n #include \"kselftest.h\"\n-#include \"hugepage_settings.h\"\n \n #define MIN_FREE_PAGES\t20\n #define NR_HUGE_PAGES\t10\t/* common number of pages to map/allocate */\ndiff --git a/tools/testing/selftests/mm/hugetlb-mmap.c b/tools/testing/selftests/mm/hugetlb-mmap.c\nindex 0f2aad1b7dbd6..a458becf58327 100644\n--- a/tools/testing/selftests/mm/hugetlb-mmap.c\n+++ b/tools/testing/selftests/mm/hugetlb-mmap.c\n@@ -18,7 +18,6 @@\n #include \u003clinux/memfd.h\u003e\n #include \"vm_util.h\"\n #include \"kselftest.h\"\n-#include \"hugepage_settings.h\"\n \n #define LENGTH (256UL*1024*1024)\n #define PROTECTION (PROT_READ | PROT_WRITE)\ndiff --git a/tools/testing/selftests/mm/hugetlb-mremap.c b/tools/testing/selftests/mm/hugetlb-mremap.c\nindex ed3d92e862d87..9b724af66e938 100644\n--- a/tools/testing/selftests/mm/hugetlb-mremap.c\n+++ b/tools/testing/selftests/mm/hugetlb-mremap.c\n@@ -26,7 +26,6 @@\n #include \u003cstdbool.h\u003e\n #include \"kselftest.h\"\n #include \"vm_util.h\"\n-#include \"hugepage_settings.h\"\n \n #define DEFAULT_LENGTH_MB 10UL\n #define MB_TO_BYTES(x) (x * 1024 * 1024)\ndiff --git a/tools/testing/selftests/mm/hugetlb-shm.c b/tools/testing/selftests/mm/hugetlb-shm.c\nindex 3ff7f062b7eb4..f4514da49e1df 100644\n--- a/tools/testing/selftests/mm/hugetlb-shm.c\n+++ b/tools/testing/selftests/mm/hugetlb-shm.c\n@@ -29,7 +29,6 @@\n #include \u003csys/mman.h\u003e\n \n #include \"vm_util.h\"\n-#include \"hugepage_settings.h\"\n \n #define LENGTH (256UL*1024*1024)\n \ndiff --git a/tools/testing/selftests/mm/hugetlb-soft-offline.c b/tools/testing/selftests/mm/hugetlb-soft-offline.c\nindex 4af9d3db7b5b6..d9565219378aa 100644\n--- a/tools/testing/selftests/mm/hugetlb-soft-offline.c\n+++ b/tools/testing/selftests/mm/hugetlb-soft-offline.c\n@@ -22,10 +22,10 @@\n #include \u003csys/mman.h\u003e\n #include \u003csys/statfs.h\u003e\n #include \u003csys/types.h\u003e\n+#include \u003cmm/hugepage_settings.h\u003e\n \n #include \"kselftest.h\"\n #include \"vm_util.h\"\n-#include \"hugepage_settings.h\"\n \n #ifndef MADV_SOFT_OFFLINE\n #define MADV_SOFT_OFFLINE 101\n@@ -85,8 +85,7 @@ static unsigned long orig_enable_soft_offline = -1UL;\n \n /*\n * Runs from an atexit handler, so it must not call anything that\n- * exits on failure: write_num() would re-enter exit() through\n- * ksft_exit_fail_msg().\n+ * exits on failure.\n */\n static void restore_enable_soft_offline(void)\n {\n@@ -152,7 +151,10 @@ static void test_soft_offline_common(int enable_soft_offline)\n \thugepagesize_kb = file_stat.f_bsize / 1024;\n \tksft_print_msg(\"Hugepagesize is %ldkB\\n\", hugepagesize_kb);\n \n-\twrite_num(ENABLE_SOFT_OFFLINE_PATH, enable_soft_offline);\n+\tret = write_num(ENABLE_SOFT_OFFLINE_PATH, enable_soft_offline);\n+\tif (ret)\n+\t\tksft_exit_fail_msg(\"Failed to write to %s: %s\\n\",\n+\t\t\t\t ENABLE_SOFT_OFFLINE_PATH, strerror(-ret));\n \n \tnr_hugepages_before = hugetlb_nr_default_pages();\n \n@@ -189,6 +191,8 @@ static void test_soft_offline_common(int enable_soft_offline)\n \n int main(int argc, char **argv)\n {\n+\tint ret;\n+\n \tksft_print_header();\n \n \tif (!hugetlb_setup_default(8))\n@@ -196,7 +200,11 @@ int main(int argc, char **argv)\n \n \tksft_set_plan(2);\n \n-\torig_enable_soft_offline = read_num(ENABLE_SOFT_OFFLINE_PATH);\n+\tret = read_num(ENABLE_SOFT_OFFLINE_PATH, \u0026orig_enable_soft_offline);\n+\tif (ret)\n+\t\tksft_exit_fail_msg(\"Failed to read %s: %s\\n\",\n+\t\t\t\t ENABLE_SOFT_OFFLINE_PATH, strerror(-ret));\n+\n \tatexit(restore_enable_soft_offline);\n \n \ttest_soft_offline_common(1);\ndiff --git a/tools/testing/selftests/mm/hugetlb_dio.c b/tools/testing/selftests/mm/hugetlb_dio.c\nindex fb4600570e131..9495974eccbea 100644\n--- a/tools/testing/selftests/mm/hugetlb_dio.c\n+++ b/tools/testing/selftests/mm/hugetlb_dio.c\n@@ -20,7 +20,6 @@\n #include \u003csys/syscall.h\u003e\n #include \"vm_util.h\"\n #include \"kselftest.h\"\n-#include \"hugepage_settings.h\"\n \n #ifndef STATX_DIOALIGN\n #define STATX_DIOALIGN\t\t0x00002000U\ndiff --git a/tools/testing/selftests/mm/hugetlb_fault_after_madv.c b/tools/testing/selftests/mm/hugetlb_fault_after_madv.c\nindex 2dc158054f666..56c5a8533e9d9 100644\n--- a/tools/testing/selftests/mm/hugetlb_fault_after_madv.c\n+++ b/tools/testing/selftests/mm/hugetlb_fault_after_madv.c\n@@ -10,7 +10,6 @@\n \n #include \"vm_util.h\"\n #include \"kselftest.h\"\n-#include \"hugepage_settings.h\"\n \n #define INLOOP_ITER 100\n \ndiff --git a/tools/testing/selftests/mm/hugetlb_madv_vs_map.c b/tools/testing/selftests/mm/hugetlb_madv_vs_map.c\nindex f94549efcc6ff..2532a42b98dff 100644\n--- a/tools/testing/selftests/mm/hugetlb_madv_vs_map.c\n+++ b/tools/testing/selftests/mm/hugetlb_madv_vs_map.c\n@@ -25,7 +25,6 @@\n #include \u003cunistd.h\u003e\n \n #include \"vm_util.h\"\n-#include \"hugepage_settings.h\"\n \n #define INLOOP_ITER 100\n \ndiff --git a/tools/testing/selftests/mm/khugepaged.c b/tools/testing/selftests/mm/khugepaged.c\nindex f82673f5f6b47..525108cace54a 100644\n--- a/tools/testing/selftests/mm/khugepaged.c\n+++ b/tools/testing/selftests/mm/khugepaged.c\n@@ -22,7 +22,6 @@\n #include \"linux/magic.h\"\n \n #include \"vm_util.h\"\n-#include \"hugepage_settings.h\"\n \n #define BASE_ADDR ((void *)(1UL \u003c\u003c 30))\n static unsigned long hpage_pmd_size;\n@@ -122,6 +121,7 @@ static void get_finfo(const char *dir)\n \tchar buf[1 \u003c\u003c 10];\n \tchar path[PATH_MAX];\n \tchar *str, *end;\n+\tint ret;\n \n \tfinfo.dir = dir;\n \tif (stat(finfo.dir, \u0026path_stat))\n@@ -142,8 +142,9 @@ static void get_finfo(const char *dir)\n \t\t major(path_stat.st_dev), minor(path_stat.st_dev))\n \t \u003e= sizeof(path))\n \t\tksft_exit_fail_msg(\"%s: Pathname is too long\\n\", __func__);\n-\tif (!read_file(path, buf, sizeof(buf)))\n-\t\tksft_exit_fail_perror(\"read_file(uevent)\");\n+\tret = read_file(path, buf, sizeof(buf));\n+\tif (ret)\n+\t\tksft_exit_fail_msg(\"read_file(%s): %s\\n\", path, strerror(-ret));\n \tif (strstr(buf, \"DEVTYPE=disk\")) {\n \t\t/* Found it */\n \t\tif (snprintf(finfo.dev_queue_read_ahead_path,\n@@ -324,7 +325,7 @@ static void *file_setup_area_common(int nr_hpages, enum file_setup_ops setup)\n {\n \tconst int open_opt = setup == FILE_SETUP_READ_ONLY_FS ? O_RDONLY : O_RDWR;\n \tconst int mmap_prot = setup == FILE_SETUP_READ_ONLY_FS ? PROT_READ : (PROT_READ | PROT_WRITE);\n-\tint fd;\n+\tint fd, ret;\n \tvoid *p;\n \tunsigned long size;\n \n@@ -362,7 +363,11 @@ static void *file_setup_area_common(int nr_hpages, enum file_setup_ops setup)\n \t\tksft_exit_fail_perror(\"mmap()\");\n \n \t/* Drop page cache */\n-\twrite_file(\"/proc/sys/vm/drop_caches\", \"3\", 2);\n+\tret = write_file(\"/proc/sys/vm/drop_caches\", \"3\", 2);\n+\tif (ret)\n+\t\tksft_exit_fail_msg(\"write_file(drop_caches): %s\\n\",\n+\t\t\t\t strerror(-ret));\n+\n \tsuccess(\"OK\");\n \treturn p;\n }\ndiff --git a/tools/testing/selftests/mm/ksm_tests.c b/tools/testing/selftests/mm/ksm_tests.c\nindex 5fd7792a0d479..6711f4c613711 100644\n--- a/tools/testing/selftests/mm/ksm_tests.c\n+++ b/tools/testing/selftests/mm/ksm_tests.c\n@@ -15,7 +15,6 @@\n #include \"kselftest.h\"\n #include \u003cinclude/vdso/time64.h\u003e\n #include \"vm_util.h\"\n-#include \"hugepage_settings.h\"\n \n #define KSM_SYSFS_PATH \"/sys/kernel/mm/ksm/\"\n #define KSM_FP(s) (KSM_SYSFS_PATH s)\ndiff --git a/tools/testing/selftests/mm/migration.c b/tools/testing/selftests/mm/migration.c\nindex f19d53c695764..a35e2b57e05b2 100644\n--- a/tools/testing/selftests/mm/migration.c\n+++ b/tools/testing/selftests/mm/migration.c\n@@ -5,7 +5,6 @@\n */\n \n #include \"kselftest_harness.h\"\n-#include \"hugepage_settings.h\"\n \n #include \u003cstring.h\u003e\n #include \u003cpthread.h\u003e\n@@ -16,6 +15,7 @@\n #include \u003csys/types.h\u003e\n #include \u003csignal.h\u003e\n #include \u003ctime.h\u003e\n+\n #include \"vm_util.h\"\n \n #define TWOMEG\t\t(2\u003c\u003c20)\ndiff --git a/tools/testing/selftests/mm/pagemap_ioctl.c b/tools/testing/selftests/mm/pagemap_ioctl.c\nindex d9a4fb782ecfe..03898b4f6cdab 100644\n--- a/tools/testing/selftests/mm/pagemap_ioctl.c\n+++ b/tools/testing/selftests/mm/pagemap_ioctl.c\n@@ -24,7 +24,6 @@\n \n #include \"vm_util.h\"\n #include \"kselftest.h\"\n-#include \"hugepage_settings.h\"\n \n #define PAGEMAP_BITS_ALL\t\t(PAGE_IS_WPALLOWED | PAGE_IS_WRITTEN |\t\\\n \t\t\t\t\t PAGE_IS_FILE | PAGE_IS_PRESENT |\t\\\ndiff --git a/tools/testing/selftests/mm/prctl_thp_disable.c b/tools/testing/selftests/mm/prctl_thp_disable.c\nindex 82c6e96ea6eb3..f9ec1408a6e30 100644\n--- a/tools/testing/selftests/mm/prctl_thp_disable.c\n+++ b/tools/testing/selftests/mm/prctl_thp_disable.c\n@@ -14,7 +14,6 @@\n #include \u003csys/wait.h\u003e\n \n #include \"kselftest_harness.h\"\n-#include \"hugepage_settings.h\"\n #include \"vm_util.h\"\n \n #ifndef PR_THP_DISABLE_EXCEPT_ADVISED\ndiff --git a/tools/testing/selftests/mm/protection_keys.c b/tools/testing/selftests/mm/protection_keys.c\nindex ae6e1530b3548..b7882ab97683f 100644\n--- a/tools/testing/selftests/mm/protection_keys.c\n+++ b/tools/testing/selftests/mm/protection_keys.c\n@@ -45,8 +45,8 @@\n #include \u003cunistd.h\u003e\n #include \u003csys/ptrace.h\u003e\n #include \u003csetjmp.h\u003e\n+#include \u003cmm/hugepage_settings.h\u003e\n \n-#include \"hugepage_settings.h\"\n #include \"pkey-helpers.h\"\n \n u64 shadow_pkey_reg;\ndiff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/selftests/mm/run_vmtests.sh\nindex d09f9f6a384ee..ae0ab5efabae6 100755\n--- a/tools/testing/selftests/mm/run_vmtests.sh\n+++ b/tools/testing/selftests/mm/run_vmtests.sh\n@@ -130,30 +130,6 @@ test_selected() {\n \tfi\n }\n \n-run_gup_matrix() {\n- # -t: thp=on, -T: thp=off, -H: hugetlb=on\n- local hugetlb_mb=256\n-\n- for huge in -t -T \"-H -m $hugetlb_mb\"; do\n- # -u: gup-fast, -U: gup-basic, -a: pin-fast, -b: pin-basic, -L: pin-longterm\n- for test_cmd in -u -U -a -b -L; do\n- # -w: write=1, -W: write=0\n- for write in -w -W; do\n- # -S: shared\n- for share in -S \" \"; do\n- # -n: How many pages to fetch together? 512 is special\n- # because it's default thp size (or 2M on x86), 123 to\n- # just test partial gup when hit a huge in whatever form\n- for num in \"-n 1\" \"-n 512\" \"-n 123\" \"-n -1\"; do\n- CATEGORY=\"gup_test\" run_test ./gup_test \\\n- $huge $test_cmd $write $share $num\n- done\n- done\n- done\n- done\n- done\n-}\n-\n # filter 64bit architectures\n ARCH64STR=\"arm64 mips64 parisc64 ppc64 ppc64le riscv64 s390x sparc64 x86_64\"\n if [ -z \"$ARCH\" ]; then\n@@ -275,18 +251,7 @@ fi\n \n CATEGORY=\"mmap\" run_test ./map_fixed_noreplace\n \n-if $RUN_ALL; then\n- run_gup_matrix\n-else\n- # get_user_pages_fast() benchmark\n- CATEGORY=\"gup_test\" run_test ./gup_test -u -n 1\n- CATEGORY=\"gup_test\" run_test ./gup_test -u -n -1\n- # pin_user_pages_fast() benchmark\n- CATEGORY=\"gup_test\" run_test ./gup_test -a -n 1\n- CATEGORY=\"gup_test\" run_test ./gup_test -a -n -1\n-fi\n-# Dump pages 0, 19, and 4096, using pin_user_pages:\n-CATEGORY=\"gup_test\" run_test ./gup_test -ct -F 0x1 0 19 0x1000\n+CATEGORY=\"gup_test\" run_test ./gup\n CATEGORY=\"gup_test\" run_test ./gup_longterm\n \n CATEGORY=\"userfaultfd\" run_test ./uffd-unit-tests\ndiff --git a/tools/testing/selftests/mm/soft-dirty.c b/tools/testing/selftests/mm/soft-dirty.c\nindex 5f278913c4d75..7f649b6733553 100644\n--- a/tools/testing/selftests/mm/soft-dirty.c\n+++ b/tools/testing/selftests/mm/soft-dirty.c\n@@ -9,7 +9,6 @@\n \n #include \"kselftest.h\"\n #include \"vm_util.h\"\n-#include \"hugepage_settings.h\"\n \n #define PAGEMAP_FILE_PATH \"/proc/self/pagemap\"\n #define TEST_ITERATIONS 10000\ndiff --git a/tools/testing/selftests/mm/split_huge_page_test.c b/tools/testing/selftests/mm/split_huge_page_test.c\nindex c01d227d7fd6d..68f508c9a355f 100644\n--- a/tools/testing/selftests/mm/split_huge_page_test.c\n+++ b/tools/testing/selftests/mm/split_huge_page_test.c\n@@ -21,7 +21,6 @@\n #include \u003ctime.h\u003e\n #include \"vm_util.h\"\n #include \"kselftest.h\"\n-#include \"hugepage_settings.h\"\n \n uint64_t pagesize;\n unsigned int pageshift;\n@@ -145,7 +144,10 @@ static void write_debugfs(const char *fmt, ...)\n \tif (ret \u003e= INPUT_MAX)\n \t\tksft_exit_fail_msg(\"%s: Debugfs input is too long\\n\", __func__);\n \n-\twrite_file(SPLIT_DEBUGFS, input, ret + 1);\n+\tret = write_file(SPLIT_DEBUGFS, input, ret + 1);\n+\tif (ret)\n+\t\tksft_exit_fail_msg(\"write_file(%s): %s\\n\", SPLIT_DEBUGFS,\n+\t\t\t\t strerror(-ret));\n }\n \n static char *allocate_zero_filled_hugepage(size_t len)\ndiff --git a/tools/testing/selftests/mm/thuge-gen.c b/tools/testing/selftests/mm/thuge-gen.c\nindex 50d0805b65db9..a04f588df780f 100644\n--- a/tools/testing/selftests/mm/thuge-gen.c\n+++ b/tools/testing/selftests/mm/thuge-gen.c\n@@ -14,7 +14,6 @@\n #include \u003cstring.h\u003e\n #include \"vm_util.h\"\n #include \"kselftest.h\"\n-#include \"hugepage_settings.h\"\n \n #if !defined(MAP_HUGETLB)\n #define MAP_HUGETLB\t0x40000\ndiff --git a/tools/testing/selftests/mm/transhuge-stress.c b/tools/testing/selftests/mm/transhuge-stress.c\nindex 8eb0c5630e7e3..96f72898ebe0a 100644\n--- a/tools/testing/selftests/mm/transhuge-stress.c\n+++ b/tools/testing/selftests/mm/transhuge-stress.c\n@@ -17,7 +17,6 @@\n #include \u003csys/mman.h\u003e\n #include \"vm_util.h\"\n #include \"kselftest.h\"\n-#include \"hugepage_settings.h\"\n \n int backing_fd = -1;\n int mmap_flags = MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE;\ndiff --git a/tools/testing/selftests/mm/uffd-common.h b/tools/testing/selftests/mm/uffd-common.h\nindex 92a21b97f745a..0723843a7626b 100644\n--- a/tools/testing/selftests/mm/uffd-common.h\n+++ b/tools/testing/selftests/mm/uffd-common.h\n@@ -37,7 +37,6 @@\n \n #include \"kselftest.h\"\n #include \"vm_util.h\"\n-#include \"hugepage_settings.h\"\n \n #define UFFD_FLAGS\t(O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY)\n \ndiff --git a/tools/testing/selftests/mm/uffd-wp-mremap.c b/tools/testing/selftests/mm/uffd-wp-mremap.c\nindex 572c2516e874d..c48eaab8e75cf 100644\n--- a/tools/testing/selftests/mm/uffd-wp-mremap.c\n+++ b/tools/testing/selftests/mm/uffd-wp-mremap.c\n@@ -7,8 +7,8 @@\n #include \u003cassert.h\u003e\n #include \u003clinux/mman.h\u003e\n #include \u003csys/mman.h\u003e\n+#include \u003cmm/hugepage_settings.h\u003e\n #include \"kselftest.h\"\n-#include \"hugepage_settings.h\"\n #include \"uffd-common.h\"\n \n static int pagemap_fd;\ndiff --git a/tools/testing/selftests/mm/va_high_addr_switch.c b/tools/testing/selftests/mm/va_high_addr_switch.c\nindex e24d7ba00b441..5a354a664d1f7 100644\n--- a/tools/testing/selftests/mm/va_high_addr_switch.c\n+++ b/tools/testing/selftests/mm/va_high_addr_switch.c\n@@ -11,7 +11,6 @@\n \n #include \"vm_util.h\"\n #include \"kselftest.h\"\n-#include \"hugepage_settings.h\"\n \n /*\n * The hint addr value is used to allocate addresses\ndiff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c\nindex 80bc9f597b521..4751db798c3ac 100644\n--- a/tools/testing/selftests/mm/vm_util.c\n+++ b/tools/testing/selftests/mm/vm_util.c\n@@ -889,111 +889,54 @@ int unpoison_memory(unsigned long pfn)\n \treturn ret \u003e 0 ? 0 : -errno;\n }\n \n-int read_file(const char *path, char *buf, size_t buflen)\n-{\n-\tint fd;\n-\tssize_t numread;\n-\n-\tfd = open(path, O_RDONLY);\n-\tif (fd == -1)\n-\t\treturn 0;\n-\n-\tnumread = read(fd, buf, buflen - 1);\n-\tif (numread \u003c 1) {\n-\t\tclose(fd);\n-\t\treturn 0;\n-\t}\n-\n-\tbuf[numread] = '\\0';\n-\tclose(fd);\n-\n-\treturn (unsigned int) numread;\n-}\n-\n-static void __write_file(const char *path, const char *buf, size_t buflen, bool ignore_einval)\n-{\n-\tint fd, saved_errno;\n-\tssize_t numwritten;\n-\n-\tif (buflen \u003c 2)\n-\t\tksft_exit_fail_msg(\"Incorrect buffer len: %zu\\n\", buflen);\n-\n-\tfd = open(path, O_WRONLY);\n-\tif (fd == -1)\n-\t\tksft_exit_fail_msg(\"%s open failed: %s\\n\", path, strerror(errno));\n-\n-\tnumwritten = write(fd, buf, buflen - 1);\n-\tsaved_errno = errno;\n-\tclose(fd);\n-\terrno = saved_errno;\n-\tif (numwritten \u003c 0) {\n-\t\tif (ignore_einval \u0026\u0026 errno == EINVAL)\n-\t\t\treturn;\n-\t\tksft_exit_fail_msg(\"%s write(%.*s) failed: %s\\n\", path, (int)(buflen - 1),\n-\t\t\t\tbuf, strerror(errno));\n-\t}\n-\tif (numwritten != buflen - 1)\n-\t\tksft_exit_fail_msg(\"%s write(%.*s) is truncated, expected %zu bytes, got %zd bytes\\n\",\n-\t\t\t\tpath, (int)(buflen - 1), buf, buflen - 1, numwritten);\n-}\n-\n-void write_file(const char *path, const char *buf, size_t buflen)\n-{\n-\t__write_file(path, buf, buflen, /* ignore_einval = */ false);\n-}\n-\n-unsigned long read_num(const char *path)\n-{\n-\tchar buf[21];\n-\n-\tif (!read_file(path, buf, sizeof(buf)))\n-\t\tksft_exit_fail_perror(\"read_file()\");\n-\n-\treturn strtoul(buf, NULL, 10);\n-}\n-\n-static void __write_num(const char *path, unsigned long num, bool ignore_einval)\n-{\n-\tchar buf[21];\n-\n-\tsprintf(buf, \"%lu\", num);\n-\t__write_file(path, buf, strlen(buf) + 1, ignore_einval);\n-}\n-\n-void write_num(const char *path, unsigned long num)\n-{\n-\treturn __write_num(path, num, /* ignore_einval = */ false);\n-}\n-\n-void write_num_ignore_einval(const char *path, unsigned long num)\n-{\n-\treturn __write_num(path, num, /* ignore_einval = */ true);\n-}\n-\n static unsigned long shmall, shmmax;\n \n void __shm_limits_restore(void)\n {\n-\tif (shmmax)\n-\t\twrite_num(\"/proc/sys/kernel/shmmax\", shmmax);\n-\tif (shmall)\n-\t\twrite_num(\"/proc/sys/kernel/shmall\", shmall);\n+\tint ret;\n+\n+\tif (shmmax) {\n+\t\tret = write_num(\"/proc/sys/kernel/shmmax\", shmmax);\n+\t\tif (ret \u003c 0)\n+\t\t\tksft_exit_fail_msg(\"Failed to restore shmmax: %s\\n\",\n+\t\t\t\t\t strerror(-ret));\n+\t}\n+\tif (shmall) {\n+\t\tret = write_num(\"/proc/sys/kernel/shmall\", shmall);\n+\t\tif (ret \u003c 0)\n+\t\t\tksft_exit_fail_msg(\"Failed to restore shmall: %s\\n\",\n+\t\t\t\t\t strerror(-ret));\n+\t}\n }\n \n void shm_limits_prepare(unsigned long length)\n {\n \tunsigned long nr = length / psize();\n \tunsigned long val;\n+\tint ret;\n+\n+\tret = read_num(\"/proc/sys/kernel/shmmax\", \u0026val);\n+\tif (ret \u003c 0)\n+\t\tksft_exit_fail_msg(\"Failed to read /proc/sys/kernel/shmmax: %s\\n\",\n+\t\t\t\t strerror(-ret));\n \n-\tval = read_num(\"/proc/sys/kernel/shmmax\");\n \tif (val \u003c length) {\n-\t\twrite_num(\"/proc/sys/kernel/shmmax\", length);\n+\t\tret = write_num(\"/proc/sys/kernel/shmmax\", length);\n+\t\tif (ret \u003c 0)\n+\t\t\tksft_exit_fail_msg(\"Failed to write %lu to /proc/sys/kernel/shmmax: %s\\n\",\n+\t\t\t\t\t length, strerror(-ret));\n \t\tshmmax = val;\n \t}\n \n-\tval = read_num(\"/proc/sys/kernel/shmall\");\n+\tret = read_num(\"/proc/sys/kernel/shmall\", \u0026val);\n+\tif (ret \u003c 0)\n+\t\tksft_exit_fail_msg(\"Failed to read /proc/sys/kernel/shmall: %s\\n\",\n+\t\t\t\t strerror(-ret));\n \tif (val \u003c nr) {\n-\t\twrite_num(\"/proc/sys/kernel/shmall\", nr);\n+\t\tret = write_num(\"/proc/sys/kernel/shmall\", nr);\n+\t\tif (ret \u003c 0)\n+\t\t\tksft_exit_fail_msg(\"Failed to write %lu to /proc/sys/kernel/shmall: %s\\n\",\n+\t\t\t\t\t nr, strerror(-ret));\n \t\tshmall = val;\n \t}\n }\ndiff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h\nindex 9a49af88702e4..64a86e8a0c41b 100644\n--- a/tools/testing/selftests/mm/vm_util.h\n+++ b/tools/testing/selftests/mm/vm_util.h\n@@ -8,6 +8,8 @@\n #include \u003cunistd.h\u003e /* _SC_PAGESIZE */\n #include \"kselftest.h\"\n #include \u003clinux/fs.h\u003e\n+#include \u003cmm/file_utils.h\u003e\n+#include \u003cmm/hugepage_settings.h\u003e\n \n #define BIT_ULL(nr) (1ULL \u003c\u003c (nr))\n #define PM_SOFT_DIRTY BIT_ULL(55)\n@@ -166,12 +168,6 @@ int unpoison_memory(unsigned long pfn);\n #define PAGEMAP_PRESENT(ent)\t(((ent) \u0026 (1ull \u003c\u003c 63)) != 0)\n #define PAGEMAP_PFN(ent)\t((ent) \u0026 ((1ull \u003c\u003c 55) - 1))\n \n-void write_file(const char *path, const char *buf, size_t buflen);\n-int read_file(const char *path, char *buf, size_t buflen);\n-unsigned long read_num(const char *path);\n-void write_num(const char *path, unsigned long num);\n-void write_num_ignore_einval(const char *path, unsigned long num);\n-\n void shm_limits_prepare(unsigned long length);\n void __shm_limits_restore(void);\n \n"
} |
| 2/1 | 2026/09/11 12:46 | agent | patch-evaluator |
0mModel:core Args: null Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch modifies only userspace tools and selftests (tools/lib/mm/, tools/mm/, tools/testing/selftests/mm/), documentation (Documentation/core-api/pin_user_pages.rst), MAINTAINERS, and Kconfig help text (mm/Kconfig). No compiled kernel C logic is affected.",
"WorthFuzzing": false
}Instruction: You are an expert Linux kernel maintainer and security engineer.
Your job is to review a provided patch series and evaluate whether it warrants fuzzing with syzkaller.
IMPORTANT: The changes have ALREADY been applied and committed as the HEAD commit in
your workspace. Do NOT rely on internal assumptions. You must actively use your code access
tools to inspect the actual source code, callers, and surrounding context.
================================================================================
1. CORE TRIAGE PHILOSOPHY
================================================================================
The goal of patch fuzzing is to discover crashes, regressions, exposed latent bugs,
and newly triggered assertions introduced by the patch series.
- REACHABILITY IS THE PRIMARY GATE:
Fuzzing can only discover bugs in code that can actually execute in standard virtualized
environments (GCE or QEMU, utilizing software-emulated devices like USB gadgets, netdev, tun/tap).
If the modified code is structurally unreachable (see Section 2), it MUST NOT be fuzzed,
regardless of whether it adds assertions or complex logic.
- DO NOT BLINDLY TRUST "NO FUNCTIONAL CHANGE" (NFCI) OR "REFACTORING" CLAIMS:
Patch authors routinely label changes as "cleanups", "refactorings", or state
"No functional change intended". Do NOT take these claims at face value.
Code refactorings that rearrange logic, introduce helper functions, or alter state management
in core subsystems frequently introduce subtle semantic shifts or uncover latent kernel bugs.
If reachable executable code is modified or refactored, it MUST be fuzzed.
- NEW OR MODIFIED ASSERTIONS IN REACHABLE CODE MUST BE FUZZED:
When a patch introduces or modifies runtime checks or assertions (e.g., WARN_ON*, VM_WARN_ON*,
BUG_ON*, lockdep_assert*) in reachable code paths, it enforces new or stricter invariants.
Even if the author believes the invariant always holds, fuzzing is essential to verify whether
an unusual sequence of operations can violate it.
================================================================================
2. WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)
================================================================================
Return WorthFuzzing=false ONLY IF all modified code falls strictly into one or more of these categories:
- Non-kernel and non-executable changes:
* Modifications to Documentation/, comments, or spelling fixes.
* User-space directories, self-tests, samples, or scripts (e.g., tools/, samples/, scripts/, usr/)
that do not affect the compiled kernel image (vmlinux) or kernel modules.
* Purely decorative logging (e.g., message strings in pr_err, printk, dev_info) or tracepoints
that do not alter control flow or data structures.
* Build system or Kconfig changes that do not alter compiled C logic.
- Structurally unreachable hardware:
* Vendor-specific PCIe switches, SmartNICs, or GPU drivers (e.g., mlxsw, pds_core, qed,
ionic, amdgpu) requiring physical ASIC/PCIe cards not emulated in standard QEMU.
- Unreachable execution paths:
* Driver teardown callbacks (.remove, .shutdown, pci_unregister_driver) executed only during
physical PCI hot-unplug or manual sysfs driver unbinding.
* Code paths exclusive to architectures other than the target architecture.
================================================================================
3. WHEN TO RETURN WorthFuzzing=true (POSITIVE CRITERIA)
================================================================================
Return WorthFuzzing=true whenever the patch touches reachable executable code, including:
- Core Subsystems:
* Any logic modifications in memory management (mm/), synchronization/locking (kernel/locking/),
BPF, scheduler, core networking, VFS, or syscall handling.
- Refactorings and Code Cleanups:
* Any restructuring of reachable data structures, helper abstractions, or algorithm flows.
- Runtime Assertions and Defensive Checks:
* Any introduction or alteration of assertions (WARN_ON*, VM_WARN_ON*, BUG_ON*, etc.) in reachable paths.
- Reachable Drivers and Protocols:
* Drivers accessible via virtual buses (virtio, USB gadget, loopback, netlink, binder, sockets, etc.).
================================================================================
4. EXTRACTING FocusSymbols (PREVENTING DILUTION)
================================================================================
When WorthFuzzing=true, you must extract specific kernel functions into FocusSymbols to guide the fuzzer:
- AVOID UBIQUITOUS LIFECYCLE HOT-PATHS:
Do NOT list generic, ubiquitous functions called by almost every program in the corpus
(including, but not limited to: general memory allocators and deallocators, page fault
and trap handlers, or core synchronization primitives; this is not an exhaustive list).
Listing ubiquitous functions causes the fuzzer to classify thousands of unrelated tests as "focused",
which severely dilutes fuzzing effort away from the actual changes.
- TARGET SPECIFIC FEATURE LOGIC AND ENTRYPOINTS:
List functions that specifically implement the logic being added or altered, or direct API entrypoints
for the subsystem feature under review.
- HANDLING STATIC INLINE FUNCTIONS IN HEADERS (.h):
Compiler-inlined static functions (such as static inlines in mm/*.h or include/linux/*.h) lack
distinct symbol addresses in vmlinux and cannot be targeted directly by symbol coverage filters.
If the changes are primarily in static inline helpers, identify non-static, feature-specific caller
functions in .c files that exercise them (avoiding ubiquitous lifecycle wrappers).
================================================================================
5. IDENTIFYING EnableConfigs
================================================================================
Identify any specific CONFIG_ options required to properly compile and reach the modified code:
- Inspect Kconfig files and #ifdef guards; do not make assumptions.
- Check "depends on" lines in Kconfig to include any non-standard parent subsystem configs needed.
- Strip any 'CONFIG_' prefix (e.g., return "NET_IPV4" instead of "CONFIG_NET_IPV4").
Prefer calling several tools at the same time to save round-trips.
Use set-results tool to provide results of the analysis.
It must be called exactly once before the final reply.
Ignore results of this tool.
Prompt: Target architecture: amd64
For your convenience, here is the diff of the changes:
commit 8130d75271d743a2b21dbcb4a6b365ba04f740d4
Author: syz-cluster <triage@syzkaller.com>
Date: Fri Sep 11 12:46:57 2026 +0000
syz-cluster: applied patch under review
diff --git a/Documentation/core-api/pin_user_pages.rst b/Documentation/core-api/pin_user_pages.rst
index c16ca163b55e3..e0acedbd1d486 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 accessed.
Unit testing
============
-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 released
since the system was booted, via two new /proc/vmstat entries: ::
diff --git a/MAINTAINERS b/MAINTAINERS
index 35262aa3e67ef..c47e655c41112 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -17187,8 +17187,9 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/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.c
F: tools/testing/selftests/mm/gup_longterm.c
-F: tools/testing/selftests/mm/gup_test.c
MEMORY MANAGEMENT - KSM (Kernel Samepage Merging)
M: Andrew Morton <akpm@linux-foundation.org>
@@ -17295,6 +17296,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/
MEMORY MANAGEMENT - NUMA MEMBLOCKS AND NUMA EMULATION
diff --git a/mm/Kconfig b/mm/Kconfig
index c180d40cd6712..61ab1b8a2ebdf 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -1291,24 +1291,19 @@ config PERCPU_STATS
be used to help understand percpu memory usage.
config GUP_TEST
- bool "Enable infrastructure for get_user_pages()-related unit tests"
+ bool "Enable infrastructure for get_user_pages()-related unit tests and benchmarks"
depends on DEBUG_FS
help
Provides /sys/kernel/debug/gup_test, which in turn provides a way
- to make ioctl calls that can launch kernel-based unit tests for
- the get_user_pages*() and pin_user_pages*() family of API calls.
+ to make ioctl calls that can launch kernel-based unit tests and
+ benchmarks for the get_user_pages*() and pin_user_pages*() families
+ of API calls.
- These tests include benchmark testing of the _fast variants of
- get_user_pages*() and pin_user_pages*(), as well as smoke tests of
+ These include benchmark testing of the _fast variants of
+ get_user_pages*() and pin_user_pages*(), as well as tests of
the non-_fast variants.
- There is also a sub-test that allows running dump_page() on any
- of up to eight pages (selected by command line args) within the
- range of user-space addresses. These pages are either pinned via
- pin_user_pages*(), or pinned via get_user_pages*(), as specified
- by other command line arguments.
-
- See tools/testing/selftests/mm/gup_test.c
+ See tools/testing/selftests/mm/gup.c and tools/mm/gup_bench.c.
comment "GUP_TEST needs to have DEBUG_FS enabled"
depends on !GUP_TEST && !DEBUG_FS
diff --git a/tools/lib/mm/file_utils.c b/tools/lib/mm/file_utils.c
new file mode 100644
index 0000000000000..9b2237e9823e9
--- /dev/null
+++ b/tools/lib/mm/file_utils.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "file_utils.h"
+
+int read_file(const char *path, char *buf, size_t buflen)
+{
+ int fd, err;
+ ssize_t numread;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return -errno;
+
+ numread = read(fd, buf, buflen - 1);
+ if (numread < 1) {
+ err = numread ? errno : ENODATA;
+ close(fd);
+ return -err;
+ }
+
+ buf[numread] = '\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 = open(path, O_WRONLY);
+ if (fd == -1)
+ return -errno;
+
+ numwritten = write(fd, buf, buflen - 1);
+ saved_errno = errno;
+ close(fd);
+
+ if (numwritten < 0)
+ return -saved_errno;
+
+ if (numwritten != (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 = 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 = 0;
+ val = strtoul(buf, &end, 10);
+ if (errno)
+ return -errno;
+
+ /* Only allow a newline after the number */
+ if (*end == '\n')
+ end++;
+
+ if (*end != '\0')
+ return -EINVAL;
+
+ *num = 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 = write_num(path, num);
+ return ret == -EINVAL ? 0 : ret;
+}
diff --git a/tools/lib/mm/file_utils.h b/tools/lib/mm/file_utils.h
new file mode 100644
index 0000000000000..50daa82c2b2b4
--- /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 <stddef.h>
+
+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/hugepage_settings.c b/tools/lib/mm/hugepage_settings.c
similarity index 87%
rename from tools/testing/selftests/mm/hugepage_settings.c
rename to tools/lib/mm/hugepage_settings.c
index d7917dce3abac..abd9f7182f88f 100644
--- a/tools/testing/selftests/mm/hugepage_settings.c
+++ b/tools/lib/mm/hugepage_settings.c
@@ -8,12 +8,18 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <errno.h>
-#include "vm_util.h"
+#include "file_utils.h"
#include "hugepage_settings.h"
#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;
@@ -48,6 +54,11 @@ static const char * const shmem_enabled_strings[] = {
NULL
};
+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 +72,9 @@ int thp_read_string(const char *name, const char * const strings[])
exit(EXIT_FAILURE);
}
- if (!read_file(path, buf, sizeof(buf))) {
- perror(path);
+ ret = read_file(path, buf, sizeof(buf));
+ if (ret) {
+ print_file_access_error(path, ret);
exit(EXIT_FAILURE);
}
@@ -103,12 +115,17 @@ void thp_write_string(const char *name, const char *val)
printf("%s: Pathname is too long\n", __func__);
exit(EXIT_FAILURE);
}
- write_file(path, val, strlen(val) + 1);
+ ret = write_file(path, val, strlen(val) + 1);
+ if (ret) {
+ print_file_access_error(path, ret);
+ exit(EXIT_FAILURE);
+ }
}
unsigned long thp_read_num(const char *name)
{
char path[PATH_MAX];
+ unsigned long num;
int ret;
ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
@@ -116,7 +133,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 = read_num(path, &num);
+ if (ret) {
+ print_file_access_error(path, ret);
+ exit(EXIT_FAILURE);
+ }
+
+ return num;
}
void thp_write_num(const char *name, unsigned long num)
@@ -129,7 +152,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 = write_num(path, num);
+ if (ret) {
+ print_file_access_error(path, ret);
+ exit(EXIT_FAILURE);
+ }
}
void thp_read_settings(struct thp_settings *settings)
@@ -157,8 +184,15 @@ void thp_read_settings(struct thp_settings *settings)
.max_ptes_shared = thp_read_num("khugepaged/max_ptes_shared"),
.pages_to_scan = thp_read_num("khugepaged/pages_to_scan"),
};
- if (dev_queue_read_ahead_path[0])
- settings->read_ahead_kb = read_num(dev_queue_read_ahead_path);
+ if (dev_queue_read_ahead_path[0]) {
+ int ret = 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);
+ }
+ }
for (i = 0; i < NR_ORDERS; i++) {
if (!((1 << i) & orders)) {
@@ -208,8 +242,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);
- 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 = 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);
+ }
+ }
for (i = 0; i < NR_ORDERS; i++) {
if (!((1 << i) & orders))
@@ -307,8 +348,15 @@ static unsigned long __thp_supported_orders(bool is_shmem)
}
ret = read_file(path, buf, sizeof(buf));
- if (ret)
- orders |= 1UL << i;
+ if (ret) {
+ if (ret != -ENOENT) {
+ print_file_access_error(path, ret);
+ exit(EXIT_FAILURE);
+ }
+ continue;
+ }
+
+ orders |= 1UL << i;
}
return orders;
@@ -382,8 +430,7 @@ int detect_hugetlb_page_sizes(unsigned long sizes[], int max)
if (sscanf(entry->d_name, "hugepages-%zukB", &kb) != 1)
continue;
sizes[count++] = 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 +472,49 @@ static void hugetlb_sysfs_path(char *buf, size_t buflen,
unsigned long hugetlb_nr_pages(unsigned long size)
{
char path[PATH_MAX];
+ unsigned long nr;
+ int ret;
hugetlb_sysfs_path(path, sizeof(path), size, "nr_hugepages");
- return read_num(path);
+ ret = read_num(path, &nr);
+ if (ret) {
+ print_file_access_error(path, ret);
+ exit(EXIT_FAILURE);
+ }
+
+ return nr;
}
void hugetlb_set_nr_pages(unsigned long size, unsigned long nr)
{
char path[PATH_MAX];
+ int ret;
hugetlb_sysfs_path(path, sizeof(path), size, "nr_hugepages");
- write_num_ignore_einval(path, nr);
+ ret = write_num_ignore_einval(path, nr);
+ if (ret) {
+ print_file_access_error(path, ret);
+ exit(EXIT_FAILURE);
+ }
}
unsigned long hugetlb_free_pages(unsigned long size)
{
char path[PATH_MAX];
+ unsigned long nr;
+ int ret;
hugetlb_sysfs_path(path, sizeof(path), size, "free_hugepages");
- return read_num(path);
+ ret = read_num(path, &nr);
+ if (ret) {
+ print_file_access_error(path, ret);
+ exit(EXIT_FAILURE);
+ }
+
+ return nr;
}
static bool __hugetlb_setup(unsigned long size, unsigned long nr)
@@ -502,7 +570,8 @@ unsigned long hugetlb_setup(unsigned long nr, unsigned long sizes[],
return 0;
if (nr_enabled > max) {
- ksft_print_msg("detected %d huge page sizes, will only test %d\n", nr_enabled, max);
+ printf("# detected %d huge page sizes, will only test %d\n",
+ nr_enabled, max);
nr_enabled = max;
}
@@ -574,8 +643,10 @@ static void hugepage_restore_settings_atexit(void)
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);
}
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/mm/.gitignore b/tools/mm/.gitignore
index 1446a659e5408..154d740be02e8 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 858186a6eefdb..f20a32d8cc22e 100644
--- a/tools/mm/Makefile
+++ b/tools/mm/Makefile
@@ -3,13 +3,15 @@
#
include ../scripts/Makefile.include
-BUILD_TARGETS=page-types slabinfo page_owner_sort page_owner_filter thp_swap_allocator_test
+BUILD_TARGETS=page-types slabinfo page_owner_sort page_owner_filter
+BUILD_TARGETS += thp_swap_allocator_test gup_bench
INSTALL_TARGETS = $(BUILD_TARGETS) thpmaps
LIB_DIR = ../lib/api
LIBS = $(LIB_DIR)/libapi.a
+GUP_BENCH_OBJS = gup_bench.c ../lib/mm/hugepage_settings.c ../lib/mm/file_utils.c
-CFLAGS += -Wall -Wextra -I../lib/ -pthread
+CFLAGS += -Wall -Wextra -I../lib/ -I../.. -pthread
LDFLAGS += $(LIBS) -pthread
all: $(BUILD_TARGETS)
@@ -22,8 +24,11 @@ $(LIBS):
%: %.c
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS)
+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_allocator_test
+ $(RM) page-types slabinfo page_owner_sort page_owner_filter thp_swap_allocator_test gup_bench
make -C $(LIB_DIR) clean
sbindir ?= /usr/sbin
diff --git a/tools/testing/selftests/mm/gup_test.c b/tools/mm/gup_bench.c
similarity index 50%
rename from tools/testing/selftests/mm/gup_test.c
rename to tools/mm/gup_bench.c
index 3f841a96f8706..ff6e466546813 100644
--- a/tools/testing/selftests/mm/gup_test.c
+++ b/tools/mm/gup_bench.c
@@ -10,11 +10,10 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <pthread.h>
-#include <assert.h>
+#include <stdbool.h>
+#include <string.h>
#include <mm/gup_test.h>
-#include "kselftest.h"
-#include "vm_util.h"
-#include "hugepage_settings.h"
+#include <mm/hugepage_settings.h>
#define MB (1UL << 20)
@@ -38,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";
}
@@ -53,39 +46,29 @@ void *gup_thread(void *data)
struct gup_test gup = *(struct gup_test *)data;
int i, status;
- /* Only report timing information on the *_BENCHMARK commands: */
- if ((cmd == PIN_FAST_BENCHMARK) || (cmd == GUP_FAST_BENCHMARK) ||
- (cmd == PIN_LONGTERM_BENCHMARK)) {
- for (i = 0; i < repeats; i++) {
- gup.size = size;
- status = ioctl(gup_fd, cmd, &gup);
- if (status)
- break;
+ for (i = 0; i < repeats; i++) {
+ gup.size = size;
+ status = ioctl(gup_fd, cmd, &gup);
+ if (status) {
+ int err = errno;
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 != 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 = size;
- status = ioctl(gup_fd, cmd, &gup);
- if (status)
- goto return_;
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 != size)
- ksft_print_msg("Truncated (size: %lld)\n", gup.size);
+ printf(", truncated (size: %lld)", gup.size);
+ printf("\n");
pthread_mutex_unlock(&print_mutex);
}
-return_:
- ksft_test_result(!status, "ioctl status %d\n", status);
return NULL;
}
@@ -93,38 +76,21 @@ int main(int argc, char **argv)
{
struct gup_test gup = { 0 };
int filed, i, opt, nr_pages = 1, thp = -1, write = 1, nthreads = 1, ret;
- int flags = MAP_PRIVATE;
+ int flags = MAP_PRIVATE, started_threads = 0, exit_status = 1;
char *file = "/dev/zero";
- bool hugetlb = false;
+ bool hugetlb = false, thread_error = false;
+ void *thread_result;
pthread_t *tid;
char *p;
- while ((opt = getopt(argc, argv, "m:r:n:F:f:abcj:tTLUuwWSHpz")) != -1) {
+ while ((opt = getopt(argc, argv, "m:r:n:F:f:aj:tTLuwWSH")) != -1) {
switch (opt) {
case 'a':
cmd = PIN_FAST_BENCHMARK;
break;
- case 'b':
- cmd = PIN_BASIC_TEST;
- break;
case 'L':
cmd = PIN_LONGTERM_BENCHMARK;
break;
- case 'c':
- cmd = 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] = 1;
- break;
- case 'p':
- /* works only with DUMP_USER_PAGES_TEST */
- gup.test_flags |= GUP_TEST_FLAG_DUMP_PAGES_USE_PIN;
- break;
case 'F':
/* strtol, so you can pass flags in hex form */
gup.gup_flags = strtol(optarg, 0, 0);
@@ -141,7 +107,7 @@ int main(int argc, char **argv)
case 'n':
nr_pages = atoi(optarg);
if (nr_pages < 0)
- nr_pages = size / psize();
+ nr_pages = size / getpagesize();
break;
case 't':
thp = 1;
@@ -149,9 +115,6 @@ int main(int argc, char **argv)
case 'T':
thp = 0;
break;
- case 'U':
- cmd = GUP_BASIC_TEST;
- break;
case 'u':
cmd = GUP_FAST_BENCHMARK;
break;
@@ -173,52 +136,41 @@ int main(int argc, char **argv)
hugetlb = true;
break;
default:
- ksft_exit_fail_msg("Wrong argument\n");
+ fprintf(stderr, "Wrong argument\n");
+ exit(1);
}
}
- if (optind < argc) {
- int extra_arg_count = 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 = strtol(argv[optind], 0, 0) + 1;
-
- gup.which_pages[extra_arg_count] = page_index;
- extra_arg_count++;
- optind++;
- }
+ if (optind != argc) {
+ fprintf(stderr, "Unexpected argument '%s'\n", argv[optind]);
+ exit(1);
}
- ksft_print_header();
+ if (geteuid()) {
+ fprintf(stderr, "Please run this test as root\n");
+ exit(1);
+ }
if (hugetlb) {
unsigned long hp_size = default_huge_page_size();
- if (!hp_size)
- ksft_exit_skip("HugeTLB is unavailable\n");
+ if (!hp_size) {
+ fprintf(stderr, "Could not determine huge page size\n");
+ return 1;
+ }
size = (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;
+ }
}
- ksft_set_plan(nthreads);
-
filed = 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;
+ }
gup.nr_pages_per_call = nr_pages;
if (write)
@@ -227,26 +179,24 @@ int main(int argc, char **argv)
gup_fd = open(GUP_TEST_FILE, O_RDWR);
if (gup_fd == -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") == 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;
}
p = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, filed, 0);
- if (p == MAP_FAILED)
- ksft_exit_fail_msg("mmap: %s\n", strerror(errno));
+ if (p == MAP_FAILED) {
+ fprintf(stderr, "mmap: %s\n", strerror(errno));
+ goto err_close_gup_fd;
+ }
gup.addr = (unsigned long)p;
if (thp == 1)
@@ -255,21 +205,43 @@ int main(int argc, char **argv)
madvise(p, size, MADV_NOHUGEPAGE);
/* Fault them in here, from user space. */
- for (; (unsigned long)p < gup.addr + size; p += psize())
+ for (; (unsigned long)p < gup.addr + size; p += getpagesize())
p[0] = 0;
tid = 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 = 0; i < nthreads; i++) {
ret = pthread_create(&tid[i], NULL, gup_thread, &gup);
- assert(ret == 0);
+ if (ret) {
+ fprintf(stderr, "pthread_create failed: %s\n", strerror(ret));
+ thread_error = true;
+ break;
+ }
+ started_threads++;
}
- for (i = 0; i < nthreads; i++) {
- ret = pthread_join(tid[i], NULL);
- assert(ret == 0);
+ for (i = 0; i < started_threads; i++) {
+ ret = pthread_join(tid[i], &thread_result);
+ if (ret) {
+ fprintf(stderr, "pthread_join failed: %s\n", strerror(ret));
+ thread_error = true;
+ } else if (thread_result)
+ thread_error = true;
}
free(tid);
-
- ksft_exit_pass();
+ if (!thread_error)
+ exit_status = 0;
+
+err_unmap:
+ munmap((void *)gup.addr, size);
+err_close_gup_fd:
+ close(gup_fd);
+err_close_filed:
+ close(filed);
+ return exit_status;
}
diff --git a/tools/testing/selftests/mm/Makefile b/tools/testing/selftests/mm/Makefile
index 2d5366196e309..9c03624fd2936 100644
--- a/tools/testing/selftests/mm/Makefile
+++ b/tools/testing/selftests/mm/Makefile
@@ -37,7 +37,8 @@ endif
# LDLIBS.
MAKEFLAGS += --no-builtin-rules
-CFLAGS = -Wall -O2 -I $(top_srcdir) $(EXTRA_CFLAGS) $(KHDR_INCLUDES) $(TOOLS_INCLUDES)
+CFLAGS = -Wall -O2 -I $(top_srcdir) -I $(top_srcdir)/tools/lib
+CFLAGS += $(EXTRA_CFLAGS) $(KHDR_INCLUDES) $(TOOLS_INCLUDES)
CFLAGS += -Wunreachable-code
LDLIBS = -lrt -lpthread -lm
@@ -57,8 +58,8 @@ endif
TEST_GEN_FILES = cow
TEST_GEN_FILES += compaction_test
+TEST_GEN_FILES += gup
TEST_GEN_FILES += gup_longterm
-TEST_GEN_FILES += gup_test
TEST_GEN_FILES += hmm-tests
TEST_GEN_FILES += hugetlb-madvise
TEST_GEN_FILES += hugetlb-mmap
@@ -187,8 +188,10 @@ TEST_FILES += write_hugetlb_memory.sh
include ../lib.mk
-$(TEST_GEN_PROGS): vm_util.c hugepage_settings.c
-$(TEST_GEN_FILES): vm_util.c hugepage_settings.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
$(OUTPUT)/uffd-stress: uffd-common.c
$(OUTPUT)/uffd-unit-tests: uffd-common.c
@@ -217,7 +220,7 @@ $(BINARIES_32): CFLAGS += -m32 -mxsave
$(BINARIES_32): LDLIBS += -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
@@ -226,7 +229,7 @@ $(BINARIES_64): CFLAGS += -m64 -mxsave
$(BINARIES_64): LDLIBS += -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
diff --git a/tools/testing/selftests/mm/compaction_test.c b/tools/testing/selftests/mm/compaction_test.c
index 30d4ace7155ae..b3f5377119cb8 100644
--- a/tools/testing/selftests/mm/compaction_test.c
+++ b/tools/testing/selftests/mm/compaction_test.c
@@ -15,9 +15,9 @@
#include <errno.h>
#include <unistd.h>
#include <string.h>
+#include <mm/hugepage_settings.h>
#include "kselftest.h"
-#include "hugepage_settings.h"
#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 8aa5249d9bef6..3264a828575bd 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"
static size_t pagesize;
static int pagemap_fd;
diff --git a/tools/testing/selftests/mm/folio_split_race_test.c b/tools/testing/selftests/mm/folio_split_race_test.c
index 1960635a953eb..e4660bf89b624 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 <unistd.h>
#include "vm_util.h"
#include "kselftest.h"
-#include "hugepage_settings.h"
uint64_t page_size;
uint64_t pmd_pagesize;
diff --git a/tools/testing/selftests/mm/guard-regions.c b/tools/testing/selftests/mm/guard-regions.c
index 5c8ec3ca75d7d..af5cd9b303395 100644
--- a/tools/testing/selftests/mm/guard-regions.c
+++ b/tools/testing/selftests/mm/guard-regions.c
@@ -21,7 +21,6 @@
#include <sys/uio.h>
#include <unistd.h>
#include "vm_util.h"
-#include "hugepage_settings.h"
#include "../pidfd/pidfd.h"
diff --git a/tools/testing/selftests/mm/gup.c b/tools/testing/selftests/mm/gup.c
new file mode 100644
index 0000000000000..31ae38e09136d
--- /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 <fcntl.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <mm/gup_test.h>
+#include "vm_util.h"
+#include "kselftest_harness.h"
+
+#define MB (1UL << 20)
+
+/* Just the flags we need, copied from the kernel internals. */
+#define FOLL_WRITE 0x01 /* check pte is writable */
+
+/* Page counts exercising single, THP-batch, partial, and full-mapping GUP. */
+static const int nr_pages_list[] = { 1, 512, 123, -1 };
+
+#define GUP_TEST_FILE "/sys/kernel/debug/gup_test"
+#define 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 = false,
+ .hugetlb = false,
+ .write = true,
+ .shared = false,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, private_read)
+{
+ .thp = false,
+ .hugetlb = false,
+ .write = false,
+ .shared = false,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, private_write_thp)
+{
+ .thp = true,
+ .hugetlb = false,
+ .write = true,
+ .shared = false,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, private_read_thp)
+{
+ .thp = true,
+ .hugetlb = false,
+ .write = false,
+ .shared = false,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, private_write_hugetlb)
+{
+ .thp = false,
+ .hugetlb = true,
+ .write = true,
+ .shared = false,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, private_read_hugetlb)
+{
+ .thp = false,
+ .hugetlb = true,
+ .write = false,
+ .shared = false,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, shared_write)
+{
+ .thp = false,
+ .hugetlb = false,
+ .write = true,
+ .shared = true,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, shared_read)
+{
+ .thp = false,
+ .hugetlb = false,
+ .write = false,
+ .shared = true,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, shared_write_thp)
+{
+ .thp = true,
+ .hugetlb = false,
+ .write = true,
+ .shared = true,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, shared_read_thp)
+{
+ .thp = true,
+ .hugetlb = false,
+ .write = false,
+ .shared = true,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, shared_write_hugetlb)
+{
+ .thp = false,
+ .hugetlb = true,
+ .write = true,
+ .shared = true,
+};
+
+FIXTURE_VARIANT_ADD(gup_test, shared_read_hugetlb)
+{
+ .thp = false,
+ .hugetlb = true,
+ .write = false,
+ .shared = true,
+};
+
+FIXTURE_SETUP(gup_test)
+{
+ int mmap_flags = MAP_PRIVATE | MAP_ANONYMOUS;
+ char *p;
+
+ self->size = 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 = NR_HUGE_PAGES * hp_size;
+ mmap_flags |= MAP_HUGETLB;
+ }
+
+ if (variant->shared)
+ mmap_flags = (mmap_flags & ~MAP_PRIVATE) | MAP_SHARED;
+
+ /* gup_fd has to be >= 0. Already checked in main() */
+ self->gup_fd = open(GUP_TEST_FILE, O_RDWR);
+ ASSERT_GE(self->gup_fd, 0);
+
+ self->addr = mmap(NULL, self->size, PROT_READ | PROT_WRITE,
+ mmap_flags, -1, 0);
+
+ ASSERT_NE(self->addr, MAP_FAILED) {
+ int err = 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 = self->addr; (unsigned long)p < (unsigned long)self->addr
+ + self->size; p += psize())
+ p[0] = 0;
+}
+
+FIXTURE_TEARDOWN(gup_test)
+{
+ munmap(self->addr, self->size);
+ close(self->gup_fd);
+}
+
+static void run_gup_cmd(struct __test_metadata *_metadata,
+ FIXTURE_DATA(gup_test) *self,
+ const FIXTURE_VARIANT(gup_test) *variant,
+ unsigned long command)
+{
+ int i;
+
+ for (i = 0; i < (int)ARRAY_SIZE(nr_pages_list); i++) {
+ struct gup_test gup = {
+ .addr = (unsigned long)self->addr,
+ .size = self->size,
+ .nr_pages_per_call = nr_pages_list[i] < 0 ?
+ self->size / psize() : nr_pages_list[i],
+ .gup_flags = variant->write ? FOLL_WRITE : 0,
+ };
+
+ TH_LOG("nr_pages_per_call=%u", gup.nr_pages_per_call);
+ ASSERT_EQ(ioctl(self->gup_fd, command, &gup), 0);
+ ASSERT_EQ(gup.size, self->size);
+ }
+}
+
+TEST_F(gup_test, get_user_pages)
+{
+ run_gup_cmd(_metadata, self, variant, GUP_BASIC_TEST);
+}
+
+TEST_F(gup_test, pin_user_pages)
+{
+ run_gup_cmd(_metadata, self, variant, PIN_BASIC_TEST);
+}
+
+TEST_F(gup_test, get_user_pages_fast)
+{
+ run_gup_cmd(_metadata, self, variant, GUP_FAST_BENCHMARK);
+}
+
+TEST_F(gup_test, pin_user_pages_fast)
+{
+ run_gup_cmd(_metadata, self, variant, PIN_FAST_BENCHMARK);
+}
+
+TEST_F(gup_test, pin_user_pages_longterm)
+{
+ run_gup_cmd(_metadata, self, variant, PIN_LONGTERM_BENCHMARK);
+}
+
+int main(int argc, char **argv)
+{
+ int fd;
+
+ fd = open(GUP_TEST_FILE, O_RDWR);
+ if (fd == -1) {
+ ksft_print_header();
+ if (errno == EACCES)
+ ksft_exit_skip("Please run this test as root\n");
+ if (errno == ENOENT) {
+ DIR *debugfs = opendir("/sys/kernel/debug");
+
+ if (!debugfs)
+ ksft_exit_skip("Mount debugfs at /sys/kernel/debug\n");
+ closedir(debugfs);
+ ksft_exit_skip("Check CONFIG_GUP_TEST in kernel config\n");
+ }
+ ksft_exit_fail_msg("Failed to open %s: %s\n", GUP_TEST_FILE, strerror(errno));
+ }
+ close(fd);
+
+ hp_size = default_huge_page_size();
+ if (hp_size)
+ hugetlb_setup_default(NR_HUGE_PAGES);
+
+ return test_harness_run(argc, argv);
+}
diff --git a/tools/testing/selftests/mm/gup_longterm.c b/tools/testing/selftests/mm/gup_longterm.c
index 510de93be6814..c9d8b44912638 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"
static size_t pagesize;
static int nr_hugetlbsizes;
diff --git a/tools/testing/selftests/mm/hmm-tests.c b/tools/testing/selftests/mm/hmm-tests.c
index e2642eca0d02b..fa1a651963fd0 100644
--- a/tools/testing/selftests/mm/hmm-tests.c
+++ b/tools/testing/selftests/mm/hmm-tests.c
@@ -10,9 +10,6 @@
* bugs.
*/
-#include "kselftest_harness.h"
-#include "hugepage_settings.h"
-
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
@@ -33,6 +30,9 @@
#include <sys/eventfd.h>
#include <linux/userfaultfd.h>
#include <poll.h>
+#include <mm/hugepage_settings.h>
+
+#include "kselftest_harness.h"
/*
* 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/selftests/mm/hugetlb-madvise.c
index 555b4b3d14307..57cf790ca478d 100644
--- a/tools/testing/selftests/mm/hugetlb-madvise.c
+++ b/tools/testing/selftests/mm/hugetlb-madvise.c
@@ -14,7 +14,6 @@
#include <fcntl.h>
#include "vm_util.h"
#include "kselftest.h"
-#include "hugepage_settings.h"
#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/selftests/mm/hugetlb-mmap.c
index 0f2aad1b7dbd6..a458becf58327 100644
--- a/tools/testing/selftests/mm/hugetlb-mmap.c
+++ b/tools/testing/selftests/mm/hugetlb-mmap.c
@@ -18,7 +18,6 @@
#include <linux/memfd.h>
#include "vm_util.h"
#include "kselftest.h"
-#include "hugepage_settings.h"
#define LENGTH (256UL*1024*1024)
#define PROTECTION (PROT_READ | PROT_WRITE)
diff --git a/tools/testing/selftests/mm/hugetlb-mremap.c b/tools/testing/selftests/mm/hugetlb-mremap.c
index ed3d92e862d87..9b724af66e938 100644
--- a/tools/testing/selftests/mm/hugetlb-mremap.c
+++ b/tools/testing/selftests/mm/hugetlb-mremap.c
@@ -26,7 +26,6 @@
#include <stdbool.h>
#include "kselftest.h"
#include "vm_util.h"
-#include "hugepage_settings.h"
#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/selftests/mm/hugetlb-shm.c
index 3ff7f062b7eb4..f4514da49e1df 100644
--- a/tools/testing/selftests/mm/hugetlb-shm.c
+++ b/tools/testing/selftests/mm/hugetlb-shm.c
@@ -29,7 +29,6 @@
#include <sys/mman.h>
#include "vm_util.h"
-#include "hugepage_settings.h"
#define LENGTH (256UL*1024*1024)
diff --git a/tools/testing/selftests/mm/hugetlb-soft-offline.c b/tools/testing/selftests/mm/hugetlb-soft-offline.c
index 4af9d3db7b5b6..d9565219378aa 100644
--- a/tools/testing/selftests/mm/hugetlb-soft-offline.c
+++ b/tools/testing/selftests/mm/hugetlb-soft-offline.c
@@ -22,10 +22,10 @@
#include <sys/mman.h>
#include <sys/statfs.h>
#include <sys/types.h>
+#include <mm/hugepage_settings.h>
#include "kselftest.h"
#include "vm_util.h"
-#include "hugepage_settings.h"
#ifndef MADV_SOFT_OFFLINE
#define MADV_SOFT_OFFLINE 101
@@ -85,8 +85,7 @@ static unsigned long orig_enable_soft_offline = -1UL;
/*
* 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_offline)
hugepagesize_kb = file_stat.f_bsize / 1024;
ksft_print_msg("Hugepagesize is %ldkB\n", hugepagesize_kb);
- write_num(ENABLE_SOFT_OFFLINE_PATH, enable_soft_offline);
+ ret = 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));
nr_hugepages_before = hugetlb_nr_default_pages();
@@ -189,6 +191,8 @@ static void test_soft_offline_common(int enable_soft_offline)
int main(int argc, char **argv)
{
+ int ret;
+
ksft_print_header();
if (!hugetlb_setup_default(8))
@@ -196,7 +200,11 @@ int main(int argc, char **argv)
ksft_set_plan(2);
- orig_enable_soft_offline = read_num(ENABLE_SOFT_OFFLINE_PATH);
+ ret = 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);
test_soft_offline_common(1);
diff --git a/tools/testing/selftests/mm/hugetlb_dio.c b/tools/testing/selftests/mm/hugetlb_dio.c
index fb4600570e131..9495974eccbea 100644
--- a/tools/testing/selftests/mm/hugetlb_dio.c
+++ b/tools/testing/selftests/mm/hugetlb_dio.c
@@ -20,7 +20,6 @@
#include <sys/syscall.h>
#include "vm_util.h"
#include "kselftest.h"
-#include "hugepage_settings.h"
#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 2dc158054f666..56c5a8533e9d9 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 @@
#include "vm_util.h"
#include "kselftest.h"
-#include "hugepage_settings.h"
#define INLOOP_ITER 100
diff --git a/tools/testing/selftests/mm/hugetlb_madv_vs_map.c b/tools/testing/selftests/mm/hugetlb_madv_vs_map.c
index f94549efcc6ff..2532a42b98dff 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 <unistd.h>
#include "vm_util.h"
-#include "hugepage_settings.h"
#define INLOOP_ITER 100
diff --git a/tools/testing/selftests/mm/khugepaged.c b/tools/testing/selftests/mm/khugepaged.c
index f82673f5f6b47..525108cace54a 100644
--- a/tools/testing/selftests/mm/khugepaged.c
+++ b/tools/testing/selftests/mm/khugepaged.c
@@ -22,7 +22,6 @@
#include "linux/magic.h"
#include "vm_util.h"
-#include "hugepage_settings.h"
#define BASE_ADDR ((void *)(1UL << 30))
static unsigned long hpage_pmd_size;
@@ -122,6 +121,7 @@ static void get_finfo(const char *dir)
char buf[1 << 10];
char path[PATH_MAX];
char *str, *end;
+ int ret;
finfo.dir = dir;
if (stat(finfo.dir, &path_stat))
@@ -142,8 +142,9 @@ static void get_finfo(const char *dir)
major(path_stat.st_dev), minor(path_stat.st_dev))
>= 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 = read_file(path, buf, sizeof(buf));
+ if (ret)
+ ksft_exit_fail_msg("read_file(%s): %s\n", path, strerror(-ret));
if (strstr(buf, "DEVTYPE=disk")) {
/* Found it */
if (snprintf(finfo.dev_queue_read_ahead_path,
@@ -324,7 +325,7 @@ static void *file_setup_area_common(int nr_hpages, enum file_setup_ops setup)
{
const int open_opt = setup == FILE_SETUP_READ_ONLY_FS ? O_RDONLY : O_RDWR;
const int mmap_prot = setup == FILE_SETUP_READ_ONLY_FS ? PROT_READ : (PROT_READ | PROT_WRITE);
- int fd;
+ int fd, ret;
void *p;
unsigned long size;
@@ -362,7 +363,11 @@ static void *file_setup_area_common(int nr_hpages, enum file_setup_ops setup)
ksft_exit_fail_perror("mmap()");
/* Drop page cache */
- write_file("/proc/sys/vm/drop_caches", "3", 2);
+ ret = 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/ksm_tests.c b/tools/testing/selftests/mm/ksm_tests.c
index 5fd7792a0d479..6711f4c613711 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/vdso/time64.h>
#include "vm_util.h"
-#include "hugepage_settings.h"
#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/selftests/mm/migration.c
index f19d53c695764..a35e2b57e05b2 100644
--- a/tools/testing/selftests/mm/migration.c
+++ b/tools/testing/selftests/mm/migration.c
@@ -5,7 +5,6 @@
*/
#include "kselftest_harness.h"
-#include "hugepage_settings.h"
#include <string.h>
#include <pthread.h>
@@ -16,6 +15,7 @@
#include <sys/types.h>
#include <signal.h>
#include <time.h>
+
#include "vm_util.h"
#define TWOMEG (2<<20)
diff --git a/tools/testing/selftests/mm/pagemap_ioctl.c b/tools/testing/selftests/mm/pagemap_ioctl.c
index d9a4fb782ecfe..03898b4f6cdab 100644
--- a/tools/testing/selftests/mm/pagemap_ioctl.c
+++ b/tools/testing/selftests/mm/pagemap_ioctl.c
@@ -24,7 +24,6 @@
#include "vm_util.h"
#include "kselftest.h"
-#include "hugepage_settings.h"
#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 82c6e96ea6eb3..f9ec1408a6e30 100644
--- a/tools/testing/selftests/mm/prctl_thp_disable.c
+++ b/tools/testing/selftests/mm/prctl_thp_disable.c
@@ -14,7 +14,6 @@
#include <sys/wait.h>
#include "kselftest_harness.h"
-#include "hugepage_settings.h"
#include "vm_util.h"
#ifndef PR_THP_DISABLE_EXCEPT_ADVISED
diff --git a/tools/testing/selftests/mm/protection_keys.c b/tools/testing/selftests/mm/protection_keys.c
index ae6e1530b3548..b7882ab97683f 100644
--- a/tools/testing/selftests/mm/protection_keys.c
+++ b/tools/testing/selftests/mm/protection_keys.c
@@ -45,8 +45,8 @@
#include <unistd.h>
#include <sys/ptrace.h>
#include <setjmp.h>
+#include <mm/hugepage_settings.h>
-#include "hugepage_settings.h"
#include "pkey-helpers.h"
u64 shadow_pkey_reg;
diff --git a/tools/testing/selftests/mm/run_vmtests.sh b/tools/testing/selftests/mm/run_vmtests.sh
index d09f9f6a384ee..ae0ab5efabae6 100755
--- a/tools/testing/selftests/mm/run_vmtests.sh
+++ b/tools/testing/selftests/mm/run_vmtests.sh
@@ -130,30 +130,6 @@ test_selected() {
fi
}
-run_gup_matrix() {
- # -t: thp=on, -T: thp=off, -H: hugetlb=on
- local hugetlb_mb=256
-
- for huge in -t -T "-H -m $hugetlb_mb"; do
- # -u: gup-fast, -U: gup-basic, -a: pin-fast, -b: pin-basic, -L: pin-longterm
- for test_cmd in -u -U -a -b -L; do
- # -w: write=1, -W: write=0
- 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 form
- for num in "-n 1" "-n 512" "-n 123" "-n -1"; do
- CATEGORY="gup_test" run_test ./gup_test \
- $huge $test_cmd $write $share $num
- done
- done
- done
- done
- done
-}
-
# filter 64bit architectures
ARCH64STR="arm64 mips64 parisc64 ppc64 ppc64le riscv64 s390x sparc64 x86_64"
if [ -z "$ARCH" ]; then
@@ -275,18 +251,7 @@ fi
CATEGORY="mmap" run_test ./map_fixed_noreplace
-if $RUN_ALL; then
- run_gup_matrix
-else
- # get_user_pages_fast() benchmark
- CATEGORY="gup_test" run_test ./gup_test -u -n 1
- CATEGORY="gup_test" run_test ./gup_test -u -n -1
- # pin_user_pages_fast() benchmark
- CATEGORY="gup_test" run_test ./gup_test -a -n 1
- CATEGORY="gup_test" run_test ./gup_test -a -n -1
-fi
-# Dump pages 0, 19, and 4096, using pin_user_pages:
-CATEGORY="gup_test" run_test ./gup_test -ct -F 0x1 0 19 0x1000
+CATEGORY="gup_test" run_test ./gup
CATEGORY="gup_test" run_test ./gup_longterm
CATEGORY="userfaultfd" run_test ./uffd-unit-tests
diff --git a/tools/testing/selftests/mm/soft-dirty.c b/tools/testing/selftests/mm/soft-dirty.c
index 5f278913c4d75..7f649b6733553 100644
--- a/tools/testing/selftests/mm/soft-dirty.c
+++ b/tools/testing/selftests/mm/soft-dirty.c
@@ -9,7 +9,6 @@
#include "kselftest.h"
#include "vm_util.h"
-#include "hugepage_settings.h"
#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/testing/selftests/mm/split_huge_page_test.c
index c01d227d7fd6d..68f508c9a355f 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 <time.h>
#include "vm_util.h"
#include "kselftest.h"
-#include "hugepage_settings.h"
uint64_t pagesize;
unsigned int pageshift;
@@ -145,7 +144,10 @@ static void write_debugfs(const char *fmt, ...)
if (ret >= INPUT_MAX)
ksft_exit_fail_msg("%s: Debugfs input is too long\n", __func__);
- write_file(SPLIT_DEBUGFS, input, ret + 1);
+ ret = write_file(SPLIT_DEBUGFS, input, ret + 1);
+ if (ret)
+ ksft_exit_fail_msg("write_file(%s): %s\n", SPLIT_DEBUGFS,
+ strerror(-ret));
}
static char *allocate_zero_filled_hugepage(size_t len)
diff --git a/tools/testing/selftests/mm/thuge-gen.c b/tools/testing/selftests/mm/thuge-gen.c
index 50d0805b65db9..a04f588df780f 100644
--- a/tools/testing/selftests/mm/thuge-gen.c
+++ b/tools/testing/selftests/mm/thuge-gen.c
@@ -14,7 +14,6 @@
#include <string.h>
#include "vm_util.h"
#include "kselftest.h"
-#include "hugepage_settings.h"
#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 8eb0c5630e7e3..96f72898ebe0a 100644
--- a/tools/testing/selftests/mm/transhuge-stress.c
+++ b/tools/testing/selftests/mm/transhuge-stress.c
@@ -17,7 +17,6 @@
#include <sys/mman.h>
#include "vm_util.h"
#include "kselftest.h"
-#include "hugepage_settings.h"
int backing_fd = -1;
int mmap_flags = MAP_ANONYMOUS | MAP_NORESERVE | MAP_PRIVATE;
diff --git a/tools/testing/selftests/mm/uffd-common.h b/tools/testing/selftests/mm/uffd-common.h
index 92a21b97f745a..0723843a7626b 100644
--- a/tools/testing/selftests/mm/uffd-common.h
+++ b/tools/testing/selftests/mm/uffd-common.h
@@ -37,7 +37,6 @@
#include "kselftest.h"
#include "vm_util.h"
-#include "hugepage_settings.h"
#define UFFD_FLAGS (O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY)
diff --git a/tools/testing/selftests/mm/uffd-wp-mremap.c b/tools/testing/selftests/mm/uffd-wp-mremap.c
index 572c2516e874d..c48eaab8e75cf 100644
--- a/tools/testing/selftests/mm/uffd-wp-mremap.c
+++ b/tools/testing/selftests/mm/uffd-wp-mremap.c
@@ -7,8 +7,8 @@
#include <assert.h>
#include <linux/mman.h>
#include <sys/mman.h>
+#include <mm/hugepage_settings.h>
#include "kselftest.h"
-#include "hugepage_settings.h"
#include "uffd-common.h"
static int pagemap_fd;
diff --git a/tools/testing/selftests/mm/va_high_addr_switch.c b/tools/testing/selftests/mm/va_high_addr_switch.c
index e24d7ba00b441..5a354a664d1f7 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 @@
#include "vm_util.h"
#include "kselftest.h"
-#include "hugepage_settings.h"
/*
* The hint addr value is used to allocate addresses
diff --git a/tools/testing/selftests/mm/vm_util.c b/tools/testing/selftests/mm/vm_util.c
index 80bc9f597b521..4751db798c3ac 100644
--- a/tools/testing/selftests/mm/vm_util.c
+++ b/tools/testing/selftests/mm/vm_util.c
@@ -889,111 +889,54 @@ int unpoison_memory(unsigned long pfn)
return ret > 0 ? 0 : -errno;
}
-int read_file(const char *path, char *buf, size_t buflen)
-{
- int fd;
- ssize_t numread;
-
- fd = open(path, O_RDONLY);
- if (fd == -1)
- return 0;
-
- numread = read(fd, buf, buflen - 1);
- if (numread < 1) {
- close(fd);
- return 0;
- }
-
- buf[numread] = '\0';
- close(fd);
-
- return (unsigned int) numread;
-}
-
-static void __write_file(const char *path, const char *buf, size_t buflen, bool ignore_einval)
-{
- int fd, saved_errno;
- ssize_t numwritten;
-
- if (buflen < 2)
- ksft_exit_fail_msg("Incorrect buffer len: %zu\n", buflen);
-
- fd = open(path, O_WRONLY);
- if (fd == -1)
- ksft_exit_fail_msg("%s open failed: %s\n", path, strerror(errno));
-
- numwritten = write(fd, buf, buflen - 1);
- saved_errno = errno;
- close(fd);
- errno = saved_errno;
- if (numwritten < 0) {
- if (ignore_einval && errno == EINVAL)
- return;
- ksft_exit_fail_msg("%s write(%.*s) failed: %s\n", path, (int)(buflen - 1),
- buf, strerror(errno));
- }
- if (numwritten != 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);
-}
-
-void write_file(const char *path, const char *buf, size_t buflen)
-{
- __write_file(path, buf, buflen, /* ignore_einval = */ false);
-}
-
-unsigned long read_num(const char *path)
-{
- char buf[21];
-
- if (!read_file(path, buf, sizeof(buf)))
- ksft_exit_fail_perror("read_file()");
-
- return strtoul(buf, NULL, 10);
-}
-
-static void __write_num(const char *path, unsigned long num, bool ignore_einval)
-{
- char buf[21];
-
- sprintf(buf, "%lu", num);
- __write_file(path, buf, strlen(buf) + 1, ignore_einval);
-}
-
-void write_num(const char *path, unsigned long num)
-{
- return __write_num(path, num, /* ignore_einval = */ false);
-}
-
-void write_num_ignore_einval(const char *path, unsigned long num)
-{
- return __write_num(path, num, /* ignore_einval = */ true);
-}
-
static unsigned long shmall, shmmax;
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 = 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 = write_num("/proc/sys/kernel/shmall", shmall);
+ if (ret < 0)
+ ksft_exit_fail_msg("Failed to restore shmall: %s\n",
+ strerror(-ret));
+ }
}
void shm_limits_prepare(unsigned long length)
{
unsigned long nr = length / psize();
unsigned long val;
+ int ret;
+
+ ret = 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));
- val = read_num("/proc/sys/kernel/shmmax");
if (val < length) {
- write_num("/proc/sys/kernel/shmmax", length);
+ ret = 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 = val;
}
- val = read_num("/proc/sys/kernel/shmall");
+ ret = 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 = 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 = val;
}
}
diff --git a/tools/testing/selftests/mm/vm_util.h b/tools/testing/selftests/mm/vm_util.h
index 9a49af88702e4..64a86e8a0c41b 100644
--- a/tools/testing/selftests/mm/vm_util.h
+++ b/tools/testing/selftests/mm/vm_util.h
@@ -8,6 +8,8 @@
#include <unistd.h> /* _SC_PAGESIZE */
#include "kselftest.h"
#include <linux/fs.h>
+#include <mm/file_utils.h>
+#include <mm/hugepage_settings.h>
#define BIT_ULL(nr) (1ULL << (nr))
#define PM_SOFT_DIRTY BIT_ULL(55)
@@ -166,12 +168,6 @@ int unpoison_memory(unsigned long pfn);
#define PAGEMAP_PRESENT(ent) (((ent) & (1ull << 63)) != 0)
#define PAGEMAP_PFN(ent) ((ent) & ((1ull << 55) - 1))
-void 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);
-
void shm_limits_prepare(unsigned long length);
void __shm_limits_restore(void);
|
| 3/2 | 2026/09/11 12:46 | llm | patch-evaluator |
0mModel:gemini-3.7-flash Args: null Results: null Tokens: input: 25515 output: 102 thoughts: 1590 Thoughts: **Patch Analysis: WorthFuzzing Evaluation** Alright, let's break this patch down. The user's given me a diff, and my initial scan highlights a few key areas of modification. First, I see a slew of changes under the `tools/` directory – a significant clue. Specifically, `tools/lib/mm/`, `tools/testing/selftests/mm/`, and `tools/mm/`. There's also some documentation (`Documentation/core-api/pin_user_pages.rst`) and a `MAINTAINERS` update. Finally, there's a touch in `mm/Kconfig`. Now, according to the "WHEN TO RETURN WorthFuzzing=false (NEGATIVE CRITERIA)" rules, this is the crucial part. The rules explicitly state that modifications to user-space directories, self-tests, and tools that *don't* affect the compiled kernel image (vmlinux) or modules are a big red flag for *not* fuzzing. We're also looking for purely documentation changes and Kconfig changes that *don't* impact the compiled C logic. Looking at the Kconfig change closely, it seems to modify the title and help text for `CONFIG_GUP_TEST`: ```diff - bool "Enable infrastructure for get_user_pages()-related unit tests" + bool "Enable infrastructure for get_user_pages()-related unit tests and benchmarks" ``` The help text is updated: the key here is, I need to check if there is any change to config logic or the compiled C logic. Here, it does *not* alter any config logic, dependencies, select, or anything that alters compiled C logic. In other words, it's a cosmetic change – only the help text is changed, it doesn't change the behavior of the kernel. This is an explicit exception. The other changes are strictly under the `tools/`, `Documentation/`, and `MAINTAINERS`. Let me confirm the critical point: Is any kernel C source code modified, especially in the `mm/` directory? Quick scan... no, it isn't. Not even `include/`. The image files remain untouched. Therefore, this patch series *only* touches `tools/`, documentation, `MAINTAINERS`, and the Kconfig help text. It falls *squarely* within the defined negative criteria. The changes are strictly non-kernel and non-executable changes, dealing with selftests, tools, and documentation. No kernel-space code is modified. My conclusion is: `WorthFuzzing = false`. Now, to set the results correctly: * `WorthFuzzing`: `false` * `Reasoning`: "The patch series only modifies userspace selftests/tools (`tools/lib/mm/`, `tools/testing/selftests/mm/`, `tools/mm/`), `Documentation/`, `MAINTAINERS`, and the help text of `CONFIG_GUP_TEST` in `mm/Kconfig`. No kernel-space executable C code or kernel image logic is modified." * `EnableConfigs`: `[]` (empty list, because no configs are relevant) * `FocusSymbols`: `[]` (empty list, because no symbols are relevant) Ready to call `set-results`. |
| 4/2 | 2026/09/11 12:47 | tool | set-results |
0mArgs:{
"EnableConfigs": [],
"FocusSymbols": [],
"Reasoning": "The patch modifies only userspace tools and selftests (tools/lib/mm/, tools/mm/, tools/testing/selftests/mm/), documentation (Documentation/core-api/pin_user_pages.rst), MAINTAINERS, and Kconfig help text (mm/Kconfig). No compiled kernel C logic is affected.",
"WorthFuzzing": false
}Results: {
"EnableConfigs": null,
"FocusSymbols": [],
"Reasoning": "The patch modifies only userspace tools and selftests (tools/lib/mm/, tools/mm/, tools/testing/selftests/mm/), documentation (Documentation/core-api/pin_user_pages.rst), MAINTAINERS, and Kconfig help text (mm/Kconfig). No compiled kernel C logic is affected.",
"WorthFuzzing": false
} |
| 5/1 | 2026/09/11 12:47 | action | If |
0mArgs:{
"WorthFuzzing": false
}Results: null |
| Total Calls | Total Tokens | Avg Tokens | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|
| Total Calls | Total Duration (Seconds) | Avg Duration (Seconds) |
|---|