• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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., 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, lseek64,
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 
main(int ac,char * av[])100 int main(int ac, char *av[])
101 {
102 	int pid, child, status, count, k, j;
103 	char name[MAXPATHLEN];
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 
crfile(int me,int count)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  */
unlfile(int me,int count)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  */
fussdir(int me,int count)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 
dotest(int me,int count)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 
dowarn(int me,char * m1,char * m2)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 
term(int sig LTP_ATTRIBUTE_UNUSED)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 
cleanup(void)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