DF-3071 / df3071d.c
/* DF-3071 - node-limit TOCTOU with per-directory parallelism (avoids the * parent-dnode lock serialization). usage: df3071d <mnt> <ndirs> <prefill_per_dir> <nthreads> */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <fcntl.h> #include <unistd.h> #include <pthread.h> static pthread_barrier_t bar; static char dirp[512]; static int ndirs; static volatile int go=0; static long total=0; static pthread_mutex_t mx=PTHREAD_MUTEX_INITIALIZER; static void *w(void *arg){ long id=(long)arg; char p[600]; pthread_barrier_wait(&bar); snprintf(p,sizeof p,"%s/d%d/b%ld",dirp,(int)(id%ndirs),id); int fd=open(p,O_CREAT|O_EXCL,0644); int ok=(fd>=0); if(fd>=0) close(fd); pthread_mutex_lock(&mx); total+=ok; pthread_mutex_unlock(&mx); return NULL; } int main(int argc,char**argv){ pthread_t th[128]; long i,n; char p[600]; int d,f; if(argc!=5){fprintf(stderr,"usage: df3071d mnt ndirs prefill_per_dir nthreads\n");return 2;} snprintf(dirp,sizeof dirp,"%s",argv[1]); ndirs=atoi(argv[2]); int pre=atoi(argv[3]); n=atol(argv[4]); if(n>128)n=128; long nodes=1; /* root */ for(d=0;d<ndirs;d++){ snprintf(p,sizeof p,"%s/d%d",dirp,d); if(mkdir(p,0777)==0) nodes++; for(f=0;f<pre;f++){ char q[640]; snprintf(q,sizeof q,"%s/p%d",p,f); int fd=open(q,O_CREAT|O_EXCL,0644); if(fd>=0){close(fd);nodes++;} } } pthread_barrier_init(&bar,NULL,n+1); for(i=0;i<n;i++) pthread_create(&th[i],NULL,w,(void*)i); pthread_barrier_wait(&bar); for(i=0;i<n;i++) pthread_join(th[i],NULL); printf("PREFILL_NODES=%ld BURST_OK=%ld CAP=67 => FINAL=%ld %s\n", nodes,total,nodes+total,(nodes+total>67)?"OVERSHOOT":"at-or-below-cap"); return 0; } |