riscv: Fix alignment-ignorant memcpy implementation
[glibc.git] / sysdeps / unix / sysv / linux / malloc-hugepages.c
blobe8f82fb24595cba9fc4fea94aa46db06c2a4ef89
1 /* Huge Page support. Linux implementation.
2 Copyright (C) 2021-2024 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public License as
7 published by the Free Software Foundation; either version 2.1 of the
8 License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; see the file COPYING.LIB. If
17 not, see <https://www.gnu.org/licenses/>. */
19 #include <intprops.h>
20 #include <dirent.h>
21 #include <malloc-hugepages.h>
22 #include <not-cancel.h>
23 #include <sys/mman.h>
25 unsigned long int
26 __malloc_default_thp_pagesize (void)
28 int fd = __open64_nocancel (
29 "/sys/kernel/mm/transparent_hugepage/hpage_pmd_size", O_RDONLY);
30 if (fd == -1)
31 return 0;
33 char str[INT_BUFSIZE_BOUND (unsigned long int)];
34 ssize_t s = __read_nocancel (fd, str, sizeof (str));
35 __close_nocancel (fd);
36 if (s < 0)
37 return 0;
39 unsigned long int r = 0;
40 for (ssize_t i = 0; i < s; i++)
42 if (str[i] == '\n')
43 break;
44 r *= 10;
45 r += str[i] - '0';
47 return r;
50 enum malloc_thp_mode_t
51 __malloc_thp_mode (void)
53 int fd = __open64_nocancel ("/sys/kernel/mm/transparent_hugepage/enabled",
54 O_RDONLY);
55 if (fd == -1)
56 return malloc_thp_mode_not_supported;
58 static const char mode_always[] = "[always] madvise never\n";
59 static const char mode_madvise[] = "always [madvise] never\n";
60 static const char mode_never[] = "always madvise [never]\n";
62 char str[sizeof(mode_always)];
63 ssize_t s = __read_nocancel (fd, str, sizeof (str));
64 if (s >= sizeof str || s < 0)
65 return malloc_thp_mode_not_supported;
66 str[s] = '\0';
67 __close_nocancel (fd);
69 if (s == sizeof (mode_always) - 1)
71 if (strcmp (str, mode_always) == 0)
72 return malloc_thp_mode_always;
73 else if (strcmp (str, mode_madvise) == 0)
74 return malloc_thp_mode_madvise;
75 else if (strcmp (str, mode_never) == 0)
76 return malloc_thp_mode_never;
78 return malloc_thp_mode_not_supported;
81 static size_t
82 malloc_default_hugepage_size (void)
84 int fd = __open64_nocancel ("/proc/meminfo", O_RDONLY);
85 if (fd == -1)
86 return 0;
88 size_t hpsize = 0;
90 char buf[512];
91 off64_t off = 0;
92 while (1)
94 ssize_t r = __pread64_nocancel (fd, buf, sizeof (buf) - 1, off);
95 if (r < 0)
96 break;
97 buf[r] = '\0';
99 /* If the tag is not found, read the last line again. */
100 const char *s = strstr (buf, "Hugepagesize:");
101 if (s == NULL)
103 char *nl = strrchr (buf, '\n');
104 if (nl == NULL)
105 break;
106 off += (nl + 1) - buf;
107 continue;
110 /* The default huge page size is in the form:
111 Hugepagesize: NUMBER kB */
112 s += sizeof ("Hugepagesize: ") - 1;
113 for (int i = 0; (s[i] >= '0' && s[i] <= '9') || s[i] == ' '; i++)
115 if (s[i] == ' ')
116 continue;
117 hpsize *= 10;
118 hpsize += s[i] - '0';
120 hpsize *= 1024;
121 break;
124 __close_nocancel (fd);
126 return hpsize;
129 static inline int
130 hugepage_flags (size_t pagesize)
132 return MAP_HUGETLB | (__builtin_ctzll (pagesize) << MAP_HUGE_SHIFT);
135 void
136 __malloc_hugepage_config (size_t requested, size_t *pagesize, int *flags)
138 *pagesize = 0;
139 *flags = 0;
141 if (requested == 0)
143 *pagesize = malloc_default_hugepage_size ();
144 if (*pagesize != 0)
145 *flags = hugepage_flags (*pagesize);
146 return;
149 /* Each entry represents a supported huge page in the form of:
150 hugepages-<size>kB. */
151 int dirfd = __open64_nocancel ("/sys/kernel/mm/hugepages",
152 O_RDONLY | O_DIRECTORY, 0);
153 if (dirfd == -1)
154 return;
156 char buffer[1024];
157 while (true)
159 #if !IS_IN(libc)
160 # define __getdents64 getdents64
161 #endif
162 ssize_t ret = __getdents64 (dirfd, buffer, sizeof (buffer));
163 if (ret == -1)
164 break;
165 else if (ret == 0)
166 break;
168 bool found = false;
169 char *begin = buffer, *end = buffer + ret;
170 while (begin != end)
172 unsigned short int d_reclen;
173 memcpy (&d_reclen, begin + offsetof (struct dirent64, d_reclen),
174 sizeof (d_reclen));
175 const char *dname = begin + offsetof (struct dirent64, d_name);
176 begin += d_reclen;
178 if (dname[0] == '.'
179 || strncmp (dname, "hugepages-", sizeof ("hugepages-") - 1) != 0)
180 continue;
182 size_t hpsize = 0;
183 const char *sizestr = dname + sizeof ("hugepages-") - 1;
184 for (int i = 0; sizestr[i] >= '0' && sizestr[i] <= '9'; i++)
186 hpsize *= 10;
187 hpsize += sizestr[i] - '0';
189 hpsize *= 1024;
191 if (hpsize == requested)
193 *pagesize = hpsize;
194 *flags = hugepage_flags (*pagesize);
195 found = true;
196 break;
199 if (found)
200 break;
203 __close_nocancel (dirfd);