#include #include #include #include #include #include #include #include #include off_t filesize = 0; int fd = -1; unsigned char *control_buf = NULL; const off_t MAX_FILESIZE = 0x40000; static void do_ftruncate(off_t offs) { if (ftruncate(fd, offs) != 0) err(1, "ftruncate"); filesize = offs; } static void do_fspacectl(ssize_t size, off_t offs) { struct spacectl_range rqsr = { .r_offset = offs, .r_len = size, }; struct spacectl_range rmsr; if (0 != fspacectl(fd, SPACECTL_DEALLOC, &rqsr, 0, &rmsr)) err(1, "fspacectl"); assert(0 == rmsr.r_len); assert(offs + size == rmsr.r_offset); memset(control_buf + offs, 0, size); } static void do_mapread(ssize_t size, off_t offs) { unsigned char *p; off_t pg_offset, page_mask; size_t map_size; int i; page_mask = getpagesize() - 1; pg_offset = offs & page_mask; map_size = pg_offset + size; p = mmap(NULL, map_size, PROT_READ, MAP_FILE | MAP_SHARED, fd, offs - pg_offset); if (p == MAP_FAILED) err(1, "mmap"); for (i=0; i < size; i++) { if (*(p + pg_offset + i) != *(control_buf + offs + i)) { errx(1, "miscompare at offset %#lx. " "expected %#02x got %#02x", offs + i, *(control_buf + offs + i), *(p + pg_offset + i)); } } if (munmap(p, map_size) != 0) err(1, "munmap"); free(control_buf); } static void do_mapwrite(ssize_t size, off_t offs) { char *buf; void *p; off_t pg_offset, page_mask; size_t map_size; long i; assert(offs + size <= MAX_FILESIZE); page_mask = getpagesize() - 1; pg_offset = offs & page_mask; map_size = pg_offset + size; buf = (char*)malloc(size); if (buf == NULL) err(1, "malloc"); for (i=0; i < size; i++) buf[i] = random(); if (offs + size > filesize) { /* * Must manually extend. vm_mmap_vnode will not implicitly * extend a vnode */ do_ftruncate(offs + size); } p = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, offs - pg_offset); if (p == MAP_FAILED) err(1, "mmap"); bcopy(buf, (char*)p + pg_offset, size); bcopy(buf, control_buf + offs, size); free(buf); // Uncomment to enable msync, which masks the bug if (msync(p, map_size, MS_SYNC) != 0) err(1, "msync"); if (munmap(p, map_size) != 0) err(1, "munmap"); } int main(int argc, char **argv) { const char *filename; if (argc != 2) { errx(1, "usage: %s ", argv[0]); } filename = argv[1]; fd = open(filename, O_CREAT | O_RDWR | O_TRUNC, 0644); if (fd < 0) err(1, "open"); srandom(12345); control_buf = calloc(MAX_FILESIZE, 1); if (control_buf == NULL) err(1, "calloc"); /* * These three operations suffice to produce miscompare on either * fusefs or UFS, albeit at different offsets. * ZFS, msdosfs, and tmpfs do not seem to be affected. */ do_mapwrite(0xd052, 0xee29); do_fspacectl(0x55b0, 0x16166); do_mapread(0xea1f, 0xbb4e); }