Use xfs.h rather than libxfs.h
[xfstests-dev.git] / src / dirstress.c
1 /*
2  * Copyright (c) 2000-2001 Silicon Graphics, Inc.
3  * All Rights Reserved.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it would be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write the Free Software Foundation,
16  * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18  
19  /*
20   * This is mostly a "crash & burn" test. -v turns on verbosity
21   * and -c actually fails on errors - but expected errors aren't
22   * expected...
23   */
24  
25 #include "global.h"
26
27 int verbose;
28 int pid;
29
30 int checkflag=0;
31
32 #define MKNOD_DEV 0
33
34 static int dirstress(char *dirname, int dirnum, int nfiles, int keep, int nprocs_per_dir);
35 static int create_entries(int nfiles);
36 static int scramble_entries(int nfiles);
37 static int remove_entries(int nfiles);
38
39 int
40 main(
41         int     argc,
42         char    *argv[])
43 {
44         char    *dirname;
45         int     nprocs;
46         int     nfiles;
47         int     c;
48         int     errflg;
49         int     i;
50         long    seed;
51         int     childpid;
52         int     nprocs_per_dir;
53         int     keep;
54         int     status, istatus;
55         
56         pid=getpid();
57
58         errflg = 0;
59         dirname = NULL;
60         nprocs = 4;
61         nfiles = 100;
62         seed = time(NULL);
63         nprocs_per_dir = 1;
64         keep = 0;
65         verbose = 0;
66         while ((c = getopt(argc, argv, "d:p:f:s:n:kvc")) != EOF) {
67                 switch(c) {
68                         case 'p':
69                                 nprocs = atoi(optarg);
70                                 break;
71                         case 'f':
72                                 nfiles = atoi(optarg);
73                                 break;
74                         case 'n':
75                                 nprocs_per_dir = atoi(optarg);
76                                 break;
77                         case 'd':
78                                 dirname = optarg;
79                                 break;
80                         case 's':
81                                 seed = strtol(optarg, NULL, 0);
82                                 break;
83                         case 'k':
84                                 keep = 1;
85                                 break;
86                         case '?':
87                                 errflg++;
88                                 break;
89                         case 'v':
90                                 verbose++;
91                                 break;
92                         case 'c':
93                                 checkflag++;
94                                 break;
95                 }
96         }
97         if (errflg || (dirname == NULL)) {
98                 printf("Usage: dirstress [-d dir] [-p nprocs] [-f nfiles] [-n procs per dir]\n"
99                        "                 [-v] [-s seed] [-k] [-c]\n");
100                 exit(0); 
101         }
102
103         printf("** [%d] Using seed %ld\n", pid, seed);
104         srandom(seed);
105
106         for (i = 0; i < nprocs; i++) {
107                 if (verbose) fprintf(stderr,"** [%d] fork\n", pid);
108                 childpid = fork();
109                 if (childpid < 0) {
110                         perror("Fork failed");
111                         exit(errno);
112                 }
113                 if (childpid == 0) {
114                         int r;
115                         /* child */
116                         pid=getpid();
117                         
118                         if (verbose) fprintf(stderr,"** [%d] forked\n", pid);
119                         r=dirstress(dirname, i / nprocs_per_dir, nfiles, keep, nprocs_per_dir);
120                         if (verbose) fprintf(stderr,"** [%d] exit %d\n", pid, r);
121                         exit(r);
122                 }
123         }
124         if (verbose) fprintf(stderr,"** [%d] wait\n", pid);
125         istatus=0;
126         
127         /* wait & reap children, accumulating error results */
128         while (wait(&status) != -1)
129             istatus+=status/256;
130         
131         printf("INFO: Dirstress complete\n");
132         if (verbose) fprintf(stderr,"** [%d] parent exit %d\n", pid, istatus);
133         return istatus;
134 }
135
136
137
138 int
139 dirstress(
140         char    *dirname,
141         int     dirnum,
142         int     nfiles,
143         int     keep,
144         int     nprocs_per_dir)
145 {
146         int             error;
147         char            buf[1024];
148         int             r;
149         
150         sprintf(buf, "%s/stressdir", dirname);
151         if (verbose) fprintf(stderr,"** [%d] mkdir %s 0777\n", pid, buf);
152         error = mkdir(buf, 0777);
153         if (error && (errno != EEXIST)) {
154                 perror("Create stressdir directory failed");
155                 return 1;
156         }
157
158         if (verbose) fprintf(stderr,"** [%d] chdir %s\n", pid, buf);
159         error = chdir(buf);
160         if (error) {
161                 perror("Cannot chdir to main directory");
162                 return 1;
163         }
164
165         sprintf(buf, "stress.%d", dirnum);
166         if (verbose) fprintf(stderr,"** [%d] mkdir %s 0777\n", pid, buf);
167         error = mkdir(buf, 0777);
168         if (error && (errno != EEXIST)) {
169                 perror("Create pid directory failed");
170                 return 1;
171         }
172
173         if (verbose) fprintf(stderr,"** [%d] chdir %s\n", pid, buf);
174         error = chdir(buf);
175         if (error) {
176                 perror("Cannot chdir to dirnum directory");
177                 return 1;
178         }
179
180         r=1; /* assume failure */
181         if (verbose) fprintf(stderr,"** [%d] create entries\n", pid);
182         if (create_entries(nfiles)) {
183             printf("!! [%d] create failed\n", pid);
184         } else {
185             if (verbose) fprintf(stderr,"** [%d] scramble entries\n", pid);
186             if (scramble_entries(nfiles)) {
187                 printf("!! [%d] scramble failed\n", pid);
188             } else {
189                 if (keep) {
190                     if (verbose) fprintf(stderr,"** [%d] keep entries\n", pid);
191                     r=0; /* success */
192                 } else {
193                     if (verbose) fprintf(stderr,"** [%d] remove entries\n", pid);
194                     if (remove_entries(nfiles)) {
195                         printf("!! [%d] remove failed\n", pid);
196                     } else {
197                         r=0; /* success */
198                     }
199                 }
200             }
201         }
202
203         if (verbose) fprintf(stderr,"** [%d] chdir ..\n", pid);
204         error = chdir("..");
205         if (error) {
206                 /* If this is multithreaded, then expecting a ENOENT here is fine */
207                 if (nprocs_per_dir > 1 && errno == ENOENT) {
208                         return 0;
209                 }
210
211                 perror("Cannot chdir out of pid directory");
212                 return 1;
213         }
214
215         if (!keep) {
216                 sprintf(buf, "stress.%d", dirnum);
217                 if (verbose) fprintf(stderr,"** [%d] rmdir %s\n", pid, buf);
218                 if (rmdir(buf)) {
219                     perror("rmdir");
220                     if (checkflag) return 1;
221                 }
222         }
223         
224         if (verbose) fprintf(stderr,"** [%d] chdir ..\n", pid);
225         error = chdir("..");
226         if (error) {
227                 /* If this is multithreaded, then expecting a ENOENT here is fine */
228                 if (nprocs_per_dir > 1 && errno == ENOENT) {
229                         return 0;
230                 }
231
232                 perror("Cannot chdir out of working directory");
233                 return 1;
234         }
235
236         if (!keep) {
237                 if (verbose) fprintf(stderr,"** [%d] rmdir stressdir\n", pid);
238                 if (rmdir("stressdir")) {
239                     perror("rmdir");
240                     if (checkflag) return 1;
241                 }
242         }
243
244         return r;
245 }
246
247 int
248 create_entries(
249        int      nfiles)
250 {
251         int     i;
252         int     fd;
253         char    buf[1024];
254
255         for (i = 0; i < nfiles; i++) {
256                 sprintf(buf, "XXXXXXXXXXXX.%d", i);
257                 switch (i % 4) {
258                 case 0:
259                         /*
260                          * Create a file
261                          */
262                         if (verbose) fprintf(stderr,"** [%d] creat %s\n", pid, buf);
263                         fd = creat(buf, 0666);
264                         if (fd > 0) {
265                                 if (verbose) fprintf(stderr,"** [%d] close %s\n", pid, buf);
266                                 close(fd);
267                         } else {
268                                 fprintf(stderr,"!! [%d] close %s failed\n", pid, buf);
269                                 perror("close");
270                                 if (checkflag) return 1;
271                         }
272                         
273                         break;
274                 case 1:
275                         /*
276                          * Make a directory.
277                          */
278                         if (verbose) fprintf(stderr,"** [%d] mkdir %s 0777\n", pid, buf);
279                         if (mkdir(buf, 0777)) {
280                             fprintf(stderr,"!! [%d] mkdir %s 0777 failed\n", pid, buf);
281                             perror("mkdir");
282                             if (checkflag) return 1;
283                         }
284                         
285                         break;
286                 case 2:
287                         /*
288                          * Make a symlink
289                          */
290                         if (verbose) fprintf(stderr,"** [%d] symlink %s %s\n", pid, buf, buf);
291                         if (symlink(buf, buf)) {
292                             fprintf(stderr,"!! [%d] symlink %s %s failed\n", pid, buf, buf);
293                             perror("symlink");
294                             if (checkflag) return 1;
295                         }
296                         
297                         break;
298                 case 3:
299                         /*
300                          * Make a dev node
301                          */
302                         if (verbose) fprintf(stderr,"** [%d] mknod %s 0x%x\n", pid, buf, MKNOD_DEV);
303                         if (mknod(buf, S_IFCHR | 0666, MKNOD_DEV)) {
304                             fprintf(stderr,"!! [%d] mknod %s 0x%x failed\n", pid, buf, MKNOD_DEV);
305                             perror("mknod");
306                             if (checkflag) return 1;
307                         }
308                         
309                         break;
310                 default:
311                         break;
312                 }
313         }
314         return 0;
315 }
316
317
318 int
319 scramble_entries(
320         int     nfiles)
321 {
322         int             i;
323         char            buf[1024];
324         char            buf1[1024];
325         long            r;
326         int             fd;
327
328         for (i = 0; i < nfiles * 2; i++) {
329                 switch (i % 5) {
330                 case 0:
331                         /*
332                          * rename two random entries
333                          */
334                         r = random() % nfiles;
335                         sprintf(buf, "XXXXXXXXXXXX.%ld", r);
336                         r = random() % nfiles;
337                         sprintf(buf1, "XXXXXXXXXXXX.%ld", r);
338
339                         if (verbose) fprintf(stderr,"** [%d] rename %s %s\n", pid, buf, buf1);
340                         if (rename(buf, buf1)) {
341                             perror("rename");
342                             if (checkflag) return 1;
343                         }
344                         break;
345                 case 1:
346                         /*
347                          * unlink a random entry
348                          */
349                         r = random() % nfiles;
350                         sprintf(buf, "XXXXXXXXXXXX.%ld", r);
351                         if (verbose) fprintf(stderr,"** [%d] unlink %s\n", pid, buf);
352                         if (unlink(buf)) {
353                             fprintf(stderr,"!! [%d] unlink %s failed\n", pid, buf);
354                             perror("unlink");
355                             if (checkflag) return 1;
356                         }
357                         break;
358                 case 2:
359                         /*
360                          * rmdir a random entry
361                          */
362                         r = random() % nfiles;
363                         sprintf(buf, "XXXXXXXXXXXX.%ld", r);
364                         if (verbose) fprintf(stderr,"** [%d] rmdir %s\n", pid, buf);
365                         if (rmdir(buf)) {
366                             fprintf(stderr,"!! [%d] rmdir %s failed\n", pid, buf);
367                             perror("rmdir");
368                             if (checkflag) return 1;
369                         }
370                         break;
371                 case 3:
372                         /*
373                          * create a random entry
374                          */
375                         r = random() % nfiles;
376                         sprintf(buf, "XXXXXXXXXXXX.%ld", r);
377
378                         if (verbose) fprintf(stderr,"** [%d] creat %s 0666\n", pid, buf);
379                         fd = creat(buf, 0666);
380                         if (fd > 0) {
381                                 if (verbose) fprintf(stderr,"** [%d] close %s\n", pid, buf);
382                                 if (close(fd)) {
383                                     fprintf(stderr,"!! [%d] close %s failed\n", pid, buf);
384                                     perror("close");
385                                     if (checkflag) return 1;
386                                 }
387                         } else {
388                             fprintf(stderr,"!! [%d] creat %s 0666 failed\n", pid, buf);
389                             perror("creat");
390                             if (checkflag) return 1;
391                         }
392                         break;
393                 case 4:
394                         /*
395                          * mkdir a random entry
396                          */
397                         r = random() % nfiles;
398                         sprintf(buf, "XXXXXXXXXXXX.%ld", r);
399                         if (verbose) fprintf(stderr,"** [%d] mkdir %s\n", pid, buf);
400                         if (mkdir(buf, 0777)) {
401                             fprintf(stderr,"!! [%d] mkdir %s failed\n", pid, buf);
402                             perror("mkdir");
403                             if (checkflag) return 1;
404                         }
405                         break;
406                 default:
407                         break;
408                 }
409         }
410         return 0;
411 }
412                         
413 int
414 remove_entries(
415         int     nfiles)
416 {
417         int             i;
418         char            buf[1024];
419         struct stat     statb;
420         int             error;
421
422         for (i = 0; i < nfiles; i++) {
423                 sprintf(buf, "XXXXXXXXXXXX.%d", i);
424                 error = lstat(buf, &statb);
425                 if (error) {
426                         /* ignore this one */
427                         continue;
428                 }
429                 if (S_ISDIR(statb.st_mode)) {
430                         if (verbose) fprintf(stderr,"** [%d] rmdir %s\n", pid, buf);
431                         if (rmdir(buf)) {
432                             fprintf(stderr,"!! [%d] rmdir %s failed\n", pid, buf);
433                             perror("rmdir");
434                             if (checkflag) return 1;
435                         }
436                 } else {
437                         if (verbose) fprintf(stderr,"** [%d] unlink %s\n", pid, buf);
438                         if (unlink(buf)) {
439                             fprintf(stderr,"!! [%d] unlink %s failed\n", pid, buf);
440                             perror("unlink");
441                             if (checkflag) return 1;
442                         }
443                 }
444         }
445         return 0;
446 }