Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/mm: factor out thp settings management

The khugepaged test has a useful framework for save/restore/pop/push of
all thp settings via the sysfs interface. This will be useful to
explicitly control multi-size THP settings in other tests, so let's move
it out of khugepaged and into its own thp_settings.[c|h] utility.

Link: https://lkml.kernel.org/r/20231207161211.2374093-7-ryan.roberts@arm.com
Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
Tested-by: Alistair Popple <apopple@nvidia.com>
Acked-by: David Hildenbrand <david@redhat.com>
Tested-by: Kefeng Wang <wangkefeng.wang@huawei.com>
Tested-by: John Hubbard <jhubbard@nvidia.com>
Cc: Anshuman Khandual <anshuman.khandual@arm.com>
Cc: Barry Song <v-songbaohua@oppo.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: David Rientjes <rientjes@google.com>
Cc: "Huang, Ying" <ying.huang@intel.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Itaru Kitayama <itaru.kitayama@gmail.com>
Cc: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Cc: Luis Chamberlain <mcgrof@kernel.org>
Cc: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: Vlastimil Babka <vbabka@suse.cz>
Cc: Yang Shi <shy828301@gmail.com>
Cc: Yin Fengwei <fengwei.yin@intel.com>
Cc: Yu Zhao <yuzhao@google.com>
Cc: Zi Yan <ziy@nvidia.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Ryan Roberts and committed by
Andrew Morton
00679a18 b6aab338

