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

selftests/mm: support multi-size THP interface in thp_settings

Save and restore the new per-size hugepage enabled setting, if available
on the running kernel.

Since the number of per-size directories is not fixed, solve this as
simply as possible by catering for a maximum number in the thp_settings
struct (20). Each array index is the order. The value of THP_NEVER is
changed to 0 so that all of these new settings default to THP_NEVER and
the user only needs to fill in the ones they want to enable.

Link: https://lkml.kernel.org/r/20231207161211.2374093-8-ryan.roberts@arm.com
Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
Tested-by: Kefeng Wang <wangkefeng.wang@huawei.com>
Tested-by: John Hubbard <jhubbard@nvidia.com>
Cc: Alistair Popple <apopple@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 Hildenbrand <david@redhat.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
4f5070a5 00679a18

+69 -4
+3
tools/testing/selftests/mm/khugepaged.c
··· 1141 1141 1142 1142 int main(int argc, const char **argv) 1143 1143 { 1144 + int hpage_pmd_order; 1144 1145 struct thp_settings default_settings = { 1145 1146 .thp_enabled = THP_MADVISE, 1146 1147 .thp_defrag = THP_DEFRAG_ALWAYS, ··· 1176 1175 exit(EXIT_FAILURE); 1177 1176 } 1178 1177 hpage_pmd_nr = hpage_pmd_size / page_size; 1178 + hpage_pmd_order = __builtin_ctz(hpage_pmd_nr); 1179 1179 1180 1180 default_settings.khugepaged.max_ptes_none = hpage_pmd_nr - 1; 1181 1181 default_settings.khugepaged.max_ptes_swap = hpage_pmd_nr / 8; 1182 1182 default_settings.khugepaged.max_ptes_shared = hpage_pmd_nr / 2; 1183 1183 default_settings.khugepaged.pages_to_scan = hpage_pmd_nr * 8; 1184 + default_settings.hugepages[hpage_pmd_order].enabled = THP_INHERIT; 1184 1185 1185 1186 save_settings(); 1186 1187 thp_push_settings(&default_settings);
+55 -2
tools/testing/selftests/mm/thp_settings.c
··· 16 16 static char dev_queue_read_ahead_path[PATH_MAX]; 17 17 18 18 static const char * const thp_enabled_strings[] = { 19 - "always", 20 - "madvise", 21 19 "never", 20 + "always", 21 + "inherit", 22 + "madvise", 22 23 NULL 23 24 }; 24 25 ··· 199 198 200 199 void thp_read_settings(struct thp_settings *settings) 201 200 { 201 + unsigned long orders = thp_supported_orders(); 202 + char path[PATH_MAX]; 203 + int i; 204 + 202 205 *settings = (struct thp_settings) { 203 206 .thp_enabled = thp_read_string("enabled", thp_enabled_strings), 204 207 .thp_defrag = thp_read_string("defrag", thp_defrag_strings), ··· 223 218 }; 224 219 if (dev_queue_read_ahead_path[0]) 225 220 settings->read_ahead_kb = read_num(dev_queue_read_ahead_path); 221 + 222 + for (i = 0; i < NR_ORDERS; i++) { 223 + if (!((1 << i) & orders)) { 224 + settings->hugepages[i].enabled = THP_NEVER; 225 + continue; 226 + } 227 + snprintf(path, PATH_MAX, "hugepages-%ukB/enabled", 228 + (getpagesize() >> 10) << i); 229 + settings->hugepages[i].enabled = 230 + thp_read_string(path, thp_enabled_strings); 231 + } 226 232 } 227 233 228 234 void thp_write_settings(struct thp_settings *settings) 229 235 { 230 236 struct khugepaged_settings *khugepaged = &settings->khugepaged; 237 + unsigned long orders = thp_supported_orders(); 238 + char path[PATH_MAX]; 239 + int enabled; 240 + int i; 231 241 232 242 thp_write_string("enabled", thp_enabled_strings[settings->thp_enabled]); 233 243 thp_write_string("defrag", thp_defrag_strings[settings->thp_defrag]); ··· 262 242 263 243 if (dev_queue_read_ahead_path[0]) 264 244 write_num(dev_queue_read_ahead_path, settings->read_ahead_kb); 245 + 246 + for (i = 0; i < NR_ORDERS; i++) { 247 + if (!((1 << i) & orders)) 248 + continue; 249 + snprintf(path, PATH_MAX, "hugepages-%ukB/enabled", 250 + (getpagesize() >> 10) << i); 251 + enabled = settings->hugepages[i].enabled; 252 + thp_write_string(path, thp_enabled_strings[enabled]); 253 + } 265 254 } 266 255 267 256 struct thp_settings *thp_current_settings(void) ··· 322 293 strncpy(dev_queue_read_ahead_path, path, 323 294 sizeof(dev_queue_read_ahead_path)); 324 295 dev_queue_read_ahead_path[sizeof(dev_queue_read_ahead_path) - 1] = '\0'; 296 + } 297 + 298 + unsigned long thp_supported_orders(void) 299 + { 300 + unsigned long orders = 0; 301 + char path[PATH_MAX]; 302 + char buf[256]; 303 + int ret; 304 + int i; 305 + 306 + for (i = 0; i < NR_ORDERS; i++) { 307 + ret = snprintf(path, PATH_MAX, THP_SYSFS "hugepages-%ukB/enabled", 308 + (getpagesize() >> 10) << i); 309 + if (ret >= PATH_MAX) { 310 + printf("%s: Pathname is too long\n", __func__); 311 + exit(EXIT_FAILURE); 312 + } 313 + 314 + ret = read_file(path, buf, sizeof(buf)); 315 + if (ret) 316 + orders |= 1UL << i; 317 + } 318 + 319 + return orders; 325 320 }
+11 -2
tools/testing/selftests/mm/thp_settings.h
··· 7 7 #include <stdint.h> 8 8 9 9 enum thp_enabled { 10 - THP_ALWAYS, 11 - THP_MADVISE, 12 10 THP_NEVER, 11 + THP_ALWAYS, 12 + THP_INHERIT, 13 + THP_MADVISE, 13 14 }; 14 15 15 16 enum thp_defrag { ··· 30 29 SHMEM_FORCE, 31 30 }; 32 31 32 + #define NR_ORDERS 20 33 + 34 + struct hugepages_settings { 35 + enum thp_enabled enabled; 36 + }; 37 + 33 38 struct khugepaged_settings { 34 39 bool defrag; 35 40 unsigned int alloc_sleep_millisecs; ··· 53 46 bool use_zero_page; 54 47 struct khugepaged_settings khugepaged; 55 48 unsigned long read_ahead_kb; 49 + struct hugepages_settings hugepages[NR_ORDERS]; 56 50 }; 57 51 58 52 int read_file(const char *path, char *buf, size_t buflen); ··· 75 67 void thp_save_settings(void); 76 68 77 69 void thp_set_read_ahead_path(char *path); 70 + unsigned long thp_supported_orders(void); 78 71 79 72 #endif /* __THP_SETTINGS_H__ */