• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) International Business Machines  Corp., 2002
3  *  04/30/2002 Narasimha Sharoff nsharoff@us.ibm.com
4  *
5  * This program is free software;  you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
13  * the GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program;  if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18  */
19 
20 /*
21  * DESCRIPTION
22  *	Fork given number of children. Each child opens the same file, but
23  *	uses its own file descriptior. The child does writes and reads from
24  *	its segment in the file. The segment to which the child writes is
25  *	determined by childnumber * bufsize. There is no need to use any locks.
26  *	Tests the combinations of buffered/direct readv(), writev() calls.
27  *	Test program contains the following test blocks:
28  *	[1] Direct Read, Buffered write
29  *	[2] Direct Write, Buffered read
30  *	[3] Direct Read, Direct Write
31  *
32  * USAGE
33  *	diotest6 [-b bufsize] [-o offset] [-n numchild] [-i iterations]
34  *			[-v nvector] [-f fileaname]
35 */
36 
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <string.h>
41 #include <sys/file.h>
42 #include <fcntl.h>
43 #include <sys/syscall.h>
44 #include <sys/uio.h>
45 #include <errno.h>
46 
47 #include "diotest_routines.h"
48 
49 #include "test.h"
50 
51 char *TCID = "diotest06";
52 int TST_TOTAL = 3;
53 
54 #ifdef O_DIRECT
55 
56 #define	BUFSIZE	4096
57 #define TRUE 1
58 #define LEN 30
59 #define	READ_DIRECT 1
60 #define	WRITE_DIRECT 2
61 #define	RDWR_DIRECT 3
62 
63 static int iter = 100;
64 static int bufsize = BUFSIZE;
65 static off64_t offset = 0;
66 static int nvector = 20;
67 static char filename[LEN];
68 static int fd1 = -1;
69 
70 static void setup(void);
71 static void cleanup(void);
72 
prg_usage(void)73 static void prg_usage(void)
74 {
75 	fprintf(stderr,
76 		"Usage: diotest6 [-b bufsize] [-o offset] [-n numchild] [-i iterations] [-v nvector] [-f filename]\n");
77 	exit(1);
78 }
79 
80 /*
81  * runtest: write the data to the file. Read the data from the file and compare.
82  *	For each iteration, write data starting at offse+iter*bufsize
83  *	location in the file and read from there.
84 */
runtest(int fd_r,int fd_w,int childnum,int action)85 int runtest(int fd_r, int fd_w, int childnum, int action)
86 {
87 	off64_t seekoff;
88 	int i, ret = -1;
89 	ssize_t n = 0;
90 	struct iovec *iov_r, *iov_w;
91 
92 	/* allocate read/write io vectors */
93 	iov_r = calloc(nvector, sizeof(*iov_r));
94 	iov_w = calloc(nvector, sizeof(*iov_w));
95 	if (!iov_r || !iov_w) {
96 		tst_resm(TBROK | TERRNO, "calloc failed for iovector array");
97 		free(iov_r);
98 		free(iov_w);
99 		return ret;
100 	}
101 
102 	/* allocate buffers and setup read/write io vectors */
103 	for (i = 0; i < nvector; i++) {
104 		iov_r[i].iov_base = valloc(bufsize);
105 		if (!iov_r[i].iov_base) {
106 			tst_resm(TBROK | TERRNO, "valloc error iov_r[%d]", i);
107 			goto err;
108 		}
109 		iov_r[i].iov_len = bufsize;
110 	}
111 	for (i = 0; i < nvector; i++) {
112 		iov_w[i].iov_base = valloc(bufsize);
113 		if (!iov_r[i].iov_base) {
114 			tst_resm(TBROK | TERRNO, "valloc error iov_w[%d]", i);
115 			goto err;
116 		}
117 		iov_w[i].iov_len = bufsize;
118 	}
119 
120 	/* seek, write, read and verify */
121 	seekoff = offset + bufsize * childnum * nvector;
122 	for (i = 0; i < iter; i++) {
123 		vfillbuf(iov_w, nvector, childnum+i);
124 
125 		if (lseek(fd_w, seekoff, SEEK_SET) < 0) {
126 			tst_resm(TFAIL, "lseek before write failed: %s",
127 				 strerror(errno));
128 			goto err;
129 		}
130 		n = writev(fd_w, iov_w, nvector);
131 		if (n < (bufsize * nvector)) {
132 			tst_resm(TFAIL | TERRNO, "writev failed, ret = %zd", n);
133 			goto err;
134 		}
135 		if (action == READ_DIRECT) {
136 			/* Make sure data is on to disk before read */
137 			if (fsync(fd_w) < 0) {
138 				tst_resm(TFAIL, "fsync failed: %s",
139 					 strerror(errno));
140 				goto err;
141 			}
142 		}
143 		if (lseek(fd_r, seekoff, SEEK_SET) < 0) {
144 			tst_resm(TFAIL, "lseek before read failed: %s",
145 				 strerror(errno));
146 			goto err;
147 		}
148 		n = readv(fd_r, iov_r, nvector);
149 		if (n < (bufsize * nvector)) {
150 			tst_resm(TFAIL | TERRNO, "readv failed, ret = %zd", n);
151 			goto err;
152 		}
153 		if (vbufcmp(iov_w, iov_r, nvector) != 0) {
154 			tst_resm(TFAIL, "comparsion failed. Child=%d offset=%d",
155 				 childnum, (int)seekoff);
156 			goto err;
157 		}
158 	}
159 	ret = 0;
160 
161 err:
162 	for (i = 0; i < nvector; i++)
163 		free(iov_r[i].iov_base);
164 	for (i = 0; i < nvector; i++)
165 		free(iov_w[i].iov_base);
166 	free(iov_r);
167 	free(iov_w);
168 	return ret;
169 }
170 
171 /*
172  * child_function: open the file for read and write. Call the runtest routine.
173 */
child_function(int childnum,int action)174 int child_function(int childnum, int action)
175 {
176 	int fd_w, fd_r;
177 
178 	switch (action) {
179 	case READ_DIRECT:
180 		if ((fd_w = open(filename, O_WRONLY | O_CREAT, 0666)) < 0) {
181 			tst_resm(TFAIL, "fd_w open failed for %s: %s",
182 				 filename, strerror(errno));
183 			return (-1);
184 		}
185 		if ((fd_r = open(filename, O_DIRECT | O_RDONLY, 0666)) < 0) {
186 			tst_resm(TFAIL, "fd_r open failed for %s: %s",
187 				 filename, strerror(errno));
188 			close(fd_w);
189 			unlink(filename);
190 			return (-1);
191 		}
192 		if (runtest(fd_r, fd_w, childnum, action) == -1) {
193 			tst_resm(TFAIL, "Read Direct-child %d failed",
194 				 childnum);
195 			close(fd_w);
196 			close(fd_r);
197 			return (-1);
198 		}
199 		break;
200 	case WRITE_DIRECT:
201 		if ((fd_w =
202 		     open(filename, O_DIRECT | O_WRONLY | O_CREAT, 0666)) < 0) {
203 			tst_resm(TFAIL, "fd_w open failed for %s: %s", filename,
204 				 strerror(errno));
205 			return (-1);
206 		}
207 		if ((fd_r = open(filename, O_RDONLY, 0666)) < 0) {
208 			tst_resm(TFAIL, "fd_r open failed for %s: %s",
209 				 filename, strerror(errno));
210 			close(fd_w);
211 			unlink(filename);
212 			return (-1);
213 		}
214 		if (runtest(fd_r, fd_w, childnum, action) == -1) {
215 			tst_resm(TFAIL, "Write Direct-child %d failed",
216 				 childnum);
217 			close(fd_w);
218 			close(fd_r);
219 			return (-1);
220 		}
221 		break;
222 	case RDWR_DIRECT:
223 		if ((fd_w =
224 		     open(filename, O_DIRECT | O_WRONLY | O_CREAT, 0666)) < 0) {
225 			tst_resm(TFAIL, "fd_w open failed for %s: %s", filename,
226 				 strerror(errno));
227 			return (-1);
228 		}
229 		if ((fd_r = open(filename, O_DIRECT | O_RDONLY, 0666)) < 0) {
230 			tst_resm(TFAIL, "fd_r open failed for %s: %s",
231 				 filename, strerror(errno));
232 			close(fd_w);
233 			return (-1);
234 		}
235 		if (runtest(fd_r, fd_w, childnum, action) == -1) {
236 			tst_resm(TFAIL, "RDWR Direct-child %d failed",
237 				 childnum);
238 			close(fd_w);
239 			close(fd_r);
240 			return (-1);
241 		}
242 		break;
243 	default:
244 		fprintf(stderr, "Invalid Action Value\n");
245 		return (-1);
246 	}
247 	close(fd_w);
248 	close(fd_r);
249 	exit(0);
250 }
251 
main(int argc,char * argv[])252 int main(int argc, char *argv[])
253 {
254 	int *pidlst;
255 	int numchild = 1;
256 	int i, fail_count = 0, failed = 0, total = 0;
257 
258 	/* Options */
259 	sprintf(filename, "testdata-6.%ld", syscall(__NR_gettid));
260 	while ((i = getopt(argc, argv, "b:o:i:n:v:f:")) != -1) {
261 		switch (i) {
262 		case 'b':
263 			if ((bufsize = atoi(optarg)) <= 0) {
264 				fprintf(stderr, "bufsize must be > 0\n");
265 				prg_usage();
266 			}
267 			if (bufsize % 4096 != 0) {
268 				fprintf(stderr,
269 					"bufsize must be multiple of 4k\n");
270 				prg_usage();
271 			}
272 			break;
273 		case 'o':
274 			if ((offset = atoi(optarg)) <= 0) {
275 				fprintf(stderr, "offset must be > 0\n");
276 				prg_usage();
277 			}
278 			break;
279 		case 'i':
280 			if ((iter = atoi(optarg)) <= 0) {
281 				fprintf(stderr, "iterations must be > 0\n");
282 				prg_usage();
283 			}
284 			break;
285 		case 'n':
286 			if ((numchild = atoi(optarg)) <= 0) {
287 				fprintf(stderr, "no of children must be > 0\n");
288 				prg_usage();
289 			}
290 			break;
291 		case 'v':
292 			if ((nvector = atoi(optarg)) <= 0) {
293 				fprintf(stderr, "vectory array must be > 0\n");
294 				prg_usage();
295 			}
296 			break;
297 		case 'f':
298 			strcpy(filename, optarg);
299 			break;
300 		default:
301 			prg_usage();
302 		}
303 	}
304 
305 	setup();
306 
307 	/* Testblock-1: Read with Direct IO, Write without */
308 	if (forkchldrn(&pidlst, numchild, READ_DIRECT, child_function) < 0) {
309 		failed = TRUE;
310 		fail_count++;
311 		tst_resm(TFAIL, "Read with Direct IO, Write without");
312 	} else {
313 		if (waitchldrn(&pidlst, numchild) < 0) {
314 			failed = TRUE;
315 			fail_count++;
316 			tst_resm(TFAIL, "Read with Direct IO, Write without");
317 		} else
318 			tst_resm(TPASS, "Read with Direct IO, Write without");
319 
320 	}
321 	unlink(filename);
322 	free(pidlst);
323 	total++;
324 
325 	/* Testblock-2: Write with Direct IO, Read without */
326 	if (forkchldrn(&pidlst, numchild, WRITE_DIRECT, child_function) < 0) {
327 		failed = TRUE;
328 		fail_count++;
329 		tst_resm(TFAIL, "Write with Direct IO, Read without");
330 	} else {
331 		if (waitchldrn(&pidlst, numchild) < 0) {
332 			failed = TRUE;
333 			fail_count++;
334 			tst_resm(TFAIL, "Write with Direct IO, Read without");
335 		} else
336 			tst_resm(TPASS, "Write with Direct IO, Read without");
337 	}
338 	unlink(filename);
339 	free(pidlst);
340 	total++;
341 
342 	/* Testblock-3: Read, Write with Direct IO. */
343 	if (forkchldrn(&pidlst, numchild, RDWR_DIRECT, child_function) < 0) {
344 		failed = TRUE;
345 		fail_count++;
346 		tst_resm(TFAIL, "Read, Write with Direct IO");
347 	} else {
348 		if (waitchldrn(&pidlst, numchild) < 0) {
349 			failed = TRUE;
350 			fail_count++;
351 			tst_resm(TFAIL, "Read, Write with Direct IO");
352 		} else
353 			tst_resm(TPASS, "Read, Write with Direct IO");
354 	}
355 	unlink(filename);
356 	free(pidlst);
357 	total++;
358 
359 	if (failed)
360 		tst_resm(TINFO, "%d/%d testblocks failed", fail_count, total);
361 	else
362 		tst_resm(TINFO,
363 			 "%d testblocks %d iterations with %d children completed",
364 			 total, iter, numchild);
365 	cleanup();
366 	tst_exit();
367 }
368 
setup(void)369 static void setup(void)
370 {
371 	tst_tmpdir();
372 
373 	if ((fd1 = open(filename, O_CREAT | O_EXCL, 0600)) < 0) {
374 		tst_brkm(TBROK, cleanup, "Couldn't create test file %s: %s",
375 			 filename, strerror(errno));
376 	}
377 	close(fd1);
378 
379 	/* Test for filesystem support of O_DIRECT */
380 	if ((fd1 = open(filename, O_DIRECT, 0600)) < 0) {
381 		tst_brkm(TCONF, cleanup,
382 			 "O_DIRECT is not supported by this filesystem. %s",
383 			 strerror(errno));
384 	}
385 	close(fd1);
386 }
387 
cleanup(void)388 static void cleanup(void)
389 {
390 	if (fd1 != -1)
391 		unlink(filename);
392 
393 	tst_rmdir();
394 }
395 
396 #else /* O_DIRECT */
397 
main(void)398 int main(void)
399 {
400 	tst_brkm(TCONF, NULL, "O_DIRECT is not defined.");
401 }
402 
403 #endif /* O_DIRECT */
404