root/user/testbin/dirconc/dirconc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. choose_name
  2. say
  3. dorename
  4. domkdir
  5. dormdir
  6. cleanup_rmdir
  7. rename_proc
  8. mkdir_proc
  9. rmdir_proc
  10. dofork
  11. run
  12. setup
  13. recursive_cleanup
  14. cleanup
  15. main

   1 /*
   2  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
   3  *      The President and Fellows of Harvard College.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. Neither the name of the University nor the names of its contributors
  14  *    may be used to endorse or promote products derived from this software
  15  *    without specific prior written permission.
  16  *
  17  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
  18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
  21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27  * SUCH DAMAGE.
  28  */
  29 
  30 /*
  31  * Concurrent directory operations test.
  32  *
  33  * Your system should survive this (without leaving a corrupted file
  34  * system behind) once the file system assignment is complete.
  35  */
  36 
  37 #include <sys/types.h>
  38 #include <sys/wait.h>
  39 #include <sys/stat.h>
  40 #include <errno.h>
  41 #include <stdio.h>
  42 #include <unistd.h>
  43 #include <stdlib.h>
  44 #include <stdarg.h>
  45 #include <string.h>
  46 
  47 #define NTRIES    100   /* loop count */
  48 #define NPROCS    5     /* actually totals 4x this +1 processes */
  49 
  50 #define TESTDIR   "dirconc"
  51 #define NNAMES    4
  52 #define NAMESIZE  32
  53 
  54 ////////////////////////////////////////////////////////////
  55 
  56 static const char *const names[NNAMES] = {
  57         "aaaa", 
  58         "bbbb",
  59         "cccc", 
  60         "dddd",
  61 };
  62 
  63 static
  64 void
  65 choose_name(char *buf, size_t len)
  66 {
  67         const char *a, *b, *c;
  68 
  69         a = names[random()%NNAMES];
  70         if (random()%2==0) {
  71                 snprintf(buf, len, "%s", a);
  72                 return;
  73         }
  74         b = names[random()%NNAMES];
  75         if (random()%2==0) {
  76                 snprintf(buf, len, "%s/%s", a, b);
  77                 return;
  78         }
  79         c = names[random()%NNAMES];
  80         snprintf(buf, len, "%s/%s/%s", a, b, c);
  81 }
  82 
  83 ////////////////////////////////////////////////////////////
  84 
  85 /*
  86  * The purpose of this is to be atomic. In our world, straight
  87  * printf tends not to be.
  88  */
  89 static
  90 void
  91 #ifdef __GNUC__
  92         __attribute__((__format__(__printf__, 1, 2)))
  93 #endif
  94 say(const char *fmt, ...)
  95 {
  96         char buf[512];
  97         va_list ap;
  98         va_start(ap, fmt);
  99         vsnprintf(buf, sizeof(buf), fmt, ap);
 100         va_end(ap);
 101         write(STDOUT_FILENO, buf, strlen(buf));
 102 }
 103 
 104 ////////////////////////////////////////////////////////////
 105 
 106 static
 107 void
 108 dorename(const char *name1, const char *name2)
 109 {
 110         if (rename(name1, name2) < 0) {
 111                 switch (errno) {
 112                     case ENOENT:
 113                     case ENOTEMPTY:
 114                     case EINVAL:
 115                         break;
 116                     default:
 117                         say("pid %d: rename %s -> %s: %s\n", 
 118                             getpid(), name1, name2, strerror(errno));
 119                         break;
 120                 }
 121         }
 122 }
 123 
 124 static
 125 void
 126 domkdir(const char *name)
 127 {
 128         if (mkdir(name, 0775)<0) {
 129                 switch (errno) {
 130                     case ENOENT:
 131                     case EEXIST:
 132                         break;
 133                     default:
 134                         say("pid %d: mkdir %s: %s\n",
 135                             getpid(), name, strerror(errno));
 136                         break;
 137                 }
 138         }
 139 }
 140 
 141 static
 142 void
 143 dormdir(const char *name)
 144 {
 145         if (rmdir(name)<0) {
 146                 switch (errno) {
 147                     case ENOENT:
 148                     case ENOTEMPTY:
 149                         break;
 150                     default:
 151                         say("pid %d: rmdir %s: %s\n",
 152                             getpid(), name, strerror(errno));
 153                         break;
 154                 }
 155         }
 156 }
 157 
 158 static
 159 void
 160 cleanup_rmdir(const char *name)
 161 {
 162         if (rmdir(name)<0) {
 163                 switch (errno) {
 164                     case ENOENT:
 165                         break;
 166                     default:
 167                         say("cleanup (pid %d): rmdir %s: %s\n",
 168                             getpid(), name, strerror(errno));
 169                         break;
 170                 }
 171         }
 172 }
 173 
 174 ////////////////////////////////////////////////////////////
 175 
 176 static
 177 void
 178 rename_proc(void)
 179 {
 180         char name1[NAMESIZE], name2[NAMESIZE];
 181         int ct;
 182         
 183         for (ct=0; ct<NTRIES; ct++) {
 184                 choose_name(name1, sizeof(name1));
 185                 choose_name(name2, sizeof(name2));
 186                 say("pid %2d: rename %s -> %s\n", (int)getpid(), name1, name2);
 187                 dorename(name1, name2);
 188         }
 189 }
 190 
 191 static
 192 void
 193 mkdir_proc(void)
 194 {
 195         char name[NAMESIZE];
 196         int ct;
 197         
 198         for (ct=0; ct<NTRIES; ct++) {
 199                 choose_name(name, sizeof(name));
 200                 say("pid %2d: mkdir  %s\n", (int)getpid(), name);
 201                 domkdir(name);
 202         }
 203 }
 204 
 205 static
 206 void
 207 rmdir_proc(void)
 208 {
 209         char name[NAMESIZE];
 210         int ct;
 211 
 212         for (ct=0; ct<NTRIES; ct++) {
 213                 choose_name(name, sizeof(name));
 214                 say("pid %2d: rmdir  %s\n", (int)getpid(), name);
 215                 dormdir(name);
 216         }
 217 }
 218 
 219 ////////////////////////////////////////////////////////////
 220 
 221 static
 222 pid_t
 223 dofork(void (*func)(void))
 224 {
 225         pid_t pid;
 226 
 227         pid = fork();
 228         if (pid < 0) {
 229                 say("fork: %s\n", strerror(errno));
 230                 return -1;
 231         }
 232         if (pid == 0) {
 233                 /* child */
 234                 func();
 235                 exit(0);
 236         }
 237         return pid;
 238 }
 239 
 240 static
 241 void
 242 run(void)
 243 {
 244         pid_t pids[NPROCS*4], wp;
 245         int i, status;
 246 
 247         for (i=0; i<NPROCS; i++) {
 248                 pids[i*4] = dofork(mkdir_proc);
 249                 pids[i*4+1] = dofork(mkdir_proc);
 250                 pids[i*4+2] = dofork(rename_proc);
 251                 pids[i*4+3] = dofork(rmdir_proc);
 252         }
 253         
 254         for (i=0; i<NPROCS*4; i++) {
 255                 if (pids[i]>=0) {
 256                         wp = waitpid(pids[i], &status, 0);
 257                         if (wp<0) {
 258                                 say("waitpid %d: %s\n", (int) pids[i], 
 259                                     strerror(errno));
 260                         }
 261                         else if (WIFSIGNALED(status)) {
 262                                 say("pid %d: signal %d\n", (int) pids[i],
 263                                     WTERMSIG(status));
 264                         }
 265                         else if (WIFEXITED(status) && WEXITSTATUS(status)!=0) {
 266                                 say("pid %d: exit %d\n", (int) pids[i], 
 267                                     WEXITSTATUS(status));
 268                         }
 269                 }
 270         }
 271 }
 272 
 273 ////////////////////////////////////////////////////////////
 274 
 275 static
 276 void
 277 setup(const char *fs)
 278 {
 279         if (chdir(fs)<0) {
 280                 say("chdir: %s: %s\n", fs, strerror(errno));
 281                 exit(1);
 282         }
 283         if (mkdir(TESTDIR, 0775)<0) {
 284                 say("mkdir: %s: %s\n", TESTDIR, strerror(errno));
 285                 exit(1);
 286         }
 287         if (chdir(TESTDIR)<0) {
 288                 say("chdir: %s: %s\n", TESTDIR, strerror(errno));
 289                 exit(1);
 290         }
 291 }
 292 
 293 static
 294 void
 295 recursive_cleanup(const char *sofar, int depth)
 296 {
 297         char buf[NAMESIZE*32];
 298         int i;
 299         
 300         for (i=0; i<NNAMES; i++) {
 301                 snprintf(buf, sizeof(buf), "%s/%s", sofar, names[i]);
 302                 if (rmdir(buf)<0) {
 303                         if (errno==ENOTEMPTY) {
 304                                 recursive_cleanup(buf, depth+1);
 305                                 cleanup_rmdir(buf);
 306                         }
 307                         else if (errno!=ENOENT) {
 308                                 say("cleanup (pid %d): rmdir %s: %s\n", 
 309                                     getpid(), buf, strerror(errno));
 310                         }
 311                 }
 312         }
 313 }
 314 
 315 static
 316 void
 317 cleanup(void)
 318 {
 319         recursive_cleanup(".", 0);
 320         
 321         chdir("..");
 322         cleanup_rmdir(TESTDIR);
 323 }
 324 
 325 ////////////////////////////////////////////////////////////
 326 
 327 int
 328 main(int argc, char *argv[])
 329 {
 330         const char *fs;
 331         long seed = 0;
 332         
 333         say("Concurrent directory ops test\n");
 334         
 335         if (argc==0 || argv==NULL) {
 336                 say("Warning: argc is 0 - assuming you mean to run on lhd1: "
 337                     "with seed 0\n");
 338                 fs = "lhd1:";
 339         }
 340         else if (argc==2) {
 341                 fs = argv[1];
 342         }
 343         else if (argc==3) {
 344                 fs = argv[1];
 345                 seed = atoi(argv[2]);
 346         }
 347         else {
 348                 say("Usage: dirconc filesystem [random-seed]\n");
 349                 exit(1);
 350         }
 351         
 352         srandom(seed);
 353         setup(fs);
 354         say("Starting in %s/%s\n", fs, TESTDIR);
 355         
 356         run();
 357         
 358         say("Cleaning up\n");
 359         cleanup();
 360         
 361         return 0;
 362 }

/* [<][>][^][v][top][bottom][index][help] */