1 /* 2 * 3 * Copyright (c) International Business Machines Corp., 2002 4 * Copyright (c) Cyril Hrubis chrubis (at) suse.cz 2009 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 14 * the GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21 /* 22 * NAME 23 * ftest02.c -- test inode things (ported from SPIE section2, filesuite, by Airong Zhang) 24 * 25 * CALLS 26 * open, close, read, write, lseek, 27 * unlink, chdir 28 * 29 * 30 * ALGORITHM 31 * 32 * 33 * ftest02 [-f tmpdirname] nchild iterations [partition] 34 * 35 * This forks some child processes, they do some random operations 36 * which use lots of directory operations. 37 * 38 * RESTRICTIONS 39 * Runs a long time with default args - can take others on input 40 * line. Use with "term mode". 41 * If run on vax the ftruncate will not be random - will always go to 42 * start of file. NOTE: produces a very high load average!! 43 * 44 */ 45 46 #include <stdio.h> 47 #include <sys/types.h> 48 #include <sys/param.h> 49 #include <sys/wait.h> 50 #include <fcntl.h> 51 #include <sys/stat.h> 52 #include <errno.h> 53 #include <sys/mount.h> 54 #include <signal.h> 55 #include <unistd.h> 56 #include "test.h" 57 #include "libftest.h" 58 59 #define MAXCHILD 25 60 #define K_1 1024 61 #define K_2 2048 62 #define K_4 4096 63 64 char *TCID = "ftest02"; 65 int TST_TOTAL = 1; 66 67 #define PASSED 1 68 #define FAILED 0 69 70 static void crfile(int, int); 71 static void unlfile(int, int); 72 static void fussdir(int, int); 73 static void dotest(int, int); 74 static void dowarn(int, char *, char *); 75 static void term(int sig); 76 static void cleanup(void); 77 78 #define M (1024*1024) 79 80 static int iterations; 81 static int nchild; 82 static int parent_pid; 83 static int pidlist[MAXCHILD]; 84 85 static char homedir[MAXPATHLEN]; 86 static char dirname[MAXPATHLEN]; 87 static char tmpname[MAXPATHLEN]; 88 static int dirlen; 89 static int mnt = 0; 90 static char startdir[MAXPATHLEN], mntpoint[MAXPATHLEN]; 91 static char *partition; 92 static char *cwd; 93 static char *fstyp; 94 static int local_flag; 95 96 int main(void) 97 { 98 int k, j, pid, child, status, count; 99 char name[128]; 100 101 /* 102 * Default values for run conditions. 103 */ 104 iterations = 50; 105 nchild = 5; 106 107 if (signal(SIGTERM, term) == SIG_ERR) { 108 tst_resm(TFAIL, "first signal failed"); 109 110 } 111 112 /* 113 * Make a directory to do this in; ignore error if already exists. 114 */ 115 local_flag = PASSED; 116 parent_pid = getpid(); 117 tst_tmpdir(); 118 119 if (!startdir[0]) { 120 if (getcwd(startdir, MAXPATHLEN) == NULL) { 121 tst_resm(TBROK, "getcwd failed"); 122 123 } 124 } 125 cwd = startdir; 126 strcat(dirname, cwd); 127 sprintf(tmpname, "/ftest02.%d", getpid()); 128 strcat(dirname, tmpname); 129 strcat(homedir, cwd); 130 sprintf(tmpname, "/ftest02h.%d", getpid()); 131 strcat(homedir, tmpname); 132 133 mkdir(dirname, 0755); 134 mkdir(homedir, 0755); 135 if (chdir(dirname) < 0) { 136 tst_resm(TBROK, "\tCan't chdir(%s), error %d.", dirname, errno); 137 cleanup(); 138 139 } 140 dirlen = strlen(dirname); 141 if (chdir(homedir) < 0) { 142 tst_resm(TBROK, "\tCan't chdir(%s), error %d.", homedir, errno); 143 cleanup(); 144 145 } 146 147 for (k = 0; k < nchild; k++) { 148 if ((child = fork()) == 0) { 149 dotest(k, iterations); 150 exit(0); 151 } 152 if (child < 0) { 153 tst_brkm(TBROK | TERRNO, cleanup, "fork failed"); 154 } 155 pidlist[k] = child; 156 } 157 158 /* 159 * Wait for children to finish. 160 */ 161 count = 0; 162 while ((child = wait(&status)) > 0) { 163 //tst_resm(TINFO,"Test{%d} exited status = 0x%x", child, status); 164 //tst_resm(TINFO,"status is %d",status); 165 if (status) { 166 tst_resm(TFAIL, "Test{%d} failed, expected 0 exit.", 167 child); 168 local_flag = FAILED; 169 } 170 ++count; 171 } 172 173 /* 174 * Should have collected all children. 175 */ 176 if (count != nchild) { 177 tst_resm(TFAIL, "Wrong # children waited on, count = %d", 178 count); 179 local_flag = FAILED; 180 } 181 182 if (local_flag == FAILED) 183 tst_resm(TFAIL, "Test failed in fork-wait part."); 184 else 185 tst_resm(TPASS, "Test passed in fork-wait part."); 186 187 if (iterations > 26) 188 iterations = 26; 189 190 for (k = 0; k < nchild; k++) 191 for (j = 0; j < iterations + 1; j++) { 192 ft_mkname(name, dirname, k, j); 193 rmdir(name); 194 unlink(name); 195 } 196 197 chdir(startdir); 198 199 pid = fork(); 200 201 if (pid < 0) { 202 tst_brkm(TBROK | TERRNO, cleanup, "fork failed"); 203 } 204 205 if (pid == 0) { 206 execl("/bin/rm", "rm", "-rf", homedir, NULL); 207 exit(1); 208 } else 209 wait(&status); 210 211 if (status) 212 tst_resm(TINFO, 213 "CAUTION - ftest02, '%s' may not have been removed.", 214 homedir); 215 216 pid = fork(); 217 218 if (pid < 0) { 219 tst_brkm(TBROK | TERRNO, cleanup, "fork failed"); 220 } 221 222 if (pid == 0) { 223 execl("/bin/rm", "rm", "-rf", dirname, NULL); 224 exit(1); 225 } else 226 wait(&status); 227 228 if (status) { 229 tst_resm(TINFO, 230 "CAUTION - ftest02, '%s' may not have been removed.", 231 dirname); 232 } 233 234 sync(); 235 236 cleanup(); 237 238 tst_exit(); 239 } 240 241 #define warn(val,m1,m2) if ((val) < 0) dowarn(me,m1,m2) 242 243 /* 244 * crfile() 245 * Create a file and write something into it. 246 */ 247 248 char crmsg[] = "Gee, let's write something in the file!\n"; 249 250 static void crfile(int me, int count) 251 { 252 int fd, val; 253 char fname[MAXPATHLEN], buf[MAXPATHLEN]; 254 255 ft_mkname(fname, dirname, me, count); 256 257 fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0666); 258 if (fd < 0 && errno == EISDIR) { 259 val = rmdir(fname); 260 warn(val, "rmdir", fname); 261 fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0666); 262 } 263 warn(fd, "creating", fname); 264 265 val = lseek(fd, (rand() % M), 0); 266 warn(val, "lseek", 0); 267 268 val = write(fd, crmsg, sizeof(crmsg) - 1); 269 warn(val, "write", 0); 270 271 val = lseek(fd, -((off_t) sizeof(crmsg) - 1), 1); 272 warn(val, "lseek", 0); 273 274 val = read(fd, buf, sizeof(crmsg) - 1); 275 warn(val, "read", 0); 276 277 if (strncmp(crmsg, buf, sizeof(crmsg) - 1)) 278 dowarn(me, "compare", 0); 279 280 val = close(fd); 281 warn(val, "close", 0); 282 } 283 284 /* 285 * unlfile() 286 * Unlink some of the files. 287 */ 288 static void unlfile(int me, int count) 289 { 290 int i; 291 int val; 292 char fname[MAXPATHLEN]; 293 294 i = count - 10; 295 296 if (i < 0) 297 i = 0; 298 299 for (; i < count; i++) { 300 ft_mkname(fname, dirname, me, i); 301 val = rmdir(fname); 302 if (val < 0) 303 val = unlink(fname); 304 if (val == 0 || errno == ENOENT) 305 continue; 306 dowarn(me, "unlink", fname); 307 } 308 } 309 310 /* 311 * fussdir() 312 * Make a directory, put stuff in it, remove it, and remove directory. 313 * 314 * Randomly leave the directory there. 315 */ 316 static void fussdir(int me, int count) 317 { 318 int val; 319 char dir[MAXPATHLEN], fname[MAXPATHLEN], savedir[MAXPATHLEN]; 320 321 ft_mkname(dir, dirname, me, count); 322 rmdir(dir); 323 unlink(dir); 324 325 val = mkdir(dir, 0755); 326 warn(val, "mkdir", dir); 327 328 /* 329 * Arrange to create files in the directory. 330 */ 331 strcpy(savedir, dirname); 332 strcpy(dirname, ""); 333 334 val = chdir(dir); 335 warn(val, "chdir", dir); 336 337 crfile(me, count); 338 crfile(me, count + 1); 339 340 val = chdir(".."); 341 warn(val, "chdir", ".."); 342 343 val = rmdir(dir); 344 345 if (val >= 0) { 346 tst_brkm(TFAIL, NULL, 347 "Test[%d]: rmdir of non-empty %s succeeds!", me, 348 dir); 349 } 350 351 val = chdir(dir); 352 warn(val, "chdir", dir); 353 354 ft_mkname(fname, dirname, me, count); 355 val = unlink(fname); 356 warn(val, "unlink", fname); 357 358 ft_mkname(fname, dirname, me, count + 1); 359 val = unlink(fname); 360 warn(val, "unlink", fname); 361 362 val = chdir(homedir); 363 warn(val, "chdir", homedir); 364 365 if (rand() & 0x01) { 366 val = rmdir(dir); 367 warn(val, "rmdir", dir); 368 } 369 370 strcpy(dirname, savedir); 371 } 372 373 /* 374 * dotest() 375 * Children execute this. 376 * 377 * Randomly do an inode thing; loop for # iterations. 378 */ 379 #define THING(p) {p, "p"} 380 381 struct ino_thing { 382 void (*it_proc) (); 383 char *it_name; 384 } ino_thing[] = { 385 THING(crfile), THING(unlfile), THING(fussdir), THING(sync),}; 386 387 #define NTHING ARRAY_SIZE(ino_thing) 388 389 int thing_cnt[NTHING]; 390 int thing_last[NTHING]; 391 392 static void dotest(int me, int count) 393 { 394 int i, thing; 395 396 //tst_resm(TINFO,"Test %d pid %d starting.", me, getpid()); 397 398 srand(getpid()); 399 400 for (i = 0; i < count; i++) { 401 thing = (rand() >> 3) % NTHING; 402 (*ino_thing[thing].it_proc) (me, i, ino_thing[thing].it_name); 403 ++thing_cnt[thing]; 404 } 405 406 //tst_resm(TINFO,"Test %d pid %d exiting.", me, getpid()); 407 } 408 409 static void dowarn(int me, char *m1, char *m2) 410 { 411 int err = errno; 412 413 tst_brkm(TBROK, NULL, "Test[%d]: error %d on %s %s", 414 me, err, m1, (m2 ? m2 : "")); 415 } 416 417 /* 418 * SIGTERM signal handler. 419 */ 420 static void term(int sig LTP_ATTRIBUTE_UNUSED) 421 { 422 int i; 423 424 if (parent_pid == getpid()) { 425 for (i = 0; i < nchild; i++) 426 if (pidlist[i]) 427 kill(pidlist[i], SIGTERM); 428 return; 429 } 430 431 tst_brkm(TBROK, NULL, "Child process exiting."); 432 } 433 434 static void cleanup(void) 435 { 436 char mount_buffer[1024]; 437 438 if (mnt == 1) { 439 440 if (chdir(startdir) < 0) 441 tst_resm(TBROK, "Could not change to %s ", startdir); 442 443 if (!strcmp(fstyp, "cfs")) { 444 445 sprintf(mount_buffer, "/bin/umount %s", partition); 446 447 if (system(mount_buffer) != 0) { 448 449 tst_resm(TBROK, "Unable to unmount %s from %s ", 450 partition, mntpoint); 451 452 if (umount(partition)) 453 tst_resm(TBROK, 454 "Unable to unmount %s from %s ", 455 partition, mntpoint); 456 else 457 tst_resm(TINFO, 458 "Forced umount for %s, /etc/mtab now dirty", 459 partition); 460 } 461 462 } else if (umount(partition)) 463 tst_resm(TBROK, "Unable to unmount %s from %s ", 464 partition, mntpoint); 465 466 if (rmdir(mntpoint) != 0) 467 tst_resm(TBROK, "Unable to rmdir %s ", mntpoint); 468 469 } 470 471 tst_rmdir(); 472 } 473