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