+391 -326
+2 -2
tools/testing/selftests/mm/Makefile
··· 117 117 118 118 include ../lib.mk 119 119 120 - $(TEST_GEN_PROGS): vm_util.c 121 - $(TEST_GEN_FILES): vm_util.c 120 + $(TEST_GEN_PROGS): vm_util.c thp_settings.c 121 + $(TEST_GEN_FILES): vm_util.c thp_settings.c 122 122 123 123 $(OUTPUT)/uffd-stress: uffd-common.c 124 124 $(OUTPUT)/uffd-unit-tests: uffd-common.c
+22 -324
tools/testing/selftests/mm/khugepaged.c
··· 22 22 #include "linux/magic.h" 23 23 24 24 #include "vm_util.h" 25 + #include "thp_settings.h" 25 26 26 27 #define BASE_ADDR ((void *)(1UL << 30)) 27 28 static unsigned long hpage_pmd_size; 28 29 static unsigned long page_size; 29 30 static int hpage_pmd_nr; 30 31 31 - #define THP_SYSFS "/sys/kernel/mm/transparent_hugepage/" 32 32 #define PID_SMAPS "/proc/self/smaps" 33 33 #define TEST_FILE "collapse_test_file" 34 34 ··· 71 71 }; 72 72 73 73 static struct file_info finfo; 74 - 75 - enum thp_enabled { 76 - THP_ALWAYS, 77 - THP_MADVISE, 78 - THP_NEVER, 79 - }; 80 - 81 - static const char *thp_enabled_strings[] = { 82 - "always", 83 - "madvise", 84 - "never", 85 - NULL 86 - }; 87 - 88 - enum thp_defrag { 89 - THP_DEFRAG_ALWAYS, 90 - THP_DEFRAG_DEFER, 91 - THP_DEFRAG_DEFER_MADVISE, 92 - THP_DEFRAG_MADVISE, 93 - THP_DEFRAG_NEVER, 94 - }; 95 - 96 - static const char *thp_defrag_strings[] = { 97 - "always", 98 - "defer", 99 - "defer+madvise", 100 - "madvise", 101 - "never", 102 - NULL 103 - }; 104 - 105 - enum shmem_enabled { 106 - SHMEM_ALWAYS, 107 - SHMEM_WITHIN_SIZE, 108 - SHMEM_ADVISE, 109 - SHMEM_NEVER, 110 - SHMEM_DENY, 111 - SHMEM_FORCE, 112 - }; 113 - 114 - static const char *shmem_enabled_strings[] = { 115 - "always", 116 - "within_size", 117 - "advise", 118 - "never", 119 - "deny", 120 - "force", 121 - NULL 122 - }; 123 - 124 - struct khugepaged_settings { 125 - bool defrag; 126 - unsigned int alloc_sleep_millisecs; 127 - unsigned int scan_sleep_millisecs; 128 - unsigned int max_ptes_none; 129 - unsigned int max_ptes_swap; 130 - unsigned int max_ptes_shared; 131 - unsigned long pages_to_scan; 132 - }; 133 - 134 - struct settings { 135 - enum thp_enabled thp_enabled; 136 - enum thp_defrag thp_defrag; 137 - enum shmem_enabled shmem_enabled; 138 - bool use_zero_page; 139 - struct khugepaged_settings khugepaged; 140 - unsigned long read_ahead_kb; 141 - }; 142 - 143 - static struct settings saved_settings; 144 74 static bool skip_settings_restore; 145 - 146 75 static int exit_status; 147 76 148 77 static void success(const char *msg) ··· 90 161 printf(" \e[33m%s\e[0m\n", msg); 91 162 } 92 163 93 - static int read_file(const char *path, char *buf, size_t buflen) 94 - { 95 - int fd; 96 - ssize_t numread; 97 - 98 - fd = open(path, O_RDONLY); 99 - if (fd == -1) 100 - return 0; 101 - 102 - numread = read(fd, buf, buflen - 1); 103 - if (numread < 1) { 104 - close(fd); 105 - return 0; 106 - } 107 - 108 - buf[numread] = '\0'; 109 - close(fd); 110 - 111 - return (unsigned int) numread; 112 - } 113 - 114 - static int write_file(const char *path, const char *buf, size_t buflen) 115 - { 116 - int fd; 117 - ssize_t numwritten; 118 - 119 - fd = open(path, O_WRONLY); 120 - if (fd == -1) { 121 - printf("open(%s)\n", path); 122 - exit(EXIT_FAILURE); 123 - return 0; 124 - } 125 - 126 - numwritten = write(fd, buf, buflen - 1); 127 - close(fd); 128 - if (numwritten < 1) { 129 - printf("write(%s)\n", buf); 130 - exit(EXIT_FAILURE); 131 - return 0; 132 - } 133 - 134 - return (unsigned int) numwritten; 135 - } 136 - 137 - static int read_string(const char *name, const char *strings[]) 138 - { 139 - char path[PATH_MAX]; 140 - char buf[256]; 141 - char *c; 142 - int ret; 143 - 144 - ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name); 145 - if (ret >= PATH_MAX) { 146 - printf("%s: Pathname is too long\n", __func__); 147 - exit(EXIT_FAILURE); 148 - } 149 - 150 - if (!read_file(path, buf, sizeof(buf))) { 151 - perror(path); 152 - exit(EXIT_FAILURE); 153 - } 154 - 155 - c = strchr(buf, '['); 156 - if (!c) { 157 - printf("%s: Parse failure\n", __func__); 158 - exit(EXIT_FAILURE); 159 - } 160 - 161 - c++; 162 - memmove(buf, c, sizeof(buf) - (c - buf)); 163 - 164 - c = strchr(buf, ']'); 165 - if (!c) { 166 - printf("%s: Parse failure\n", __func__); 167 - exit(EXIT_FAILURE); 168 - } 169 - *c = '\0'; 170 - 171 - ret = 0; 172 - while (strings[ret]) { 173 - if (!strcmp(strings[ret], buf)) 174 - return ret; 175 - ret++; 176 - } 177 - 178 - printf("Failed to parse %s\n", name); 179 - exit(EXIT_FAILURE); 180 - } 181 - 182 - static void write_string(const char *name, const char *val) 183 - { 184 - char path[PATH_MAX]; 185 - int ret; 186 - 187 - ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name); 188 - if (ret >= PATH_MAX) { 189 - printf("%s: Pathname is too long\n", __func__); 190 - exit(EXIT_FAILURE); 191 - } 192 - 193 - if (!write_file(path, val, strlen(val) + 1)) { 194 - perror(path); 195 - exit(EXIT_FAILURE); 196 - } 197 - } 198 - 199 - static const unsigned long _read_num(const char *path) 200 - { 201 - char buf[21]; 202 - 203 - if (read_file(path, buf, sizeof(buf)) < 0) { 204 - perror("read_file(read_num)"); 205 - exit(EXIT_FAILURE); 206 - } 207 - 208 - return strtoul(buf, NULL, 10); 209 - } 210 - 211 - static const unsigned long read_num(const char *name) 212 - { 213 - char path[PATH_MAX]; 214 - int ret; 215 - 216 - ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name); 217 - if (ret >= PATH_MAX) { 218 - printf("%s: Pathname is too long\n", __func__); 219 - exit(EXIT_FAILURE); 220 - } 221 - return _read_num(path); 222 - } 223 - 224 - static void _write_num(const char *path, unsigned long num) 225 - { 226 - char buf[21]; 227 - 228 - sprintf(buf, "%ld", num); 229 - if (!write_file(path, buf, strlen(buf) + 1)) { 230 - perror(path); 231 - exit(EXIT_FAILURE); 232 - } 233 - } 234 - 235 - static void write_num(const char *name, unsigned long num) 236 - { 237 - char path[PATH_MAX]; 238 - int ret; 239 - 240 - ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name); 241 - if (ret >= PATH_MAX) { 242 - printf("%s: Pathname is too long\n", __func__); 243 - exit(EXIT_FAILURE); 244 - } 245 - _write_num(path, num); 246 - } 247 - 248 - static void write_settings(struct settings *settings) 249 - { 250 - struct khugepaged_settings *khugepaged = &settings->khugepaged; 251 - 252 - write_string("enabled", thp_enabled_strings[settings->thp_enabled]); 253 - write_string("defrag", thp_defrag_strings[settings->thp_defrag]); 254 - write_string("shmem_enabled", 255 - shmem_enabled_strings[settings->shmem_enabled]); 256 - write_num("use_zero_page", settings->use_zero_page); 257 - 258 - write_num("khugepaged/defrag", khugepaged->defrag); 259 - write_num("khugepaged/alloc_sleep_millisecs", 260 - khugepaged->alloc_sleep_millisecs); 261 - write_num("khugepaged/scan_sleep_millisecs", 262 - khugepaged->scan_sleep_millisecs); 263 - write_num("khugepaged/max_ptes_none", khugepaged->max_ptes_none); 264 - write_num("khugepaged/max_ptes_swap", khugepaged->max_ptes_swap); 265 - write_num("khugepaged/max_ptes_shared", khugepaged->max_ptes_shared); 266 - write_num("khugepaged/pages_to_scan", khugepaged->pages_to_scan); 267 - 268 - if (file_ops && finfo.type == VMA_FILE) 269 - _write_num(finfo.dev_queue_read_ahead_path, 270 - settings->read_ahead_kb); 271 - } 272 - 273 - #define MAX_SETTINGS_DEPTH 4 274 - static struct settings settings_stack[MAX_SETTINGS_DEPTH]; 275 - static int settings_index; 276 - 277 - static struct settings *current_settings(void) 278 - { 279 - if (!settings_index) { 280 - printf("Fail: No settings set"); 281 - exit(EXIT_FAILURE); 282 - } 283 - return settings_stack + settings_index - 1; 284 - } 285 - 286 - static void push_settings(struct settings *settings) 287 - { 288 - if (settings_index >= MAX_SETTINGS_DEPTH) { 289 - printf("Fail: Settings stack exceeded"); 290 - exit(EXIT_FAILURE); 291 - } 292 - settings_stack[settings_index++] = *settings; 293 - write_settings(current_settings()); 294 - } 295 - 296 - static void pop_settings(void) 297 - { 298 - if (settings_index <= 0) { 299 - printf("Fail: Settings stack empty"); 300 - exit(EXIT_FAILURE); 301 - } 302 - --settings_index; 303 - write_settings(current_settings()); 304 - } 305 - 306 164 static void restore_settings_atexit(void) 307 165 { 308 166 if (skip_settings_restore) 309 167 return; 310 168 311 169 printf("Restore THP and khugepaged settings..."); 312 - write_settings(&saved_settings); 170 + thp_restore_settings(); 313 171 success("OK"); 314 172 315 173 skip_settings_restore = true; ··· 111 395 static void save_settings(void) 112 396 { 113 397 printf("Save THP and khugepaged settings..."); 114 - saved_settings = (struct settings) { 115 - .thp_enabled = read_string("enabled", thp_enabled_strings), 116 - .thp_defrag = read_string("defrag", thp_defrag_strings), 117 - .shmem_enabled = 118 - read_string("shmem_enabled", shmem_enabled_strings), 119 - .use_zero_page = read_num("use_zero_page"), 120 - }; 121 - saved_settings.khugepaged = (struct khugepaged_settings) { 122 - .defrag = read_num("khugepaged/defrag"), 123 - .alloc_sleep_millisecs = 124 - read_num("khugepaged/alloc_sleep_millisecs"), 125 - .scan_sleep_millisecs = 126 - read_num("khugepaged/scan_sleep_millisecs"), 127 - .max_ptes_none = read_num("khugepaged/max_ptes_none"), 128 - .max_ptes_swap = read_num("khugepaged/max_ptes_swap"), 129 - .max_ptes_shared = read_num("khugepaged/max_ptes_shared"), 130 - .pages_to_scan = read_num("khugepaged/pages_to_scan"), 131 - }; 132 398 if (file_ops && finfo.type == VMA_FILE) 133 - saved_settings.read_ahead_kb = 134 - _read_num(finfo.dev_queue_read_ahead_path); 399 + thp_set_read_ahead_path(finfo.dev_queue_read_ahead_path); 400 + thp_save_settings(); 135 401 136 402 success("OK"); 137 403 ··· 496 798 struct mem_ops *ops, bool expect) 497 799 { 498 800 int ret; 499 - struct settings settings = *current_settings(); 801 + struct thp_settings settings = *thp_current_settings(); 500 802 501 803 printf("%s...", msg); 502 804 ··· 506 808 */ 507 809 settings.thp_enabled = THP_NEVER; 508 810 settings.shmem_enabled = SHMEM_NEVER; 509 - push_settings(&settings); 811 + thp_push_settings(&settings); 510 812 511 813 /* Clear VM_NOHUGEPAGE */ 512 814 madvise(p, nr_hpages * hpage_pmd_size, MADV_HUGEPAGE); ··· 518 820 else 519 821 success("OK"); 520 822 521 - pop_settings(); 823 + thp_pop_settings(); 522 824 } 523 825 524 826 static void madvise_collapse(const char *msg, char *p, int nr_hpages, ··· 548 850 madvise(p, nr_hpages * hpage_pmd_size, MADV_HUGEPAGE); 549 851 550 852 /* Wait until the second full_scan completed */ 551 - full_scans = read_num("khugepaged/full_scans") + 2; 853 + full_scans = thp_read_num("khugepaged/full_scans") + 2; 552 854 553 855 printf("%s...", msg); 554 856 while (timeout--) { 555 857 if (ops->check_huge(p, nr_hpages)) 556 858 break; 557 - if (read_num("khugepaged/full_scans") >= full_scans) 859 + if (thp_read_num("khugepaged/full_scans") >= full_scans) 558 860 break; 559 861 printf("."); 560 862 usleep(TICK); ··· 609 911 610 912 static void alloc_at_fault(void) 611 913 { 612 - struct settings settings = *current_settings(); 914 + struct thp_settings settings = *thp_current_settings(); 613 915 char *p; 614 916 615 917 settings.thp_enabled = THP_ALWAYS; 616 - push_settings(&settings); 918 + thp_push_settings(&settings); 617 919 618 920 p = alloc_mapping(1); 619 921 *p = 1; ··· 623 925 else 624 926 fail("Fail"); 625 927 626 - pop_settings(); 928 + thp_pop_settings(); 627 929 628 930 madvise(p, page_size, MADV_DONTNEED); 629 931 printf("Split huge PMD on MADV_DONTNEED..."); ··· 671 973 static void collapse_max_ptes_none(struct collapse_context *c, struct mem_ops *ops) 672 974 { 673 975 int max_ptes_none = hpage_pmd_nr / 2; 674 - struct settings settings = *current_settings(); 976 + struct thp_settings settings = *thp_current_settings(); 675 977 void *p; 676 978 677 979 settings.khugepaged.max_ptes_none = max_ptes_none; 678 - push_settings(&settings); 980 + thp_push_settings(&settings); 679 981 680 982 p = ops->setup_area(1); 681 983 ··· 700 1002 } 701 1003 skip: 702 1004 ops->cleanup_area(p, hpage_pmd_size); 703 - pop_settings(); 1005 + thp_pop_settings(); 704 1006 } 705 1007 706 1008 static void collapse_swapin_single_pte(struct collapse_context *c, struct mem_ops *ops) ··· 731 1033 732 1034 static void collapse_max_ptes_swap(struct collapse_context *c, struct mem_ops *ops) 733 1035 { 734 - int max_ptes_swap = read_num("khugepaged/max_ptes_swap"); 1036 + int max_ptes_swap = thp_read_num("khugepaged/max_ptes_swap"); 735 1037 void *p; 736 1038 737 1039 p = ops->setup_area(1); ··· 948 1250 fail("Fail"); 949 1251 ops->fault(p, 0, page_size); 950 1252 951 - write_num("khugepaged/max_ptes_shared", hpage_pmd_nr - 1); 1253 + thp_write_num("khugepaged/max_ptes_shared", hpage_pmd_nr - 1); 952 1254 c->collapse("Collapse PTE table full of compound pages in child", 953 1255 p, 1, ops, true); 954 - write_num("khugepaged/max_ptes_shared", 955 - current_settings()->khugepaged.max_ptes_shared); 1256 + thp_write_num("khugepaged/max_ptes_shared", 1257 + thp_current_settings()->khugepaged.max_ptes_shared); 956 1258 957 1259 validate_memory(p, 0, hpage_pmd_size); 958 1260 ops->cleanup_area(p, hpage_pmd_size); ··· 973 1275 974 1276 static void collapse_max_ptes_shared(struct collapse_context *c, struct mem_ops *ops) 975 1277 { 976 - int max_ptes_shared = read_num("khugepaged/max_ptes_shared"); 1278 + int max_ptes_shared = thp_read_num("khugepaged/max_ptes_shared"); 977 1279 int wstatus; 978 1280 void *p; 979 1281 ··· 1141 1443 1142 1444 int main(int argc, const char **argv) 1143 1445 { 1144 - struct settings default_settings = { 1446 + struct thp_settings default_settings = { 1145 1447 .thp_enabled = THP_MADVISE, 1146 1448 .thp_defrag = THP_DEFRAG_ALWAYS, 1147 1449 .shmem_enabled = SHMEM_ADVISE, ··· 1182 1484 default_settings.khugepaged.pages_to_scan = hpage_pmd_nr * 8; 1183 1485 1184 1486 save_settings(); 1185 - push_settings(&default_settings); 1487 + thp_push_settings(&default_settings); 1186 1488 1187 1489 alloc_at_fault(); 1188 1490
+296
tools/testing/selftests/mm/thp_settings.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #include <fcntl.h> 3 + #include <limits.h> 4 + #include <stdio.h> 5 + #include <stdlib.h> 6 + #include <string.h> 7 + #include <unistd.h> 8 + 9 + #include "thp_settings.h" 10 + 11 + #define THP_SYSFS "/sys/kernel/mm/transparent_hugepage/" 12 + #define MAX_SETTINGS_DEPTH 4 13 + static struct thp_settings settings_stack[MAX_SETTINGS_DEPTH]; 14 + static int settings_index; 15 + static struct thp_settings saved_settings; 16 + static char dev_queue_read_ahead_path[PATH_MAX]; 17 + 18 + static const char * const thp_enabled_strings[] = { 19 + "always", 20 + "madvise", 21 + "never", 22 + NULL 23 + }; 24 + 25 + static const char * const thp_defrag_strings[] = { 26 + "always", 27 + "defer", 28 + "defer+madvise", 29 + "madvise", 30 + "never", 31 + NULL 32 + }; 33 + 34 + static const char * const shmem_enabled_strings[] = { 35 + "always", 36 + "within_size", 37 + "advise", 38 + "never", 39 + "deny", 40 + "force", 41 + NULL 42 + }; 43 + 44 + int read_file(const char *path, char *buf, size_t buflen) 45 + { 46 + int fd; 47 + ssize_t numread; 48 + 49 + fd = open(path, O_RDONLY); 50 + if (fd == -1) 51 + return 0; 52 + 53 + numread = read(fd, buf, buflen - 1); 54 + if (numread < 1) { 55 + close(fd); 56 + return 0; 57 + } 58 + 59 + buf[numread] = '\0'; 60 + close(fd); 61 + 62 + return (unsigned int) numread; 63 + } 64 + 65 + int write_file(const char *path, const char *buf, size_t buflen) 66 + { 67 + int fd; 68 + ssize_t numwritten; 69 + 70 + fd = open(path, O_WRONLY); 71 + if (fd == -1) { 72 + printf("open(%s)\n", path); 73 + exit(EXIT_FAILURE); 74 + return 0; 75 + } 76 + 77 + numwritten = write(fd, buf, buflen - 1); 78 + close(fd); 79 + if (numwritten < 1) { 80 + printf("write(%s)\n", buf); 81 + exit(EXIT_FAILURE); 82 + return 0; 83 + } 84 + 85 + return (unsigned int) numwritten; 86 + } 87 + 88 + const unsigned long read_num(const char *path) 89 + { 90 + char buf[21]; 91 + 92 + if (read_file(path, buf, sizeof(buf)) < 0) { 93 + perror("read_file()"); 94 + exit(EXIT_FAILURE); 95 + } 96 + 97 + return strtoul(buf, NULL, 10); 98 + } 99 + 100 + void write_num(const char *path, unsigned long num) 101 + { 102 + char buf[21]; 103 + 104 + sprintf(buf, "%ld", num); 105 + if (!write_file(path, buf, strlen(buf) + 1)) { 106 + perror(path); 107 + exit(EXIT_FAILURE); 108 + } 109 + } 110 + 111 + int thp_read_string(const char *name, const char * const strings[]) 112 + { 113 + char path[PATH_MAX]; 114 + char buf[256]; 115 + char *c; 116 + int ret; 117 + 118 + ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name); 119 + if (ret >= PATH_MAX) { 120 + printf("%s: Pathname is too long\n", __func__); 121 + exit(EXIT_FAILURE); 122 + } 123 + 124 + if (!read_file(path, buf, sizeof(buf))) { 125 + perror(path); 126 + exit(EXIT_FAILURE); 127 + } 128 + 129 + c = strchr(buf, '['); 130 + if (!c) { 131 + printf("%s: Parse failure\n", __func__); 132 + exit(EXIT_FAILURE); 133 + } 134 + 135 + c++; 136 + memmove(buf, c, sizeof(buf) - (c - buf)); 137 + 138 + c = strchr(buf, ']'); 139 + if (!c) { 140 + printf("%s: Parse failure\n", __func__); 141 + exit(EXIT_FAILURE); 142 + } 143 + *c = '\0'; 144 + 145 + ret = 0; 146 + while (strings[ret]) { 147 + if (!strcmp(strings[ret], buf)) 148 + return ret; 149 + ret++; 150 + } 151 + 152 + printf("Failed to parse %s\n", name); 153 + exit(EXIT_FAILURE); 154 + } 155 + 156 + void thp_write_string(const char *name, const char *val) 157 + { 158 + char path[PATH_MAX]; 159 + int ret; 160 + 161 + ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name); 162 + if (ret >= PATH_MAX) { 163 + printf("%s: Pathname is too long\n", __func__); 164 + exit(EXIT_FAILURE); 165 + } 166 + 167 + if (!write_file(path, val, strlen(val) + 1)) { 168 + perror(path); 169 + exit(EXIT_FAILURE); 170 + } 171 + } 172 + 173 + const unsigned long thp_read_num(const char *name) 174 + { 175 + char path[PATH_MAX]; 176 + int ret; 177 + 178 + ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name); 179 + if (ret >= PATH_MAX) { 180 + printf("%s: Pathname is too long\n", __func__); 181 + exit(EXIT_FAILURE); 182 + } 183 + return read_num(path); 184 + } 185 + 186 + void thp_write_num(const char *name, unsigned long num) 187 + { 188 + char path[PATH_MAX]; 189 + int ret; 190 + 191 + ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name); 192 + if (ret >= PATH_MAX) { 193 + printf("%s: Pathname is too long\n", __func__); 194 + exit(EXIT_FAILURE); 195 + } 196 + write_num(path, num); 197 + } 198 + 199 + void thp_read_settings(struct thp_settings *settings) 200 + { 201 + *settings = (struct thp_settings) { 202 + .thp_enabled = thp_read_string("enabled", thp_enabled_strings), 203 + .thp_defrag = thp_read_string("defrag", thp_defrag_strings), 204 + .shmem_enabled = 205 + thp_read_string("shmem_enabled", shmem_enabled_strings), 206 + .use_zero_page = thp_read_num("use_zero_page"), 207 + }; 208 + settings->khugepaged = (struct khugepaged_settings) { 209 + .defrag = thp_read_num("khugepaged/defrag"), 210 + .alloc_sleep_millisecs = 211 + thp_read_num("khugepaged/alloc_sleep_millisecs"), 212 + .scan_sleep_millisecs = 213 + thp_read_num("khugepaged/scan_sleep_millisecs"), 214 + .max_ptes_none = thp_read_num("khugepaged/max_ptes_none"), 215 + .max_ptes_swap = thp_read_num("khugepaged/max_ptes_swap"), 216 + .max_ptes_shared = thp_read_num("khugepaged/max_ptes_shared"), 217 + .pages_to_scan = thp_read_num("khugepaged/pages_to_scan"), 218 + }; 219 + if (dev_queue_read_ahead_path[0]) 220 + settings->read_ahead_kb = read_num(dev_queue_read_ahead_path); 221 + } 222 + 223 + void thp_write_settings(struct thp_settings *settings) 224 + { 225 + struct khugepaged_settings *khugepaged = &settings->khugepaged; 226 + 227 + thp_write_string("enabled", thp_enabled_strings[settings->thp_enabled]); 228 + thp_write_string("defrag", thp_defrag_strings[settings->thp_defrag]); 229 + thp_write_string("shmem_enabled", 230 + shmem_enabled_strings[settings->shmem_enabled]); 231 + thp_write_num("use_zero_page", settings->use_zero_page); 232 + 233 + thp_write_num("khugepaged/defrag", khugepaged->defrag); 234 + thp_write_num("khugepaged/alloc_sleep_millisecs", 235 + khugepaged->alloc_sleep_millisecs); 236 + thp_write_num("khugepaged/scan_sleep_millisecs", 237 + khugepaged->scan_sleep_millisecs); 238 + thp_write_num("khugepaged/max_ptes_none", khugepaged->max_ptes_none); 239 + thp_write_num("khugepaged/max_ptes_swap", khugepaged->max_ptes_swap); 240 + thp_write_num("khugepaged/max_ptes_shared", khugepaged->max_ptes_shared); 241 + thp_write_num("khugepaged/pages_to_scan", khugepaged->pages_to_scan); 242 + 243 + if (dev_queue_read_ahead_path[0]) 244 + write_num(dev_queue_read_ahead_path, settings->read_ahead_kb); 245 + } 246 + 247 + struct thp_settings *thp_current_settings(void) 248 + { 249 + if (!settings_index) { 250 + printf("Fail: No settings set"); 251 + exit(EXIT_FAILURE); 252 + } 253 + return settings_stack + settings_index - 1; 254 + } 255 + 256 + void thp_push_settings(struct thp_settings *settings) 257 + { 258 + if (settings_index >= MAX_SETTINGS_DEPTH) { 259 + printf("Fail: Settings stack exceeded"); 260 + exit(EXIT_FAILURE); 261 + } 262 + settings_stack[settings_index++] = *settings; 263 + thp_write_settings(thp_current_settings()); 264 + } 265 + 266 + void thp_pop_settings(void) 267 + { 268 + if (settings_index <= 0) { 269 + printf("Fail: Settings stack empty"); 270 + exit(EXIT_FAILURE); 271 + } 272 + --settings_index; 273 + thp_write_settings(thp_current_settings()); 274 + } 275 + 276 + void thp_restore_settings(void) 277 + { 278 + thp_write_settings(&saved_settings); 279 + } 280 + 281 + void thp_save_settings(void) 282 + { 283 + thp_read_settings(&saved_settings); 284 + } 285 + 286 + void thp_set_read_ahead_path(char *path) 287 + { 288 + if (!path) { 289 + dev_queue_read_ahead_path[0] = '\0'; 290 + return; 291 + } 292 + 293 + strncpy(dev_queue_read_ahead_path, path, 294 + sizeof(dev_queue_read_ahead_path)); 295 + dev_queue_read_ahead_path[sizeof(dev_queue_read_ahead_path) - 1] = '\0'; 296 + }
+71
tools/testing/selftests/mm/thp_settings.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef __THP_SETTINGS_H__ 3 + #define __THP_SETTINGS_H__ 4 + 5 + #include <stdbool.h> 6 + #include <stddef.h> 7 + #include <stdint.h> 8 + 9 + enum thp_enabled { 10 + THP_ALWAYS, 11 + THP_MADVISE, 12 + THP_NEVER, 13 + }; 14 + 15 + enum thp_defrag { 16 + THP_DEFRAG_ALWAYS, 17 + THP_DEFRAG_DEFER, 18 + THP_DEFRAG_DEFER_MADVISE, 19 + THP_DEFRAG_MADVISE, 20 + THP_DEFRAG_NEVER, 21 + }; 22 + 23 + enum shmem_enabled { 24 + SHMEM_ALWAYS, 25 + SHMEM_WITHIN_SIZE, 26 + SHMEM_ADVISE, 27 + SHMEM_NEVER, 28 + SHMEM_DENY, 29 + SHMEM_FORCE, 30 + }; 31 + 32 + struct khugepaged_settings { 33 + bool defrag; 34 + unsigned int alloc_sleep_millisecs; 35 + unsigned int scan_sleep_millisecs; 36 + unsigned int max_ptes_none; 37 + unsigned int max_ptes_swap; 38 + unsigned int max_ptes_shared; 39 + unsigned long pages_to_scan; 40 + }; 41 + 42 + struct thp_settings { 43 + enum thp_enabled thp_enabled; 44 + enum thp_defrag thp_defrag; 45 + enum shmem_enabled shmem_enabled; 46 + bool use_zero_page; 47 + struct khugepaged_settings khugepaged; 48 + unsigned long read_ahead_kb; 49 + }; 50 + 51 + int read_file(const char *path, char *buf, size_t buflen); 52 + int write_file(const char *path, const char *buf, size_t buflen); 53 + const unsigned long read_num(const char *path); 54 + void write_num(const char *path, unsigned long num); 55 + 56 + int thp_read_string(const char *name, const char * const strings[]); 57 + void thp_write_string(const char *name, const char *val); 58 + const unsigned long thp_read_num(const char *name); 59 + void thp_write_num(const char *name, unsigned long num); 60 + 61 + void thp_write_settings(struct thp_settings *settings); 62 + void thp_read_settings(struct thp_settings *settings); 63 + struct thp_settings *thp_current_settings(void); 64 + void thp_push_settings(struct thp_settings *settings); 65 + void thp_pop_settings(void); 66 + void thp_restore_settings(void); 67 + void thp_save_settings(void); 68 + 69 + void thp_set_read_ahead_path(char *path); 70 + 71 + #endif /* __THP_SETTINGS_H__ */