* [merged mm-stable] tools-lib-mm-move-hugepage_settings-out-of-selftests.patch removed from -mm tree
@ 2026-10-13 4:33 Andrew Morton
0 siblings, 0 replies; only message in thread
From: Andrew Morton @ 2026-10-13 4:33 UTC (permalink / raw)
To: mm-commits, ziy, usama.anjum, surenb, shuah, ryan.roberts, rppt,
peterx, npache, mhocko, ljs, liam, leon, lance.yang, jhubbard,
jgg, dev.jain, david, corbet, broonie, baolin.wang, baohua,
anshuman.khandual, sarthak.sharma, akpm
The quilt patch titled
Subject: tools/lib/mm: move hugepage_settings out of selftests
has been removed from the -mm tree. Its filename was
tools-lib-mm-move-hugepage_settings-out-of-selftests.patch
This patch was dropped because it was merged into the mm-stable branch
of git://git.kernel.org/pub/scm/linux/kernel/git/akpm/mm
------------------------------------------------------
From: Sarthak Sharma <sarthak.sharma@arm.com>
Subject: tools/lib/mm: move hugepage_settings out of selftests
Date: Fri, 18 Sep 2026 16:52:31 +0530
Move hugepage_settings.[ch] from tools/testing/selftests/mm/ to
tools/lib/mm/ so the THP and HugeTLB helpers can be shared more easily
between selftests and other tools.
Keep the helpers exposed to mm selftests through vm_util.h where possible,
and use direct <mm/hugepage_settings.h> includes for files that do not
include vm_util.h. Adjust the selftests/mm build to compile the moved
implementation from its new location.
Remove the remaining kselftest dependency by including file_utils.h
directly and using EXIT_FAILURE in the signal handler.
Link: https://lore.kernel.org/20260918112234.195857-4-sarthak.sharma@arm.com
Signed-off-by: Sarthak Sharma <sarthak.sharma@arm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Acked-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Acked-by: David Hildenbrand (Arm) <david@kernel.org>
Tested-by: Muhammad Usama Anjum <usama.anjum@arm.com>
Cc: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: Barry Song <baohua@kernel.org>
Cc: Dev Jain <dev.jain@arm.com>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Lance Yang <lance.yang@linux.dev>
Cc: Leon Romanovsky <leon@kernel.org>
Cc: Liam R. Howlett <liam@infradead.org>
Cc: Lorenzo Stoakes <ljs@kernel.org>
Cc: Mark Brown <broonie@kernel.org>
Cc: Michal Hocko <mhocko@suse.com>
Cc: Nico Pache <npache@redhat.com>
Cc: Peter Xu <peterx@redhat.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Shuah Khan <shuah@kernel.org>
Cc: Suren Baghdasaryan <surenb@google.com>
Cc: Zi Yan <ziy@nvidia.com>
---
tools/lib/mm/hugepage_settings.c | 688 ++++++++++
tools/lib/mm/hugepage_settings.h | 156 ++
tools/testing/selftests/mm/Makefile | 6
tools/testing/selftests/mm/compaction_test.c | 2
tools/testing/selftests/mm/cow.c | 1
tools/testing/selftests/mm/folio_split_race_test.c | 1
tools/testing/selftests/mm/guard-regions.c | 1
tools/testing/selftests/mm/gup_longterm.c | 1
tools/testing/selftests/mm/gup_test.c | 1
tools/testing/selftests/mm/hmm-tests.c | 6
tools/testing/selftests/mm/hugepage_settings.c | 681 ---------
tools/testing/selftests/mm/hugepage_settings.h | 156 --
tools/testing/selftests/mm/hugetlb-madvise.c | 1
tools/testing/selftests/mm/hugetlb-mmap.c | 1
tools/testing/selftests/mm/hugetlb-mremap.c | 1
tools/testing/selftests/mm/hugetlb-shm.c | 1
tools/testing/selftests/mm/hugetlb-soft-offline.c | 2
tools/testing/selftests/mm/hugetlb_dio.c | 1
tools/testing/selftests/mm/hugetlb_fault_after_madv.c | 1
tools/testing/selftests/mm/hugetlb_madv_vs_map.c | 1
tools/testing/selftests/mm/khugepaged.c | 1
tools/testing/selftests/mm/ksm_tests.c | 1
tools/testing/selftests/mm/migration.c | 2
tools/testing/selftests/mm/pagemap_ioctl.c | 1
tools/testing/selftests/mm/prctl_thp_disable.c | 1
tools/testing/selftests/mm/protection_keys.c | 2
tools/testing/selftests/mm/soft-dirty.c | 1
tools/testing/selftests/mm/split_huge_page_test.c | 1
tools/testing/selftests/mm/thuge-gen.c | 1
tools/testing/selftests/mm/transhuge-stress.c | 1
tools/testing/selftests/mm/uffd-common.h | 1
tools/testing/selftests/mm/uffd-wp-mremap.c | 2
tools/testing/selftests/mm/va_high_addr_switch.c | 1
tools/testing/selftests/mm/vm_util.h | 1
34 files changed, 857 insertions(+), 869 deletions(-)
diff --git a/tools/lib/mm/hugepage_settings.c a/tools/lib/mm/hugepage_settings.c
new file mode 100644
--- /dev/null
+++ a/tools/lib/mm/hugepage_settings.c
@@ -0,0 +1,688 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <dirent.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.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;
+static char dev_queue_read_ahead_path[PATH_MAX];
+static bool thp_settings_saved;
+
+static const char * const thp_enabled_strings[] = {
+ "never",
+ "always",
+ "inherit",
+ "madvise",
+ NULL
+};
+
+static const char * const thp_defrag_strings[] = {
+ "always",
+ "defer",
+ "defer+madvise",
+ "madvise",
+ "never",
+ NULL
+};
+
+static const char * const shmem_enabled_strings[] = {
+ "never",
+ "always",
+ "within_size",
+ "advise",
+ "inherit",
+ "deny",
+ "force",
+ 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];
+ char buf[256];
+ char *c;
+ int ret;
+
+ ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
+ if (ret >= PATH_MAX) {
+ printf("%s: Pathname is too long\n", __func__);
+ exit(EXIT_FAILURE);
+ }
+
+ ret = read_file(path, buf, sizeof(buf));
+ if (ret) {
+ print_file_access_error(path, ret);
+ exit(EXIT_FAILURE);
+ }
+
+ c = strchr(buf, '[');
+ if (!c) {
+ printf("%s: Parse failure\n", __func__);
+ exit(EXIT_FAILURE);
+ }
+
+ c++;
+ memmove(buf, c, sizeof(buf) - (c - buf));
+
+ c = strchr(buf, ']');
+ if (!c) {
+ printf("%s: Parse failure\n", __func__);
+ exit(EXIT_FAILURE);
+ }
+ *c = '\0';
+
+ ret = 0;
+ while (strings[ret]) {
+ if (!strcmp(strings[ret], buf))
+ return ret;
+ ret++;
+ }
+
+ printf("Failed to parse %s\n", name);
+ exit(EXIT_FAILURE);
+}
+
+void thp_write_string(const char *name, const char *val)
+{
+ char path[PATH_MAX];
+ int ret;
+
+ ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
+ if (ret >= PATH_MAX) {
+ printf("%s: Pathname is too long\n", __func__);
+ exit(EXIT_FAILURE);
+ }
+ 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);
+ if (ret >= PATH_MAX) {
+ printf("%s: Pathname is too long\n", __func__);
+ exit(EXIT_FAILURE);
+ }
+ 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)
+{
+ char path[PATH_MAX];
+ int ret;
+
+ ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
+ if (ret >= PATH_MAX) {
+ printf("%s: Pathname is too long\n", __func__);
+ exit(EXIT_FAILURE);
+ }
+ ret = write_num(path, num);
+ if (ret) {
+ print_file_access_error(path, ret);
+ exit(EXIT_FAILURE);
+ }
+}
+
+void thp_read_settings(struct thp_settings *settings)
+{
+ unsigned long orders = thp_supported_orders();
+ unsigned long shmem_orders = thp_shmem_supported_orders();
+ char path[PATH_MAX];
+ int i;
+
+ *settings = (struct thp_settings) {
+ .thp_enabled = thp_read_string("enabled", thp_enabled_strings),
+ .thp_defrag = thp_read_string("defrag", thp_defrag_strings),
+ .shmem_enabled =
+ thp_read_string("shmem_enabled", shmem_enabled_strings),
+ .use_zero_page = thp_read_num("use_zero_page"),
+ };
+ settings->khugepaged = (struct khugepaged_settings) {
+ .defrag = thp_read_num("khugepaged/defrag"),
+ .alloc_sleep_millisecs =
+ thp_read_num("khugepaged/alloc_sleep_millisecs"),
+ .scan_sleep_millisecs =
+ thp_read_num("khugepaged/scan_sleep_millisecs"),
+ .max_ptes_none = thp_read_num("khugepaged/max_ptes_none"),
+ .max_ptes_swap = thp_read_num("khugepaged/max_ptes_swap"),
+ .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]) {
+ 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)) {
+ settings->hugepages[i].enabled = THP_NEVER;
+ continue;
+ }
+ snprintf(path, PATH_MAX, "hugepages-%ukB/enabled",
+ (getpagesize() >> 10) << i);
+ settings->hugepages[i].enabled =
+ thp_read_string(path, thp_enabled_strings);
+ }
+
+ for (i = 0; i < NR_ORDERS; i++) {
+ if (!((1 << i) & shmem_orders)) {
+ settings->shmem_hugepages[i].enabled = SHMEM_NEVER;
+ continue;
+ }
+ snprintf(path, PATH_MAX, "hugepages-%ukB/shmem_enabled",
+ (getpagesize() >> 10) << i);
+ settings->shmem_hugepages[i].enabled =
+ thp_read_string(path, shmem_enabled_strings);
+ }
+}
+
+void thp_write_settings(struct thp_settings *settings)
+{
+ struct khugepaged_settings *khugepaged = &settings->khugepaged;
+ unsigned long orders = thp_supported_orders();
+ unsigned long shmem_orders = thp_shmem_supported_orders();
+ char path[PATH_MAX];
+ int enabled;
+ int i;
+
+ thp_write_string("enabled", thp_enabled_strings[settings->thp_enabled]);
+ thp_write_string("defrag", thp_defrag_strings[settings->thp_defrag]);
+ thp_write_string("shmem_enabled",
+ shmem_enabled_strings[settings->shmem_enabled]);
+ thp_write_num("use_zero_page", settings->use_zero_page);
+
+ thp_write_num("khugepaged/defrag", khugepaged->defrag);
+ thp_write_num("khugepaged/alloc_sleep_millisecs",
+ khugepaged->alloc_sleep_millisecs);
+ thp_write_num("khugepaged/scan_sleep_millisecs",
+ khugepaged->scan_sleep_millisecs);
+ thp_write_num("khugepaged/max_ptes_none", khugepaged->max_ptes_none);
+ thp_write_num("khugepaged/max_ptes_swap", khugepaged->max_ptes_swap);
+ 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]) {
+ 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))
+ continue;
+ snprintf(path, PATH_MAX, "hugepages-%ukB/enabled",
+ (getpagesize() >> 10) << i);
+ enabled = settings->hugepages[i].enabled;
+ thp_write_string(path, thp_enabled_strings[enabled]);
+ }
+
+ for (i = 0; i < NR_ORDERS; i++) {
+ if (!((1 << i) & shmem_orders))
+ continue;
+ snprintf(path, PATH_MAX, "hugepages-%ukB/shmem_enabled",
+ (getpagesize() >> 10) << i);
+ enabled = settings->shmem_hugepages[i].enabled;
+ thp_write_string(path, shmem_enabled_strings[enabled]);
+ }
+}
+
+struct thp_settings *thp_current_settings(void)
+{
+ if (!settings_index) {
+ printf("Fail: No settings set");
+ exit(EXIT_FAILURE);
+ }
+ return settings_stack + settings_index - 1;
+}
+
+void thp_push_settings(struct thp_settings *settings)
+{
+ if (settings_index >= MAX_SETTINGS_DEPTH) {
+ printf("Fail: Settings stack exceeded");
+ exit(EXIT_FAILURE);
+ }
+ settings_stack[settings_index++] = *settings;
+ thp_write_settings(thp_current_settings());
+}
+
+void thp_pop_settings(void)
+{
+ if (settings_index <= 0) {
+ printf("Fail: Settings stack empty");
+ exit(EXIT_FAILURE);
+ }
+ --settings_index;
+ thp_write_settings(thp_current_settings());
+}
+
+void thp_restore_settings(void)
+{
+ if (thp_settings_saved)
+ thp_write_settings(&saved_settings);
+}
+
+static void __thp_save_settings(void)
+{
+ if (!thp_available())
+ return;
+
+ if (thp_settings_saved)
+ return;
+
+ thp_read_settings(&saved_settings);
+ thp_settings_saved = true;
+}
+
+void thp_set_read_ahead_path(char *path)
+{
+ if (!path) {
+ dev_queue_read_ahead_path[0] = '\0';
+ return;
+ }
+
+ strncpy(dev_queue_read_ahead_path, path,
+ sizeof(dev_queue_read_ahead_path));
+ dev_queue_read_ahead_path[sizeof(dev_queue_read_ahead_path) - 1] = '\0';
+}
+
+static unsigned long __thp_supported_orders(bool is_shmem)
+{
+ unsigned long orders = 0;
+ char path[PATH_MAX];
+ char buf[256];
+ int ret, i;
+ char anon_dir[] = "enabled";
+ char shmem_dir[] = "shmem_enabled";
+
+ for (i = 0; i < NR_ORDERS; i++) {
+ ret = snprintf(path, PATH_MAX, THP_SYSFS "hugepages-%ukB/%s",
+ (getpagesize() >> 10) << i, is_shmem ? shmem_dir : anon_dir);
+ if (ret >= PATH_MAX) {
+ printf("%s: Pathname is too long\n", __func__);
+ exit(EXIT_FAILURE);
+ }
+
+ ret = read_file(path, buf, sizeof(buf));
+ if (ret) {
+ if (ret != -ENOENT) {
+ print_file_access_error(path, ret);
+ exit(EXIT_FAILURE);
+ }
+ continue;
+ }
+
+ orders |= 1UL << i;
+ }
+
+ return orders;
+}
+
+unsigned long thp_supported_orders(void)
+{
+ return __thp_supported_orders(false);
+}
+
+unsigned long thp_shmem_supported_orders(void)
+{
+ return __thp_supported_orders(true);
+}
+
+bool thp_available(void)
+{
+ if (access(THP_SYSFS, F_OK) != 0)
+ return false;
+ return true;
+}
+
+bool thp_is_enabled(void)
+{
+ if (!thp_available())
+ return false;
+
+ int mode = thp_read_string("enabled", thp_enabled_strings);
+
+ /* THP is considered enabled if it's either "always" or "madvise" */
+ return mode == 1 || mode == 3;
+}
+
+#define HUGETLB_MAX_NR_PAGESIZES 10
+struct hugetlb_settings {
+ unsigned long nr_hugepages[HUGETLB_MAX_NR_PAGESIZES];
+ unsigned long sizes[HUGETLB_MAX_NR_PAGESIZES];
+ unsigned long default_size;
+ int nr_sizes;
+};
+
+static struct hugetlb_settings hugetlb_saved_settings;
+static bool hugetlb_settings_saved;
+
+int detect_hugetlb_page_sizes(unsigned long sizes[], int max)
+{
+ static struct hugetlb_settings *settings = &hugetlb_saved_settings;
+ DIR *dir;
+ int count = 0;
+
+ if (settings->nr_sizes) {
+ if (settings->nr_sizes < max)
+ max = settings->nr_sizes;
+ for (count = 0; count < max; count++)
+ sizes[count] = settings->sizes[count];
+ return count;
+ }
+
+ dir = opendir("/sys/kernel/mm/hugepages/");
+ if (!dir)
+ return 0;
+
+ while (count < max) {
+ struct dirent *entry = readdir(dir);
+ size_t kb;
+
+ if (!entry)
+ break;
+ if (entry->d_type != DT_DIR)
+ continue;
+ if (sscanf(entry->d_name, "hugepages-%zukB", &kb) != 1)
+ continue;
+ sizes[count++] = kb * 1024;
+ printf("# [INFO] detected hugetlb page size: %zu KiB\n", kb);
+ }
+ closedir(dir);
+ return count;
+}
+
+unsigned long default_huge_page_size(void)
+{
+ static struct hugetlb_settings *settings = &hugetlb_saved_settings;
+ unsigned long hps = 0;
+ char *line = NULL;
+ size_t linelen = 0;
+ FILE *f;
+
+ if (settings->default_size)
+ return settings->default_size;
+
+ f = fopen("/proc/meminfo", "r");
+ if (!f)
+ return 0;
+ while (getline(&line, &linelen, f) > 0) {
+ if (sscanf(line, "Hugepagesize: %lu kB", &hps) == 1) {
+ hps <<= 10;
+ break;
+ }
+ }
+
+ free(line);
+ fclose(f);
+ return hps;
+}
+
+static void hugetlb_sysfs_path(char *buf, size_t buflen,
+ unsigned long size, const char *attr)
+{
+ snprintf(buf, buflen, "/sys/kernel/mm/hugepages/hugepages-%lukB/%s",
+ size / 1024, attr);
+}
+
+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");
+
+ 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");
+
+ 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");
+
+ ret = read_num(path, &nr);
+ if (ret) {
+ print_file_access_error(path, ret);
+ exit(EXIT_FAILURE);
+ }
+
+ return nr;
+}
+
+unsigned long hugetlb_nr_resv_pages(unsigned long size)
+{
+ char path[PATH_MAX];
+ unsigned long nr;
+ int ret;
+
+ hugetlb_sysfs_path(path, sizeof(path), size, "resv_hugepages");
+
+ 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)
+{
+ unsigned long free = hugetlb_free_pages(size);
+ unsigned long total = hugetlb_nr_pages(size);
+
+ if (free >= nr)
+ return true;
+
+ hugetlb_set_nr_pages(size, total + (nr - free));
+
+ return hugetlb_free_pages(size) >= nr;
+}
+
+bool hugetlb_setup_default(unsigned long nr)
+{
+ unsigned long size;
+
+ hugetlb_save_settings();
+ size = default_huge_page_size();
+ if (!size)
+ return false;
+
+ return __hugetlb_setup(size, nr);
+}
+
+bool hugetlb_setup_default_exact(unsigned long nr)
+{
+ unsigned long size;
+
+ hugetlb_save_settings();
+ size = default_huge_page_size();
+ if (!size)
+ return false;
+
+ hugetlb_set_nr_pages(size, nr);
+
+ return hugetlb_free_pages(size) == nr;
+}
+
+unsigned long hugetlb_setup(unsigned long nr, unsigned long sizes[],
+ int max)
+{
+ unsigned long enabled[10];
+ int nr_sizes = 0;
+ int nr_enabled;
+
+ hugetlb_save_settings();
+
+ nr_enabled = detect_hugetlb_page_sizes(enabled, ARRAY_SIZE(enabled));
+ if (!nr_enabled)
+ return 0;
+
+ if (nr_enabled > max) {
+ printf("# detected %d huge page sizes, will only test %d\n",
+ nr_enabled, max);
+ nr_enabled = max;
+ }
+
+ /* request nr HugeTLB pages of every size. */
+ for (int i = 0; i < nr_enabled; i++) {
+ if (!__hugetlb_setup(enabled[i], nr))
+ continue;
+ sizes[nr_sizes++] = enabled[i];
+ }
+
+ return nr_sizes;
+}
+
+static void __hugetlb_save_settings(void)
+{
+ struct hugetlb_settings *settings = &hugetlb_saved_settings;
+ int nr_sizes;
+
+ if (hugetlb_settings_saved)
+ return;
+
+ settings->default_size = default_huge_page_size();
+ if (!settings->default_size)
+ return;
+
+ nr_sizes = detect_hugetlb_page_sizes(settings->sizes,
+ HUGETLB_MAX_NR_PAGESIZES);
+ if (!nr_sizes) {
+ settings->default_size = 0;
+ return;
+ }
+
+ for (int i = 0; i < nr_sizes; i++) {
+ unsigned long sz = settings->sizes[i];
+
+ if (!sz)
+ continue;
+ settings->nr_hugepages[i] = hugetlb_nr_pages(sz);
+ }
+
+ settings->nr_sizes = nr_sizes;
+ hugetlb_settings_saved = true;
+}
+
+void hugetlb_restore_settings(void)
+{
+ struct hugetlb_settings *settings = &hugetlb_saved_settings;
+
+ if (!hugetlb_settings_saved || !settings->default_size)
+ return;
+
+ for (int i = 0; i < HUGETLB_MAX_NR_PAGESIZES; i++) {
+ unsigned long sz = settings->sizes[i];
+
+ if (!sz)
+ continue;
+
+ hugetlb_set_nr_pages(sz, settings->nr_hugepages[i]);
+ }
+}
+
+static void hugepage_restore_settings_atexit(void)
+{
+ if (thp_settings_saved)
+ thp_restore_settings();
+ if (hugetlb_settings_saved)
+ hugetlb_restore_settings();
+}
+
+static void hugepage_restore_settings_sighandler(int sig)
+{
+ (void)sig;
+
+ /* exit() will invoke the hugepage_restore_settings_atexit handler. */
+ exit(EXIT_FAILURE);
+}
+
+void hugepage_save_settings(bool thp, bool hugetlb)
+{
+ if (!thp && !hugetlb)
+ return;
+
+ if (thp)
+ __thp_save_settings();
+ if (hugetlb)
+ __hugetlb_save_settings();
+
+ /*
+ * setup exit hooks to make sure THP and HugeTLB settings are
+ * restored on graceful and error exits and signals
+ */
+ atexit(hugepage_restore_settings_atexit);
+ signal(SIGTERM, hugepage_restore_settings_sighandler);
+ signal(SIGINT, hugepage_restore_settings_sighandler);
+ signal(SIGHUP, hugepage_restore_settings_sighandler);
+ signal(SIGQUIT, hugepage_restore_settings_sighandler);
+}
diff --git a/tools/lib/mm/hugepage_settings.h a/tools/lib/mm/hugepage_settings.h
new file mode 100644
--- /dev/null
+++ a/tools/lib/mm/hugepage_settings.h
@@ -0,0 +1,156 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __HUGEPAGE_SETTINGS_H__
+#define __HUGEPAGE_SETTINGS_H__
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdint.h>
+
+void hugepage_save_settings(bool thp, bool hugetlb);
+
+/* Transparent Huge Pages (THP) */
+
+enum thp_enabled {
+ THP_NEVER,
+ THP_ALWAYS,
+ THP_INHERIT,
+ THP_MADVISE,
+};
+
+enum thp_defrag {
+ THP_DEFRAG_ALWAYS,
+ THP_DEFRAG_DEFER,
+ THP_DEFRAG_DEFER_MADVISE,
+ THP_DEFRAG_MADVISE,
+ THP_DEFRAG_NEVER,
+};
+
+enum shmem_enabled {
+ SHMEM_NEVER,
+ SHMEM_ALWAYS,
+ SHMEM_WITHIN_SIZE,
+ SHMEM_ADVISE,
+ SHMEM_INHERIT,
+ SHMEM_DENY,
+ SHMEM_FORCE,
+};
+
+#define NR_ORDERS 20
+
+struct hugepages_settings {
+ enum thp_enabled enabled;
+};
+
+struct khugepaged_settings {
+ bool defrag;
+ unsigned int alloc_sleep_millisecs;
+ unsigned int scan_sleep_millisecs;
+ unsigned int max_ptes_none;
+ unsigned int max_ptes_swap;
+ unsigned int max_ptes_shared;
+ unsigned long pages_to_scan;
+};
+
+struct shmem_hugepages_settings {
+ enum shmem_enabled enabled;
+};
+
+struct thp_settings {
+ enum thp_enabled thp_enabled;
+ enum thp_defrag thp_defrag;
+ enum shmem_enabled shmem_enabled;
+ bool use_zero_page;
+ struct khugepaged_settings khugepaged;
+ unsigned long read_ahead_kb;
+ struct hugepages_settings hugepages[NR_ORDERS];
+ struct shmem_hugepages_settings shmem_hugepages[NR_ORDERS];
+};
+
+int thp_read_string(const char *name, const char * const strings[]);
+void thp_write_string(const char *name, const char *val);
+unsigned long thp_read_num(const char *name);
+void thp_write_num(const char *name, unsigned long num);
+
+void thp_write_settings(struct thp_settings *settings);
+void thp_read_settings(struct thp_settings *settings);
+struct thp_settings *thp_current_settings(void);
+void thp_push_settings(struct thp_settings *settings);
+void thp_pop_settings(void);
+void thp_restore_settings(void);
+
+static inline void thp_save_settings(void)
+{
+ hugepage_save_settings(/* thp = */ true, /* hugetlb = */ false);
+}
+
+void thp_set_read_ahead_path(char *path);
+unsigned long thp_supported_orders(void);
+unsigned long thp_shmem_supported_orders(void);
+
+bool thp_available(void);
+bool thp_is_enabled(void);
+
+/* HugeTLB */
+
+int detect_hugetlb_page_sizes(unsigned long sizes[], int max);
+unsigned long default_huge_page_size(void);
+
+unsigned long hugetlb_nr_pages(unsigned long size);
+void hugetlb_set_nr_pages(unsigned long size, unsigned long nr);
+unsigned long hugetlb_free_pages(unsigned long size);
+unsigned long hugetlb_nr_resv_pages(unsigned long size);
+
+static inline void hugetlb_save_settings(void)
+{
+ hugepage_save_settings(/* thp = */ false, /* hugetlb = */ true);
+}
+
+void hugetlb_restore_settings(void);
+
+static inline unsigned long hugetlb_nr_default_pages(void)
+{
+ unsigned long size = default_huge_page_size();
+
+ if (!size)
+ return 0;
+
+ return hugetlb_nr_pages(size);
+}
+
+static inline void hugetlb_set_nr_default_pages(unsigned long nr)
+{
+ unsigned long size = default_huge_page_size();
+
+ if (!size)
+ return;
+
+ hugetlb_set_nr_pages(size, nr);
+}
+
+static inline unsigned long hugetlb_free_default_pages(void)
+{
+ unsigned long size = default_huge_page_size();
+
+ if (!size)
+ return 0;
+
+ return hugetlb_free_pages(size);
+}
+
+static inline bool hugetlb_available(void)
+{
+ return default_huge_page_size() != 0;
+}
+
+bool hugetlb_setup_default(unsigned long nr);
+bool hugetlb_setup_default_exact(unsigned long nr);
+unsigned long hugetlb_setup(unsigned long nr, unsigned long sizes[],
+ int max);
+
+#define HUGETLB_SETUP_DEFAULT_PAGES(nr_pages) \
+static void __attribute__((constructor)) __hugetlb_setup_default(void) \
+{ \
+ hugetlb_setup_default((nr_pages)); \
+}
+
+#endif /* __HUGEPAGE_SETTINGS_H__ */
--- a/tools/testing/selftests/mm/compaction_test.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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)
--- a/tools/testing/selftests/mm/cow.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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;
--- a/tools/testing/selftests/mm/folio_split_race_test.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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;
--- a/tools/testing/selftests/mm/guard-regions.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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"
--- a/tools/testing/selftests/mm/gup_longterm.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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;
--- a/tools/testing/selftests/mm/gup_test.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/tools/testing/selftests/mm/gup_test.c
@@ -14,7 +14,6 @@
#include <mm/gup_test.h>
#include "kselftest.h"
#include "vm_util.h"
-#include "hugepage_settings.h"
#define MB (1UL << 20)
--- a/tools/testing/selftests/mm/hmm-tests.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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/hugepage_settings.c a/tools/testing/selftests/mm/hugepage_settings.c
deleted file mode 100644
--- a/tools/testing/selftests/mm/hugepage_settings.c
+++ /dev/null
@@ -1,681 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <dirent.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <signal.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include "vm_util.h"
-#include "hugepage_settings.h"
-
-#define THP_SYSFS "/sys/kernel/mm/transparent_hugepage/"
-#define MAX_SETTINGS_DEPTH 4
-static struct thp_settings settings_stack[MAX_SETTINGS_DEPTH];
-static int settings_index;
-static struct thp_settings saved_settings;
-static char dev_queue_read_ahead_path[PATH_MAX];
-static bool thp_settings_saved;
-
-static const char * const thp_enabled_strings[] = {
- "never",
- "always",
- "inherit",
- "madvise",
- NULL
-};
-
-static const char * const thp_defrag_strings[] = {
- "always",
- "defer",
- "defer+madvise",
- "madvise",
- "never",
- NULL
-};
-
-static const char * const shmem_enabled_strings[] = {
- "never",
- "always",
- "within_size",
- "advise",
- "inherit",
- "deny",
- "force",
- 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];
- char buf[256];
- char *c;
- int ret;
-
- ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
- if (ret >= PATH_MAX) {
- printf("%s: Pathname is too long\n", __func__);
- exit(EXIT_FAILURE);
- }
-
- ret = read_file(path, buf, sizeof(buf));
- if (ret) {
- print_file_access_error(path, ret);
- exit(EXIT_FAILURE);
- }
-
- c = strchr(buf, '[');
- if (!c) {
- printf("%s: Parse failure\n", __func__);
- exit(EXIT_FAILURE);
- }
-
- c++;
- memmove(buf, c, sizeof(buf) - (c - buf));
-
- c = strchr(buf, ']');
- if (!c) {
- printf("%s: Parse failure\n", __func__);
- exit(EXIT_FAILURE);
- }
- *c = '\0';
-
- ret = 0;
- while (strings[ret]) {
- if (!strcmp(strings[ret], buf))
- return ret;
- ret++;
- }
-
- printf("Failed to parse %s\n", name);
- exit(EXIT_FAILURE);
-}
-
-void thp_write_string(const char *name, const char *val)
-{
- char path[PATH_MAX];
- int ret;
-
- ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
- if (ret >= PATH_MAX) {
- printf("%s: Pathname is too long\n", __func__);
- exit(EXIT_FAILURE);
- }
- 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);
- if (ret >= PATH_MAX) {
- printf("%s: Pathname is too long\n", __func__);
- exit(EXIT_FAILURE);
- }
- 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)
-{
- char path[PATH_MAX];
- int ret;
-
- ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
- if (ret >= PATH_MAX) {
- printf("%s: Pathname is too long\n", __func__);
- exit(EXIT_FAILURE);
- }
- ret = write_num(path, num);
- if (ret) {
- print_file_access_error(path, ret);
- exit(EXIT_FAILURE);
- }
-}
-
-void thp_read_settings(struct thp_settings *settings)
-{
- unsigned long orders = thp_supported_orders();
- unsigned long shmem_orders = thp_shmem_supported_orders();
- char path[PATH_MAX];
- int i;
-
- *settings = (struct thp_settings) {
- .thp_enabled = thp_read_string("enabled", thp_enabled_strings),
- .thp_defrag = thp_read_string("defrag", thp_defrag_strings),
- .shmem_enabled =
- thp_read_string("shmem_enabled", shmem_enabled_strings),
- .use_zero_page = thp_read_num("use_zero_page"),
- };
- settings->khugepaged = (struct khugepaged_settings) {
- .defrag = thp_read_num("khugepaged/defrag"),
- .alloc_sleep_millisecs =
- thp_read_num("khugepaged/alloc_sleep_millisecs"),
- .scan_sleep_millisecs =
- thp_read_num("khugepaged/scan_sleep_millisecs"),
- .max_ptes_none = thp_read_num("khugepaged/max_ptes_none"),
- .max_ptes_swap = thp_read_num("khugepaged/max_ptes_swap"),
- .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]) {
- 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)) {
- settings->hugepages[i].enabled = THP_NEVER;
- continue;
- }
- snprintf(path, PATH_MAX, "hugepages-%ukB/enabled",
- (getpagesize() >> 10) << i);
- settings->hugepages[i].enabled =
- thp_read_string(path, thp_enabled_strings);
- }
-
- for (i = 0; i < NR_ORDERS; i++) {
- if (!((1 << i) & shmem_orders)) {
- settings->shmem_hugepages[i].enabled = SHMEM_NEVER;
- continue;
- }
- snprintf(path, PATH_MAX, "hugepages-%ukB/shmem_enabled",
- (getpagesize() >> 10) << i);
- settings->shmem_hugepages[i].enabled =
- thp_read_string(path, shmem_enabled_strings);
- }
-}
-
-void thp_write_settings(struct thp_settings *settings)
-{
- struct khugepaged_settings *khugepaged = &settings->khugepaged;
- unsigned long orders = thp_supported_orders();
- unsigned long shmem_orders = thp_shmem_supported_orders();
- char path[PATH_MAX];
- int enabled;
- int i;
-
- thp_write_string("enabled", thp_enabled_strings[settings->thp_enabled]);
- thp_write_string("defrag", thp_defrag_strings[settings->thp_defrag]);
- thp_write_string("shmem_enabled",
- shmem_enabled_strings[settings->shmem_enabled]);
- thp_write_num("use_zero_page", settings->use_zero_page);
-
- thp_write_num("khugepaged/defrag", khugepaged->defrag);
- thp_write_num("khugepaged/alloc_sleep_millisecs",
- khugepaged->alloc_sleep_millisecs);
- thp_write_num("khugepaged/scan_sleep_millisecs",
- khugepaged->scan_sleep_millisecs);
- thp_write_num("khugepaged/max_ptes_none", khugepaged->max_ptes_none);
- thp_write_num("khugepaged/max_ptes_swap", khugepaged->max_ptes_swap);
- 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]) {
- 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))
- continue;
- snprintf(path, PATH_MAX, "hugepages-%ukB/enabled",
- (getpagesize() >> 10) << i);
- enabled = settings->hugepages[i].enabled;
- thp_write_string(path, thp_enabled_strings[enabled]);
- }
-
- for (i = 0; i < NR_ORDERS; i++) {
- if (!((1 << i) & shmem_orders))
- continue;
- snprintf(path, PATH_MAX, "hugepages-%ukB/shmem_enabled",
- (getpagesize() >> 10) << i);
- enabled = settings->shmem_hugepages[i].enabled;
- thp_write_string(path, shmem_enabled_strings[enabled]);
- }
-}
-
-struct thp_settings *thp_current_settings(void)
-{
- if (!settings_index) {
- printf("Fail: No settings set");
- exit(EXIT_FAILURE);
- }
- return settings_stack + settings_index - 1;
-}
-
-void thp_push_settings(struct thp_settings *settings)
-{
- if (settings_index >= MAX_SETTINGS_DEPTH) {
- printf("Fail: Settings stack exceeded");
- exit(EXIT_FAILURE);
- }
- settings_stack[settings_index++] = *settings;
- thp_write_settings(thp_current_settings());
-}
-
-void thp_pop_settings(void)
-{
- if (settings_index <= 0) {
- printf("Fail: Settings stack empty");
- exit(EXIT_FAILURE);
- }
- --settings_index;
- thp_write_settings(thp_current_settings());
-}
-
-void thp_restore_settings(void)
-{
- if (thp_settings_saved)
- thp_write_settings(&saved_settings);
-}
-
-static void __thp_save_settings(void)
-{
- if (!thp_available())
- return;
-
- if (thp_settings_saved)
- return;
-
- thp_read_settings(&saved_settings);
- thp_settings_saved = true;
-}
-
-void thp_set_read_ahead_path(char *path)
-{
- if (!path) {
- dev_queue_read_ahead_path[0] = '\0';
- return;
- }
-
- strncpy(dev_queue_read_ahead_path, path,
- sizeof(dev_queue_read_ahead_path));
- dev_queue_read_ahead_path[sizeof(dev_queue_read_ahead_path) - 1] = '\0';
-}
-
-static unsigned long __thp_supported_orders(bool is_shmem)
-{
- unsigned long orders = 0;
- char path[PATH_MAX];
- char buf[256];
- int ret, i;
- char anon_dir[] = "enabled";
- char shmem_dir[] = "shmem_enabled";
-
- for (i = 0; i < NR_ORDERS; i++) {
- ret = snprintf(path, PATH_MAX, THP_SYSFS "hugepages-%ukB/%s",
- (getpagesize() >> 10) << i, is_shmem ? shmem_dir : anon_dir);
- if (ret >= PATH_MAX) {
- printf("%s: Pathname is too long\n", __func__);
- exit(EXIT_FAILURE);
- }
-
- ret = read_file(path, buf, sizeof(buf));
- if (ret) {
- if (ret != -ENOENT) {
- print_file_access_error(path, ret);
- exit(EXIT_FAILURE);
- }
- continue;
- }
-
- orders |= 1UL << i;
- }
-
- return orders;
-}
-
-unsigned long thp_supported_orders(void)
-{
- return __thp_supported_orders(false);
-}
-
-unsigned long thp_shmem_supported_orders(void)
-{
- return __thp_supported_orders(true);
-}
-
-bool thp_available(void)
-{
- if (access(THP_SYSFS, F_OK) != 0)
- return false;
- return true;
-}
-
-bool thp_is_enabled(void)
-{
- if (!thp_available())
- return false;
-
- int mode = thp_read_string("enabled", thp_enabled_strings);
-
- /* THP is considered enabled if it's either "always" or "madvise" */
- return mode == 1 || mode == 3;
-}
-
-#define HUGETLB_MAX_NR_PAGESIZES 10
-struct hugetlb_settings {
- unsigned long nr_hugepages[HUGETLB_MAX_NR_PAGESIZES];
- unsigned long sizes[HUGETLB_MAX_NR_PAGESIZES];
- unsigned long default_size;
- int nr_sizes;
-};
-
-static struct hugetlb_settings hugetlb_saved_settings;
-static bool hugetlb_settings_saved;
-
-int detect_hugetlb_page_sizes(unsigned long sizes[], int max)
-{
- static struct hugetlb_settings *settings = &hugetlb_saved_settings;
- DIR *dir;
- int count = 0;
-
- if (settings->nr_sizes) {
- if (settings->nr_sizes < max)
- max = settings->nr_sizes;
- for (count = 0; count < max; count++)
- sizes[count] = settings->sizes[count];
- return count;
- }
-
- dir = opendir("/sys/kernel/mm/hugepages/");
- if (!dir)
- return 0;
-
- while (count < max) {
- struct dirent *entry = readdir(dir);
- size_t kb;
-
- if (!entry)
- break;
- if (entry->d_type != DT_DIR)
- continue;
- if (sscanf(entry->d_name, "hugepages-%zukB", &kb) != 1)
- continue;
- sizes[count++] = kb * 1024;
- printf("# [INFO] detected hugetlb page size: %zu KiB\n", kb);
- }
- closedir(dir);
- return count;
-}
-
-unsigned long default_huge_page_size(void)
-{
- static struct hugetlb_settings *settings = &hugetlb_saved_settings;
- unsigned long hps = 0;
- char *line = NULL;
- size_t linelen = 0;
- FILE *f;
-
- if (settings->default_size)
- return settings->default_size;
-
- f = fopen("/proc/meminfo", "r");
- if (!f)
- return 0;
- while (getline(&line, &linelen, f) > 0) {
- if (sscanf(line, "Hugepagesize: %lu kB", &hps) == 1) {
- hps <<= 10;
- break;
- }
- }
-
- free(line);
- fclose(f);
- return hps;
-}
-
-static void hugetlb_sysfs_path(char *buf, size_t buflen,
- unsigned long size, const char *attr)
-{
- snprintf(buf, buflen, "/sys/kernel/mm/hugepages/hugepages-%lukB/%s",
- size / 1024, attr);
-}
-
-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");
-
- 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");
-
- 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");
-
- ret = read_num(path, &nr);
- if (ret) {
- print_file_access_error(path, ret);
- exit(EXIT_FAILURE);
- }
-
- return nr;
-}
-
-unsigned long hugetlb_nr_resv_pages(unsigned long size)
-{
- char path[PATH_MAX];
- unsigned long nr;
- int ret;
-
- hugetlb_sysfs_path(path, sizeof(path), size, "resv_hugepages");
-
- 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)
-{
- unsigned long free = hugetlb_free_pages(size);
- unsigned long total = hugetlb_nr_pages(size);
-
- if (free >= nr)
- return true;
-
- hugetlb_set_nr_pages(size, total + (nr - free));
-
- return hugetlb_free_pages(size) >= nr;
-}
-
-bool hugetlb_setup_default(unsigned long nr)
-{
- unsigned long size;
-
- hugetlb_save_settings();
- size = default_huge_page_size();
- if (!size)
- return false;
-
- return __hugetlb_setup(size, nr);
-}
-
-bool hugetlb_setup_default_exact(unsigned long nr)
-{
- unsigned long size;
-
- hugetlb_save_settings();
- size = default_huge_page_size();
- if (!size)
- return false;
-
- hugetlb_set_nr_pages(size, nr);
-
- return hugetlb_free_pages(size) == nr;
-}
-
-unsigned long hugetlb_setup(unsigned long nr, unsigned long sizes[],
- int max)
-{
- unsigned long enabled[10];
- int nr_sizes = 0;
- int nr_enabled;
-
- hugetlb_save_settings();
-
- nr_enabled = detect_hugetlb_page_sizes(enabled, ARRAY_SIZE(enabled));
- if (!nr_enabled)
- return 0;
-
- if (nr_enabled > max) {
- printf("# detected %d huge page sizes, will only test %d\n",
- nr_enabled, max);
- nr_enabled = max;
- }
-
- /* request nr HugeTLB pages of every size. */
- for (int i = 0; i < nr_enabled; i++) {
- if (!__hugetlb_setup(enabled[i], nr))
- continue;
- sizes[nr_sizes++] = enabled[i];
- }
-
- return nr_sizes;
-}
-
-static void __hugetlb_save_settings(void)
-{
- struct hugetlb_settings *settings = &hugetlb_saved_settings;
- int nr_sizes;
-
- if (hugetlb_settings_saved)
- return;
-
- settings->default_size = default_huge_page_size();
- if (!settings->default_size)
- return;
-
- nr_sizes = detect_hugetlb_page_sizes(settings->sizes,
- HUGETLB_MAX_NR_PAGESIZES);
- if (!nr_sizes) {
- settings->default_size = 0;
- return;
- }
-
- for (int i = 0; i < nr_sizes; i++) {
- unsigned long sz = settings->sizes[i];
-
- if (!sz)
- continue;
- settings->nr_hugepages[i] = hugetlb_nr_pages(sz);
- }
-
- settings->nr_sizes = nr_sizes;
- hugetlb_settings_saved = true;
-}
-
-void hugetlb_restore_settings(void)
-{
- struct hugetlb_settings *settings = &hugetlb_saved_settings;
-
- if (!hugetlb_settings_saved || !settings->default_size)
- return;
-
- for (int i = 0; i < HUGETLB_MAX_NR_PAGESIZES; i++) {
- unsigned long sz = settings->sizes[i];
-
- if (!sz)
- continue;
-
- hugetlb_set_nr_pages(sz, settings->nr_hugepages[i]);
- }
-}
-
-static void hugepage_restore_settings_atexit(void)
-{
- if (thp_settings_saved)
- thp_restore_settings();
- if (hugetlb_settings_saved)
- hugetlb_restore_settings();
-}
-
-static void hugepage_restore_settings_sighandler(int sig)
-{
- /* exit() will invoke the hugepage_restore_settings_atexit handler. */
- exit(KSFT_FAIL);
-}
-
-void hugepage_save_settings(bool thp, bool hugetlb)
-{
- if (!thp && !hugetlb)
- return;
-
- if (thp)
- __thp_save_settings();
- if (hugetlb)
- __hugetlb_save_settings();
-
- /*
- * setup exit hooks to make sure THP and HugeTLB settings are
- * restored on graceful and error exits and signals
- */
- atexit(hugepage_restore_settings_atexit);
- signal(SIGTERM, hugepage_restore_settings_sighandler);
- signal(SIGINT, hugepage_restore_settings_sighandler);
- signal(SIGHUP, hugepage_restore_settings_sighandler);
- signal(SIGQUIT, hugepage_restore_settings_sighandler);
-}
diff --git a/tools/testing/selftests/mm/hugepage_settings.h a/tools/testing/selftests/mm/hugepage_settings.h
deleted file mode 100644
--- a/tools/testing/selftests/mm/hugepage_settings.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef __HUGEPAGE_SETTINGS_H__
-#define __HUGEPAGE_SETTINGS_H__
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-void hugepage_save_settings(bool thp, bool hugetlb);
-
-/* Transparent Huge Pages (THP) */
-
-enum thp_enabled {
- THP_NEVER,
- THP_ALWAYS,
- THP_INHERIT,
- THP_MADVISE,
-};
-
-enum thp_defrag {
- THP_DEFRAG_ALWAYS,
- THP_DEFRAG_DEFER,
- THP_DEFRAG_DEFER_MADVISE,
- THP_DEFRAG_MADVISE,
- THP_DEFRAG_NEVER,
-};
-
-enum shmem_enabled {
- SHMEM_NEVER,
- SHMEM_ALWAYS,
- SHMEM_WITHIN_SIZE,
- SHMEM_ADVISE,
- SHMEM_INHERIT,
- SHMEM_DENY,
- SHMEM_FORCE,
-};
-
-#define NR_ORDERS 20
-
-struct hugepages_settings {
- enum thp_enabled enabled;
-};
-
-struct khugepaged_settings {
- bool defrag;
- unsigned int alloc_sleep_millisecs;
- unsigned int scan_sleep_millisecs;
- unsigned int max_ptes_none;
- unsigned int max_ptes_swap;
- unsigned int max_ptes_shared;
- unsigned long pages_to_scan;
-};
-
-struct shmem_hugepages_settings {
- enum shmem_enabled enabled;
-};
-
-struct thp_settings {
- enum thp_enabled thp_enabled;
- enum thp_defrag thp_defrag;
- enum shmem_enabled shmem_enabled;
- bool use_zero_page;
- struct khugepaged_settings khugepaged;
- unsigned long read_ahead_kb;
- struct hugepages_settings hugepages[NR_ORDERS];
- struct shmem_hugepages_settings shmem_hugepages[NR_ORDERS];
-};
-
-int thp_read_string(const char *name, const char * const strings[]);
-void thp_write_string(const char *name, const char *val);
-unsigned long thp_read_num(const char *name);
-void thp_write_num(const char *name, unsigned long num);
-
-void thp_write_settings(struct thp_settings *settings);
-void thp_read_settings(struct thp_settings *settings);
-struct thp_settings *thp_current_settings(void);
-void thp_push_settings(struct thp_settings *settings);
-void thp_pop_settings(void);
-void thp_restore_settings(void);
-
-static inline void thp_save_settings(void)
-{
- hugepage_save_settings(/* thp = */ true, /* hugetlb = */ false);
-}
-
-void thp_set_read_ahead_path(char *path);
-unsigned long thp_supported_orders(void);
-unsigned long thp_shmem_supported_orders(void);
-
-bool thp_available(void);
-bool thp_is_enabled(void);
-
-/* HugeTLB */
-
-int detect_hugetlb_page_sizes(unsigned long sizes[], int max);
-unsigned long default_huge_page_size(void);
-
-unsigned long hugetlb_nr_pages(unsigned long size);
-void hugetlb_set_nr_pages(unsigned long size, unsigned long nr);
-unsigned long hugetlb_free_pages(unsigned long size);
-unsigned long hugetlb_nr_resv_pages(unsigned long size);
-
-static inline void hugetlb_save_settings(void)
-{
- hugepage_save_settings(/* thp = */ false, /* hugetlb = */ true);
-}
-
-void hugetlb_restore_settings(void);
-
-static inline unsigned long hugetlb_nr_default_pages(void)
-{
- unsigned long size = default_huge_page_size();
-
- if (!size)
- return 0;
-
- return hugetlb_nr_pages(size);
-}
-
-static inline void hugetlb_set_nr_default_pages(unsigned long nr)
-{
- unsigned long size = default_huge_page_size();
-
- if (!size)
- return;
-
- hugetlb_set_nr_pages(size, nr);
-}
-
-static inline unsigned long hugetlb_free_default_pages(void)
-{
- unsigned long size = default_huge_page_size();
-
- if (!size)
- return 0;
-
- return hugetlb_free_pages(size);
-}
-
-static inline bool hugetlb_available(void)
-{
- return default_huge_page_size() != 0;
-}
-
-bool hugetlb_setup_default(unsigned long nr);
-bool hugetlb_setup_default_exact(unsigned long nr);
-unsigned long hugetlb_setup(unsigned long nr, unsigned long sizes[],
- int max);
-
-#define HUGETLB_SETUP_DEFAULT_PAGES(nr_pages) \
-static void __attribute__((constructor)) __hugetlb_setup_default(void) \
-{ \
- hugetlb_setup_default((nr_pages)); \
-}
-
-#endif /* __HUGEPAGE_SETTINGS_H__ */
--- a/tools/testing/selftests/mm/hugetlb_dio.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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
--- a/tools/testing/selftests/mm/hugetlb_fault_after_madv.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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
--- a/tools/testing/selftests/mm/hugetlb-madvise.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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 */
--- a/tools/testing/selftests/mm/hugetlb_madv_vs_map.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/tools/testing/selftests/mm/hugetlb_madv_vs_map.c
@@ -14,7 +14,6 @@
#include <unistd.h>
#include "vm_util.h"
-#include "hugepage_settings.h"
#define INLOOP_ITER 100
--- a/tools/testing/selftests/mm/hugetlb-mmap.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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)
--- a/tools/testing/selftests/mm/hugetlb-mremap.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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)
--- a/tools/testing/selftests/mm/hugetlb-shm.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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)
--- a/tools/testing/selftests/mm/hugetlb-soft-offline.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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
--- a/tools/testing/selftests/mm/khugepaged.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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;
--- a/tools/testing/selftests/mm/ksm_tests.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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)
--- a/tools/testing/selftests/mm/Makefile~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/tools/testing/selftests/mm/Makefile
@@ -185,8 +185,10 @@ TEST_FILES += write_hugetlb_memory.sh
include ../lib.mk
-$(TEST_GEN_PROGS): vm_util.c hugepage_settings.c $(top_srcdir)/tools/lib/mm/file_utils.c
-$(TEST_GEN_FILES): vm_util.c hugepage_settings.c $(top_srcdir)/tools/lib/mm/file_utils.c
+$(TEST_GEN_PROGS): vm_util.c $(top_srcdir)/tools/lib/mm/hugepage_settings.c \
+ $(top_srcdir)/tools/lib/mm/file_utils.c
+$(TEST_GEN_FILES): vm_util.c $(top_srcdir)/tools/lib/mm/hugepage_settings.c \
+ $(top_srcdir)/tools/lib/mm/file_utils.c
$(OUTPUT)/uffd-stress: uffd-common.c
$(OUTPUT)/uffd-unit-tests: uffd-common.c
--- a/tools/testing/selftests/mm/migration.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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)
--- a/tools/testing/selftests/mm/pagemap_ioctl.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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 | \
--- a/tools/testing/selftests/mm/prctl_thp_disable.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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
--- a/tools/testing/selftests/mm/protection_keys.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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;
--- a/tools/testing/selftests/mm/soft-dirty.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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
--- a/tools/testing/selftests/mm/split_huge_page_test.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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;
--- a/tools/testing/selftests/mm/thuge-gen.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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
--- a/tools/testing/selftests/mm/transhuge-stress.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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;
--- a/tools/testing/selftests/mm/uffd-common.h~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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)
--- a/tools/testing/selftests/mm/uffd-wp-mremap.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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;
--- a/tools/testing/selftests/mm/va_high_addr_switch.c~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/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
--- a/tools/testing/selftests/mm/vm_util.h~tools-lib-mm-move-hugepage_settings-out-of-selftests
+++ a/tools/testing/selftests/mm/vm_util.h
@@ -9,6 +9,7 @@
#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)
_
Patches currently in -mm which might be from sarthak.sharma@arm.com are
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2026-10-13 4:33 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-13 4:33 [merged mm-stable] tools-lib-mm-move-hugepage_settings-out-of-selftests.patch removed from -mm tree Andrew Morton
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.