Home | History | Annotate | Download | only in ftest
      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