#define _GNU_SOURCE #include #include #include #include #include #include #include /* * the 'abusive' case is where we * grow the file via pwrite * unmap the previous mapping, * do the new mapping * * the non-abusive case we * unmap the previous mapping * grow the file * do the new mapping * * the difference being that in the abusive case, * we maintain a mapping during the pwrite. * * If we grow the file via pwrite and maintain a * mapping, the mapped pages are never written out. * * If we either grow the file via ftruncate or remove * old mappings before growing the file, then all is * fine. */ #ifdef ABUSE #define UNMAP_AFTER() munmap(mapping, size) #define UNMAP_BEFORE() struct eat_semi #else #define UNMAP_AFTER() struct eat_semi #define UNMAP_BEFORE() munmap(mapping, size) #endif int main(int argc, char* argv[]) { int fd; unsigned int const size = 4096 * 1024; unsigned int offset = 0; if (argc != 2) { printf("usage: %s \n", argv[0]); return 0; } fd = open(argv[1], O_RDWR | O_CREAT | O_TRUNC | O_LARGEFILE | O_DIRECT, 0644); if (fd < 0) { perror("open"); return 0; } pwrite64(fd, "", 1, offset + size); //ftruncate64(fd, offset + size); char* mapping = (char*)mmap64(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset); memset(mapping, 'a', size); UNMAP_BEFORE(); for (;;) { offset += size; pwrite64(fd, "", 1, offset + size); //ftruncate64(fd, offset + size); UNMAP_AFTER(); mapping = (char*)mmap64(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset); memset(mapping, 'a', size); UNMAP_BEFORE(); } close(fd); return 0; }