ftest02.c revision 2c28215423293e443469a07ae7011135d058b671
1/* 2 * 3 * Copyright (c) International Business Machines Corp., 2002 4 * Copyright (c) Cyril Hrubis chrubis@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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 "usctest.h" 58#include "libftest.h" 59 60#define MAXCHILD 25 61#define K_1 1024 62#define K_2 2048 63#define K_4 4096 64 65char *TCID = "ftest02"; 66int TST_TOTAL = 1; 67 68#define PASSED 1 69#define FAILED 0 70 71static void crfile(int, int); 72static void unlfile(int, int); 73static void fussdir(int, int); 74static void dotest(int, int); 75static void dowarn(int, char*, char*); 76static void term(int sig); 77static void cleanup(void); 78 79#define M (1024*1024) 80 81static int iterations; 82static int nchild; 83static int parent_pid; 84static int pidlist[MAXCHILD]; 85 86static char homedir[MAXPATHLEN]; 87static char dirname[MAXPATHLEN]; 88static char tmpname[MAXPATHLEN]; 89static int dirlen; 90static int mnt = 0; 91static char startdir[MAXPATHLEN], mntpoint[MAXPATHLEN]; 92static char *partition; 93static char *cwd; 94static char *fstyp; 95static int local_flag; 96 97int main(void) 98{ 99 int k, j, pid, child, status, count; 100 char name[128]; 101 102 /* 103 * Default values for run conditions. 104 */ 105 iterations = 50; 106 nchild = 5; 107 108 if (signal(SIGTERM, term) == SIG_ERR) { 109 tst_resm(TFAIL, "first signal failed"); 110 111 } 112 113 /* 114 * Make a directory to do this in; ignore error if already exists. 115 */ 116 local_flag = PASSED; 117 parent_pid = getpid(); 118 tst_tmpdir(); 119 120 if (!startdir[0]) { 121 if (getcwd(startdir, MAXPATHLEN) == NULL) { 122 tst_resm(TBROK,"getcwd failed"); 123 124 } 125 } 126 cwd = startdir; 127 strcat(dirname, cwd); 128 sprintf(tmpname, "/ftest02.%d", getpid()); 129 strcat(dirname, tmpname); 130 strcat(homedir, cwd); 131 sprintf(tmpname, "/ftest02h.%d", getpid()); 132 strcat(homedir, tmpname); 133 134 mkdir(dirname, 0755); 135 mkdir(homedir, 0755); 136 if (chdir(dirname) < 0) { 137 tst_resm(TBROK,"\tCan't chdir(%s), error %d.", dirname, errno); 138 cleanup(); 139 140 } 141 dirlen = strlen(dirname); 142 if (chdir(homedir) < 0) { 143 tst_resm(TBROK,"\tCan't chdir(%s), error %d.", homedir, errno); 144 cleanup(); 145 146 } 147 148 for (k = 0; k < nchild; k++) { 149 if ((child = fork()) == 0) { 150 dotest(k, iterations); 151 exit(0); 152 } 153 if (child < 0) { 154 tst_brkm(TBROK|TERRNO, cleanup, "fork failed"); 155 } 156 pidlist[k] = child; 157 } 158 159 /* 160 * Wait for children to finish. 161 */ 162 count = 0; 163 while ((child = wait(&status)) > 0) { 164 //tst_resm(TINFO,"Test{%d} exited status = 0x%x", child, status); 165 //tst_resm(TINFO,"status is %d",status); 166 if (status) { 167 tst_resm(TFAIL,"Test{%d} failed, expected 0 exit.", 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", count); 178 local_flag = FAILED; 179 } 180 181 if (local_flag == FAILED) 182 tst_resm(TFAIL, "Test failed in fork-wait part."); 183 else 184 tst_resm(TPASS, "Test passed in fork-wait part."); 185 186 if (iterations > 26) 187 iterations = 26; 188 189 for (k = 0; k < nchild; k++) 190 for (j = 0; j < iterations + 1; j++) { 191 ft_mkname(name, dirname, k, j); 192 rmdir(name); 193 unlink(name); 194 } 195 196 chdir(startdir); 197 198 pid = fork(); 199 200 if (pid < 0) { 201 tst_brkm(TBROK|TERRNO, cleanup, "fork failed"); 202 } 203 204 if (pid == 0) { 205 execl("/bin/rm", "rm", "-rf", homedir, NULL); 206 exit(1); 207 } else 208 wait(&status); 209 210 if (status) 211 tst_resm(TINFO,"CAUTION - ftest02, '%s' may not have been removed.", 212 homedir); 213 214 pid = fork(); 215 216 if (pid < 0) { 217 tst_brkm(TBROK|TERRNO, cleanup, "fork failed"); 218 } 219 220 if (pid == 0) { 221 execl("/bin/rm", "rm", "-rf", dirname, NULL); 222 exit(1); 223 } else 224 wait(&status); 225 226 if (status) { 227 tst_resm(TINFO,"CAUTION - ftest02, '%s' may not have been removed.", 228 dirname); 229 } 230 231 sync(); 232 233 cleanup(); 234 235} 236 237#define warn(val,m1,m2) if ((val) < 0) dowarn(me,m1,m2) 238 239/* 240 * crfile() 241 * Create a file and write something into it. 242 */ 243 244char crmsg[] = "Gee, let's write something in the file!\n"; 245 246static void crfile(int me, int count) 247{ 248 int fd, val; 249 char fname[MAXPATHLEN], buf[MAXPATHLEN]; 250 251 ft_mkname(fname, dirname, me, count); 252 253 fd = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666); 254 if (fd < 0 && errno == EISDIR) { 255 val = rmdir(fname); 256 warn(val, "rmdir", fname); 257 fd = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666); 258 } 259 warn(fd, "creating", fname); 260 261 val = lseek(fd, (rand() % M), 0); 262 warn(val, "lseek", 0); 263 264 val = write(fd, crmsg, sizeof(crmsg)-1); 265 warn(val, "write", 0); 266 267 val = lseek(fd, -(sizeof(crmsg)-1), 1); 268 warn(val, "lseek", 0); 269 270 val = read(fd, buf, sizeof(crmsg)-1); 271 warn(val, "read", 0); 272 273 if (strncmp(crmsg, buf, sizeof(crmsg)-1)) 274 dowarn(me, "compare", 0); 275 276 val = close(fd); 277 warn(val, "close", 0); 278} 279 280/* 281 * unlfile() 282 * Unlink some of the files. 283 */ 284static void unlfile(int me, int count) 285{ 286 int i; 287 int val; 288 char fname[MAXPATHLEN]; 289 290 i = count - 10; 291 292 if (i < 0) 293 i = 0; 294 295 for (; i < count; i++) { 296 ft_mkname(fname, dirname, me, i); 297 val = rmdir(fname); 298 if (val < 0) 299 val = unlink(fname); 300 if (val == 0 || errno == ENOENT) 301 continue; 302 dowarn(me, "unlink", fname); 303 } 304} 305 306/* 307 * fussdir() 308 * Make a directory, put stuff in it, remove it, and remove directory. 309 * 310 * Randomly leave the directory there. 311 */ 312static void fussdir(int me, int count) 313{ 314 int val; 315 char dir[MAXPATHLEN], fname[MAXPATHLEN], savedir[MAXPATHLEN]; 316 317 ft_mkname(dir, dirname, me, count); 318 rmdir(dir); 319 unlink(dir); 320 321 val = mkdir(dir, 0755); 322 warn(val, "mkdir", dir); 323 324 /* 325 * Arrange to create files in the directory. 326 */ 327 strcpy(savedir, dirname); 328 strcpy(dirname, ""); 329 330 val = chdir(dir); 331 warn(val, "chdir", dir); 332 333 crfile(me, count); 334 crfile(me, count+1); 335 336 val = chdir(".."); 337 warn(val, "chdir", ".."); 338 339 val = rmdir(dir); 340 341 if (val >= 0) { 342 tst_resm(TFAIL,"Test[%d]: rmdir of non-empty %s succeeds!", me, dir); 343 tst_exit(); 344 } 345 346 val = chdir(dir); 347 warn(val, "chdir", dir); 348 349 ft_mkname(fname, dirname, me, count); 350 val = unlink(fname); 351 warn(val, "unlink", fname); 352 353 ft_mkname(fname, dirname, me, count+1); 354 val = unlink(fname); 355 warn(val, "unlink", fname); 356 357 val = chdir(homedir); 358 warn(val, "chdir", homedir); 359 360 if (rand() & 0x01) { 361 val = rmdir(dir); 362 warn(val, "rmdir", dir); 363 } 364 365 strcpy(dirname, savedir); 366} 367 368/* 369 * dotest() 370 * Children execute this. 371 * 372 * Randomly do an inode thing; loop for # iterations. 373 */ 374#define THING(p) {p, "p"} 375 376struct ino_thing { 377 void (*it_proc)(); 378 char *it_name; 379} ino_thing[] = { 380 THING(crfile), 381 THING(unlfile), 382 THING(fussdir), 383 THING(sync), 384}; 385 386#define NTHING (sizeof(ino_thing) / sizeof(ino_thing[0])) 387 388int thing_cnt[NTHING]; 389int thing_last[NTHING]; 390 391static void dotest(int me, int count) 392{ 393 int i, thing; 394 395 //tst_resm(TINFO,"Test %d pid %d starting.", me, getpid()); 396 397 srand(getpid()); 398 399 for (i = 0; i < count; i++) { 400 thing = (rand() >> 3) % NTHING; 401 (*ino_thing[thing].it_proc)(me, i, ino_thing[thing].it_name); 402 ++thing_cnt[thing]; 403 } 404 405 //tst_resm(TINFO,"Test %d pid %d exiting.", me, getpid()); 406} 407 408static void dowarn(int me, char *m1, char *m2) 409{ 410 int err = errno; 411 412 tst_resm(TBROK,"Test[%d]: error %d on %s %s", 413 me, err, m1, (m2 ? m2 : "")); 414 tst_exit(); 415} 416 417/* 418 * SIGTERM signal handler. 419 */ 420static 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_resm(TBROK, "Child process exiting."); 432 tst_exit(); 433} 434 435static void cleanup(void) 436{ 437 char mount_buffer[1024]; 438 439 if (mnt == 1) { 440 441 if (chdir(startdir) < 0) 442 tst_resm(TBROK,"Could not change to %s ", startdir); 443 444 if (!strcmp(fstyp, "cfs")) { 445 446 sprintf(mount_buffer, "/bin/umount %s", partition); 447 448 if (system(mount_buffer) != 0) { 449 450 tst_resm(TBROK,"Unable to unmount %s from %s ", partition, mntpoint); 451 452 if (umount(partition)) 453 tst_resm(TBROK,"Unable to unmount %s from %s ", partition, mntpoint); 454 else 455 tst_resm(TINFO, "Forced umount for %s, /etc/mtab now dirty", partition); 456 } 457 458 } else 459 if (umount(partition)) 460 tst_resm(TBROK,"Unable to unmount %s from %s ", partition, mntpoint); 461 462 if (rmdir(mntpoint) != 0) 463 tst_resm(TBROK,"Unable to rmdir %s ", mntpoint); 464 465 } 466 467 tst_rmdir(); 468}