hmm-tests.c (40954B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * HMM stands for Heterogeneous Memory Management, it is a helper layer inside 4 * the linux kernel to help device drivers mirror a process address space in 5 * the device. This allows the device to use the same address space which 6 * makes communication and data exchange a lot easier. 7 * 8 * This framework's sole purpose is to exercise various code paths inside 9 * the kernel to make sure that HMM performs as expected and to flush out any 10 * bugs. 11 */ 12 13#include "../kselftest_harness.h" 14 15#include <errno.h> 16#include <fcntl.h> 17#include <stdio.h> 18#include <stdlib.h> 19#include <stdint.h> 20#include <unistd.h> 21#include <strings.h> 22#include <time.h> 23#include <pthread.h> 24#include <sys/types.h> 25#include <sys/stat.h> 26#include <sys/mman.h> 27#include <sys/ioctl.h> 28 29#include "./local_config.h" 30#ifdef LOCAL_CONFIG_HAVE_LIBHUGETLBFS 31#include <hugetlbfs.h> 32#endif 33 34/* 35 * This is a private UAPI to the kernel test module so it isn't exported 36 * in the usual include/uapi/... directory. 37 */ 38#include "../../../../lib/test_hmm_uapi.h" 39 40struct hmm_buffer { 41 void *ptr; 42 void *mirror; 43 unsigned long size; 44 int fd; 45 uint64_t cpages; 46 uint64_t faults; 47}; 48 49#define TWOMEG (1 << 21) 50#define HMM_BUFFER_SIZE (1024 << 12) 51#define HMM_PATH_MAX 64 52#define NTIMES 10 53 54#define ALIGN(x, a) (((x) + (a - 1)) & (~((a) - 1))) 55 56FIXTURE(hmm) 57{ 58 int fd; 59 unsigned int page_size; 60 unsigned int page_shift; 61}; 62 63FIXTURE(hmm2) 64{ 65 int fd0; 66 int fd1; 67 unsigned int page_size; 68 unsigned int page_shift; 69}; 70 71static int hmm_open(int unit) 72{ 73 char pathname[HMM_PATH_MAX]; 74 int fd; 75 76 snprintf(pathname, sizeof(pathname), "/dev/hmm_dmirror%d", unit); 77 fd = open(pathname, O_RDWR, 0); 78 if (fd < 0) 79 fprintf(stderr, "could not open hmm dmirror driver (%s)\n", 80 pathname); 81 return fd; 82} 83 84FIXTURE_SETUP(hmm) 85{ 86 self->page_size = sysconf(_SC_PAGE_SIZE); 87 self->page_shift = ffs(self->page_size) - 1; 88 89 self->fd = hmm_open(0); 90 ASSERT_GE(self->fd, 0); 91} 92 93FIXTURE_SETUP(hmm2) 94{ 95 self->page_size = sysconf(_SC_PAGE_SIZE); 96 self->page_shift = ffs(self->page_size) - 1; 97 98 self->fd0 = hmm_open(0); 99 ASSERT_GE(self->fd0, 0); 100 self->fd1 = hmm_open(1); 101 ASSERT_GE(self->fd1, 0); 102} 103 104FIXTURE_TEARDOWN(hmm) 105{ 106 int ret = close(self->fd); 107 108 ASSERT_EQ(ret, 0); 109 self->fd = -1; 110} 111 112FIXTURE_TEARDOWN(hmm2) 113{ 114 int ret = close(self->fd0); 115 116 ASSERT_EQ(ret, 0); 117 self->fd0 = -1; 118 119 ret = close(self->fd1); 120 ASSERT_EQ(ret, 0); 121 self->fd1 = -1; 122} 123 124static int hmm_dmirror_cmd(int fd, 125 unsigned long request, 126 struct hmm_buffer *buffer, 127 unsigned long npages) 128{ 129 struct hmm_dmirror_cmd cmd; 130 int ret; 131 132 /* Simulate a device reading system memory. */ 133 cmd.addr = (__u64)buffer->ptr; 134 cmd.ptr = (__u64)buffer->mirror; 135 cmd.npages = npages; 136 137 for (;;) { 138 ret = ioctl(fd, request, &cmd); 139 if (ret == 0) 140 break; 141 if (errno == EINTR) 142 continue; 143 return -errno; 144 } 145 buffer->cpages = cmd.cpages; 146 buffer->faults = cmd.faults; 147 148 return 0; 149} 150 151static void hmm_buffer_free(struct hmm_buffer *buffer) 152{ 153 if (buffer == NULL) 154 return; 155 156 if (buffer->ptr) 157 munmap(buffer->ptr, buffer->size); 158 free(buffer->mirror); 159 free(buffer); 160} 161 162/* 163 * Create a temporary file that will be deleted on close. 164 */ 165static int hmm_create_file(unsigned long size) 166{ 167 char path[HMM_PATH_MAX]; 168 int fd; 169 170 strcpy(path, "/tmp"); 171 fd = open(path, O_TMPFILE | O_EXCL | O_RDWR, 0600); 172 if (fd >= 0) { 173 int r; 174 175 do { 176 r = ftruncate(fd, size); 177 } while (r == -1 && errno == EINTR); 178 if (!r) 179 return fd; 180 close(fd); 181 } 182 return -1; 183} 184 185/* 186 * Return a random unsigned number. 187 */ 188static unsigned int hmm_random(void) 189{ 190 static int fd = -1; 191 unsigned int r; 192 193 if (fd < 0) { 194 fd = open("/dev/urandom", O_RDONLY); 195 if (fd < 0) { 196 fprintf(stderr, "%s:%d failed to open /dev/urandom\n", 197 __FILE__, __LINE__); 198 return ~0U; 199 } 200 } 201 read(fd, &r, sizeof(r)); 202 return r; 203} 204 205static void hmm_nanosleep(unsigned int n) 206{ 207 struct timespec t; 208 209 t.tv_sec = 0; 210 t.tv_nsec = n; 211 nanosleep(&t, NULL); 212} 213 214/* 215 * Simple NULL test of device open/close. 216 */ 217TEST_F(hmm, open_close) 218{ 219} 220 221/* 222 * Read private anonymous memory. 223 */ 224TEST_F(hmm, anon_read) 225{ 226 struct hmm_buffer *buffer; 227 unsigned long npages; 228 unsigned long size; 229 unsigned long i; 230 int *ptr; 231 int ret; 232 int val; 233 234 npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; 235 ASSERT_NE(npages, 0); 236 size = npages << self->page_shift; 237 238 buffer = malloc(sizeof(*buffer)); 239 ASSERT_NE(buffer, NULL); 240 241 buffer->fd = -1; 242 buffer->size = size; 243 buffer->mirror = malloc(size); 244 ASSERT_NE(buffer->mirror, NULL); 245 246 buffer->ptr = mmap(NULL, size, 247 PROT_READ | PROT_WRITE, 248 MAP_PRIVATE | MAP_ANONYMOUS, 249 buffer->fd, 0); 250 ASSERT_NE(buffer->ptr, MAP_FAILED); 251 252 /* 253 * Initialize buffer in system memory but leave the first two pages 254 * zero (pte_none and pfn_zero). 255 */ 256 i = 2 * self->page_size / sizeof(*ptr); 257 for (ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 258 ptr[i] = i; 259 260 /* Set buffer permission to read-only. */ 261 ret = mprotect(buffer->ptr, size, PROT_READ); 262 ASSERT_EQ(ret, 0); 263 264 /* Populate the CPU page table with a special zero page. */ 265 val = *(int *)(buffer->ptr + self->page_size); 266 ASSERT_EQ(val, 0); 267 268 /* Simulate a device reading system memory. */ 269 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_READ, buffer, npages); 270 ASSERT_EQ(ret, 0); 271 ASSERT_EQ(buffer->cpages, npages); 272 ASSERT_EQ(buffer->faults, 1); 273 274 /* Check what the device read. */ 275 ptr = buffer->mirror; 276 for (i = 0; i < 2 * self->page_size / sizeof(*ptr); ++i) 277 ASSERT_EQ(ptr[i], 0); 278 for (; i < size / sizeof(*ptr); ++i) 279 ASSERT_EQ(ptr[i], i); 280 281 hmm_buffer_free(buffer); 282} 283 284/* 285 * Read private anonymous memory which has been protected with 286 * mprotect() PROT_NONE. 287 */ 288TEST_F(hmm, anon_read_prot) 289{ 290 struct hmm_buffer *buffer; 291 unsigned long npages; 292 unsigned long size; 293 unsigned long i; 294 int *ptr; 295 int ret; 296 297 npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; 298 ASSERT_NE(npages, 0); 299 size = npages << self->page_shift; 300 301 buffer = malloc(sizeof(*buffer)); 302 ASSERT_NE(buffer, NULL); 303 304 buffer->fd = -1; 305 buffer->size = size; 306 buffer->mirror = malloc(size); 307 ASSERT_NE(buffer->mirror, NULL); 308 309 buffer->ptr = mmap(NULL, size, 310 PROT_READ | PROT_WRITE, 311 MAP_PRIVATE | MAP_ANONYMOUS, 312 buffer->fd, 0); 313 ASSERT_NE(buffer->ptr, MAP_FAILED); 314 315 /* Initialize buffer in system memory. */ 316 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 317 ptr[i] = i; 318 319 /* Initialize mirror buffer so we can verify it isn't written. */ 320 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 321 ptr[i] = -i; 322 323 /* Protect buffer from reading. */ 324 ret = mprotect(buffer->ptr, size, PROT_NONE); 325 ASSERT_EQ(ret, 0); 326 327 /* Simulate a device reading system memory. */ 328 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_READ, buffer, npages); 329 ASSERT_EQ(ret, -EFAULT); 330 331 /* Allow CPU to read the buffer so we can check it. */ 332 ret = mprotect(buffer->ptr, size, PROT_READ); 333 ASSERT_EQ(ret, 0); 334 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 335 ASSERT_EQ(ptr[i], i); 336 337 /* Check what the device read. */ 338 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 339 ASSERT_EQ(ptr[i], -i); 340 341 hmm_buffer_free(buffer); 342} 343 344/* 345 * Write private anonymous memory. 346 */ 347TEST_F(hmm, anon_write) 348{ 349 struct hmm_buffer *buffer; 350 unsigned long npages; 351 unsigned long size; 352 unsigned long i; 353 int *ptr; 354 int ret; 355 356 npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; 357 ASSERT_NE(npages, 0); 358 size = npages << self->page_shift; 359 360 buffer = malloc(sizeof(*buffer)); 361 ASSERT_NE(buffer, NULL); 362 363 buffer->fd = -1; 364 buffer->size = size; 365 buffer->mirror = malloc(size); 366 ASSERT_NE(buffer->mirror, NULL); 367 368 buffer->ptr = mmap(NULL, size, 369 PROT_READ | PROT_WRITE, 370 MAP_PRIVATE | MAP_ANONYMOUS, 371 buffer->fd, 0); 372 ASSERT_NE(buffer->ptr, MAP_FAILED); 373 374 /* Initialize data that the device will write to buffer->ptr. */ 375 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 376 ptr[i] = i; 377 378 /* Simulate a device writing system memory. */ 379 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_WRITE, buffer, npages); 380 ASSERT_EQ(ret, 0); 381 ASSERT_EQ(buffer->cpages, npages); 382 ASSERT_EQ(buffer->faults, 1); 383 384 /* Check what the device wrote. */ 385 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 386 ASSERT_EQ(ptr[i], i); 387 388 hmm_buffer_free(buffer); 389} 390 391/* 392 * Write private anonymous memory which has been protected with 393 * mprotect() PROT_READ. 394 */ 395TEST_F(hmm, anon_write_prot) 396{ 397 struct hmm_buffer *buffer; 398 unsigned long npages; 399 unsigned long size; 400 unsigned long i; 401 int *ptr; 402 int ret; 403 404 npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; 405 ASSERT_NE(npages, 0); 406 size = npages << self->page_shift; 407 408 buffer = malloc(sizeof(*buffer)); 409 ASSERT_NE(buffer, NULL); 410 411 buffer->fd = -1; 412 buffer->size = size; 413 buffer->mirror = malloc(size); 414 ASSERT_NE(buffer->mirror, NULL); 415 416 buffer->ptr = mmap(NULL, size, 417 PROT_READ, 418 MAP_PRIVATE | MAP_ANONYMOUS, 419 buffer->fd, 0); 420 ASSERT_NE(buffer->ptr, MAP_FAILED); 421 422 /* Simulate a device reading a zero page of memory. */ 423 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_READ, buffer, 1); 424 ASSERT_EQ(ret, 0); 425 ASSERT_EQ(buffer->cpages, 1); 426 ASSERT_EQ(buffer->faults, 1); 427 428 /* Initialize data that the device will write to buffer->ptr. */ 429 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 430 ptr[i] = i; 431 432 /* Simulate a device writing system memory. */ 433 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_WRITE, buffer, npages); 434 ASSERT_EQ(ret, -EPERM); 435 436 /* Check what the device wrote. */ 437 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 438 ASSERT_EQ(ptr[i], 0); 439 440 /* Now allow writing and see that the zero page is replaced. */ 441 ret = mprotect(buffer->ptr, size, PROT_WRITE | PROT_READ); 442 ASSERT_EQ(ret, 0); 443 444 /* Simulate a device writing system memory. */ 445 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_WRITE, buffer, npages); 446 ASSERT_EQ(ret, 0); 447 ASSERT_EQ(buffer->cpages, npages); 448 ASSERT_EQ(buffer->faults, 1); 449 450 /* Check what the device wrote. */ 451 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 452 ASSERT_EQ(ptr[i], i); 453 454 hmm_buffer_free(buffer); 455} 456 457/* 458 * Check that a device writing an anonymous private mapping 459 * will copy-on-write if a child process inherits the mapping. 460 */ 461TEST_F(hmm, anon_write_child) 462{ 463 struct hmm_buffer *buffer; 464 unsigned long npages; 465 unsigned long size; 466 unsigned long i; 467 int *ptr; 468 pid_t pid; 469 int child_fd; 470 int ret; 471 472 npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; 473 ASSERT_NE(npages, 0); 474 size = npages << self->page_shift; 475 476 buffer = malloc(sizeof(*buffer)); 477 ASSERT_NE(buffer, NULL); 478 479 buffer->fd = -1; 480 buffer->size = size; 481 buffer->mirror = malloc(size); 482 ASSERT_NE(buffer->mirror, NULL); 483 484 buffer->ptr = mmap(NULL, size, 485 PROT_READ | PROT_WRITE, 486 MAP_PRIVATE | MAP_ANONYMOUS, 487 buffer->fd, 0); 488 ASSERT_NE(buffer->ptr, MAP_FAILED); 489 490 /* Initialize buffer->ptr so we can tell if it is written. */ 491 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 492 ptr[i] = i; 493 494 /* Initialize data that the device will write to buffer->ptr. */ 495 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 496 ptr[i] = -i; 497 498 pid = fork(); 499 if (pid == -1) 500 ASSERT_EQ(pid, 0); 501 if (pid != 0) { 502 waitpid(pid, &ret, 0); 503 ASSERT_EQ(WIFEXITED(ret), 1); 504 505 /* Check that the parent's buffer did not change. */ 506 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 507 ASSERT_EQ(ptr[i], i); 508 return; 509 } 510 511 /* Check that we see the parent's values. */ 512 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 513 ASSERT_EQ(ptr[i], i); 514 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 515 ASSERT_EQ(ptr[i], -i); 516 517 /* The child process needs its own mirror to its own mm. */ 518 child_fd = hmm_open(0); 519 ASSERT_GE(child_fd, 0); 520 521 /* Simulate a device writing system memory. */ 522 ret = hmm_dmirror_cmd(child_fd, HMM_DMIRROR_WRITE, buffer, npages); 523 ASSERT_EQ(ret, 0); 524 ASSERT_EQ(buffer->cpages, npages); 525 ASSERT_EQ(buffer->faults, 1); 526 527 /* Check what the device wrote. */ 528 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 529 ASSERT_EQ(ptr[i], -i); 530 531 close(child_fd); 532 exit(0); 533} 534 535/* 536 * Check that a device writing an anonymous shared mapping 537 * will not copy-on-write if a child process inherits the mapping. 538 */ 539TEST_F(hmm, anon_write_child_shared) 540{ 541 struct hmm_buffer *buffer; 542 unsigned long npages; 543 unsigned long size; 544 unsigned long i; 545 int *ptr; 546 pid_t pid; 547 int child_fd; 548 int ret; 549 550 npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; 551 ASSERT_NE(npages, 0); 552 size = npages << self->page_shift; 553 554 buffer = malloc(sizeof(*buffer)); 555 ASSERT_NE(buffer, NULL); 556 557 buffer->fd = -1; 558 buffer->size = size; 559 buffer->mirror = malloc(size); 560 ASSERT_NE(buffer->mirror, NULL); 561 562 buffer->ptr = mmap(NULL, size, 563 PROT_READ | PROT_WRITE, 564 MAP_SHARED | MAP_ANONYMOUS, 565 buffer->fd, 0); 566 ASSERT_NE(buffer->ptr, MAP_FAILED); 567 568 /* Initialize buffer->ptr so we can tell if it is written. */ 569 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 570 ptr[i] = i; 571 572 /* Initialize data that the device will write to buffer->ptr. */ 573 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 574 ptr[i] = -i; 575 576 pid = fork(); 577 if (pid == -1) 578 ASSERT_EQ(pid, 0); 579 if (pid != 0) { 580 waitpid(pid, &ret, 0); 581 ASSERT_EQ(WIFEXITED(ret), 1); 582 583 /* Check that the parent's buffer did change. */ 584 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 585 ASSERT_EQ(ptr[i], -i); 586 return; 587 } 588 589 /* Check that we see the parent's values. */ 590 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 591 ASSERT_EQ(ptr[i], i); 592 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 593 ASSERT_EQ(ptr[i], -i); 594 595 /* The child process needs its own mirror to its own mm. */ 596 child_fd = hmm_open(0); 597 ASSERT_GE(child_fd, 0); 598 599 /* Simulate a device writing system memory. */ 600 ret = hmm_dmirror_cmd(child_fd, HMM_DMIRROR_WRITE, buffer, npages); 601 ASSERT_EQ(ret, 0); 602 ASSERT_EQ(buffer->cpages, npages); 603 ASSERT_EQ(buffer->faults, 1); 604 605 /* Check what the device wrote. */ 606 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 607 ASSERT_EQ(ptr[i], -i); 608 609 close(child_fd); 610 exit(0); 611} 612 613/* 614 * Write private anonymous huge page. 615 */ 616TEST_F(hmm, anon_write_huge) 617{ 618 struct hmm_buffer *buffer; 619 unsigned long npages; 620 unsigned long size; 621 unsigned long i; 622 void *old_ptr; 623 void *map; 624 int *ptr; 625 int ret; 626 627 size = 2 * TWOMEG; 628 629 buffer = malloc(sizeof(*buffer)); 630 ASSERT_NE(buffer, NULL); 631 632 buffer->fd = -1; 633 buffer->size = size; 634 buffer->mirror = malloc(size); 635 ASSERT_NE(buffer->mirror, NULL); 636 637 buffer->ptr = mmap(NULL, size, 638 PROT_READ | PROT_WRITE, 639 MAP_PRIVATE | MAP_ANONYMOUS, 640 buffer->fd, 0); 641 ASSERT_NE(buffer->ptr, MAP_FAILED); 642 643 size = TWOMEG; 644 npages = size >> self->page_shift; 645 map = (void *)ALIGN((uintptr_t)buffer->ptr, size); 646 ret = madvise(map, size, MADV_HUGEPAGE); 647 ASSERT_EQ(ret, 0); 648 old_ptr = buffer->ptr; 649 buffer->ptr = map; 650 651 /* Initialize data that the device will write to buffer->ptr. */ 652 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 653 ptr[i] = i; 654 655 /* Simulate a device writing system memory. */ 656 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_WRITE, buffer, npages); 657 ASSERT_EQ(ret, 0); 658 ASSERT_EQ(buffer->cpages, npages); 659 ASSERT_EQ(buffer->faults, 1); 660 661 /* Check what the device wrote. */ 662 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 663 ASSERT_EQ(ptr[i], i); 664 665 buffer->ptr = old_ptr; 666 hmm_buffer_free(buffer); 667} 668 669#ifdef LOCAL_CONFIG_HAVE_LIBHUGETLBFS 670/* 671 * Write huge TLBFS page. 672 */ 673TEST_F(hmm, anon_write_hugetlbfs) 674{ 675 struct hmm_buffer *buffer; 676 unsigned long npages; 677 unsigned long size; 678 unsigned long i; 679 int *ptr; 680 int ret; 681 long pagesizes[4]; 682 int n, idx; 683 684 /* Skip test if we can't allocate a hugetlbfs page. */ 685 686 n = gethugepagesizes(pagesizes, 4); 687 if (n <= 0) 688 SKIP(return, "Huge page size could not be determined"); 689 for (idx = 0; --n > 0; ) { 690 if (pagesizes[n] < pagesizes[idx]) 691 idx = n; 692 } 693 size = ALIGN(TWOMEG, pagesizes[idx]); 694 npages = size >> self->page_shift; 695 696 buffer = malloc(sizeof(*buffer)); 697 ASSERT_NE(buffer, NULL); 698 699 buffer->ptr = get_hugepage_region(size, GHR_STRICT); 700 if (buffer->ptr == NULL) { 701 free(buffer); 702 SKIP(return, "Huge page could not be allocated"); 703 } 704 705 buffer->fd = -1; 706 buffer->size = size; 707 buffer->mirror = malloc(size); 708 ASSERT_NE(buffer->mirror, NULL); 709 710 /* Initialize data that the device will write to buffer->ptr. */ 711 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 712 ptr[i] = i; 713 714 /* Simulate a device writing system memory. */ 715 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_WRITE, buffer, npages); 716 ASSERT_EQ(ret, 0); 717 ASSERT_EQ(buffer->cpages, npages); 718 ASSERT_EQ(buffer->faults, 1); 719 720 /* Check what the device wrote. */ 721 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 722 ASSERT_EQ(ptr[i], i); 723 724 free_hugepage_region(buffer->ptr); 725 buffer->ptr = NULL; 726 hmm_buffer_free(buffer); 727} 728#endif /* LOCAL_CONFIG_HAVE_LIBHUGETLBFS */ 729 730/* 731 * Read mmap'ed file memory. 732 */ 733TEST_F(hmm, file_read) 734{ 735 struct hmm_buffer *buffer; 736 unsigned long npages; 737 unsigned long size; 738 unsigned long i; 739 int *ptr; 740 int ret; 741 int fd; 742 ssize_t len; 743 744 npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; 745 ASSERT_NE(npages, 0); 746 size = npages << self->page_shift; 747 748 fd = hmm_create_file(size); 749 ASSERT_GE(fd, 0); 750 751 buffer = malloc(sizeof(*buffer)); 752 ASSERT_NE(buffer, NULL); 753 754 buffer->fd = fd; 755 buffer->size = size; 756 buffer->mirror = malloc(size); 757 ASSERT_NE(buffer->mirror, NULL); 758 759 /* Write initial contents of the file. */ 760 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 761 ptr[i] = i; 762 len = pwrite(fd, buffer->mirror, size, 0); 763 ASSERT_EQ(len, size); 764 memset(buffer->mirror, 0, size); 765 766 buffer->ptr = mmap(NULL, size, 767 PROT_READ, 768 MAP_SHARED, 769 buffer->fd, 0); 770 ASSERT_NE(buffer->ptr, MAP_FAILED); 771 772 /* Simulate a device reading system memory. */ 773 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_READ, buffer, npages); 774 ASSERT_EQ(ret, 0); 775 ASSERT_EQ(buffer->cpages, npages); 776 ASSERT_EQ(buffer->faults, 1); 777 778 /* Check what the device read. */ 779 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 780 ASSERT_EQ(ptr[i], i); 781 782 hmm_buffer_free(buffer); 783} 784 785/* 786 * Write mmap'ed file memory. 787 */ 788TEST_F(hmm, file_write) 789{ 790 struct hmm_buffer *buffer; 791 unsigned long npages; 792 unsigned long size; 793 unsigned long i; 794 int *ptr; 795 int ret; 796 int fd; 797 ssize_t len; 798 799 npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; 800 ASSERT_NE(npages, 0); 801 size = npages << self->page_shift; 802 803 fd = hmm_create_file(size); 804 ASSERT_GE(fd, 0); 805 806 buffer = malloc(sizeof(*buffer)); 807 ASSERT_NE(buffer, NULL); 808 809 buffer->fd = fd; 810 buffer->size = size; 811 buffer->mirror = malloc(size); 812 ASSERT_NE(buffer->mirror, NULL); 813 814 buffer->ptr = mmap(NULL, size, 815 PROT_READ | PROT_WRITE, 816 MAP_SHARED, 817 buffer->fd, 0); 818 ASSERT_NE(buffer->ptr, MAP_FAILED); 819 820 /* Initialize data that the device will write to buffer->ptr. */ 821 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 822 ptr[i] = i; 823 824 /* Simulate a device writing system memory. */ 825 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_WRITE, buffer, npages); 826 ASSERT_EQ(ret, 0); 827 ASSERT_EQ(buffer->cpages, npages); 828 ASSERT_EQ(buffer->faults, 1); 829 830 /* Check what the device wrote. */ 831 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 832 ASSERT_EQ(ptr[i], i); 833 834 /* Check that the device also wrote the file. */ 835 len = pread(fd, buffer->mirror, size, 0); 836 ASSERT_EQ(len, size); 837 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 838 ASSERT_EQ(ptr[i], i); 839 840 hmm_buffer_free(buffer); 841} 842 843/* 844 * Migrate anonymous memory to device private memory. 845 */ 846TEST_F(hmm, migrate) 847{ 848 struct hmm_buffer *buffer; 849 unsigned long npages; 850 unsigned long size; 851 unsigned long i; 852 int *ptr; 853 int ret; 854 855 npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; 856 ASSERT_NE(npages, 0); 857 size = npages << self->page_shift; 858 859 buffer = malloc(sizeof(*buffer)); 860 ASSERT_NE(buffer, NULL); 861 862 buffer->fd = -1; 863 buffer->size = size; 864 buffer->mirror = malloc(size); 865 ASSERT_NE(buffer->mirror, NULL); 866 867 buffer->ptr = mmap(NULL, size, 868 PROT_READ | PROT_WRITE, 869 MAP_PRIVATE | MAP_ANONYMOUS, 870 buffer->fd, 0); 871 ASSERT_NE(buffer->ptr, MAP_FAILED); 872 873 /* Initialize buffer in system memory. */ 874 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 875 ptr[i] = i; 876 877 /* Migrate memory to device. */ 878 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_MIGRATE, buffer, npages); 879 ASSERT_EQ(ret, 0); 880 ASSERT_EQ(buffer->cpages, npages); 881 882 /* Check what the device read. */ 883 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 884 ASSERT_EQ(ptr[i], i); 885 886 hmm_buffer_free(buffer); 887} 888 889/* 890 * Migrate anonymous memory to device private memory and fault some of it back 891 * to system memory, then try migrating the resulting mix of system and device 892 * private memory to the device. 893 */ 894TEST_F(hmm, migrate_fault) 895{ 896 struct hmm_buffer *buffer; 897 unsigned long npages; 898 unsigned long size; 899 unsigned long i; 900 int *ptr; 901 int ret; 902 903 npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; 904 ASSERT_NE(npages, 0); 905 size = npages << self->page_shift; 906 907 buffer = malloc(sizeof(*buffer)); 908 ASSERT_NE(buffer, NULL); 909 910 buffer->fd = -1; 911 buffer->size = size; 912 buffer->mirror = malloc(size); 913 ASSERT_NE(buffer->mirror, NULL); 914 915 buffer->ptr = mmap(NULL, size, 916 PROT_READ | PROT_WRITE, 917 MAP_PRIVATE | MAP_ANONYMOUS, 918 buffer->fd, 0); 919 ASSERT_NE(buffer->ptr, MAP_FAILED); 920 921 /* Initialize buffer in system memory. */ 922 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 923 ptr[i] = i; 924 925 /* Migrate memory to device. */ 926 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_MIGRATE, buffer, npages); 927 ASSERT_EQ(ret, 0); 928 ASSERT_EQ(buffer->cpages, npages); 929 930 /* Check what the device read. */ 931 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 932 ASSERT_EQ(ptr[i], i); 933 934 /* Fault half the pages back to system memory and check them. */ 935 for (i = 0, ptr = buffer->ptr; i < size / (2 * sizeof(*ptr)); ++i) 936 ASSERT_EQ(ptr[i], i); 937 938 /* Migrate memory to the device again. */ 939 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_MIGRATE, buffer, npages); 940 ASSERT_EQ(ret, 0); 941 ASSERT_EQ(buffer->cpages, npages); 942 943 /* Check what the device read. */ 944 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 945 ASSERT_EQ(ptr[i], i); 946 947 hmm_buffer_free(buffer); 948} 949 950/* 951 * Migrate anonymous shared memory to device private memory. 952 */ 953TEST_F(hmm, migrate_shared) 954{ 955 struct hmm_buffer *buffer; 956 unsigned long npages; 957 unsigned long size; 958 int ret; 959 960 npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; 961 ASSERT_NE(npages, 0); 962 size = npages << self->page_shift; 963 964 buffer = malloc(sizeof(*buffer)); 965 ASSERT_NE(buffer, NULL); 966 967 buffer->fd = -1; 968 buffer->size = size; 969 buffer->mirror = malloc(size); 970 ASSERT_NE(buffer->mirror, NULL); 971 972 buffer->ptr = mmap(NULL, size, 973 PROT_READ | PROT_WRITE, 974 MAP_SHARED | MAP_ANONYMOUS, 975 buffer->fd, 0); 976 ASSERT_NE(buffer->ptr, MAP_FAILED); 977 978 /* Migrate memory to device. */ 979 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_MIGRATE, buffer, npages); 980 ASSERT_EQ(ret, -ENOENT); 981 982 hmm_buffer_free(buffer); 983} 984 985/* 986 * Try to migrate various memory types to device private memory. 987 */ 988TEST_F(hmm2, migrate_mixed) 989{ 990 struct hmm_buffer *buffer; 991 unsigned long npages; 992 unsigned long size; 993 int *ptr; 994 unsigned char *p; 995 int ret; 996 int val; 997 998 npages = 6; 999 size = npages << self->page_shift; 1000 1001 buffer = malloc(sizeof(*buffer)); 1002 ASSERT_NE(buffer, NULL); 1003 1004 buffer->fd = -1; 1005 buffer->size = size; 1006 buffer->mirror = malloc(size); 1007 ASSERT_NE(buffer->mirror, NULL); 1008 1009 /* Reserve a range of addresses. */ 1010 buffer->ptr = mmap(NULL, size, 1011 PROT_NONE, 1012 MAP_PRIVATE | MAP_ANONYMOUS, 1013 buffer->fd, 0); 1014 ASSERT_NE(buffer->ptr, MAP_FAILED); 1015 p = buffer->ptr; 1016 1017 /* Migrating a protected area should be an error. */ 1018 ret = hmm_dmirror_cmd(self->fd1, HMM_DMIRROR_MIGRATE, buffer, npages); 1019 ASSERT_EQ(ret, -EINVAL); 1020 1021 /* Punch a hole after the first page address. */ 1022 ret = munmap(buffer->ptr + self->page_size, self->page_size); 1023 ASSERT_EQ(ret, 0); 1024 1025 /* We expect an error if the vma doesn't cover the range. */ 1026 ret = hmm_dmirror_cmd(self->fd1, HMM_DMIRROR_MIGRATE, buffer, 3); 1027 ASSERT_EQ(ret, -EINVAL); 1028 1029 /* Page 2 will be a read-only zero page. */ 1030 ret = mprotect(buffer->ptr + 2 * self->page_size, self->page_size, 1031 PROT_READ); 1032 ASSERT_EQ(ret, 0); 1033 ptr = (int *)(buffer->ptr + 2 * self->page_size); 1034 val = *ptr + 3; 1035 ASSERT_EQ(val, 3); 1036 1037 /* Page 3 will be read-only. */ 1038 ret = mprotect(buffer->ptr + 3 * self->page_size, self->page_size, 1039 PROT_READ | PROT_WRITE); 1040 ASSERT_EQ(ret, 0); 1041 ptr = (int *)(buffer->ptr + 3 * self->page_size); 1042 *ptr = val; 1043 ret = mprotect(buffer->ptr + 3 * self->page_size, self->page_size, 1044 PROT_READ); 1045 ASSERT_EQ(ret, 0); 1046 1047 /* Page 4-5 will be read-write. */ 1048 ret = mprotect(buffer->ptr + 4 * self->page_size, 2 * self->page_size, 1049 PROT_READ | PROT_WRITE); 1050 ASSERT_EQ(ret, 0); 1051 ptr = (int *)(buffer->ptr + 4 * self->page_size); 1052 *ptr = val; 1053 ptr = (int *)(buffer->ptr + 5 * self->page_size); 1054 *ptr = val; 1055 1056 /* Now try to migrate pages 2-5 to device 1. */ 1057 buffer->ptr = p + 2 * self->page_size; 1058 ret = hmm_dmirror_cmd(self->fd1, HMM_DMIRROR_MIGRATE, buffer, 4); 1059 ASSERT_EQ(ret, 0); 1060 ASSERT_EQ(buffer->cpages, 4); 1061 1062 /* Page 5 won't be migrated to device 0 because it's on device 1. */ 1063 buffer->ptr = p + 5 * self->page_size; 1064 ret = hmm_dmirror_cmd(self->fd0, HMM_DMIRROR_MIGRATE, buffer, 1); 1065 ASSERT_EQ(ret, -ENOENT); 1066 buffer->ptr = p; 1067 1068 buffer->ptr = p; 1069 hmm_buffer_free(buffer); 1070} 1071 1072/* 1073 * Migrate anonymous memory to device private memory and fault it back to system 1074 * memory multiple times. 1075 */ 1076TEST_F(hmm, migrate_multiple) 1077{ 1078 struct hmm_buffer *buffer; 1079 unsigned long npages; 1080 unsigned long size; 1081 unsigned long i; 1082 unsigned long c; 1083 int *ptr; 1084 int ret; 1085 1086 npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; 1087 ASSERT_NE(npages, 0); 1088 size = npages << self->page_shift; 1089 1090 for (c = 0; c < NTIMES; c++) { 1091 buffer = malloc(sizeof(*buffer)); 1092 ASSERT_NE(buffer, NULL); 1093 1094 buffer->fd = -1; 1095 buffer->size = size; 1096 buffer->mirror = malloc(size); 1097 ASSERT_NE(buffer->mirror, NULL); 1098 1099 buffer->ptr = mmap(NULL, size, 1100 PROT_READ | PROT_WRITE, 1101 MAP_PRIVATE | MAP_ANONYMOUS, 1102 buffer->fd, 0); 1103 ASSERT_NE(buffer->ptr, MAP_FAILED); 1104 1105 /* Initialize buffer in system memory. */ 1106 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 1107 ptr[i] = i; 1108 1109 /* Migrate memory to device. */ 1110 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_MIGRATE, buffer, 1111 npages); 1112 ASSERT_EQ(ret, 0); 1113 ASSERT_EQ(buffer->cpages, npages); 1114 1115 /* Check what the device read. */ 1116 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 1117 ASSERT_EQ(ptr[i], i); 1118 1119 /* Fault pages back to system memory and check them. */ 1120 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 1121 ASSERT_EQ(ptr[i], i); 1122 1123 hmm_buffer_free(buffer); 1124 } 1125} 1126 1127/* 1128 * Read anonymous memory multiple times. 1129 */ 1130TEST_F(hmm, anon_read_multiple) 1131{ 1132 struct hmm_buffer *buffer; 1133 unsigned long npages; 1134 unsigned long size; 1135 unsigned long i; 1136 unsigned long c; 1137 int *ptr; 1138 int ret; 1139 1140 npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; 1141 ASSERT_NE(npages, 0); 1142 size = npages << self->page_shift; 1143 1144 for (c = 0; c < NTIMES; c++) { 1145 buffer = malloc(sizeof(*buffer)); 1146 ASSERT_NE(buffer, NULL); 1147 1148 buffer->fd = -1; 1149 buffer->size = size; 1150 buffer->mirror = malloc(size); 1151 ASSERT_NE(buffer->mirror, NULL); 1152 1153 buffer->ptr = mmap(NULL, size, 1154 PROT_READ | PROT_WRITE, 1155 MAP_PRIVATE | MAP_ANONYMOUS, 1156 buffer->fd, 0); 1157 ASSERT_NE(buffer->ptr, MAP_FAILED); 1158 1159 /* Initialize buffer in system memory. */ 1160 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 1161 ptr[i] = i + c; 1162 1163 /* Simulate a device reading system memory. */ 1164 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_READ, buffer, 1165 npages); 1166 ASSERT_EQ(ret, 0); 1167 ASSERT_EQ(buffer->cpages, npages); 1168 ASSERT_EQ(buffer->faults, 1); 1169 1170 /* Check what the device read. */ 1171 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 1172 ASSERT_EQ(ptr[i], i + c); 1173 1174 hmm_buffer_free(buffer); 1175 } 1176} 1177 1178void *unmap_buffer(void *p) 1179{ 1180 struct hmm_buffer *buffer = p; 1181 1182 /* Delay for a bit and then unmap buffer while it is being read. */ 1183 hmm_nanosleep(hmm_random() % 32000); 1184 munmap(buffer->ptr + buffer->size / 2, buffer->size / 2); 1185 buffer->ptr = NULL; 1186 1187 return NULL; 1188} 1189 1190/* 1191 * Try reading anonymous memory while it is being unmapped. 1192 */ 1193TEST_F(hmm, anon_teardown) 1194{ 1195 unsigned long npages; 1196 unsigned long size; 1197 unsigned long c; 1198 void *ret; 1199 1200 npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; 1201 ASSERT_NE(npages, 0); 1202 size = npages << self->page_shift; 1203 1204 for (c = 0; c < NTIMES; ++c) { 1205 pthread_t thread; 1206 struct hmm_buffer *buffer; 1207 unsigned long i; 1208 int *ptr; 1209 int rc; 1210 1211 buffer = malloc(sizeof(*buffer)); 1212 ASSERT_NE(buffer, NULL); 1213 1214 buffer->fd = -1; 1215 buffer->size = size; 1216 buffer->mirror = malloc(size); 1217 ASSERT_NE(buffer->mirror, NULL); 1218 1219 buffer->ptr = mmap(NULL, size, 1220 PROT_READ | PROT_WRITE, 1221 MAP_PRIVATE | MAP_ANONYMOUS, 1222 buffer->fd, 0); 1223 ASSERT_NE(buffer->ptr, MAP_FAILED); 1224 1225 /* Initialize buffer in system memory. */ 1226 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 1227 ptr[i] = i + c; 1228 1229 rc = pthread_create(&thread, NULL, unmap_buffer, buffer); 1230 ASSERT_EQ(rc, 0); 1231 1232 /* Simulate a device reading system memory. */ 1233 rc = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_READ, buffer, 1234 npages); 1235 if (rc == 0) { 1236 ASSERT_EQ(buffer->cpages, npages); 1237 ASSERT_EQ(buffer->faults, 1); 1238 1239 /* Check what the device read. */ 1240 for (i = 0, ptr = buffer->mirror; 1241 i < size / sizeof(*ptr); 1242 ++i) 1243 ASSERT_EQ(ptr[i], i + c); 1244 } 1245 1246 pthread_join(thread, &ret); 1247 hmm_buffer_free(buffer); 1248 } 1249} 1250 1251/* 1252 * Test memory snapshot without faulting in pages accessed by the device. 1253 */ 1254TEST_F(hmm, mixedmap) 1255{ 1256 struct hmm_buffer *buffer; 1257 unsigned long npages; 1258 unsigned long size; 1259 unsigned char *m; 1260 int ret; 1261 1262 npages = 1; 1263 size = npages << self->page_shift; 1264 1265 buffer = malloc(sizeof(*buffer)); 1266 ASSERT_NE(buffer, NULL); 1267 1268 buffer->fd = -1; 1269 buffer->size = size; 1270 buffer->mirror = malloc(npages); 1271 ASSERT_NE(buffer->mirror, NULL); 1272 1273 1274 /* Reserve a range of addresses. */ 1275 buffer->ptr = mmap(NULL, size, 1276 PROT_READ | PROT_WRITE, 1277 MAP_PRIVATE, 1278 self->fd, 0); 1279 ASSERT_NE(buffer->ptr, MAP_FAILED); 1280 1281 /* Simulate a device snapshotting CPU pagetables. */ 1282 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_SNAPSHOT, buffer, npages); 1283 ASSERT_EQ(ret, 0); 1284 ASSERT_EQ(buffer->cpages, npages); 1285 1286 /* Check what the device saw. */ 1287 m = buffer->mirror; 1288 ASSERT_EQ(m[0], HMM_DMIRROR_PROT_READ); 1289 1290 hmm_buffer_free(buffer); 1291} 1292 1293/* 1294 * Test memory snapshot without faulting in pages accessed by the device. 1295 */ 1296TEST_F(hmm2, snapshot) 1297{ 1298 struct hmm_buffer *buffer; 1299 unsigned long npages; 1300 unsigned long size; 1301 int *ptr; 1302 unsigned char *p; 1303 unsigned char *m; 1304 int ret; 1305 int val; 1306 1307 npages = 7; 1308 size = npages << self->page_shift; 1309 1310 buffer = malloc(sizeof(*buffer)); 1311 ASSERT_NE(buffer, NULL); 1312 1313 buffer->fd = -1; 1314 buffer->size = size; 1315 buffer->mirror = malloc(npages); 1316 ASSERT_NE(buffer->mirror, NULL); 1317 1318 /* Reserve a range of addresses. */ 1319 buffer->ptr = mmap(NULL, size, 1320 PROT_NONE, 1321 MAP_PRIVATE | MAP_ANONYMOUS, 1322 buffer->fd, 0); 1323 ASSERT_NE(buffer->ptr, MAP_FAILED); 1324 p = buffer->ptr; 1325 1326 /* Punch a hole after the first page address. */ 1327 ret = munmap(buffer->ptr + self->page_size, self->page_size); 1328 ASSERT_EQ(ret, 0); 1329 1330 /* Page 2 will be read-only zero page. */ 1331 ret = mprotect(buffer->ptr + 2 * self->page_size, self->page_size, 1332 PROT_READ); 1333 ASSERT_EQ(ret, 0); 1334 ptr = (int *)(buffer->ptr + 2 * self->page_size); 1335 val = *ptr + 3; 1336 ASSERT_EQ(val, 3); 1337 1338 /* Page 3 will be read-only. */ 1339 ret = mprotect(buffer->ptr + 3 * self->page_size, self->page_size, 1340 PROT_READ | PROT_WRITE); 1341 ASSERT_EQ(ret, 0); 1342 ptr = (int *)(buffer->ptr + 3 * self->page_size); 1343 *ptr = val; 1344 ret = mprotect(buffer->ptr + 3 * self->page_size, self->page_size, 1345 PROT_READ); 1346 ASSERT_EQ(ret, 0); 1347 1348 /* Page 4-6 will be read-write. */ 1349 ret = mprotect(buffer->ptr + 4 * self->page_size, 3 * self->page_size, 1350 PROT_READ | PROT_WRITE); 1351 ASSERT_EQ(ret, 0); 1352 ptr = (int *)(buffer->ptr + 4 * self->page_size); 1353 *ptr = val; 1354 1355 /* Page 5 will be migrated to device 0. */ 1356 buffer->ptr = p + 5 * self->page_size; 1357 ret = hmm_dmirror_cmd(self->fd0, HMM_DMIRROR_MIGRATE, buffer, 1); 1358 ASSERT_EQ(ret, 0); 1359 ASSERT_EQ(buffer->cpages, 1); 1360 1361 /* Page 6 will be migrated to device 1. */ 1362 buffer->ptr = p + 6 * self->page_size; 1363 ret = hmm_dmirror_cmd(self->fd1, HMM_DMIRROR_MIGRATE, buffer, 1); 1364 ASSERT_EQ(ret, 0); 1365 ASSERT_EQ(buffer->cpages, 1); 1366 1367 /* Simulate a device snapshotting CPU pagetables. */ 1368 buffer->ptr = p; 1369 ret = hmm_dmirror_cmd(self->fd0, HMM_DMIRROR_SNAPSHOT, buffer, npages); 1370 ASSERT_EQ(ret, 0); 1371 ASSERT_EQ(buffer->cpages, npages); 1372 1373 /* Check what the device saw. */ 1374 m = buffer->mirror; 1375 ASSERT_EQ(m[0], HMM_DMIRROR_PROT_ERROR); 1376 ASSERT_EQ(m[1], HMM_DMIRROR_PROT_ERROR); 1377 ASSERT_EQ(m[2], HMM_DMIRROR_PROT_ZERO | HMM_DMIRROR_PROT_READ); 1378 ASSERT_EQ(m[3], HMM_DMIRROR_PROT_READ); 1379 ASSERT_EQ(m[4], HMM_DMIRROR_PROT_WRITE); 1380 ASSERT_EQ(m[5], HMM_DMIRROR_PROT_DEV_PRIVATE_LOCAL | 1381 HMM_DMIRROR_PROT_WRITE); 1382 ASSERT_EQ(m[6], HMM_DMIRROR_PROT_NONE); 1383 1384 hmm_buffer_free(buffer); 1385} 1386 1387#ifdef LOCAL_CONFIG_HAVE_LIBHUGETLBFS 1388/* 1389 * Test the hmm_range_fault() HMM_PFN_PMD flag for large pages that 1390 * should be mapped by a large page table entry. 1391 */ 1392TEST_F(hmm, compound) 1393{ 1394 struct hmm_buffer *buffer; 1395 unsigned long npages; 1396 unsigned long size; 1397 int *ptr; 1398 unsigned char *m; 1399 int ret; 1400 long pagesizes[4]; 1401 int n, idx; 1402 unsigned long i; 1403 1404 /* Skip test if we can't allocate a hugetlbfs page. */ 1405 1406 n = gethugepagesizes(pagesizes, 4); 1407 if (n <= 0) 1408 return; 1409 for (idx = 0; --n > 0; ) { 1410 if (pagesizes[n] < pagesizes[idx]) 1411 idx = n; 1412 } 1413 size = ALIGN(TWOMEG, pagesizes[idx]); 1414 npages = size >> self->page_shift; 1415 1416 buffer = malloc(sizeof(*buffer)); 1417 ASSERT_NE(buffer, NULL); 1418 1419 buffer->ptr = get_hugepage_region(size, GHR_STRICT); 1420 if (buffer->ptr == NULL) { 1421 free(buffer); 1422 return; 1423 } 1424 1425 buffer->size = size; 1426 buffer->mirror = malloc(npages); 1427 ASSERT_NE(buffer->mirror, NULL); 1428 1429 /* Initialize the pages the device will snapshot in buffer->ptr. */ 1430 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 1431 ptr[i] = i; 1432 1433 /* Simulate a device snapshotting CPU pagetables. */ 1434 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_SNAPSHOT, buffer, npages); 1435 ASSERT_EQ(ret, 0); 1436 ASSERT_EQ(buffer->cpages, npages); 1437 1438 /* Check what the device saw. */ 1439 m = buffer->mirror; 1440 for (i = 0; i < npages; ++i) 1441 ASSERT_EQ(m[i], HMM_DMIRROR_PROT_WRITE | 1442 HMM_DMIRROR_PROT_PMD); 1443 1444 /* Make the region read-only. */ 1445 ret = mprotect(buffer->ptr, size, PROT_READ); 1446 ASSERT_EQ(ret, 0); 1447 1448 /* Simulate a device snapshotting CPU pagetables. */ 1449 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_SNAPSHOT, buffer, npages); 1450 ASSERT_EQ(ret, 0); 1451 ASSERT_EQ(buffer->cpages, npages); 1452 1453 /* Check what the device saw. */ 1454 m = buffer->mirror; 1455 for (i = 0; i < npages; ++i) 1456 ASSERT_EQ(m[i], HMM_DMIRROR_PROT_READ | 1457 HMM_DMIRROR_PROT_PMD); 1458 1459 free_hugepage_region(buffer->ptr); 1460 buffer->ptr = NULL; 1461 hmm_buffer_free(buffer); 1462} 1463#endif /* LOCAL_CONFIG_HAVE_LIBHUGETLBFS */ 1464 1465/* 1466 * Test two devices reading the same memory (double mapped). 1467 */ 1468TEST_F(hmm2, double_map) 1469{ 1470 struct hmm_buffer *buffer; 1471 unsigned long npages; 1472 unsigned long size; 1473 unsigned long i; 1474 int *ptr; 1475 int ret; 1476 1477 npages = 6; 1478 size = npages << self->page_shift; 1479 1480 buffer = malloc(sizeof(*buffer)); 1481 ASSERT_NE(buffer, NULL); 1482 1483 buffer->fd = -1; 1484 buffer->size = size; 1485 buffer->mirror = malloc(npages); 1486 ASSERT_NE(buffer->mirror, NULL); 1487 1488 /* Reserve a range of addresses. */ 1489 buffer->ptr = mmap(NULL, size, 1490 PROT_READ | PROT_WRITE, 1491 MAP_PRIVATE | MAP_ANONYMOUS, 1492 buffer->fd, 0); 1493 ASSERT_NE(buffer->ptr, MAP_FAILED); 1494 1495 /* Initialize buffer in system memory. */ 1496 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 1497 ptr[i] = i; 1498 1499 /* Make region read-only. */ 1500 ret = mprotect(buffer->ptr, size, PROT_READ); 1501 ASSERT_EQ(ret, 0); 1502 1503 /* Simulate device 0 reading system memory. */ 1504 ret = hmm_dmirror_cmd(self->fd0, HMM_DMIRROR_READ, buffer, npages); 1505 ASSERT_EQ(ret, 0); 1506 ASSERT_EQ(buffer->cpages, npages); 1507 ASSERT_EQ(buffer->faults, 1); 1508 1509 /* Check what the device read. */ 1510 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 1511 ASSERT_EQ(ptr[i], i); 1512 1513 /* Simulate device 1 reading system memory. */ 1514 ret = hmm_dmirror_cmd(self->fd1, HMM_DMIRROR_READ, buffer, npages); 1515 ASSERT_EQ(ret, 0); 1516 ASSERT_EQ(buffer->cpages, npages); 1517 ASSERT_EQ(buffer->faults, 1); 1518 1519 /* Check what the device read. */ 1520 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 1521 ASSERT_EQ(ptr[i], i); 1522 1523 /* Punch a hole after the first page address. */ 1524 ret = munmap(buffer->ptr + self->page_size, self->page_size); 1525 ASSERT_EQ(ret, 0); 1526 1527 hmm_buffer_free(buffer); 1528} 1529 1530/* 1531 * Basic check of exclusive faulting. 1532 */ 1533TEST_F(hmm, exclusive) 1534{ 1535 struct hmm_buffer *buffer; 1536 unsigned long npages; 1537 unsigned long size; 1538 unsigned long i; 1539 int *ptr; 1540 int ret; 1541 1542 npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; 1543 ASSERT_NE(npages, 0); 1544 size = npages << self->page_shift; 1545 1546 buffer = malloc(sizeof(*buffer)); 1547 ASSERT_NE(buffer, NULL); 1548 1549 buffer->fd = -1; 1550 buffer->size = size; 1551 buffer->mirror = malloc(size); 1552 ASSERT_NE(buffer->mirror, NULL); 1553 1554 buffer->ptr = mmap(NULL, size, 1555 PROT_READ | PROT_WRITE, 1556 MAP_PRIVATE | MAP_ANONYMOUS, 1557 buffer->fd, 0); 1558 ASSERT_NE(buffer->ptr, MAP_FAILED); 1559 1560 /* Initialize buffer in system memory. */ 1561 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 1562 ptr[i] = i; 1563 1564 /* Map memory exclusively for device access. */ 1565 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_EXCLUSIVE, buffer, npages); 1566 ASSERT_EQ(ret, 0); 1567 ASSERT_EQ(buffer->cpages, npages); 1568 1569 /* Check what the device read. */ 1570 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 1571 ASSERT_EQ(ptr[i], i); 1572 1573 /* Fault pages back to system memory and check them. */ 1574 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 1575 ASSERT_EQ(ptr[i]++, i); 1576 1577 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 1578 ASSERT_EQ(ptr[i], i+1); 1579 1580 /* Check atomic access revoked */ 1581 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_CHECK_EXCLUSIVE, buffer, npages); 1582 ASSERT_EQ(ret, 0); 1583 1584 hmm_buffer_free(buffer); 1585} 1586 1587TEST_F(hmm, exclusive_mprotect) 1588{ 1589 struct hmm_buffer *buffer; 1590 unsigned long npages; 1591 unsigned long size; 1592 unsigned long i; 1593 int *ptr; 1594 int ret; 1595 1596 npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; 1597 ASSERT_NE(npages, 0); 1598 size = npages << self->page_shift; 1599 1600 buffer = malloc(sizeof(*buffer)); 1601 ASSERT_NE(buffer, NULL); 1602 1603 buffer->fd = -1; 1604 buffer->size = size; 1605 buffer->mirror = malloc(size); 1606 ASSERT_NE(buffer->mirror, NULL); 1607 1608 buffer->ptr = mmap(NULL, size, 1609 PROT_READ | PROT_WRITE, 1610 MAP_PRIVATE | MAP_ANONYMOUS, 1611 buffer->fd, 0); 1612 ASSERT_NE(buffer->ptr, MAP_FAILED); 1613 1614 /* Initialize buffer in system memory. */ 1615 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 1616 ptr[i] = i; 1617 1618 /* Map memory exclusively for device access. */ 1619 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_EXCLUSIVE, buffer, npages); 1620 ASSERT_EQ(ret, 0); 1621 ASSERT_EQ(buffer->cpages, npages); 1622 1623 /* Check what the device read. */ 1624 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i) 1625 ASSERT_EQ(ptr[i], i); 1626 1627 ret = mprotect(buffer->ptr, size, PROT_READ); 1628 ASSERT_EQ(ret, 0); 1629 1630 /* Simulate a device writing system memory. */ 1631 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_WRITE, buffer, npages); 1632 ASSERT_EQ(ret, -EPERM); 1633 1634 hmm_buffer_free(buffer); 1635} 1636 1637/* 1638 * Check copy-on-write works. 1639 */ 1640TEST_F(hmm, exclusive_cow) 1641{ 1642 struct hmm_buffer *buffer; 1643 unsigned long npages; 1644 unsigned long size; 1645 unsigned long i; 1646 int *ptr; 1647 int ret; 1648 1649 npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift; 1650 ASSERT_NE(npages, 0); 1651 size = npages << self->page_shift; 1652 1653 buffer = malloc(sizeof(*buffer)); 1654 ASSERT_NE(buffer, NULL); 1655 1656 buffer->fd = -1; 1657 buffer->size = size; 1658 buffer->mirror = malloc(size); 1659 ASSERT_NE(buffer->mirror, NULL); 1660 1661 buffer->ptr = mmap(NULL, size, 1662 PROT_READ | PROT_WRITE, 1663 MAP_PRIVATE | MAP_ANONYMOUS, 1664 buffer->fd, 0); 1665 ASSERT_NE(buffer->ptr, MAP_FAILED); 1666 1667 /* Initialize buffer in system memory. */ 1668 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 1669 ptr[i] = i; 1670 1671 /* Map memory exclusively for device access. */ 1672 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_EXCLUSIVE, buffer, npages); 1673 ASSERT_EQ(ret, 0); 1674 ASSERT_EQ(buffer->cpages, npages); 1675 1676 fork(); 1677 1678 /* Fault pages back to system memory and check them. */ 1679 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 1680 ASSERT_EQ(ptr[i]++, i); 1681 1682 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i) 1683 ASSERT_EQ(ptr[i], i+1); 1684 1685 hmm_buffer_free(buffer); 1686} 1687 1688TEST_HARNESS_MAIN