~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/mm/thp_settings.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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         "never",
 20         "always",
 21         "inherit",
 22         "madvise",
 23         NULL
 24 };
 25 
 26 static const char * const thp_defrag_strings[] = {
 27         "always",
 28         "defer",
 29         "defer+madvise",
 30         "madvise",
 31         "never",
 32         NULL
 33 };
 34 
 35 static const char * const shmem_enabled_strings[] = {
 36         "always",
 37         "within_size",
 38         "advise",
 39         "never",
 40         "deny",
 41         "force",
 42         NULL
 43 };
 44 
 45 int read_file(const char *path, char *buf, size_t buflen)
 46 {
 47         int fd;
 48         ssize_t numread;
 49 
 50         fd = open(path, O_RDONLY);
 51         if (fd == -1)
 52                 return 0;
 53 
 54         numread = read(fd, buf, buflen - 1);
 55         if (numread < 1) {
 56                 close(fd);
 57                 return 0;
 58         }
 59 
 60         buf[numread] = '\0';
 61         close(fd);
 62 
 63         return (unsigned int) numread;
 64 }
 65 
 66 int write_file(const char *path, const char *buf, size_t buflen)
 67 {
 68         int fd;
 69         ssize_t numwritten;
 70 
 71         fd = open(path, O_WRONLY);
 72         if (fd == -1) {
 73                 printf("open(%s)\n", path);
 74                 exit(EXIT_FAILURE);
 75                 return 0;
 76         }
 77 
 78         numwritten = write(fd, buf, buflen - 1);
 79         close(fd);
 80         if (numwritten < 1) {
 81                 printf("write(%s)\n", buf);
 82                 exit(EXIT_FAILURE);
 83                 return 0;
 84         }
 85 
 86         return (unsigned int) numwritten;
 87 }
 88 
 89 const unsigned long read_num(const char *path)
 90 {
 91         char buf[21];
 92 
 93         if (read_file(path, buf, sizeof(buf)) < 0) {
 94                 perror("read_file()");
 95                 exit(EXIT_FAILURE);
 96         }
 97 
 98         return strtoul(buf, NULL, 10);
 99 }
