00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include <sys/types.h>
00038 #include <sys/wait.h>
00039 #include <sys/stat.h>
00040 #include <errno.h>
00041 #include <stdio.h>
00042 #include <unistd.h>
00043 #include <stdlib.h>
00044 #include <stdarg.h>
00045 #include <string.h>
00046
00047 #define NTRIES 100
00048 #define NPROCS 5
00049
00050 #define TESTDIR "dirconc"
00051 #define NNAMES 4
00052 #define NAMESIZE 32
00053
00054
00055
00056 static const char *const names[NNAMES] = {
00057 "aaaa",
00058 "bbbb",
00059 "cccc",
00060 "dddd",
00061 };
00062
00063 static
00064 void
00065 choose_name(char *buf, size_t len)
00066 {
00067 const char *a, *b, *c;
00068
00069 a = names[random()%NNAMES];
00070 if (random()%2==0) {
00071 snprintf(buf, len, "%s", a);
00072 return;
00073 }
00074 b = names[random()%NNAMES];
00075 if (random()%2==0) {
00076 snprintf(buf, len, "%s/%s", a, b);
00077 return;
00078 }
00079 c = names[random()%NNAMES];
00080 snprintf(buf, len, "%s/%s/%s", a, b, c);
00081 }
00082
00083
00084
00085
00086
00087
00088
00089 static
00090 void
00091 #ifdef __GNUC__
00092 __attribute__((__format__(__printf__, 1, 2)))
00093 #endif
00094 say(const char *fmt, ...)
00095 {
00096 char buf[512];
00097 va_list ap;
00098 va_start(ap, fmt);
00099 vsnprintf(buf, sizeof(buf), fmt, ap);
00100 va_end(ap);
00101 write(STDOUT_FILENO, buf, strlen(buf));
00102 }
00103
00104
00105
00106 static
00107 void
00108 dorename(const char *name1, const char *name2)
00109 {
00110 if (rename(name1, name2) < 0) {
00111 switch (errno) {
00112 case ENOENT:
00113 case ENOTEMPTY:
00114 case EINVAL:
00115 break;
00116 default:
00117 say("pid %d: rename %s -> %s: %s\n",
00118 getpid(), name1, name2, strerror(errno));
00119 break;
00120 }
00121 }
00122 }
00123
00124 static
00125 void
00126 domkdir(const char *name)
00127 {
00128 if (mkdir(name, 0775)<0) {
00129 switch (errno) {
00130 case ENOENT:
00131 case EEXIST:
00132 break;
00133 default:
00134 say("pid %d: mkdir %s: %s\n",
00135 getpid(), name, strerror(errno));
00136 break;
00137 }
00138 }
00139 }
00140
00141 static
00142 void
00143 dormdir(const char *name)
00144 {
00145 if (rmdir(name)<0) {
00146 switch (errno) {
00147 case ENOENT:
00148 case ENOTEMPTY:
00149 break;
00150 default:
00151 say("pid %d: rmdir %s: %s\n",
00152 getpid(), name, strerror(errno));
00153 break;
00154 }
00155 }
00156 }
00157
00158 static
00159 void
00160 cleanup_rmdir(const char *name)
00161 {
00162 if (rmdir(name)<0) {
00163 switch (errno) {
00164 case ENOENT:
00165 break;
00166 default:
00167 say("cleanup (pid %d): rmdir %s: %s\n",
00168 getpid(), name, strerror(errno));
00169 break;
00170 }
00171 }
00172 }
00173
00174
00175
00176 static
00177 void
00178 rename_proc(void)
00179 {
00180 char name1[NAMESIZE], name2[NAMESIZE];
00181 int ct;
00182
00183 for (ct=0; ct<NTRIES; ct++) {
00184 choose_name(name1, sizeof(name1));
00185 choose_name(name2, sizeof(name2));
00186 say("pid %2d: rename %s -> %s\n", (int)getpid(), name1, name2);
00187 dorename(name1, name2);
00188 }
00189 }
00190
00191 static
00192 void
00193 mkdir_proc(void)
00194 {
00195 char name[NAMESIZE];
00196 int ct;
00197
00198 for (ct=0; ct<NTRIES; ct++) {
00199 choose_name(name, sizeof(name));
00200 say("pid %2d: mkdir %s\n", (int)getpid(), name);
00201 domkdir(name);
00202 }
00203 }
00204
00205 static
00206 void
00207 rmdir_proc(void)
00208 {
00209 char name[NAMESIZE];
00210 int ct;
00211
00212 for (ct=0; ct<NTRIES; ct++) {
00213 choose_name(name, sizeof(name));
00214 say("pid %2d: rmdir %s\n", (int)getpid(), name);
00215 dormdir(name);
00216 }
00217 }
00218
00219
00220
00221 static
00222 pid_t
00223 dofork(void (*func)(void))
00224 {
00225 pid_t pid;
00226
00227 pid = fork();
00228 if (pid < 0) {
00229 say("fork: %s\n", strerror(errno));
00230 return -1;
00231 }
00232 if (pid == 0) {
00233
00234 func();
00235 exit(0);
00236 }
00237 return pid;
00238 }
00239
00240 static
00241 void
00242 run(void)
00243 {
00244 pid_t pids[NPROCS*4], wp;
00245 int i, status;
00246
00247 for (i=0; i<NPROCS; i++) {
00248 pids[i*4] = dofork(mkdir_proc);
00249 pids[i*4+1] = dofork(mkdir_proc);
00250 pids[i*4+2] = dofork(rename_proc);
00251 pids[i*4+3] = dofork(rmdir_proc);
00252 }
00253
00254 for (i=0; i<NPROCS*4; i++) {
00255 if (pids[i]>=0) {
00256 wp = waitpid(pids[i], &status, 0);
00257 if (wp<0) {
00258 say("waitpid %d: %s\n", (int) pids[i],
00259 strerror(errno));
00260 }
00261 else if (WIFSIGNALED(status)) {
00262 say("pid %d: signal %d\n", (int) pids[i],
00263 WTERMSIG(status));
00264 }
00265 else if (WIFEXITED(status) && WEXITSTATUS(status)!=0) {
00266 say("pid %d: exit %d\n", (int) pids[i],
00267 WEXITSTATUS(status));
00268 }
00269 }
00270 }
00271 }
00272
00273
00274
00275 static
00276 void
00277 setup(const char *fs)
00278 {
00279 if (chdir(fs)<0) {
00280 say("chdir: %s: %s\n", fs, strerror(errno));
00281 exit(1);
00282 }
00283 if (mkdir(TESTDIR, 0775)<0) {
00284 say("mkdir: %s: %s\n", TESTDIR, strerror(errno));
00285 exit(1);
00286 }
00287 if (chdir(TESTDIR)<0) {
00288 say("chdir: %s: %s\n", TESTDIR, strerror(errno));
00289 exit(1);
00290 }
00291 }
00292
00293 static
00294 void
00295 recursive_cleanup(const char *sofar, int depth)
00296 {
00297 char buf[NAMESIZE*32];
00298 int i;
00299
00300 for (i=0; i<NNAMES; i++) {
00301 snprintf(buf, sizeof(buf), "%s/%s", sofar, names[i]);
00302 if (rmdir(buf)<0) {
00303 if (errno==ENOTEMPTY) {
00304 recursive_cleanup(buf, depth+1);
00305 cleanup_rmdir(buf);
00306 }
00307 else if (errno!=ENOENT) {
00308 say("cleanup (pid %d): rmdir %s: %s\n",
00309 getpid(), buf, strerror(errno));
00310 }
00311 }
00312 }
00313 }
00314
00315 static
00316 void
00317 cleanup(void)
00318 {
00319 recursive_cleanup(".", 0);
00320
00321 chdir("..");
00322 cleanup_rmdir(TESTDIR);
00323 }
00324
00325
00326
00327 int
00328 main(int argc, char *argv[])
00329 {
00330 const char *fs;
00331 long seed = 0;
00332
00333 say("Concurrent directory ops test\n");
00334
00335 if (argc==0 || argv==NULL) {
00336 say("Warning: argc is 0 - assuming you mean to run on lhd1: "
00337 "with seed 0\n");
00338 fs = "lhd1:";
00339 }
00340 else if (argc==2) {
00341 fs = argv[1];
00342 }
00343 else if (argc==3) {
00344 fs = argv[1];
00345 seed = atoi(argv[2]);
00346 }
00347 else {
00348 say("Usage: dirconc filesystem [random-seed]\n");
00349 exit(1);
00350 }
00351
00352 srandom(seed);
00353 setup(fs);
00354 say("Starting in %s/%s\n", fs, TESTDIR);
00355
00356 run();
00357
00358 say("Cleaning up\n");
00359 cleanup();
00360
00361 return 0;
00362 }