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

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/mm/hugetlb-soft-offline.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 /*
  3  * Test soft offline behavior for HugeTLB pages:
  4  * - if enable_soft_offline = 0, hugepages should stay intact and soft
  5  *   offlining failed with EOPNOTSUPP.
  6  * - if enable_soft_offline = 1, a hugepage should be dissolved and
  7  *   nr_hugepages/free_hugepages should be reduced by 1.
  8  *
  9  * Before running, make sure more than 2 hugepages of default_hugepagesz
 10  * are allocated. For example, if /proc/meminfo/Hugepagesize is 2048kB:
 11  *   echo 8 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages
 12  */
 13 
 14 #define _GNU_SOURCE
 15 #include <errno.h>
 16 #include <stdlib.h>
 17 #include <stdio.h>
 18 #include <string.h>
 19 #include <unistd.h>
 20 
 21 #include <linux/magic.h>
 22 #include <linux/memfd.h>
 23 #include <sys/mman.h>
 24 #include <sys/statfs.h>
 25 #include <sys/types.h>
 26 
 27 #include "../kselftest.h"
 28 
 29 #ifndef MADV_SOFT_OFFLINE
 30 #define MADV_SOFT_OFFLINE 101
 31 #endif
 32 
 33 #define EPREFIX " !!! "
 34 
 35 static int do_soft_offline(int fd, size_t len, int expect_errno)
 36 {
 37         char *filemap = NULL;
 38         char *hwp_addr = NULL;
 39         const unsigned long pagesize = getpagesize();
 40         int ret = 0;
 41 
 42         if (ftruncate(fd, len) < 0) {
 43                 ksft_perror(EPREFIX "ftruncate to len failed");
 44                 return -1;
 45         }
 46 
 47         filemap = mmap(NULL, len, PROT_READ | PROT_WRITE,
 48                        MAP_SHARED | MAP_POPULATE, fd, 0);
 49         if (filemap == MAP_FAILED) {
 50                 ksft_perror(EPREFIX "mmap failed");
 51                 ret = -1;
 52                 goto untruncate;
 53         }
 54 
 55         memset(filemap, 0xab, len);
 56         ksft_print_msg("Allocated %#lx bytes of hugetlb pages\n", len);
 57 
 58         hwp_addr = filemap + len / 2;
 59         ret = madvise(hwp_addr, pagesize, MADV_SOFT_OFFLINE);
 60         ksft_print_msg("MADV_SOFT_OFFLINE %p ret=%d, errno=%d\n",
 61                        hwp_addr, ret, errno);
 62         if (ret != 0)
 63                 ksft_perror(EPREFIX "madvise failed");
 64 
 65         if (errno == expect_errno)
 66                 ret = 0;
 67         else {
 68                 ksft_print_msg("MADV_SOFT_OFFLINE should ret %d\n",
 69                                expect_errno);
 70                 ret = -1;
 71         }
 72 
 73         munmap(filemap, len);
 74 untruncate:
 75         if (ftruncate(fd, 0) < 0)
 76                 ksft_perror(EPREFIX "ftruncate back to 0 failed");
 77 
 78         return ret;
 79 }
 80 
 81 static int set_enable_soft_offline(int value)
 82 {
 83         char cmd[256] = {0};
 84         FILE *cmdfile = NULL;
 85 
 86         if (value != 0 && value != 1)
 87                 return -EINVAL;
 88 
 89         sprintf(cmd, "echo %d > /proc/sys/vm/enable_soft_offline", value);
 90         cmdfile = popen(cmd, "r");
 91 
 92         if (cmdfile)
 93                 ksft_print_msg("enable_soft_offline => %d\n", value);
 94         else {
 95                 ksft_perror(EPREFIX "failed to set enable_soft_offline");
 96                 return errno;
 97         }
 98 
 99         pclose(cmdfile);
100         return 0;
101 }
102 
103 static int read_nr_hugepages(unsigned long hugepage_size,
104                              unsigned long *nr_hugepages)
105 {
106         char buffer[256] = {0};
107         char cmd[256] = {0};
108 
109         sprintf(cmd, "cat /sys/kernel/mm/hugepages/hugepages-%ldkB/nr_hugepages",
110                 hugepage_size);
111         FILE *cmdfile = popen(cmd, "r");
112 
113         if (cmdfile == NULL) {
114                 ksft_perror(EPREFIX "failed to popen nr_hugepages");
115                 return -1;
116         }
117 
118         if (!fgets(buffer, sizeof(buffer), cmdfile)) {
119                 ksft_perror(EPREFIX "failed to read nr_hugepages");
120                 pclose(cmdfile);
121                 return -1;
122         }
123 
124         *nr_hugepages = atoll(buffer);
125         pclose(cmdfile);
126         return 0;
127 }
128 
129 static int create_hugetlbfs_file(struct statfs *file_stat)
130 {
131         int fd;
132 
133         fd = memfd_create("hugetlb_tmp", MFD_HUGETLB);
134         if (fd < 0) {
135                 ksft_perror(EPREFIX "could not open hugetlbfs file");
136                 return -1;
137         }
138 
139         memset(file_stat, 0, sizeof(*file_stat));
140         if (fstatfs(fd, file_stat)) {
141                 ksft_perror(EPREFIX "fstatfs failed");
142                 goto close;
143         }
144         if (file_stat->f_type != HUGETLBFS_MAGIC) {
145                 ksft_print_msg(EPREFIX "not hugetlbfs file\n");
146                 goto close;
147         }
148 
149         return fd;
150 close:
151         close(fd);
152         return -1;
153 }
154 
155 static void test_soft_offline_common(int enable_soft_offline)
156 {
157         int fd;
158         int expect_errno = enable_soft_offline ? 0 : EOPNOTSUPP;
159         struct statfs file_stat;
160         unsigned long hugepagesize_kb = 0;
161         unsigned long nr_hugepages_before = 0;
162         unsigned long nr_hugepages_after = 0;
163         int ret;
164 
165         ksft_print_msg("Test soft-offline when enabled_soft_offline=%d\n",
166                        enable_soft_offline);
167 
168         fd = create_hugetlbfs_file(&file_stat);
169         if (fd < 0)
170                 ksft_exit_fail_msg("Failed to create hugetlbfs file\n");
171 
172         hugepagesize_kb = file_stat.f_bsize / 1024;
173         ksft_print_msg("Hugepagesize is %ldkB\n", hugepagesize_kb);
174 
175         if (set_enable_soft_offline(enable_soft_offline) != 0) {
176                 close(fd);
177                 ksft_exit_fail_msg("Failed to set enable_soft_offline\n");
178         }
179 
180         if (read_nr_hugepages(hugepagesize_kb, &nr_hugepages_before) != 0) {
181                 close(fd);
182                 ksft_exit_fail_msg("Failed to read nr_hugepages\n");
183         }
184 
185         ksft_print_msg("Before MADV_SOFT_OFFLINE nr_hugepages=%ld\n",
186                        nr_hugepages_before);
187 
188         ret = do_soft_offline(fd, 2 * file_stat.f_bsize, expect_errno);
189 
190         if (read_nr_hugepages(hugepagesize_kb, &nr_hugepages_after) != 0) {
191                 close(fd);
192                 ksft_exit_fail_msg("Failed to read nr_hugepages\n");
193         }
194 
195         ksft_print_msg("After MADV_SOFT_OFFLINE nr_hugepages=%ld\n",
196                 nr_hugepages_after);
197 
198         // No need for the hugetlbfs file from now on.
199         close(fd);
200 
201         if (enable_soft_offline) {
202                 if (nr_hugepages_before != nr_hugepages_after + 1) {
203                         ksft_test_result_fail("MADV_SOFT_OFFLINE should reduced 1 hugepage\n");
204                         return;
205                 }
206         } else {
207                 if (nr_hugepages_before != nr_hugepages_after) {
208                         ksft_test_result_fail("MADV_SOFT_OFFLINE reduced %lu hugepages\n",
209                                 nr_hugepages_before - nr_hugepages_after);
210                         return;
211                 }
212         }
213 
214         ksft_test_result(ret == 0,
215                          "Test soft-offline when enabled_soft_offline=%d\n",
216                          enable_soft_offline);
217 }
218 
219 int main(int argc, char **argv)
220 {
221         ksft_print_header();
222         ksft_set_plan(2);
223 
224         test_soft_offline_common(1);
225         test_soft_offline_common(0);
226 
227         ksft_finished();
228 }
229 

~ [ 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