100 
101 void write_num(const char *path, unsigned long num)
102 {
103         char buf[21];
104 
105         sprintf(buf, "%ld", num);
106         if (!write_file(path, buf, strlen(buf) + 1)) {
107                 perror(path);
108                 exit(EXIT_FAILURE);
109         }
110 }
111 
112 int thp_read_string(const char *name, const char * const strings[])
113 {
114         char path[PATH_MAX];
115         char buf[256];
116         char *c;
117         int ret;
118 
119         ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
120         if (ret >= PATH_MAX) {
121                 printf("%s: Pathname is too long\n", __func__);
122                 exit(EXIT_FAILURE);
123         }
124 
125         if (!read_file(path, buf, sizeof(buf))) {
126                 perror(path);
127                 exit(EXIT_FAILURE);
128         }
129 
130         c = strchr(buf, '[');
131         if (!c) {
132                 printf("%s: Parse failure\n", __func__);
133                 exit(EXIT_FAILURE);
134         }
135 
136         c++;
137         memmove(buf, c, sizeof(buf) - (c - buf));
138 
139         c = strchr(buf, ']');
140         if (!c) {
141                 printf("%s: Parse failure\n", __func__);
142                 exit(EXIT_FAILURE);
143         }
144         *c = '\0';
145 
146         ret = 0;
147         while (strings[ret]) {
148                 if (!strcmp(strings[ret], buf))
149                         return ret;
150                 ret++;
151         }
152 
153         printf("Failed to parse %s\n", name);
154         exit(EXIT_FAILURE);
155 }
156 
157 void thp_write_string(const char *name, const char *val)
158 {
159         char path[PATH_MAX];
160         int ret;
161 
162         ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
163         if (ret >= PATH_MAX) {
164                 printf("%s: Pathname is too long\n", __func__);
165                 exit(EXIT_FAILURE);
166         }
167 
168         if (!write_file(path, val, strlen(val) + 1)) {
169                 perror(path);
170                 exit(EXIT_FAILURE);
171         }
172 }
173 
174 const unsigned long thp_read_num(const char *name)
175 {
176         char path[PATH_MAX];
177         int ret;
178 
179         ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
180         if (ret >= PATH_MAX) {
181                 printf("%s: Pathname is too long\n", __func__);
182                 exit(EXIT_FAILURE);
183         }
184         return read_num(path);
185 }
186 
187 void thp_write_num(const char *name, unsigned long num)
188 {
189         char path[PATH_MAX];
190         int ret;
191 
192         ret = snprintf(path, PATH_MAX, THP_SYSFS "%s", name);
193         if (ret >= PATH_MAX) {
194                 printf("%s: Pathname is too long\n", __func__);
195                 exit(EXIT_FAILURE);
196         }
197         write_num(path, num);
198 }
199 
200 void thp_read_settings(struct thp_settings *settings)
201 {
202         unsigned long orders = thp_supported_orders();
203         char path[PATH_MAX];
204         int i;
205 
206         *settings = (struct thp_settings) {
207                 .thp_enabled = thp_read_string("enabled", thp_enabled_strings),
208                 .thp_defrag = thp_read_string("defrag", thp_defrag_strings),
209                 .shmem_enabled =
210                         thp_read_string("shmem_enabled", shmem_enabled_strings),
211                 .use_zero_page = thp_read_num("use_zero_page"),
212         };
213         settings->khugepaged = (struct khugepaged_settings) {
214                 .defrag = thp_read_num("khugepaged/defrag"),
215                 .alloc_sleep_millisecs =
216                         thp_read_num("khugepaged/alloc_sleep_millisecs"),
217                 .scan_sleep_millisecs =
218                         thp_read_num("khugepaged/scan_sleep_millisecs"),
219                 .max_ptes_none = thp_read_num("khugepaged/max_ptes_none"),
220                 .max_ptes_swap = thp_read_num("khugepaged/max_ptes_swap"),
221                 .max_ptes_shared = thp_read_num("khugepaged/max_ptes_shared"),
222                 .pages_to_scan = thp_read_num("khugepaged/pages_to_scan"),
223         };
224         if (dev_queue_read_ahead_path[0])
225                 settings->read_ahead_kb = read_num(dev_queue_read_ahead_path);
226 
227         for (i = 0; i < NR_ORDERS; i++) {
228                 if (!((1 << i) & orders)) {
229                         settings->hugepages[i].enabled = THP_NEVER;
230                         continue;
231                 }
232                 snprintf(path, PATH_MAX, "hugepages-%ukB/enabled",
233                         (getpagesize() >> 10) << i);
234                 settings->hugepages[i].enabled =
235                         thp_read_string(path, thp_enabled_strings);
236         }
237 }
238 
239 void thp_write_settings(struct thp_settings *settings)
240 {
241         struct khugepaged_settings *khugepaged = &settings->khugepaged;
242         unsigned long orders = thp_supported_orders();
243         char path[PATH_MAX];
244         int enabled;
245         int i;
246 
247         thp_write_string("enabled", thp_enabled_strings[settings->thp_enabled]);
248         thp_write_string("defrag", thp_defrag_strings[settings->thp_defrag]);
249         thp_write_string("shmem_enabled",
250                         shmem_enabled_strings[settings->shmem_enabled]);
251         thp_write_num("use_zero_page", settings->use_zero_page);
252 
253         thp_write_num("khugepaged/defrag", khugepaged->defrag);
254         thp_write_num("khugepaged/alloc_sleep_millisecs",
255                         khugepaged->alloc_sleep_millisecs);
256         thp_write_num("khugepaged/scan_sleep_millisecs",
257                         khugepaged->scan_sleep_millisecs);
258         thp_write_num("khugepaged/max_ptes_none", khugepaged->max_ptes_none);
259         thp_write_num("khugepaged/max_ptes_swap", khugepaged->max_ptes_swap);
260         thp_write_num("khugepaged/max_ptes_shared", khugepaged->max_ptes_shared);
261         thp_write_num("khugepaged/pages_to_scan", khugepaged->pages_to_scan);
262 
263         if (dev_queue_read_ahead_path[0])
264                 write_num(dev_queue_read_ahead_path, settings->read_ahead_kb);
265 
266         for (i = 0; i < NR_ORDERS; i++) {
267                 if (!((1 << i) & orders))
268                         continue;
269                 snprintf(path, PATH_MAX, "hugepages-%ukB/enabled",
270                         (getpagesize() >> 10) << i);
271                 enabled = settings->hugepages[i].enabled;
272                 thp_write_string(path, thp_enabled_strings[enabled]);
273         }
274 }
275 
276 struct thp_settings *thp_current_settings(void)
277 {
278         if (!settings_index) {
279                 printf("Fail: No settings set");
280                 exit(EXIT_FAILURE);
281         }
282         return settings_stack + settings_index - 1;
283 }
284 
285 void thp_push_settings(struct thp_settings *settings)
286 {
287         if (settings_index >= MAX_SETTINGS_DEPTH) {
288                 printf("Fail: Settings stack exceeded");
289                 exit(EXIT_FAILURE);
290         }
291         settings_stack[settings_index++] = *settings;
292         thp_write_settings(thp_current_settings());
293 }
294 
295 void thp_pop_settings(void)
296 {
297         if (settings_index <= 0) {
298                 printf("Fail: Settings stack empty");
299                 exit(EXIT_FAILURE);
300         }
301         --settings_index;
302         thp_write_settings(thp_current_settings());
303 }
304 
305 void thp_restore_settings(void)
306 {
307         thp_write_settings(&saved_settings);
308 }
309 
310 void thp_save_settings(void)
311 {
312         thp_read_settings(&saved_settings);
313 }
314 
315 void thp_set_read_ahead_path(char *path)
316 {
317         if (!path) {
318                 dev_queue_read_ahead_path[0] = '\0';
319                 return;
320         }
321 
322         strncpy(dev_queue_read_ahead_path, path,
323                 sizeof(dev_queue_read_ahead_path));
324         dev_queue_read_ahead_path[sizeof(dev_queue_read_ahead_path) - 1] = '\0';
325 }
326 
327 unsigned long thp_supported_orders(void)
328 {
329         unsigned long orders = 0;
330         char path[PATH_MAX];
331         char buf[256];
332         int ret;
333         int i;
334 
335         for (i = 0; i < NR_ORDERS; i++) {
336                 ret = snprintf(path, PATH_MAX, THP_SYSFS "hugepages-%ukB/enabled",
337                         (getpagesize() >> 10) << i);
338                 if (ret >= PATH_MAX) {
339                         printf("%s: Pathname is too long\n", __func__);
340                         exit(EXIT_FAILURE);
341                 }
342 
343                 ret = read_file(path, buf, sizeof(buf));
344                 if (ret)
345                         orders |= 1UL << i;
346         }
347 
348         return orders;
349 }
350 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php