1
2
3
4
5
6
7
8
9
10
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
36
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
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
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
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
216
217TEST_F(hmm, open_close)
218{
219}
220
221
222
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
254
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
261 ret = mprotect(buffer->ptr, size, PROT_READ);
262 ASSERT_EQ(ret, 0);
263
264
265 val = *(int *)(buffer->ptr + self->page_size);
266 ASSERT_EQ(val, 0);
267
268
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
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
286
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
316 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
317 ptr[i] = i;
318
319
320 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
321 ptr[i] = -i;
322
323
324 ret = mprotect(buffer->ptr, size, PROT_NONE);
325 ASSERT_EQ(ret, 0);
326
327
328 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_READ, buffer, npages);
329 ASSERT_EQ(ret, -EFAULT);
330
331
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
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
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
375 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
376 ptr[i] = i;
377
378
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
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
393
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
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
429 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
430 ptr[i] = i;
431
432
433 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_WRITE, buffer, npages);
434 ASSERT_EQ(ret, -EPERM);
435
436
437 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
438 ASSERT_EQ(ptr[i], 0);
439
440
441 ret = mprotect(buffer->ptr, size, PROT_WRITE | PROT_READ);
442 ASSERT_EQ(ret, 0);
443
444
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
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
459
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
491 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
492 ptr[i] = i;
493
494
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
506 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
507 ASSERT_EQ(ptr[i], i);
508 return;
509 }
510
511
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
518 child_fd = hmm_open(0);
519 ASSERT_GE(child_fd, 0);
520
521
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
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
537
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
569 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
570 ptr[i] = i;
571
572
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
584 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
585 ASSERT_EQ(ptr[i], -i);
586 return;
587 }
588
589
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
596 child_fd = hmm_open(0);
597 ASSERT_GE(child_fd, 0);
598
599
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
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
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
652 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
653 ptr[i] = i;
654
655
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
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
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
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
711 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
712 ptr[i] = i;
713
714
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
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
729
730
731
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
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
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
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
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
821 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
822 ptr[i] = i;
823
824
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
831 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
832 ASSERT_EQ(ptr[i], i);
833
834
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
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
874 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
875 ptr[i] = i;
876
877
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
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
891
892
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
922 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
923 ptr[i] = i;
924
925
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
931 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
932 ASSERT_EQ(ptr[i], i);
933
934
935 for (i = 0, ptr = buffer->ptr; i < size / (2 * sizeof(*ptr)); ++i)
936 ASSERT_EQ(ptr[i], i);
937
938
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
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
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
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
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
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
1018 ret = hmm_dmirror_cmd(self->fd1, HMM_DMIRROR_MIGRATE, buffer, npages);
1019 ASSERT_EQ(ret, -EINVAL);
1020
1021
1022 ret = munmap(buffer->ptr + self->page_size, self->page_size);
1023 ASSERT_EQ(ret, 0);
1024
1025
1026 ret = hmm_dmirror_cmd(self->fd1, HMM_DMIRROR_MIGRATE, buffer, 3);
1027 ASSERT_EQ(ret, -EINVAL);
1028
1029
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
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
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
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
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
1074
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
1106 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
1107 ptr[i] = i;
1108
1109
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
1116 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
1117 ASSERT_EQ(ptr[i], i);
1118
1119
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
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
1160 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
1161 ptr[i] = i + c;
1162
1163
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
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
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
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
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
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
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
1253
1254TEST_F(hmm2, snapshot)
1255{
1256 struct hmm_buffer *buffer;
1257 unsigned long npages;
1258 unsigned long size;
1259 int *ptr;
1260 unsigned char *p;
1261 unsigned char *m;
1262 int ret;
1263 int val;
1264
1265 npages = 7;
1266 size = npages << self->page_shift;
1267
1268 buffer = malloc(sizeof(*buffer));
1269 ASSERT_NE(buffer, NULL);
1270
1271 buffer->fd = -1;
1272 buffer->size = size;
1273 buffer->mirror = malloc(npages);
1274 ASSERT_NE(buffer->mirror, NULL);
1275
1276
1277 buffer->ptr = mmap(NULL, size,
1278 PROT_NONE,
1279 MAP_PRIVATE | MAP_ANONYMOUS,
1280 buffer->fd, 0);
1281 ASSERT_NE(buffer->ptr, MAP_FAILED);
1282 p = buffer->ptr;
1283
1284
1285 ret = munmap(buffer->ptr + self->page_size, self->page_size);
1286 ASSERT_EQ(ret, 0);
1287
1288
1289 ret = mprotect(buffer->ptr + 2 * self->page_size, self->page_size,
1290 PROT_READ);
1291 ASSERT_EQ(ret, 0);
1292 ptr = (int *)(buffer->ptr + 2 * self->page_size);
1293 val = *ptr + 3;
1294 ASSERT_EQ(val, 3);
1295
1296
1297 ret = mprotect(buffer->ptr + 3 * self->page_size, self->page_size,
1298 PROT_READ | PROT_WRITE);
1299 ASSERT_EQ(ret, 0);
1300 ptr = (int *)(buffer->ptr + 3 * self->page_size);
1301 *ptr = val;
1302 ret = mprotect(buffer->ptr + 3 * self->page_size, self->page_size,
1303 PROT_READ);
1304 ASSERT_EQ(ret, 0);
1305
1306
1307 ret = mprotect(buffer->ptr + 4 * self->page_size, 3 * self->page_size,
1308 PROT_READ | PROT_WRITE);
1309 ASSERT_EQ(ret, 0);
1310 ptr = (int *)(buffer->ptr + 4 * self->page_size);
1311 *ptr = val;
1312
1313
1314 buffer->ptr = p + 5 * self->page_size;
1315 ret = hmm_dmirror_cmd(self->fd0, HMM_DMIRROR_MIGRATE, buffer, 1);
1316 ASSERT_EQ(ret, 0);
1317 ASSERT_EQ(buffer->cpages, 1);
1318
1319
1320 buffer->ptr = p + 6 * self->page_size;
1321 ret = hmm_dmirror_cmd(self->fd1, HMM_DMIRROR_MIGRATE, buffer, 1);
1322 ASSERT_EQ(ret, 0);
1323 ASSERT_EQ(buffer->cpages, 1);
1324
1325
1326 buffer->ptr = p;
1327 ret = hmm_dmirror_cmd(self->fd0, HMM_DMIRROR_SNAPSHOT, buffer, npages);
1328 ASSERT_EQ(ret, 0);
1329 ASSERT_EQ(buffer->cpages, npages);
1330
1331
1332 m = buffer->mirror;
1333 ASSERT_EQ(m[0], HMM_DMIRROR_PROT_ERROR);
1334 ASSERT_EQ(m[1], HMM_DMIRROR_PROT_ERROR);
1335 ASSERT_EQ(m[2], HMM_DMIRROR_PROT_ZERO | HMM_DMIRROR_PROT_READ);
1336 ASSERT_EQ(m[3], HMM_DMIRROR_PROT_READ);
1337 ASSERT_EQ(m[4], HMM_DMIRROR_PROT_WRITE);
1338 ASSERT_EQ(m[5], HMM_DMIRROR_PROT_DEV_PRIVATE_LOCAL |
1339 HMM_DMIRROR_PROT_WRITE);
1340 ASSERT_EQ(m[6], HMM_DMIRROR_PROT_NONE);
1341
1342 hmm_buffer_free(buffer);
1343}
1344
1345#ifdef LOCAL_CONFIG_HAVE_LIBHUGETLBFS
1346
1347
1348
1349
1350TEST_F(hmm, compound)
1351{
1352 struct hmm_buffer *buffer;
1353 unsigned long npages;
1354 unsigned long size;
1355 int *ptr;
1356 unsigned char *m;
1357 int ret;
1358 long pagesizes[4];
1359 int n, idx;
1360 unsigned long i;
1361
1362
1363
1364 n = gethugepagesizes(pagesizes, 4);
1365 if (n <= 0)
1366 return;
1367 for (idx = 0; --n > 0; ) {
1368 if (pagesizes[n] < pagesizes[idx])
1369 idx = n;
1370 }
1371 size = ALIGN(TWOMEG, pagesizes[idx]);
1372 npages = size >> self->page_shift;
1373
1374 buffer = malloc(sizeof(*buffer));
1375 ASSERT_NE(buffer, NULL);
1376
1377 buffer->ptr = get_hugepage_region(size, GHR_STRICT);
1378 if (buffer->ptr == NULL) {
1379 free(buffer);
1380 return;
1381 }
1382
1383 buffer->size = size;
1384 buffer->mirror = malloc(npages);
1385 ASSERT_NE(buffer->mirror, NULL);
1386
1387
1388 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
1389 ptr[i] = i;
1390
1391
1392 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_SNAPSHOT, buffer, npages);
1393 ASSERT_EQ(ret, 0);
1394 ASSERT_EQ(buffer->cpages, npages);
1395
1396
1397 m = buffer->mirror;
1398 for (i = 0; i < npages; ++i)
1399 ASSERT_EQ(m[i], HMM_DMIRROR_PROT_WRITE |
1400 HMM_DMIRROR_PROT_PMD);
1401
1402
1403 ret = mprotect(buffer->ptr, size, PROT_READ);
1404 ASSERT_EQ(ret, 0);
1405
1406
1407 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_SNAPSHOT, buffer, npages);
1408 ASSERT_EQ(ret, 0);
1409 ASSERT_EQ(buffer->cpages, npages);
1410
1411
1412 m = buffer->mirror;
1413 for (i = 0; i < npages; ++i)
1414 ASSERT_EQ(m[i], HMM_DMIRROR_PROT_READ |
1415 HMM_DMIRROR_PROT_PMD);
1416
1417 free_hugepage_region(buffer->ptr);
1418 buffer->ptr = NULL;
1419 hmm_buffer_free(buffer);
1420}
1421#endif
1422
1423
1424
1425
1426TEST_F(hmm2, double_map)
1427{
1428 struct hmm_buffer *buffer;
1429 unsigned long npages;
1430 unsigned long size;
1431 unsigned long i;
1432 int *ptr;
1433 int ret;
1434
1435 npages = 6;
1436 size = npages << self->page_shift;
1437
1438 buffer = malloc(sizeof(*buffer));
1439 ASSERT_NE(buffer, NULL);
1440
1441 buffer->fd = -1;
1442 buffer->size = size;
1443 buffer->mirror = malloc(npages);
1444 ASSERT_NE(buffer->mirror, NULL);
1445
1446
1447 buffer->ptr = mmap(NULL, size,
1448 PROT_READ | PROT_WRITE,
1449 MAP_PRIVATE | MAP_ANONYMOUS,
1450 buffer->fd, 0);
1451 ASSERT_NE(buffer->ptr, MAP_FAILED);
1452
1453
1454 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
1455 ptr[i] = i;
1456
1457
1458 ret = mprotect(buffer->ptr, size, PROT_READ);
1459 ASSERT_EQ(ret, 0);
1460
1461
1462 ret = hmm_dmirror_cmd(self->fd0, HMM_DMIRROR_READ, buffer, npages);
1463 ASSERT_EQ(ret, 0);
1464 ASSERT_EQ(buffer->cpages, npages);
1465 ASSERT_EQ(buffer->faults, 1);
1466
1467
1468 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
1469 ASSERT_EQ(ptr[i], i);
1470
1471
1472 ret = hmm_dmirror_cmd(self->fd1, HMM_DMIRROR_READ, buffer, npages);
1473 ASSERT_EQ(ret, 0);
1474 ASSERT_EQ(buffer->cpages, npages);
1475 ASSERT_EQ(buffer->faults, 1);
1476
1477
1478 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
1479 ASSERT_EQ(ptr[i], i);
1480
1481
1482 ret = munmap(buffer->ptr + self->page_size, self->page_size);
1483 ASSERT_EQ(ret, 0);
1484
1485 hmm_buffer_free(buffer);
1486}
1487
1488
1489
1490
1491TEST_F(hmm, exclusive)
1492{
1493 struct hmm_buffer *buffer;
1494 unsigned long npages;
1495 unsigned long size;
1496 unsigned long i;
1497 int *ptr;
1498 int ret;
1499
1500 npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
1501 ASSERT_NE(npages, 0);
1502 size = npages << self->page_shift;
1503
1504 buffer = malloc(sizeof(*buffer));
1505 ASSERT_NE(buffer, NULL);
1506
1507 buffer->fd = -1;
1508 buffer->size = size;
1509 buffer->mirror = malloc(size);
1510 ASSERT_NE(buffer->mirror, NULL);
1511
1512 buffer->ptr = mmap(NULL, size,
1513 PROT_READ | PROT_WRITE,
1514 MAP_PRIVATE | MAP_ANONYMOUS,
1515 buffer->fd, 0);
1516 ASSERT_NE(buffer->ptr, MAP_FAILED);
1517
1518
1519 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
1520 ptr[i] = i;
1521
1522
1523 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_EXCLUSIVE, buffer, npages);
1524 ASSERT_EQ(ret, 0);
1525 ASSERT_EQ(buffer->cpages, npages);
1526
1527
1528 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
1529 ASSERT_EQ(ptr[i], i);
1530
1531
1532 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
1533 ASSERT_EQ(ptr[i]++, i);
1534
1535 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
1536 ASSERT_EQ(ptr[i], i+1);
1537
1538
1539 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_CHECK_EXCLUSIVE, buffer, npages);
1540 ASSERT_EQ(ret, 0);
1541
1542 hmm_buffer_free(buffer);
1543}
1544
1545TEST_F(hmm, exclusive_mprotect)
1546{
1547 struct hmm_buffer *buffer;
1548 unsigned long npages;
1549 unsigned long size;
1550 unsigned long i;
1551 int *ptr;
1552 int ret;
1553
1554 npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
1555 ASSERT_NE(npages, 0);
1556 size = npages << self->page_shift;
1557
1558 buffer = malloc(sizeof(*buffer));
1559 ASSERT_NE(buffer, NULL);
1560
1561 buffer->fd = -1;
1562 buffer->size = size;
1563 buffer->mirror = malloc(size);
1564 ASSERT_NE(buffer->mirror, NULL);
1565
1566 buffer->ptr = mmap(NULL, size,
1567 PROT_READ | PROT_WRITE,
1568 MAP_PRIVATE | MAP_ANONYMOUS,
1569 buffer->fd, 0);
1570 ASSERT_NE(buffer->ptr, MAP_FAILED);
1571
1572
1573 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
1574 ptr[i] = i;
1575
1576
1577 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_EXCLUSIVE, buffer, npages);
1578 ASSERT_EQ(ret, 0);
1579 ASSERT_EQ(buffer->cpages, npages);
1580
1581
1582 for (i = 0, ptr = buffer->mirror; i < size / sizeof(*ptr); ++i)
1583 ASSERT_EQ(ptr[i], i);
1584
1585 ret = mprotect(buffer->ptr, size, PROT_READ);
1586 ASSERT_EQ(ret, 0);
1587
1588
1589 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_WRITE, buffer, npages);
1590 ASSERT_EQ(ret, -EPERM);
1591
1592 hmm_buffer_free(buffer);
1593}
1594
1595
1596
1597
1598TEST_F(hmm, exclusive_cow)
1599{
1600 struct hmm_buffer *buffer;
1601 unsigned long npages;
1602 unsigned long size;
1603 unsigned long i;
1604 int *ptr;
1605 int ret;
1606
1607 npages = ALIGN(HMM_BUFFER_SIZE, self->page_size) >> self->page_shift;
1608 ASSERT_NE(npages, 0);
1609 size = npages << self->page_shift;
1610
1611 buffer = malloc(sizeof(*buffer));
1612 ASSERT_NE(buffer, NULL);
1613
1614 buffer->fd = -1;
1615 buffer->size = size;
1616 buffer->mirror = malloc(size);
1617 ASSERT_NE(buffer->mirror, NULL);
1618
1619 buffer->ptr = mmap(NULL, size,
1620 PROT_READ | PROT_WRITE,
1621 MAP_PRIVATE | MAP_ANONYMOUS,
1622 buffer->fd, 0);
1623 ASSERT_NE(buffer->ptr, MAP_FAILED);
1624
1625
1626 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
1627 ptr[i] = i;
1628
1629
1630 ret = hmm_dmirror_cmd(self->fd, HMM_DMIRROR_EXCLUSIVE, buffer, npages);
1631 ASSERT_EQ(ret, 0);
1632 ASSERT_EQ(buffer->cpages, npages);
1633
1634 fork();
1635
1636
1637 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
1638 ASSERT_EQ(ptr[i]++, i);
1639
1640 for (i = 0, ptr = buffer->ptr; i < size / sizeof(*ptr); ++i)
1641 ASSERT_EQ(ptr[i], i+1);
1642
1643 hmm_buffer_free(buffer);
1644}
1645
1646TEST_HARNESS_MAIN
1647