1 // SPDX-License-Identifier: GPL-2.0 2 #define _GNU_SOURCE 3 #include <stdio.h> 4 #include <fcntl.h> 5 #include <string.h> 6 #include <sys/mman.h> 7 #include <errno.h> 8 #include <malloc.h> 9 #include "vm_util.h" 10 #include "../kselftest.h" 11 #include <linux/types.h> 12 #include <linux/memfd.h> 13 #include <linux/userfaultfd.h> 14 #include <linux/fs.h> 15 #include <sys/ioctl.h> 16 #include <sys/stat.h> 17 #include <math.h> 18 #include <asm/unistd.h> 19 #include <pthread.h> 20 #include <sys/resource.h> 21 #include <assert.h> 22 #include <sys/ipc.h> 23 #include <sys/shm.h> 24 25 #define PAGEMAP_BITS_ALL (PAGE_IS_WPALLOWED | PAGE_IS_WRITTEN | \ 26 PAGE_IS_FILE | PAGE_IS_PRESENT | \ 27 PAGE_IS_SWAPPED | PAGE_IS_PFNZERO | \ 28 PAGE_IS_HUGE) 29 #define PAGEMAP_NON_WRITTEN_BITS (PAGE_IS_WPALLOWED | PAGE_IS_FILE | \ 30 PAGE_IS_PRESENT | PAGE_IS_SWAPPED | \ 31 PAGE_IS_PFNZERO | PAGE_IS_HUGE) 32 33 #define TEST_ITERATIONS 100 34 #define PAGEMAP "/proc/self/pagemap" 35 int pagemap_fd; 36 int uffd; 37 int page_size; 38 int hpage_size; 39 40 #define LEN(region) ((region.end - region.start)/page_size) 41 42 static long pagemap_ioctl(void *start, int len, void *vec, int vec_len, int flag, 43 int max_pages, long required_mask, long anyof_mask, long excluded_mask, 44 long return_mask) 45 { 46 struct pm_scan_arg arg; 47 48 arg.start = (uintptr_t)start; 49 arg.end = (uintptr_t)(start + len); 50 arg.vec = (uintptr_t)vec; 51 arg.vec_len = vec_len; 52 arg.flags = flag; 53 arg.size = sizeof(struct pm_scan_arg); 54 arg.max_pages = max_pages; 55 arg.category_mask = required_mask; 56 arg.category_anyof_mask = anyof_mask; 57 arg.category_inverted = excluded_mask; 58 arg.return_mask = return_mask; 59 60 return ioctl(pagemap_fd, PAGEMAP_SCAN, &arg); 61 } 62 63 static long pagemap_ioc(void *start, int len, void *vec, int vec_len, int flag, 64 int max_pages, long required_mask, long anyof_mask, long excluded_mask, 65 long return_mask, long *walk_end) 66 { 67 struct pm_scan_arg arg; 68 int ret; 69 70 arg.start = (uintptr_t)start; 71 arg.end = (uintptr_t)(start + len); 72 arg.vec = (uintptr_t)vec; 73 arg.vec_len = vec_len; 74 arg.flags = flag; 75 arg.size = sizeof(struct pm_scan_arg); 76 arg.max_pages = max_pages; 77 arg.category_mask = required_mask; 78 arg.category_anyof_mask = anyof_mask; 79 arg.category_inverted = excluded_mask; 80 arg.return_mask = return_mask; 81 82 ret = ioctl(pagemap_fd, PAGEMAP_SCAN, &arg); 83 84 if (walk_end) 85 *walk_end = arg.walk_end; 86 87 return ret; 88 } 89 90 91 int init_uffd(void) 92 { 93 struct uffdio_api uffdio_api; 94 95 uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK | UFFD_USER_MODE_ONLY); 96 if (uffd == -1) 97 ksft_exit_fail_msg("uffd syscall failed\n"); 98 99 uffdio_api.api = UFFD_API; 100 uffdio_api.features = UFFD_FEATURE_WP_UNPOPULATED | UFFD_FEATURE_WP_ASYNC | 101 UFFD_FEATURE_WP_HUGETLBFS_SHMEM; 102 if (ioctl(uffd, UFFDIO_API, &uffdio_api)) 103 ksft_exit_fail_msg("UFFDIO_API\n"); 104 105 if (!(uffdio_api.api & UFFDIO_REGISTER_MODE_WP) || 106 !(uffdio_api.features & UFFD_FEATURE_WP_UNPOPULATED) || 107 !(uffdio_api.features & UFFD_FEATURE_WP_ASYNC) || 108 !(uffdio_api.features & UFFD_FEATURE_WP_HUGETLBFS_SHMEM)) 109 ksft_exit_fail_msg("UFFDIO_API error %llu\n", uffdio_api.api); 110 111 return 0; 112 } 113 114 int wp_init(void *lpBaseAddress, int dwRegionSize) 115 { 116 struct uffdio_register uffdio_register; 117 struct uffdio_writeprotect wp; 118 119 uffdio_register.range.start = (unsigned long)lpBaseAddress; 120 uffdio_register.range.len = dwRegionSize; 121 uffdio_register.mode = UFFDIO_REGISTER_MODE_WP; 122 if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register)) 123 ksft_exit_fail_msg("ioctl(UFFDIO_REGISTER) %d %s\n", errno, strerror(errno)); 124 125 if (!(uffdio_register.ioctls & UFFDIO_WRITEPROTECT)) 126 ksft_exit_fail_msg("ioctl set is incorrect\n"); 127 128 wp.range.start = (unsigned long)lpBaseAddress; 129 wp.range.len = dwRegionSize; 130 wp.mode = UFFDIO_WRITEPROTECT_MODE_WP; 131 132 if (ioctl(uffd, UFFDIO_WRITEPROTECT, &wp)) 133 ksft_exit_fail_msg("ioctl(UFFDIO_WRITEPROTECT)\n"); 134 135 return 0; 136 } 137 138 int wp_free(void *lpBaseAddress, int dwRegionSize) 139 { 140 struct uffdio_register uffdio_register; 141 142 uffdio_register.range.start = (unsigned long)lpBaseAddress; 143 uffdio_register.range.len = dwRegionSize; 144 uffdio_register.mode = UFFDIO_REGISTER_MODE_WP; 145 if (ioctl(uffd, UFFDIO_UNREGISTER, &uffdio_register.range)) 146 ksft_exit_fail_msg("ioctl unregister failure\n"); 147 return 0; 148 } 149 150 int wp_addr_range(void *lpBaseAddress, int dwRegionSize) 151 { 152 if (pagemap_ioctl(lpBaseAddress, dwRegionSize, NULL, 0, 153 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 154 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN) < 0) 155 ksft_exit_fail_msg("error %d %d %s\n", 1, errno, strerror(errno)); 156 157 return 0; 158 } 159 160 void *gethugetlb_mem(int size, int *shmid) 161 { 162 char *mem; 163 164 if (shmid) { 165 *shmid = shmget(2, size, SHM_HUGETLB | IPC_CREAT | SHM_R | SHM_W); 166 if (*shmid < 0) 167 return NULL; 168 169 mem = shmat(*shmid, 0, 0); 170 if (mem == (char *)-1) { 171 shmctl(*shmid, IPC_RMID, NULL); 172 ksft_exit_fail_msg("Shared memory attach failure\n"); 173 } 174 } else { 175 mem = mmap(NULL, size, PROT_READ | PROT_WRITE, 176 MAP_ANONYMOUS | MAP_HUGETLB | MAP_PRIVATE, -1, 0); 177 if (mem == MAP_FAILED) 178 return NULL; 179 } 180 181 return mem; 182 } 183 184 int userfaultfd_tests(void) 185 { 186 int mem_size, vec_size, written, num_pages = 16; 187 char *mem, *vec; 188 189 mem_size = num_pages * page_size; 190 mem = mmap(NULL, mem_size, PROT_NONE, MAP_PRIVATE | MAP_ANON, -1, 0); 191 if (mem == MAP_FAILED) 192 ksft_exit_fail_msg("error nomem\n"); 193 194 wp_init(mem, mem_size); 195 196 /* Change protection of pages differently */ 197 mprotect(mem, mem_size/8, PROT_READ|PROT_WRITE); 198 mprotect(mem + 1 * mem_size/8, mem_size/8, PROT_READ); 199 mprotect(mem + 2 * mem_size/8, mem_size/8, PROT_READ|PROT_WRITE); 200 mprotect(mem + 3 * mem_size/8, mem_size/8, PROT_READ); 201 mprotect(mem + 4 * mem_size/8, mem_size/8, PROT_READ|PROT_WRITE); 202 mprotect(mem + 5 * mem_size/8, mem_size/8, PROT_NONE); 203 mprotect(mem + 6 * mem_size/8, mem_size/8, PROT_READ|PROT_WRITE); 204 mprotect(mem + 7 * mem_size/8, mem_size/8, PROT_READ); 205 206 wp_addr_range(mem + (mem_size/16), mem_size - 2 * (mem_size/8)); 207 wp_addr_range(mem, mem_size); 208 209 vec_size = mem_size/page_size; 210 vec = malloc(sizeof(struct page_region) * vec_size); 211 212 written = pagemap_ioctl(mem, mem_size, vec, 1, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 213 vec_size - 2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 214 if (written < 0) 215 ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno)); 216 217 ksft_test_result(written == 0, "%s all new pages must not be written (dirty)\n", __func__); 218 219 wp_free(mem, mem_size); 220 munmap(mem, mem_size); 221 free(vec); 222 return 0; 223 } 224 225 int get_reads(struct page_region *vec, int vec_size) 226 { 227 int i, sum = 0; 228 229 for (i = 0; i < vec_size; i++) 230 sum += LEN(vec[i]); 231 232 return sum; 233 } 234 235 int sanity_tests_sd(void) 236 { 237 int mem_size, vec_size, ret, ret2, ret3, i, num_pages = 1000, total_pages = 0; 238 int total_writes, total_reads, reads, count; 239 struct page_region *vec, *vec2; 240 char *mem, *m[2]; 241 long walk_end; 242 243 vec_size = num_pages/2; 244 mem_size = num_pages * page_size; 245 246 vec = malloc(sizeof(struct page_region) * vec_size); 247 if (!vec) 248 ksft_exit_fail_msg("error nomem\n"); 249 250 vec2 = malloc(sizeof(struct page_region) * vec_size); 251 if (!vec2) 252 ksft_exit_fail_msg("error nomem\n"); 253 254 mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 255 if (mem == MAP_FAILED) 256 ksft_exit_fail_msg("error nomem\n"); 257 258 wp_init(mem, mem_size); 259 wp_addr_range(mem, mem_size); 260 261 /* 1. wrong operation */ 262 ksft_test_result(pagemap_ioctl(mem, 0, vec, vec_size, 0, 263 0, PAGEMAP_BITS_ALL, 0, 0, PAGEMAP_BITS_ALL) == 0, 264 "%s Zero range size is valid\n", __func__); 265 266 ksft_test_result(pagemap_ioctl(mem, mem_size, NULL, vec_size, 0, 267 0, PAGEMAP_BITS_ALL, 0, 0, PAGEMAP_BITS_ALL) < 0, 268 "%s output buffer must be specified with size\n", __func__); 269 270 ksft_test_result(pagemap_ioctl(mem, mem_size, vec, 0, 0, 271 0, PAGEMAP_BITS_ALL, 0, 0, PAGEMAP_BITS_ALL) == 0, 272 "%s output buffer can be 0\n", __func__); 273 274 ksft_test_result(pagemap_ioctl(mem, mem_size, 0, 0, 0, 275 0, PAGEMAP_BITS_ALL, 0, 0, PAGEMAP_BITS_ALL) == 0, 276 "%s output buffer can be 0\n", __func__); 277 278 ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size, -1, 279 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN) < 0, 280 "%s wrong flag specified\n", __func__); 281 282 ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size, 283 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC | 0xFF, 284 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN) < 0, 285 "%s flag has extra bits specified\n", __func__); 286 287 ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 288 0, 0, 0, 0, PAGE_IS_WRITTEN) >= 0, 289 "%s no selection mask is specified\n", __func__); 290 291 ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 292 0, PAGE_IS_WRITTEN, PAGE_IS_WRITTEN, 0, 0) == 0, 293 "%s no return mask is specified\n", __func__); 294 295 ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 296 0, PAGE_IS_WRITTEN, 0, 0, 0x1000) < 0, 297 "%s wrong return mask specified\n", __func__); 298 299 ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size, 300 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 301 0, 0xFFF, PAGE_IS_WRITTEN, 0, PAGE_IS_WRITTEN) < 0, 302 "%s mixture of correct and wrong flag\n", __func__); 303 304 ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size, 305 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 306 0, 0, 0, PAGEMAP_BITS_ALL, PAGE_IS_WRITTEN) >= 0, 307 "%s PAGEMAP_BITS_ALL can be specified with PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC\n", 308 __func__); 309 310 /* 2. Clear area with larger vec size */ 311 ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 312 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 0, 313 PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 314 ksft_test_result(ret >= 0, "%s Clear area with larger vec size\n", __func__); 315 316 /* 3. Repeated pattern of written and non-written pages */ 317 for (i = 0; i < mem_size; i += 2 * page_size) 318 mem[i]++; 319 320 ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0, PAGE_IS_WRITTEN, 0, 321 0, PAGE_IS_WRITTEN); 322 if (ret < 0) 323 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 324 325 ksft_test_result(ret == mem_size/(page_size * 2), 326 "%s Repeated pattern of written and non-written pages\n", __func__); 327 328 /* 4. Repeated pattern of written and non-written pages in parts */ 329 ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 330 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 331 num_pages/2 - 2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 332 if (ret < 0) 333 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 334 335 ret2 = pagemap_ioctl(mem, mem_size, vec, 2, 0, 0, PAGE_IS_WRITTEN, 0, 0, 336 PAGE_IS_WRITTEN); 337 if (ret2 < 0) 338 ksft_exit_fail_msg("error %d %d %s\n", ret2, errno, strerror(errno)); 339 340 ret3 = pagemap_ioctl(mem, mem_size, vec, vec_size, 341 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 342 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 343 if (ret3 < 0) 344 ksft_exit_fail_msg("error %d %d %s\n", ret3, errno, strerror(errno)); 345 346 ksft_test_result((ret + ret3) == num_pages/2 && ret2 == 2, 347 "%s Repeated pattern of written and non-written pages in parts %d %d %d\n", 348 __func__, ret, ret3, ret2); 349 350 /* 5. Repeated pattern of written and non-written pages max_pages */ 351 for (i = 0; i < mem_size; i += 2 * page_size) 352 mem[i]++; 353 mem[(mem_size/page_size - 1) * page_size]++; 354 355 ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 356 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 357 num_pages/2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 358 if (ret < 0) 359 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 360 361 ret2 = pagemap_ioctl(mem, mem_size, vec, vec_size, 362 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 363 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 364 if (ret2 < 0) 365 ksft_exit_fail_msg("error %d %d %s\n", ret2, errno, strerror(errno)); 366 367 ksft_test_result(ret == num_pages/2 && ret2 == 1, 368 "%s Repeated pattern of written and non-written pages max_pages\n", 369 __func__); 370 371 /* 6. only get 2 dirty pages and clear them as well */ 372 vec_size = mem_size/page_size; 373 memset(mem, -1, mem_size); 374 375 /* get and clear second and third pages */ 376 ret = pagemap_ioctl(mem + page_size, 2 * page_size, vec, 1, 377 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 378 2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 379 if (ret < 0) 380 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 381 382 ret2 = pagemap_ioctl(mem, mem_size, vec2, vec_size, 0, 0, 383 PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 384 if (ret2 < 0) 385 ksft_exit_fail_msg("error %d %d %s\n", ret2, errno, strerror(errno)); 386 387 ksft_test_result(ret == 1 && LEN(vec[0]) == 2 && 388 vec[0].start == (uintptr_t)(mem + page_size) && 389 ret2 == 2 && LEN(vec2[0]) == 1 && vec2[0].start == (uintptr_t)mem && 390 LEN(vec2[1]) == vec_size - 3 && 391 vec2[1].start == (uintptr_t)(mem + 3 * page_size), 392 "%s only get 2 written pages and clear them as well\n", __func__); 393 394 wp_free(mem, mem_size); 395 munmap(mem, mem_size); 396 397 /* 7. Two regions */ 398 m[0] = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 399 if (m[0] == MAP_FAILED) 400 ksft_exit_fail_msg("error nomem\n"); 401 m[1] = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 402 if (m[1] == MAP_FAILED) 403 ksft_exit_fail_msg("error nomem\n"); 404 405 wp_init(m[0], mem_size); 406 wp_init(m[1], mem_size); 407 wp_addr_range(m[0], mem_size); 408 wp_addr_range(m[1], mem_size); 409 410 memset(m[0], 'a', mem_size); 411 memset(m[1], 'b', mem_size); 412 413 wp_addr_range(m[0], mem_size); 414 415 ret = pagemap_ioctl(m[1], mem_size, vec, 1, 0, 0, PAGE_IS_WRITTEN, 0, 0, 416 PAGE_IS_WRITTEN); 417 if (ret < 0) 418 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 419 420 ksft_test_result(ret == 1 && LEN(vec[0]) == mem_size/page_size, 421 "%s Two regions\n", __func__); 422 423 wp_free(m[0], mem_size); 424 wp_free(m[1], mem_size); 425 munmap(m[0], mem_size); 426 munmap(m[1], mem_size); 427 428 free(vec); 429 free(vec2); 430 431 /* 8. Smaller vec */ 432 mem_size = 1050 * page_size; 433 vec_size = mem_size/(page_size*2); 434 435 vec = malloc(sizeof(struct page_region) * vec_size); 436 if (!vec) 437 ksft_exit_fail_msg("error nomem\n"); 438 439 mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 440 if (mem == MAP_FAILED) 441 ksft_exit_fail_msg("error nomem\n"); 442 443 wp_init(mem, mem_size); 444 wp_addr_range(mem, mem_size); 445 446 ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 447 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 0, 448 PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 449 if (ret < 0) 450 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 451 452 for (i = 0; i < mem_size/page_size; i += 2) 453 mem[i * page_size]++; 454 455 ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 456 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 457 mem_size/(page_size*5), PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 458 if (ret < 0) 459 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 460 461 total_pages += ret; 462 463 ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 464 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 465 mem_size/(page_size*5), PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 466 if (ret < 0) 467 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 468 469 total_pages += ret; 470 471 ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 472 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 473 mem_size/(page_size*5), PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 474 if (ret < 0) 475 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 476 477 total_pages += ret; 478 479 ksft_test_result(total_pages == mem_size/(page_size*2), "%s Smaller max_pages\n", __func__); 480 481 free(vec); 482 wp_free(mem, mem_size); 483 munmap(mem, mem_size); 484 total_pages = 0; 485 486 /* 9. Smaller vec */ 487 mem_size = 10000 * page_size; 488 vec_size = 50; 489 490 vec = malloc(sizeof(struct page_region) * vec_size); 491 if (!vec) 492 ksft_exit_fail_msg("error nomem\n"); 493 494 mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 495 if (mem == MAP_FAILED) 496 ksft_exit_fail_msg("error nomem\n"); 497 498 wp_init(mem, mem_size); 499 wp_addr_range(mem, mem_size); 500 501 for (count = 0; count < TEST_ITERATIONS; count++) { 502 total_writes = total_reads = 0; 503 walk_end = (long)mem; 504 505 for (i = 0; i < mem_size; i += page_size) { 506 if (rand() % 2) { 507 mem[i]++; 508 total_writes++; 509 } 510 } 511 512 while (total_reads < total_writes) { 513 ret = pagemap_ioc((void *)walk_end, mem_size-(walk_end - (long)mem), vec, 514 vec_size, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 515 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); 516 if (ret < 0) 517 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 518 519 if (ret > vec_size) 520 break; 521 522 reads = get_reads(vec, ret); 523 total_reads += reads; 524 } 525 526 if (total_reads != total_writes) 527 break; 528 } 529 530 ksft_test_result(count == TEST_ITERATIONS, "Smaller vec\n"); 531 532 free(vec); 533 wp_free(mem, mem_size); 534 munmap(mem, mem_size); 535 536 /* 10. Walk_end tester */ 537 vec_size = 1000; 538 mem_size = vec_size * page_size; 539 540 vec = malloc(sizeof(struct page_region) * vec_size); 541 if (!vec) 542 ksft_exit_fail_msg("error nomem\n"); 543 544 mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 545 if (mem == MAP_FAILED) 546 ksft_exit_fail_msg("error nomem\n"); 547 548 wp_init(mem, mem_size); 549 wp_addr_range(mem, mem_size); 550 551 memset(mem, 0, mem_size); 552 553 ret = pagemap_ioc(mem, 0, vec, vec_size, 0, 554 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); 555 if (ret < 0) 556 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 557 ksft_test_result(ret == 0 && walk_end == (long)mem, 558 "Walk_end: Same start and end address\n"); 559 560 ret = pagemap_ioc(mem, 0, vec, vec_size, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 561 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); 562 if (ret < 0) 563 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 564 ksft_test_result(ret == 0 && walk_end == (long)mem, 565 "Walk_end: Same start and end with WP\n"); 566 567 ret = pagemap_ioc(mem, 0, vec, 0, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 568 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); 569 if (ret < 0) 570 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 571 ksft_test_result(ret == 0 && walk_end == (long)mem, 572 "Walk_end: Same start and end with 0 output buffer\n"); 573 574 ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0, 575 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); 576 if (ret < 0) 577 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 578 ksft_test_result(ret == 1 && walk_end == (long)(mem + mem_size), 579 "Walk_end: Big vec\n"); 580 581 ret = pagemap_ioc(mem, mem_size, vec, 1, 0, 582 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); 583 if (ret < 0) 584 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 585 ksft_test_result(ret == 1 && walk_end == (long)(mem + mem_size), 586 "Walk_end: vec of minimum length\n"); 587 588 ret = pagemap_ioc(mem, mem_size, vec, 1, 0, 589 vec_size, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); 590 if (ret < 0) 591 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 592 ksft_test_result(ret == 1 && walk_end == (long)(mem + mem_size), 593 "Walk_end: Max pages specified\n"); 594 595 ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0, 596 vec_size/2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); 597 if (ret < 0) 598 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 599 ksft_test_result(ret == 1 && walk_end == (long)(mem + mem_size/2), 600 "Walk_end: Half max pages\n"); 601 602 ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0, 603 1, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); 604 if (ret < 0) 605 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 606 ksft_test_result(ret == 1 && walk_end == (long)(mem + page_size), 607 "Walk_end: 1 max page\n"); 608 609 ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0, 610 -1, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); 611 if (ret < 0) 612 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 613 ksft_test_result(ret == 1 && walk_end == (long)(mem + mem_size), 614 "Walk_end: max pages\n"); 615 616 wp_addr_range(mem, mem_size); 617 for (i = 0; i < mem_size; i += 2 * page_size) 618 mem[i]++; 619 620 ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0, 621 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); 622 if (ret < 0) 623 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 624 ksft_test_result(ret == vec_size/2 && walk_end == (long)(mem + mem_size), 625 "Walk_end sparse: Big vec\n"); 626 627 ret = pagemap_ioc(mem, mem_size, vec, 1, 0, 628 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); 629 if (ret < 0) 630 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 631 ksft_test_result(ret == 1 && walk_end == (long)(mem + page_size * 2), 632 "Walk_end sparse: vec of minimum length\n"); 633 634 ret = pagemap_ioc(mem, mem_size, vec, 1, 0, 635 vec_size, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); 636 if (ret < 0) 637 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 638 ksft_test_result(ret == 1 && walk_end == (long)(mem + page_size * 2), 639 "Walk_end sparse: Max pages specified\n"); 640 641 ret = pagemap_ioc(mem, mem_size, vec, vec_size/2, 0, 642 vec_size, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); 643 if (ret < 0) 644 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 645 ksft_test_result(ret == vec_size/2 && walk_end == (long)(mem + mem_size), 646 "Walk_end sparse: Max pages specified\n"); 647 648 ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0, 649 vec_size, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); 650 if (ret < 0) 651 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 652 ksft_test_result(ret == vec_size/2 && walk_end == (long)(mem + mem_size), 653 "Walk_end sparse: Max pages specified\n"); 654 655 ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0, 656 vec_size/2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); 657 if (ret < 0) 658 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 659 ksft_test_result(ret == vec_size/2 && walk_end == (long)(mem + mem_size), 660 "Walk_endsparse : Half max pages\n"); 661 662 ret = pagemap_ioc(mem, mem_size, vec, vec_size, 0, 663 1, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN, &walk_end); 664 if (ret < 0) 665 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 666 ksft_test_result(ret == 1 && walk_end == (long)(mem + page_size * 2), 667 "Walk_end: 1 max page\n"); 668 669 free(vec); 670 wp_free(mem, mem_size); 671 munmap(mem, mem_size); 672 673 return 0; 674 } 675 676 int base_tests(char *prefix, char *mem, int mem_size, int skip) 677 { 678 int vec_size, written; 679 struct page_region *vec, *vec2; 680 681 if (skip) { 682 ksft_test_result_skip("%s all new pages must not be written (dirty)\n", prefix); 683 ksft_test_result_skip("%s all pages must be written (dirty)\n", prefix); 684 ksft_test_result_skip("%s all pages dirty other than first and the last one\n", 685 prefix); 686 ksft_test_result_skip("%s PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC\n", prefix); 687 ksft_test_result_skip("%s only middle page dirty\n", prefix); 688 ksft_test_result_skip("%s only two middle pages dirty\n", prefix); 689 return 0; 690 } 691 692 vec_size = mem_size/page_size; 693 vec = malloc(sizeof(struct page_region) * vec_size); 694 vec2 = malloc(sizeof(struct page_region) * vec_size); 695 696 /* 1. all new pages must be not be written (dirty) */ 697 written = pagemap_ioctl(mem, mem_size, vec, 1, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 698 vec_size - 2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 699 if (written < 0) 700 ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno)); 701 702 ksft_test_result(written == 0, "%s all new pages must not be written (dirty)\n", prefix); 703 704 /* 2. all pages must be written */ 705 memset(mem, -1, mem_size); 706 707 written = pagemap_ioctl(mem, mem_size, vec, 1, 0, 0, PAGE_IS_WRITTEN, 0, 0, 708 PAGE_IS_WRITTEN); 709 if (written < 0) 710 ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno)); 711 712 ksft_test_result(written == 1 && LEN(vec[0]) == mem_size/page_size, 713 "%s all pages must be written (dirty)\n", prefix); 714 715 /* 3. all pages dirty other than first and the last one */ 716 written = pagemap_ioctl(mem, mem_size, vec, 1, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 717 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 718 if (written < 0) 719 ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno)); 720 721 memset(mem + page_size, 0, mem_size - (2 * page_size)); 722 723 written = pagemap_ioctl(mem, mem_size, vec, 1, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 724 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 725 if (written < 0) 726 ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno)); 727 728 ksft_test_result(written == 1 && LEN(vec[0]) >= vec_size - 2 && LEN(vec[0]) <= vec_size, 729 "%s all pages dirty other than first and the last one\n", prefix); 730 731 written = pagemap_ioctl(mem, mem_size, vec, 1, 0, 0, 732 PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 733 if (written < 0) 734 ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno)); 735 736 ksft_test_result(written == 0, 737 "%s PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC\n", prefix); 738 739 /* 4. only middle page dirty */ 740 written = pagemap_ioctl(mem, mem_size, vec, 1, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 741 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 742 if (written < 0) 743 ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno)); 744 745 mem[vec_size/2 * page_size]++; 746 747 written = pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0, PAGE_IS_WRITTEN, 748 0, 0, PAGE_IS_WRITTEN); 749 if (written < 0) 750 ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno)); 751 752 ksft_test_result(written == 1 && LEN(vec[0]) >= 1, 753 "%s only middle page dirty\n", prefix); 754 755 /* 5. only two middle pages dirty and walk over only middle pages */ 756 written = pagemap_ioctl(mem, mem_size, vec, 1, PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 757 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN | PAGE_IS_HUGE); 758 if (written < 0) 759 ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno)); 760 761 mem[vec_size/2 * page_size]++; 762 mem[(vec_size/2 + 1) * page_size]++; 763 764 written = pagemap_ioctl(&mem[vec_size/2 * page_size], 2 * page_size, vec, 1, 0, 765 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN | PAGE_IS_HUGE); 766 if (written < 0) 767 ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno)); 768 769 ksft_test_result(written == 1 && vec[0].start == (uintptr_t)(&mem[vec_size/2 * page_size]) 770 && LEN(vec[0]) == 2, 771 "%s only two middle pages dirty\n", prefix); 772 773 free(vec); 774 free(vec2); 775 return 0; 776 } 777 778 void *gethugepage(int map_size) 779 { 780 int ret; 781 char *map; 782 783 map = memalign(hpage_size, map_size); 784 if (!map) 785 ksft_exit_fail_msg("memalign failed %d %s\n", errno, strerror(errno)); 786 787 ret = madvise(map, map_size, MADV_HUGEPAGE); 788 if (ret) 789 return NULL; 790 791 memset(map, 0, map_size); 792 793 return map; 794 } 795 796 int hpage_unit_tests(void) 797 { 798 char *map; 799 int ret, ret2; 800 size_t num_pages = 10; 801 int map_size = hpage_size * num_pages; 802 int vec_size = map_size/page_size; 803 struct page_region *vec, *vec2; 804 805 vec = malloc(sizeof(struct page_region) * vec_size); 806 vec2 = malloc(sizeof(struct page_region) * vec_size); 807 if (!vec || !vec2) 808 ksft_exit_fail_msg("malloc failed\n"); 809 810 map = gethugepage(map_size); 811 if (map) { 812 wp_init(map, map_size); 813 wp_addr_range(map, map_size); 814 815 /* 1. all new huge page must not be written (dirty) */ 816 ret = pagemap_ioctl(map, map_size, vec, vec_size, 817 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 0, 818 PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 819 if (ret < 0) 820 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 821 822 ksft_test_result(ret == 0, "%s all new huge page must not be written (dirty)\n", 823 __func__); 824 825 /* 2. all the huge page must not be written */ 826 ret = pagemap_ioctl(map, map_size, vec, vec_size, 0, 0, 827 PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 828 if (ret < 0) 829 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 830 831 ksft_test_result(ret == 0, "%s all the huge page must not be written\n", __func__); 832 833 /* 3. all the huge page must be written and clear dirty as well */ 834 memset(map, -1, map_size); 835 ret = pagemap_ioctl(map, map_size, vec, vec_size, 836 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 837 0, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 838 if (ret < 0) 839 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 840 841 ksft_test_result(ret == 1 && vec[0].start == (uintptr_t)map && 842 LEN(vec[0]) == vec_size && vec[0].categories == PAGE_IS_WRITTEN, 843 "%s all the huge page must be written and clear\n", __func__); 844 845 /* 4. only middle page written */ 846 wp_free(map, map_size); 847 free(map); 848 map = gethugepage(map_size); 849 wp_init(map, map_size); 850 wp_addr_range(map, map_size); 851 map[vec_size/2 * page_size]++; 852 853 ret = pagemap_ioctl(map, map_size, vec, vec_size, 0, 0, 854 PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 855 if (ret < 0) 856 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 857 858 ksft_test_result(ret == 1 && LEN(vec[0]) > 0, 859 "%s only middle page written\n", __func__); 860 861 wp_free(map, map_size); 862 free(map); 863 } else { 864 ksft_test_result_skip("%s all new huge page must be written\n", __func__); 865 ksft_test_result_skip("%s all the huge page must not be written\n", __func__); 866 ksft_test_result_skip("%s all the huge page must be written and clear\n", __func__); 867 ksft_test_result_skip("%s only middle page written\n", __func__); 868 } 869 870 /* 5. clear first half of huge page */ 871 map = gethugepage(map_size); 872 if (map) { 873 wp_init(map, map_size); 874 wp_addr_range(map, map_size); 875 876 memset(map, 0, map_size); 877 878 wp_addr_range(map, map_size/2); 879 880 ret = pagemap_ioctl(map, map_size, vec, vec_size, 0, 0, 881 PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 882 if (ret < 0) 883 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 884 885 ksft_test_result(ret == 1 && LEN(vec[0]) == vec_size/2 && 886 vec[0].start == (uintptr_t)(map + map_size/2), 887 "%s clear first half of huge page\n", __func__); 888 wp_free(map, map_size); 889 free(map); 890 } else { 891 ksft_test_result_skip("%s clear first half of huge page\n", __func__); 892 } 893 894 /* 6. clear first half of huge page with limited buffer */ 895 map = gethugepage(map_size); 896 if (map) { 897 wp_init(map, map_size); 898 wp_addr_range(map, map_size); 899 900 memset(map, 0, map_size); 901 902 ret = pagemap_ioctl(map, map_size, vec, vec_size, 903 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 904 vec_size/2, PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 905 if (ret < 0) 906 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 907 908 ret = pagemap_ioctl(map, map_size, vec, vec_size, 0, 0, 909 PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 910 if (ret < 0) 911 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 912 913 ksft_test_result(ret == 1 && LEN(vec[0]) == vec_size/2 && 914 vec[0].start == (uintptr_t)(map + map_size/2), 915 "%s clear first half of huge page with limited buffer\n", 916 __func__); 917 wp_free(map, map_size); 918 free(map); 919 } else { 920 ksft_test_result_skip("%s clear first half of huge page with limited buffer\n", 921 __func__); 922 } 923 924 /* 7. clear second half of huge page */ 925 map = gethugepage(map_size); 926 if (map) { 927 wp_init(map, map_size); 928 wp_addr_range(map, map_size); 929 930 memset(map, -1, map_size); 931 932 ret = pagemap_ioctl(map + map_size/2, map_size/2, vec, vec_size, 933 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, vec_size/2, 934 PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 935 if (ret < 0) 936 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 937 938 ret = pagemap_ioctl(map, map_size, vec, vec_size, 0, 0, 939 PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 940 if (ret < 0) 941 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 942 943 ksft_test_result(ret == 1 && LEN(vec[0]) == vec_size/2, 944 "%s clear second half huge page\n", __func__); 945 wp_free(map, map_size); 946 free(map); 947 } else { 948 ksft_test_result_skip("%s clear second half huge page\n", __func__); 949 } 950 951 /* 8. get half huge page */ 952 map = gethugepage(map_size); 953 if (map) { 954 wp_init(map, map_size); 955 wp_addr_range(map, map_size); 956 957 memset(map, -1, map_size); 958 usleep(100); 959 960 ret = pagemap_ioctl(map, map_size, vec, 1, 961 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 962 hpage_size/(2*page_size), PAGE_IS_WRITTEN, 0, 0, 963 PAGE_IS_WRITTEN); 964 if (ret < 0) 965 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 966 967 ksft_test_result(ret == 1 && LEN(vec[0]) == hpage_size/(2*page_size), 968 "%s get half huge page\n", __func__); 969 970 ret2 = pagemap_ioctl(map, map_size, vec, vec_size, 0, 0, 971 PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN); 972 if (ret2 < 0) 973 ksft_exit_fail_msg("error %d %d %s\n", ret2, errno, strerror(errno)); 974 975 ksft_test_result(ret2 == 1 && LEN(vec[0]) == (map_size - hpage_size/2)/page_size, 976 "%s get half huge page\n", __func__); 977 978 wp_free(map, map_size); 979 free(map); 980 } else { 981 ksft_test_result_skip("%s get half huge page\n", __func__); 982 ksft_test_result_skip("%s get half huge page\n", __func__); 983 } 984 985 free(vec); 986 free(vec2); 987 return 0; 988 } 989 990 int unmapped_region_tests(void) 991 { 992 void *start = (void *)0x10000000; 993 int written, len = 0x00040000; 994 int vec_size = len / page_size; 995 struct page_region *vec = malloc(sizeof(struct page_region) * vec_size); 996 997 /* 1. Get written pages */ 998 written = pagemap_ioctl(start, len, vec, vec_size, 0, 0, 999 PAGEMAP_NON_WRITTEN_BITS, 0, 0, PAGEMAP_NON_WRITTEN_BITS); 1000 if (written < 0) 1001 ksft_exit_fail_msg("error %d %d %s\n", written, errno, strerror(errno)); 1002 1003 ksft_test_result(written >= 0, "%s Get status of pages\n", __func__); 1004 1005 free(vec); 1006 return 0; 1007 } 1008 1009 static void test_simple(void) 1010 { 1011 int i; 1012 char *map; 1013 struct page_region vec; 1014 1015 map = aligned_alloc(page_size, page_size); 1016 if (!map) 1017 ksft_exit_fail_msg("aligned_alloc failed\n"); 1018 1019 wp_init(map, page_size); 1020 wp_addr_range(map, page_size); 1021 1022 for (i = 0 ; i < TEST_ITERATIONS; i++) { 1023 if (pagemap_ioctl(map, page_size, &vec, 1, 0, 0, 1024 PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN) == 1) { 1025 ksft_print_msg("written bit was 1, but should be 0 (i=%d)\n", i); 1026 break; 1027 } 1028 1029 wp_addr_range(map, page_size); 1030 /* Write something to the page to get the written bit enabled on the page */ 1031 map[0]++; 1032 1033 if (pagemap_ioctl(map, page_size, &vec, 1, 0, 0, 1034 PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN) == 0) { 1035 ksft_print_msg("written bit was 0, but should be 1 (i=%d)\n", i); 1036 break; 1037 } 1038 1039 wp_addr_range(map, page_size); 1040 } 1041 wp_free(map, page_size); 1042 free(map); 1043 1044 ksft_test_result(i == TEST_ITERATIONS, "Test %s\n", __func__); 1045 } 1046 1047 int sanity_tests(void) 1048 { 1049 int mem_size, vec_size, ret, fd, i, buf_size; 1050 struct page_region *vec; 1051 char *mem, *fmem; 1052 struct stat sbuf; 1053 char *tmp_buf; 1054 1055 /* 1. wrong operation */ 1056 mem_size = 10 * page_size; 1057 vec_size = mem_size / page_size; 1058 1059 vec = malloc(sizeof(struct page_region) * vec_size); 1060 mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 1061 if (mem == MAP_FAILED || vec == MAP_FAILED) 1062 ksft_exit_fail_msg("error nomem\n"); 1063 1064 wp_init(mem, mem_size); 1065 wp_addr_range(mem, mem_size); 1066 1067 ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size, 1068 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 1069 0, PAGEMAP_BITS_ALL, 0, 0, PAGEMAP_BITS_ALL) >= 0, 1070 "%s WP op can be specified with !PAGE_IS_WRITTEN\n", __func__); 1071 ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0, 1072 PAGEMAP_BITS_ALL, 0, 0, PAGEMAP_BITS_ALL) >= 0, 1073 "%s required_mask specified\n", __func__); 1074 ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0, 1075 0, PAGEMAP_BITS_ALL, 0, PAGEMAP_BITS_ALL) >= 0, 1076 "%s anyof_mask specified\n", __func__); 1077 ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0, 1078 0, 0, PAGEMAP_BITS_ALL, PAGEMAP_BITS_ALL) >= 0, 1079 "%s excluded_mask specified\n", __func__); 1080 ksft_test_result(pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0, 1081 PAGEMAP_BITS_ALL, PAGEMAP_BITS_ALL, 0, 1082 PAGEMAP_BITS_ALL) >= 0, 1083 "%s required_mask and anyof_mask specified\n", __func__); 1084 wp_free(mem, mem_size); 1085 munmap(mem, mem_size); 1086 1087 /* 2. Get sd and present pages with anyof_mask */ 1088 mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 1089 if (mem == MAP_FAILED) 1090 ksft_exit_fail_msg("error nomem\n"); 1091 wp_init(mem, mem_size); 1092 wp_addr_range(mem, mem_size); 1093 1094 memset(mem, 0, mem_size); 1095 1096 ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0, 1097 0, PAGEMAP_BITS_ALL, 0, PAGEMAP_BITS_ALL); 1098 ksft_test_result(ret >= 0 && vec[0].start == (uintptr_t)mem && LEN(vec[0]) == vec_size && 1099 (vec[0].categories & (PAGE_IS_WRITTEN | PAGE_IS_PRESENT)) == 1100 (PAGE_IS_WRITTEN | PAGE_IS_PRESENT), 1101 "%s Get sd and present pages with anyof_mask\n", __func__); 1102 1103 /* 3. Get sd and present pages with required_mask */ 1104 ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0, 1105 PAGEMAP_BITS_ALL, 0, 0, PAGEMAP_BITS_ALL); 1106 ksft_test_result(ret >= 0 && vec[0].start == (uintptr_t)mem && LEN(vec[0]) == vec_size && 1107 (vec[0].categories & (PAGE_IS_WRITTEN | PAGE_IS_PRESENT)) == 1108 (PAGE_IS_WRITTEN | PAGE_IS_PRESENT), 1109 "%s Get all the pages with required_mask\n", __func__); 1110 1111 /* 4. Get sd and present pages with required_mask and anyof_mask */ 1112 ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0, 1113 PAGE_IS_WRITTEN, PAGE_IS_PRESENT, 0, PAGEMAP_BITS_ALL); 1114 ksft_test_result(ret >= 0 && vec[0].start == (uintptr_t)mem && LEN(vec[0]) == vec_size && 1115 (vec[0].categories & (PAGE_IS_WRITTEN | PAGE_IS_PRESENT)) == 1116 (PAGE_IS_WRITTEN | PAGE_IS_PRESENT), 1117 "%s Get sd and present pages with required_mask and anyof_mask\n", 1118 __func__); 1119 1120 /* 5. Don't get sd pages */ 1121 ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0, 1122 PAGE_IS_WRITTEN, 0, PAGE_IS_WRITTEN, PAGEMAP_BITS_ALL); 1123 ksft_test_result(ret == 0, "%s Don't get sd pages\n", __func__); 1124 1125 /* 6. Don't get present pages */ 1126 ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 0, 0, 1127 PAGE_IS_PRESENT, 0, PAGE_IS_PRESENT, PAGEMAP_BITS_ALL); 1128 ksft_test_result(ret == 0, "%s Don't get present pages\n", __func__); 1129 1130 wp_free(mem, mem_size); 1131 munmap(mem, mem_size); 1132 1133 /* 8. Find written present pages with return mask */ 1134 mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 1135 if (mem == MAP_FAILED) 1136 ksft_exit_fail_msg("error nomem\n"); 1137 wp_init(mem, mem_size); 1138 wp_addr_range(mem, mem_size); 1139 1140 memset(mem, 0, mem_size); 1141 1142 ret = pagemap_ioctl(mem, mem_size, vec, vec_size, 1143 PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC, 0, 1144 0, PAGEMAP_BITS_ALL, 0, PAGE_IS_WRITTEN); 1145 ksft_test_result(ret >= 0 && vec[0].start == (uintptr_t)mem && LEN(vec[0]) == vec_size && 1146 vec[0].categories == PAGE_IS_WRITTEN, 1147 "%s Find written present pages with return mask\n", __func__); 1148 wp_free(mem, mem_size); 1149 munmap(mem, mem_size); 1150 1151 /* 9. Memory mapped file */ 1152 fd = open(__FILE__, O_RDONLY); 1153 if (fd < 0) 1154 ksft_exit_fail_msg("%s Memory mapped file\n"); 1155 1156 ret = stat(__FILE__, &sbuf); 1157 if (ret < 0) 1158 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 1159 1160 fmem = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 1161 if (fmem == MAP_FAILED) 1162 ksft_exit_fail_msg("error nomem %ld %s\n", errno, strerror(errno)); 1163 1164 tmp_buf = malloc(sbuf.st_size); 1165 memcpy(tmp_buf, fmem, sbuf.st_size); 1166 1167 ret = pagemap_ioctl(fmem, sbuf.st_size, vec, vec_size, 0, 0, 1168 0, PAGEMAP_NON_WRITTEN_BITS, 0, PAGEMAP_NON_WRITTEN_BITS); 1169 1170 ksft_test_result(ret >= 0 && vec[0].start == (uintptr_t)fmem && 1171 LEN(vec[0]) == ceilf((float)sbuf.st_size/page_size) && 1172 (vec[0].categories & PAGE_IS_FILE), 1173 "%s Memory mapped file\n", __func__); 1174 1175 munmap(fmem, sbuf.st_size); 1176 close(fd); 1177 1178 /* 10. Create and read/write to a memory mapped file */ 1179 buf_size = page_size * 10; 1180 1181 fd = open(__FILE__".tmp2", O_RDWR | O_CREAT, 0666); 1182 if (fd < 0) 1183 ksft_exit_fail_msg("Read/write to memory: %s\n", 1184 strerror(errno)); 1185 1186 for (i = 0; i < buf_size; i++) 1187 if (write(fd, "c", 1) < 0) 1188 ksft_exit_fail_msg("Create and read/write to a memory mapped file\n"); 1189 1190 fmem = mmap(NULL, buf_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 1191 if (fmem == MAP_FAILED) 1192 ksft_exit_fail_msg("error nomem %ld %s\n", errno, strerror(errno)); 1193 1194 wp_init(fmem, buf_size); 1195 wp_addr_range(fmem, buf_size); 1196 1197 for (i = 0; i < buf_size; i++) 1198 fmem[i] = 'z'; 1199 1200 msync(fmem, buf_size, MS_SYNC); 1201 1202 ret = pagemap_ioctl(fmem, buf_size, vec, vec_size, 0, 0, 1203 PAGE_IS_WRITTEN, PAGE_IS_PRESENT | PAGE_IS_SWAPPED | PAGE_IS_FILE, 0, 1204 PAGEMAP_BITS_ALL); 1205 1206 ksft_test_result(ret >= 0 && vec[0].start == (uintptr_t)fmem && 1207 LEN(vec[0]) == (buf_size/page_size) && 1208 (vec[0].categories & PAGE_IS_WRITTEN), 1209 "%s Read/write to memory\n", __func__); 1210 1211 wp_free(fmem, buf_size); 1212 munmap(fmem, buf_size); 1213 close(fd); 1214 1215 free(vec); 1216 return 0; 1217 } 1218 1219 int mprotect_tests(void) 1220 { 1221 int ret; 1222 char *mem, *mem2; 1223 struct page_region vec; 1224 int pagemap_fd = open("/proc/self/pagemap", O_RDONLY); 1225 1226 if (pagemap_fd < 0) { 1227 fprintf(stderr, "open() failed\n"); 1228 exit(1); 1229 } 1230 1231 /* 1. Map two pages */ 1232 mem = mmap(0, 2 * page_size, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 1233 if (mem == MAP_FAILED) 1234 ksft_exit_fail_msg("error nomem\n"); 1235 wp_init(mem, 2 * page_size); 1236 wp_addr_range(mem, 2 * page_size); 1237 1238 /* Populate both pages. */ 1239 memset(mem, 1, 2 * page_size); 1240 1241 ret = pagemap_ioctl(mem, 2 * page_size, &vec, 1, 0, 0, PAGE_IS_WRITTEN, 1242 0, 0, PAGE_IS_WRITTEN); 1243 if (ret < 0) 1244 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 1245 1246 ksft_test_result(ret == 1 && LEN(vec) == 2, "%s Both pages written\n", __func__); 1247 1248 /* 2. Start tracking */ 1249 wp_addr_range(mem, 2 * page_size); 1250 1251 ksft_test_result(pagemap_ioctl(mem, 2 * page_size, &vec, 1, 0, 0, 1252 PAGE_IS_WRITTEN, 0, 0, PAGE_IS_WRITTEN) == 0, 1253 "%s Both pages are not written (dirty)\n", __func__); 1254 1255 /* 3. Remap the second page */ 1256 mem2 = mmap(mem + page_size, page_size, PROT_READ|PROT_WRITE, 1257 MAP_PRIVATE|MAP_ANON|MAP_FIXED, -1, 0); 1258 if (mem2 == MAP_FAILED) 1259 ksft_exit_fail_msg("error nomem\n"); 1260 wp_init(mem2, page_size); 1261 wp_addr_range(mem2, page_size); 1262 1263 /* Protect + unprotect. */ 1264 mprotect(mem, page_size, PROT_NONE); 1265 mprotect(mem, 2 * page_size, PROT_READ); 1266 mprotect(mem, 2 * page_size, PROT_READ|PROT_WRITE); 1267 1268 /* Modify both pages. */ 1269 memset(mem, 2, 2 * page_size); 1270 1271 /* Protect + unprotect. */ 1272 mprotect(mem, page_size, PROT_NONE); 1273 mprotect(mem, page_size, PROT_READ); 1274 mprotect(mem, page_size, PROT_READ|PROT_WRITE); 1275 1276 ret = pagemap_ioctl(mem, 2 * page_size, &vec, 1, 0, 0, PAGE_IS_WRITTEN, 1277 0, 0, PAGE_IS_WRITTEN); 1278 if (ret < 0) 1279 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 1280 1281 ksft_test_result(ret == 1 && LEN(vec) == 2, 1282 "%s Both pages written after remap and mprotect\n", __func__); 1283 1284 /* 4. Clear and make the pages written */ 1285 wp_addr_range(mem, 2 * page_size); 1286 1287 memset(mem, 'A', 2 * page_size); 1288 1289 ret = pagemap_ioctl(mem, 2 * page_size, &vec, 1, 0, 0, PAGE_IS_WRITTEN, 1290 0, 0, PAGE_IS_WRITTEN); 1291 if (ret < 0) 1292 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 1293 1294 ksft_test_result(ret == 1 && LEN(vec) == 2, 1295 "%s Clear and make the pages written\n", __func__); 1296 1297 wp_free(mem, 2 * page_size); 1298 munmap(mem, 2 * page_size); 1299 return 0; 1300 } 1301 1302 /* transact test */ 1303 static const unsigned int nthreads = 6, pages_per_thread = 32, access_per_thread = 8; 1304 static pthread_barrier_t start_barrier, end_barrier; 1305 static unsigned int extra_thread_faults; 1306 static unsigned int iter_count = 1000; 1307 static volatile int finish; 1308 1309 static ssize_t get_dirty_pages_reset(char *mem, unsigned int count, 1310 int reset, int page_size) 1311 { 1312 struct pm_scan_arg arg = {0}; 1313 struct page_region rgns[256]; 1314 int i, j, cnt, ret; 1315 1316 arg.size = sizeof(struct pm_scan_arg); 1317 arg.start = (uintptr_t)mem; 1318 arg.max_pages = count; 1319 arg.end = (uintptr_t)(mem + count * page_size); 1320 arg.vec = (uintptr_t)rgns; 1321 arg.vec_len = sizeof(rgns) / sizeof(*rgns); 1322 if (reset) 1323 arg.flags |= PM_SCAN_WP_MATCHING | PM_SCAN_CHECK_WPASYNC; 1324 arg.category_mask = PAGE_IS_WRITTEN; 1325 arg.return_mask = PAGE_IS_WRITTEN; 1326 1327 ret = ioctl(pagemap_fd, PAGEMAP_SCAN, &arg); 1328 if (ret < 0) 1329 ksft_exit_fail_msg("ioctl failed\n"); 1330 1331 cnt = 0; 1332 for (i = 0; i < ret; ++i) { 1333 if (rgns[i].categories != PAGE_IS_WRITTEN) 1334 ksft_exit_fail_msg("wrong flags\n"); 1335 1336 for (j = 0; j < LEN(rgns[i]); ++j) 1337 cnt++; 1338 } 1339 1340 return cnt; 1341 } 1342 1343 void *thread_proc(void *mem) 1344 { 1345 int *m = mem; 1346 long curr_faults, faults; 1347 struct rusage r; 1348 unsigned int i; 1349 int ret; 1350 1351 if (getrusage(RUSAGE_THREAD, &r)) 1352 ksft_exit_fail_msg("getrusage\n"); 1353 1354 curr_faults = r.ru_minflt; 1355 1356 while (!finish) { 1357 ret = pthread_barrier_wait(&start_barrier); 1358 if (ret && ret != PTHREAD_BARRIER_SERIAL_THREAD) 1359 ksft_exit_fail_msg("pthread_barrier_wait\n"); 1360 1361 for (i = 0; i < access_per_thread; ++i) 1362 __atomic_add_fetch(m + i * (0x1000 / sizeof(*m)), 1, __ATOMIC_SEQ_CST); 1363 1364 ret = pthread_barrier_wait(&end_barrier); 1365 if (ret && ret != PTHREAD_BARRIER_SERIAL_THREAD) 1366 ksft_exit_fail_msg("pthread_barrier_wait\n"); 1367 1368 if (getrusage(RUSAGE_THREAD, &r)) 1369 ksft_exit_fail_msg("getrusage\n"); 1370 1371 faults = r.ru_minflt - curr_faults; 1372 if (faults < access_per_thread) 1373 ksft_exit_fail_msg("faults < access_per_thread"); 1374 1375 __atomic_add_fetch(&extra_thread_faults, faults - access_per_thread, 1376 __ATOMIC_SEQ_CST); 1377 curr_faults = r.ru_minflt; 1378 } 1379 1380 return NULL; 1381 } 1382 1383 static void transact_test(int page_size) 1384 { 1385 unsigned int i, count, extra_pages; 1386 pthread_t th; 1387 char *mem; 1388 int ret, c; 1389 1390 if (pthread_barrier_init(&start_barrier, NULL, nthreads + 1)) 1391 ksft_exit_fail_msg("pthread_barrier_init\n"); 1392 1393 if (pthread_barrier_init(&end_barrier, NULL, nthreads + 1)) 1394 ksft_exit_fail_msg("pthread_barrier_init\n"); 1395 1396 mem = mmap(NULL, 0x1000 * nthreads * pages_per_thread, PROT_READ | PROT_WRITE, 1397 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 1398 if (mem == MAP_FAILED) 1399 ksft_exit_fail_msg("Error mmap %s.\n", strerror(errno)); 1400 1401 wp_init(mem, 0x1000 * nthreads * pages_per_thread); 1402 wp_addr_range(mem, 0x1000 * nthreads * pages_per_thread); 1403 1404 memset(mem, 0, 0x1000 * nthreads * pages_per_thread); 1405 1406 count = get_dirty_pages_reset(mem, nthreads * pages_per_thread, 1, page_size); 1407 ksft_test_result(count > 0, "%s count %d\n", __func__, count); 1408 count = get_dirty_pages_reset(mem, nthreads * pages_per_thread, 1, page_size); 1409 ksft_test_result(count == 0, "%s count %d\n", __func__, count); 1410 1411 finish = 0; 1412 for (i = 0; i < nthreads; ++i) 1413 pthread_create(&th, NULL, thread_proc, mem + 0x1000 * i * pages_per_thread); 1414 1415 extra_pages = 0; 1416 for (i = 0; i < iter_count; ++i) { 1417 count = 0; 1418 1419 ret = pthread_barrier_wait(&start_barrier); 1420 if (ret && ret != PTHREAD_BARRIER_SERIAL_THREAD) 1421 ksft_exit_fail_msg("pthread_barrier_wait\n"); 1422 1423 count = get_dirty_pages_reset(mem, nthreads * pages_per_thread, 1, 1424 page_size); 1425 1426 ret = pthread_barrier_wait(&end_barrier); 1427 if (ret && ret != PTHREAD_BARRIER_SERIAL_THREAD) 1428 ksft_exit_fail_msg("pthread_barrier_wait\n"); 1429 1430 if (count > nthreads * access_per_thread) 1431 ksft_exit_fail_msg("Too big count %d expected %d, iter %d\n", 1432 count, nthreads * access_per_thread, i); 1433 1434 c = get_dirty_pages_reset(mem, nthreads * pages_per_thread, 1, page_size); 1435 count += c; 1436 1437 if (c > nthreads * access_per_thread) { 1438 ksft_test_result_fail(" %s count > nthreads\n", __func__); 1439 return; 1440 } 1441 1442 if (count != nthreads * access_per_thread) { 1443 /* 1444 * The purpose of the test is to make sure that no page updates are lost 1445 * when the page updates and read-resetting soft dirty flags are performed 1446 * in parallel. However, it is possible that the application will get the 1447 * soft dirty flags twice on the two consecutive read-resets. This seems 1448 * unavoidable as soft dirty flag is handled in software through page faults 1449 * in kernel. While the updating the flags is supposed to be synchronized 1450 * between page fault handling and read-reset, it is possible that 1451 * read-reset happens after page fault PTE update but before the application 1452 * re-executes write instruction. So read-reset gets the flag, clears write 1453 * access and application gets page fault again for the same write. 1454 */ 1455 if (count < nthreads * access_per_thread) { 1456 ksft_test_result_fail("Lost update, iter %d, %d vs %d.\n", i, count, 1457 nthreads * access_per_thread); 1458 return; 1459 } 1460 1461 extra_pages += count - nthreads * access_per_thread; 1462 } 1463 } 1464 1465 pthread_barrier_wait(&start_barrier); 1466 finish = 1; 1467 pthread_barrier_wait(&end_barrier); 1468 1469 ksft_test_result_pass("%s Extra pages %u (%.1lf%%), extra thread faults %d.\n", __func__, 1470 extra_pages, 1471 100.0 * extra_pages / (iter_count * nthreads * access_per_thread), 1472 extra_thread_faults); 1473 } 1474 1475 int main(void) 1476 { 1477 int mem_size, shmid, buf_size, fd, i, ret; 1478 char *mem, *map, *fmem; 1479 struct stat sbuf; 1480 1481 ksft_print_header(); 1482 ksft_set_plan(115); 1483 1484 page_size = getpagesize(); 1485 hpage_size = read_pmd_pagesize(); 1486 1487 pagemap_fd = open(PAGEMAP, O_RDONLY); 1488 if (pagemap_fd < 0) 1489 return -EINVAL; 1490 1491 if (init_uffd()) 1492 ksft_exit_fail_msg("uffd init failed\n"); 1493 1494 /* 1. Sanity testing */ 1495 sanity_tests_sd(); 1496 1497 /* 2. Normal page testing */ 1498 mem_size = 10 * page_size; 1499 mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 1500 if (mem == MAP_FAILED) 1501 ksft_exit_fail_msg("error nomem\n"); 1502 wp_init(mem, mem_size); 1503 wp_addr_range(mem, mem_size); 1504 1505 base_tests("Page testing:", mem, mem_size, 0); 1506 1507 wp_free(mem, mem_size); 1508 munmap(mem, mem_size); 1509 1510 /* 3. Large page testing */ 1511 mem_size = 512 * 10 * page_size; 1512 mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); 1513 if (mem == MAP_FAILED) 1514 ksft_exit_fail_msg("error nomem\n"); 1515 wp_init(mem, mem_size); 1516 wp_addr_range(mem, mem_size); 1517 1518 base_tests("Large Page testing:", mem, mem_size, 0); 1519 1520 wp_free(mem, mem_size); 1521 munmap(mem, mem_size); 1522 1523 /* 4. Huge page testing */ 1524 map = gethugepage(hpage_size); 1525 if (map) { 1526 wp_init(map, hpage_size); 1527 wp_addr_range(map, hpage_size); 1528 base_tests("Huge page testing:", map, hpage_size, 0); 1529 wp_free(map, hpage_size); 1530 free(map); 1531 } else { 1532 base_tests("Huge page testing:", NULL, 0, 1); 1533 } 1534 1535 /* 5. SHM Hugetlb page testing */ 1536 mem_size = 2*1024*1024; 1537 mem = gethugetlb_mem(mem_size, &shmid); 1538 if (mem) { 1539 wp_init(mem, mem_size); 1540 wp_addr_range(mem, mem_size); 1541 1542 base_tests("Hugetlb shmem testing:", mem, mem_size, 0); 1543 1544 wp_free(mem, mem_size); 1545 shmctl(shmid, IPC_RMID, NULL); 1546 } else { 1547 base_tests("Hugetlb shmem testing:", NULL, 0, 1); 1548 } 1549 1550 /* 6. Hugetlb page testing */ 1551 mem = gethugetlb_mem(mem_size, NULL); 1552 if (mem) { 1553 wp_init(mem, mem_size); 1554 wp_addr_range(mem, mem_size); 1555 1556 base_tests("Hugetlb mem testing:", mem, mem_size, 0); 1557 1558 wp_free(mem, mem_size); 1559 } else { 1560 base_tests("Hugetlb mem testing:", NULL, 0, 1); 1561 } 1562 1563 /* 7. File Hugetlb testing */ 1564 mem_size = 2*1024*1024; 1565 fd = memfd_create("uffd-test", MFD_HUGETLB | MFD_NOEXEC_SEAL); 1566 mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 1567 if (mem) { 1568 wp_init(mem, mem_size); 1569 wp_addr_range(mem, mem_size); 1570 1571 base_tests("Hugetlb shmem testing:", mem, mem_size, 0); 1572 1573 wp_free(mem, mem_size); 1574 shmctl(shmid, IPC_RMID, NULL); 1575 } else { 1576 base_tests("Hugetlb shmem testing:", NULL, 0, 1); 1577 } 1578 close(fd); 1579 1580 /* 8. File memory testing */ 1581 buf_size = page_size * 10; 1582 1583 fd = open(__FILE__".tmp0", O_RDWR | O_CREAT, 0777); 1584 if (fd < 0) 1585 ksft_exit_fail_msg("Create and read/write to a memory mapped file: %s\n", 1586 strerror(errno)); 1587 1588 for (i = 0; i < buf_size; i++) 1589 if (write(fd, "c", 1) < 0) 1590 ksft_exit_fail_msg("Create and read/write to a memory mapped file\n"); 1591 1592 ret = stat(__FILE__".tmp0", &sbuf); 1593 if (ret < 0) 1594 ksft_exit_fail_msg("error %d %d %s\n", ret, errno, strerror(errno)); 1595 1596 fmem = mmap(NULL, sbuf.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 1597 if (fmem == MAP_FAILED) 1598 ksft_exit_fail_msg("error nomem %ld %s\n", errno, strerror(errno)); 1599 1600 wp_init(fmem, sbuf.st_size); 1601 wp_addr_range(fmem, sbuf.st_size); 1602 1603 base_tests("File memory testing:", fmem, sbuf.st_size, 0); 1604 1605 wp_free(fmem, sbuf.st_size); 1606 munmap(fmem, sbuf.st_size); 1607 close(fd); 1608 1609 /* 9. File memory testing */ 1610 buf_size = page_size * 10; 1611 1612 fd = memfd_create(__FILE__".tmp00", MFD_NOEXEC_SEAL); 1613 if (fd < 0) 1614 ksft_exit_fail_msg("Create and read/write to a memory mapped file: %s\n", 1615 strerror(errno)); 1616 1617 if (ftruncate(fd, buf_size)) 1618 ksft_exit_fail_msg("Error ftruncate\n"); 1619 1620 for (i = 0; i < buf_size; i++) 1621 if (write(fd, "c", 1) < 0) 1622 ksft_exit_fail_msg("Create and read/write to a memory mapped file\n"); 1623 1624 fmem = mmap(NULL, buf_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); 1625 if (fmem == MAP_FAILED) 1626 ksft_exit_fail_msg("error nomem %ld %s\n", errno, strerror(errno)); 1627 1628 wp_init(fmem, buf_size); 1629 wp_addr_range(fmem, buf_size); 1630 1631 base_tests("File anonymous memory testing:", fmem, buf_size, 0); 1632 1633 wp_free(fmem, buf_size); 1634 munmap(fmem, buf_size); 1635 close(fd); 1636 1637 /* 10. Huge page tests */ 1638 hpage_unit_tests(); 1639 1640 /* 11. Iterative test */ 1641 test_simple(); 1642 1643 /* 12. Mprotect test */ 1644 mprotect_tests(); 1645 1646 /* 13. Transact test */ 1647 transact_test(page_size); 1648 1649 /* 14. Sanity testing */ 1650 sanity_tests(); 1651 1652 /*15. Unmapped address test */ 1653 unmapped_region_tests(); 1654 1655 /* 16. Userfaultfd tests */ 1656 userfaultfd_tests(); 1657 1658 close(pagemap_fd); 1659 return ksft_exit_pass(); 1660 } 1661