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