DF-0813 / dirstress_h2.c
/* * DF-0813 targeted: stress a single hammer2 directory to force indirect-block * topology churn (chain parentage changes) concurrent with sync flush. * * The race we want to hit: hammer2_flush.c retry loop (397-406) where * chain->parent becomes NULL during flush_core's unlock window, then the loop * body derefs info.parent at :403(drop)/:405(ref) without a NULL guard. * * Strategy: one shared directory; writers create/delete hundreds of files in it * (forcing block-table growth/shrink => indirect block topology changes => * chain->parent mutations); syncers hammer sync() to drive flush concurrently. */ #include <sys/types.h> #include <sys/stat.h> #include <sys/wait.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <errno.h> #include <time.h> #include <signal.h> static volatile sig_atomic_t g_run=1; static void h(int s){(void)s;g_run=0;} static double now(void){struct timespec ts;clock_gettime(CLOCK_MONOTONIC,&ts);return ts.tv_sec+ts.tv_nsec/1e9;} static void writer(const char *dir,int id){ char p[300]; unsigned long round=0; while(g_run){ int n=200+id*13%200; for(int i=0;i<n&&g_run;i++){ snprintf(p,sizeof(p),"%s/f%d_%lu_%d",dir,id,round,i); int fd=open(p,O_WRONLY|O_CREAT|O_TRUNC,0644); if(fd>=0){ write(fd,p,64); close(fd); } } /* delete half to shrink the dir (topology merge) */ for(int i=0;i<n&&g_run;i+=2){ snprintf(p,sizeof(p),"%s/f%d_%lu_%d",dir,id,round,i); unlink(p); } round++; } fprintf(stderr,"[w%d] %lu rounds\n",id,round); } static void syncer(const char *dir){ unsigned long n=0; while(g_run){ sync(); int fd=open(dir,O_RDONLY); if(fd>=0){fsync(fd);close(fd);} n++; } fprintf(stderr,"[sync] %lu\n",n); } int main(int argc,char**argv){ const char *dir=getenv("H2DIR"); if(!dir) dir="/mnt/h2"; int secs=60, nw=8, ns=3; if(argc>1) dir=argv[1]; if(argc>2) secs=atoi(argv[2]); char *e; if((e=getenv("NW")))nw=atoi(e); if((e=getenv("NS")))ns=atoi(e); if(access(dir,W_OK)<0){perror(dir);return 2;} signal(SIGTERM,h);signal(SIGINT,h); /* clean slate */ fprintf(stderr,"DF-0813 dir-stress dir=%s nw=%d ns=%d secs=%d\n",dir,nw,ns,secs); double t0=now(); pid_t kids[64]; int nk=0; for(int i=0;i<nw&&nk<64;i++){pid_t p=fork();if(!p){writer(dir,i);_exit(0);}if(p>0)kids[nk++]=p;} for(int i=0;i<ns&&nk<64;i++){pid_t p=fork();if(!p){syncer(dir);_exit(0);}if(p>0)kids[nk++]=p;} while(g_run&&(now()-t0)<secs) sleep(1); g_run=0; for(int i=0;i<nk;i++) kill(kids[i],SIGTERM); for(int i=0;i<nk;i++){int st;waitpid(kids[i],&st,0);} fprintf(stderr,"DF-0813 dir-stress done.\n"); return 0; } |