dirconc.c 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  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. * Concurrent directory operations test.
  31. *
  32. * Your system should survive this (without leaving a corrupted file
  33. * system behind) once the file system assignment is complete.
  34. */
  35. #include <sys/types.h>
  36. #include <sys/wait.h>
  37. #include <sys/stat.h>
  38. #include <errno.h>
  39. #include <stdio.h>
  40. #include <unistd.h>
  41. #include <stdlib.h>
  42. #include <stdarg.h>
  43. #include <string.h>
  44. #define NTRIES 100 /* loop count */
  45. #define NPROCS 5 /* actually totals 4x this +1 processes */
  46. #define TESTDIR "dirconc"
  47. #define NNAMES 4
  48. #define NAMESIZE 32
  49. ////////////////////////////////////////////////////////////
  50. static const char *const names[NNAMES] = {
  51. "aaaa",
  52. "bbbb",
  53. "cccc",
  54. "dddd",
  55. };
  56. static
  57. void
  58. choose_name(char *buf, size_t len)
  59. {
  60. const char *a, *b, *c;
  61. a = names[random()%NNAMES];
  62. if (random()%2==0) {
  63. snprintf(buf, len, "%s", a);
  64. return;
  65. }
  66. b = names[random()%NNAMES];
  67. if (random()%2==0) {
  68. snprintf(buf, len, "%s/%s", a, b);
  69. return;
  70. }
  71. c = names[random()%NNAMES];
  72. snprintf(buf, len, "%s/%s/%s", a, b, c);
  73. }
  74. ////////////////////////////////////////////////////////////
  75. /*
  76. * The purpose of this is to be atomic. In our world, straight
  77. * printf tends not to be.
  78. */
  79. static
  80. void
  81. #ifdef __GNUC__
  82. __attribute__((__format__(__printf__, 1, 2)))
  83. #endif
  84. say(const char *fmt, ...)
  85. {
  86. char buf[512];
  87. va_list ap;
  88. va_start(ap, fmt);
  89. vsnprintf(buf, sizeof(buf), fmt, ap);
  90. va_end(ap);
  91. write(STDOUT_FILENO, buf, strlen(buf));
  92. }
  93. ////////////////////////////////////////////////////////////
  94. static
  95. void
  96. dorename(const char *name1, const char *name2)
  97. {
  98. if (rename(name1, name2) < 0) {
  99. switch (errno) {
  100. case ENOENT:
  101. case ENOTEMPTY:
  102. case EINVAL:
  103. break;
  104. default:
  105. say("pid %d: rename %s -> %s: %s\n",
  106. getpid(), name1, name2, strerror(errno));
  107. break;
  108. }
  109. }
  110. }
  111. static
  112. void
  113. domkdir(const char *name)
  114. {
  115. if (mkdir(name, 0775)<0) {
  116. switch (errno) {
  117. case ENOENT:
  118. case EEXIST:
  119. break;
  120. default:
  121. say("pid %d: mkdir %s: %s\n",
  122. getpid(), name, strerror(errno));
  123. break;
  124. }
  125. }
  126. }
  127. static
  128. void
  129. dormdir(const char *name)
  130. {
  131. if (rmdir(name)<0) {
  132. switch (errno) {
  133. case ENOENT:
  134. case ENOTEMPTY:
  135. break;
  136. default:
  137. say("pid %d: rmdir %s: %s\n",
  138. getpid(), name, strerror(errno));
  139. break;
  140. }
  141. }
  142. }
  143. static
  144. void
  145. cleanup_rmdir(const char *name)
  146. {
  147. if (rmdir(name)<0) {
  148. switch (errno) {
  149. case ENOENT:
  150. break;
  151. default:
  152. say("cleanup (pid %d): rmdir %s: %s\n",
  153. getpid(), name, strerror(errno));
  154. break;
  155. }
  156. }
  157. }
  158. ////////////////////////////////////////////////////////////
  159. static
  160. void
  161. rename_proc(void)
  162. {
  163. char name1[NAMESIZE], name2[NAMESIZE];
  164. int ct;
  165. for (ct=0; ct<NTRIES; ct++) {
  166. choose_name(name1, sizeof(name1));
  167. choose_name(name2, sizeof(name2));
  168. say("pid %2d: rename %s -> %s\n", (int)getpid(), name1, name2);
  169. dorename(name1, name2);
  170. }
  171. }
  172. static
  173. void
  174. mkdir_proc(void)
  175. {
  176. char name[NAMESIZE];
  177. int ct;
  178. for (ct=0; ct<NTRIES; ct++) {
  179. choose_name(name, sizeof(name));
  180. say("pid %2d: mkdir %s\n", (int)getpid(), name);
  181. domkdir(name);
  182. }
  183. }
  184. static
  185. void
  186. rmdir_proc(void)
  187. {
  188. char name[NAMESIZE];
  189. int ct;
  190. for (ct=0; ct<NTRIES; ct++) {
  191. choose_name(name, sizeof(name));
  192. say("pid %2d: rmdir %s\n", (int)getpid(), name);
  193. dormdir(name);
  194. }
  195. }
  196. ////////////////////////////////////////////////////////////
  197. static
  198. pid_t
  199. dofork(void (*func)(void))
  200. {
  201. pid_t pid;
  202. pid = fork();
  203. if (pid < 0) {
  204. say("fork: %s\n", strerror(errno));
  205. return -1;
  206. }
  207. if (pid == 0) {
  208. /* child */
  209. func();
  210. exit(0);
  211. }
  212. return pid;
  213. }
  214. static
  215. void
  216. run(void)
  217. {
  218. pid_t pids[NPROCS*4], wp;
  219. int i, status;
  220. for (i=0; i<NPROCS; i++) {
  221. pids[i*4] = dofork(mkdir_proc);
  222. pids[i*4+1] = dofork(mkdir_proc);
  223. pids[i*4+2] = dofork(rename_proc);
  224. pids[i*4+3] = dofork(rmdir_proc);
  225. }
  226. for (i=0; i<NPROCS*4; i++) {
  227. if (pids[i]>=0) {
  228. wp = waitpid(pids[i], &status, 0);
  229. if (wp<0) {
  230. say("waitpid %d: %s\n", (int) pids[i],
  231. strerror(errno));
  232. }
  233. else if (WIFSIGNALED(status)) {
  234. say("pid %d: signal %d\n", (int) pids[i],
  235. WTERMSIG(status));
  236. }
  237. else if (WIFEXITED(status) && WEXITSTATUS(status)!=0) {
  238. say("pid %d: exit %d\n", (int) pids[i],
  239. WEXITSTATUS(status));
  240. }
  241. }
  242. }
  243. }
  244. ////////////////////////////////////////////////////////////
  245. static
  246. void
  247. setup(const char *fs)
  248. {
  249. if (chdir(fs)<0) {
  250. say("chdir: %s: %s\n", fs, strerror(errno));
  251. exit(1);
  252. }
  253. if (mkdir(TESTDIR, 0775)<0) {
  254. say("mkdir: %s: %s\n", TESTDIR, strerror(errno));
  255. exit(1);
  256. }
  257. if (chdir(TESTDIR)<0) {
  258. say("chdir: %s: %s\n", TESTDIR, strerror(errno));
  259. exit(1);
  260. }
  261. }
  262. static
  263. void
  264. recursive_cleanup(const char *sofar, int depth)
  265. {
  266. char buf[NAMESIZE*32];
  267. int i;
  268. for (i=0; i<NNAMES; i++) {
  269. snprintf(buf, sizeof(buf), "%s/%s", sofar, names[i]);
  270. if (rmdir(buf)<0) {
  271. if (errno==ENOTEMPTY) {
  272. recursive_cleanup(buf, depth+1);
  273. cleanup_rmdir(buf);
  274. }
  275. else if (errno!=ENOENT) {
  276. say("cleanup (pid %d): rmdir %s: %s\n",
  277. getpid(), buf, strerror(errno));
  278. }
  279. }
  280. }
  281. }
  282. static
  283. void
  284. cleanup(void)
  285. {
  286. recursive_cleanup(".", 0);
  287. chdir("..");
  288. cleanup_rmdir(TESTDIR);
  289. }
  290. ////////////////////////////////////////////////////////////
  291. int
  292. main(int argc, char *argv[])
  293. {
  294. const char *fs;
  295. long seed = 0;
  296. say("Concurrent directory ops test\n");
  297. if (argc==0 || argv==NULL) {
  298. say("Warning: argc is 0 - assuming you mean to run on lhd1: "
  299. "with seed 0\n");
  300. fs = "lhd1:";
  301. }
  302. else if (argc==2) {
  303. fs = argv[1];
  304. }
  305. else if (argc==3) {
  306. fs = argv[1];
  307. seed = atoi(argv[2]);
  308. }
  309. else {
  310. say("Usage: dirconc filesystem [random-seed]\n");
  311. exit(1);
  312. }
  313. srandom(seed);
  314. setup(fs);
  315. say("Starting in %s/%s\n", fs, TESTDIR);
  316. run();
  317. say("Cleaning up\n");
  318. cleanup();
  319. return 0;
  320. }