#define _GNU_SOURCE #define _XOPEN_SOURCE 500 #include #include #include #include #include #include #include #include #include #define BUFLEN 4096 static char wistmpfile[] = "/mnt/willitscale.XXXXXX"; char *testcase_description = "mremap"; char *buf; char *newbuf = (char *)0x700000000000; #define FILE_SIZE (4096*128) static void mdelay(int ms) { int i; // gain io permission for the delay assert(ioperm(0x80, 8, 1) == 0); for (i = 0; i < ms; i++) inb(0x80); } void testcase_prepare(void) { int fd = mkstemp(wistmpfile); assert(fd >= 0); assert(pwrite(fd, "X", 1, FILE_SIZE-1) == 1); buf = mmap(NULL, FILE_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); assert(buf != (void *)-1); close(fd); } static volatile int step = 0; void testcase(unsigned long long *iterations) { int cpu = sched_getcpu(); int fd = open(wistmpfile, O_RDWR); off_t offset = sched_getcpu() * BUFLEN; long counterread = 0; long *counterbuf = (void *)&buf[offset]; assert(fd >= 0); printf("cpu%d runs\n", cpu); while (1) { int ret; if (cpu == 0) { void *tmpbuf; // wait for step 1 done while (step < 1); // step 2: start mremap to have the old PTE emptied printf("cpu%d: going to remap\n", cpu); step = 2; tmpbuf = mremap(buf, FILE_SIZE, FILE_SIZE, MREMAP_FIXED | MREMAP_MAYMOVE, newbuf); assert(tmpbuf == newbuf); printf("cpu%d: remap done\n", cpu); pause(); } // step 1: dirty the old PTE *counterbuf = 1; step = 1; while (step < 2); // step 3: clean this page // delay a little while to give mremap some time // to empty the old PTE and setup new PTE mdelay(1000); printf("cpu%d: going to clean the page\n", cpu); posix_fadvise(fd, offset, BUFLEN, POSIX_FADV_DONTNEED); // step 4: now the page is cleaned, its new PTE is // write protected but since mremap didn't flush tlb // for the old PTE yet, we could still access the old // addr and that will not dirty anything printf("cpu%d: going to write 2\n", cpu); *counterbuf = 2; printf("cpu%d wrote 2\n", cpu); // step 5: drop this page from page cache and then // read it back to verify if the last write gets lost // munmap the page first, or the FADV_DONTNEED won't // kick the page out of page cache munmap(newbuf + offset, BUFLEN); posix_fadvise(fd, offset, BUFLEN, POSIX_FADV_DONTNEED); ret = pread(fd, &counterread, sizeof(counterread), offset); assert(ret == sizeof(counterread)); if (counterread != 2) { printf("*cpu%d wrote 2 gets lost\n", cpu); fflush(stdout); } exit(0); } } void testcase_cleanup(void) { unlink(wistmpfile); }