DF-2568 / race_flush_v7.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | /* * DF-2568 — v7: large-file flush race on configurable fs. * * Uses LARGER writes (FILE_KB per file) to force indirect-block chains, * making the downward flush recursion take longer and widening the :662-665 * window for the concurrent unlink to arrive and block on the chain lock. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <signal.h> #include <sys/wait.h> #include <sys/stat.h> #include <errno.h> static volatile sig_atomic_t stop = 0; static void on_alarm(int s){ (void)s;stop=1; } #define BLK 65536 static const char *g_dir; static int g_pool; static int g_filekb; static void dirtier(int id, long iters) { char path[512], *buf; long i; unsigned seed = (unsigned)(id * 7 + 1); int blocks = g_filekb * 1024 / BLK; if (blocks < 1) blocks = 1; buf = malloc(BLK); if (!buf) _exit(1); memset(buf, (char)(id + 0x43), BLK); for (i = 0; i < iters && !stop; i++) { int idx = rand_r(&seed) % g_pool; int fd, b; snprintf(path, sizeof(path), "%s/pool_%d", g_dir, idx); fd = open(path, O_RDWR | O_CREAT, 0666); if (fd < 0) continue; buf[0] = (char)(id ^ i); for (b = 0; b < blocks; b++) write(fd, buf, BLK); fsync(fd); /* dispatches flush xop, BLOCKS — concurrent unlink races */ close(fd); } free(buf); _exit(0); } static void unlinker(int id, long iters) { char path[512]; long i; unsigned seed = (unsigned)(id * 13 + 3); for (i = 0; i < iters && !stop; i++) { int idx = rand_r(&seed) % g_pool; int fd; snprintf(path, sizeof(path), "%s/pool_%d", g_dir, idx); unlink(path); fd = open(path, O_CREAT | O_TRUNC | O_RDWR, 0666); if (fd >= 0) { char c=(char)(id^i); write(fd,&c,1); close(fd); } } _exit(0); } static void syncer(int id, long iters) { long i; for (i = 0; i < iters && !stop; i++) sync(); _exit(0); } int main(int argc, char **argv) { const char *dir = NULL; int ndirty = 12, nunlink = 12, nsync = 4; int pool = 16, filekb = 256; long iters = 99999999; int timeout = 0, opt; while ((opt = getopt(argc, argv, "d:D:U:s:p:f:i:t:")) != -1) { switch (opt) { case 'd': dir = optarg; break; case 'D': ndirty = atoi(optarg); break; case 'U': nunlink = atoi(optarg); break; case 's': nsync = atoi(optarg); break; case 'p': pool = atoi(optarg); break; case 'f': filekb = atoi(optarg); break; case 'i': iters = atol(optarg); break; case 't': timeout = atoi(optarg); break; default: fprintf(stderr,"usage: %s -d dir [-D ndirty] [-U nunlink] [-s nsync] [-p pool] [-f filekb] [-i iters] [-t sec]\n",argv[0]); return 2; } } if (!dir) { fprintf(stderr,"%s: need -d dir\n",argv[0]); return 2; } g_dir = dir; g_pool = pool; g_filekb = filekb; fprintf(stderr,"DF-2568 v7: dir=%s dirty=%d unlink=%d sync=%d pool=%d filekb=%d timeout=%d\n", dir, ndirty, nunlink, nsync, pool, filekb, timeout); /* pre-populate pool with large files */ { char path[512], *buf; int i, fd, b; int blocks = filekb * 1024 / BLK; if (blocks < 1) blocks = 1; buf = malloc(BLK); memset(buf, 'P', BLK); for (i = 0; i < pool; i++) { snprintf(path, sizeof(path), "%s/pool_%d", dir, i); fd = open(path, O_CREAT|O_TRUNC|O_RDWR, 0666); if (fd >= 0) { for (b=0;b<blocks;b++) write(fd,buf,BLK); close(fd); } } free(buf); } signal(SIGALRM, on_alarm); if (timeout > 0) alarm((unsigned)timeout); int nkids = ndirty + nunlink + nsync; pid_t *kids = calloc(nkids, sizeof(pid_t)); int k, ki = 0; for (k=0;k<ndirty;k++){pid_t p=fork();if(p<0){perror("fork");return 1;}if(p==0)dirtier(k,iters);kids[ki++]=p;} for (k=0;k<nunlink;k++){pid_t p=fork();if(p<0){perror("fork");return 1;}if(p==0)unlinker(k,iters);kids[ki++]=p;} for (k=0;k<nsync;k++){pid_t p=fork();if(p<0){perror("fork");return 1;}if(p==0)syncer(k,iters);kids[ki++]=p;} for (k=0;k<nkids;k++) if(kids[k]>0) waitpid(kids[k],NULL,0); fprintf(stderr,"DF-2568 v7: done (no panic)\n"); return 0; } |