• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *   Copyright (c) International Business Machines  Corp., 2002
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  * NAME
22  *      diotest2.c
23  *
24  * DESCRIPTION
25  *	Program tests the combinations of direct and buffered read, write.
26  *	The bufsize should be in n*4k size for direct read, write. The offset
27  *	value marks the starting position in file from where to start the
28  *	read and write. Larger files can be created using the offset parameter.
29  *	Test data file can be specified through commandline and is useful
30  *	for running test with raw devices as a file.
31  *	Test blocks:
32  *	[1] Direct read, Buffered write
33  *	[2] Direct write, Buffered read
34  *	[3] Direct read, Direct write
35  *
36  * USAGE
37  *      diotest2 [-b bufsize] [-o offset] [-i iterations] [-f filename]
38  *
39  * History
40  *	04/22/2002	Narasimha Sharoff nsharoff@us.ibm.com
41  *
42  * RESTRICTIONS
43  *	None
44 */
45 
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <unistd.h>
49 #include <fcntl.h>
50 #include <string.h>
51 #include <sys/file.h>
52 #include <sys/types.h>
53 #include <sys/syscall.h>
54 #include <errno.h>
55 
56 #include "diotest_routines.h"
57 
58 #include "test.h"
59 
60 char *TCID = "diotest02";	/* Test program identifier.    */
61 int TST_TOTAL = 3;		/* Total number of test conditions */
62 
63 #ifdef O_DIRECT
64 
65 #define	BUFSIZE	4096
66 #define TRUE	1
67 #define LEN	30
68 #define READ_DIRECT 1
69 #define WRITE_DIRECT 2
70 #define RDWR_DIRECT 3
71 
72 /*
73  * runtest: write the data to the file. Read the data from the file and compare.
74  *	For each iteration, write data starting at offse+iter*bufsize
75  *	location in the file and read from there.
76 */
runtest(int fd_r,int fd_w,int iter,off64_t offset,int action)77 int runtest(int fd_r, int fd_w, int iter, off64_t offset, int action)
78 {
79 	char *buf1;
80 	char *buf2;
81 	int i, bufsize = BUFSIZE;
82 
83 	/* Allocate for buffers */
84 	if ((buf1 = valloc(bufsize)) == 0) {
85 		tst_resm(TFAIL, "valloc() buf1 failed: %s", strerror(errno));
86 		return (-1);
87 	}
88 	if ((buf2 = valloc(bufsize)) == 0) {
89 		tst_resm(TFAIL, "valloc() buf2 failed: %s", strerror(errno));
90 		return (-1);
91 	}
92 
93 	/* seek bufsize*iteration and write. seek and read. verify. */
94 	for (i = 0; i < iter; i++) {
95 		fillbuf(buf1, bufsize, i);
96 		if (lseek(fd_w, offset + iter * bufsize, SEEK_SET) < 0) {
97 			tst_resm(TFAIL, "lseek before write failed: %s",
98 				 strerror(errno));
99 			return (-1);
100 		}
101 		if (write(fd_w, buf1, bufsize) < bufsize) {
102 			tst_resm(TFAIL, "write failed: %s", strerror(errno));
103 			return (-1);
104 		}
105 		if (lseek(fd_r, offset + iter * bufsize, SEEK_SET) < 0) {
106 			tst_resm(TFAIL, "lseek before read failed: %s",
107 				 strerror(errno));
108 			return (-1);
109 		}
110 		if (read(fd_r, buf2, bufsize) < bufsize) {
111 			tst_resm(TFAIL, "read failed: %s", strerror(errno));
112 			return (-1);
113 		}
114 		if (bufcmp(buf1, buf2, bufsize) != 0) {
115 			tst_resm(TFAIL, "read/write comparision failed");
116 			return (-1);
117 		}
118 	}
119 	return 0;
120 }
121 
122 /*
123  * prg_usage: display the program usage.
124 */
prg_usage()125 void prg_usage()
126 {
127 	fprintf(stderr,
128 		"Usage: diotest2 [-b bufsize] [-o offset] [-i iterations] [-f filename]\n");
129 	exit(1);
130 }
131 
132 int fd1 = -1;
133 char filename[LEN];
134 static void setup(void);
135 static void cleanup(void);
136 
main(int argc,char * argv[])137 int main(int argc, char *argv[])
138 {
139 	int iter = 100;		/* Iterations. Default 100 */
140 	int bufsize = BUFSIZE;	/* Buffer size. Default 4k */
141 	off64_t offset = 0;	/* Offset. Default 0 */
142 	int i, action, fd_r, fd_w;
143 	int fail_count = 0, total = 0, failed = 0;
144 
145 	/* Options */
146 	sprintf(filename, "testdata-2.%ld", syscall(__NR_gettid));
147 	while ((i = getopt(argc, argv, "b:o:i:f:")) != -1) {
148 		switch (i) {
149 		case 'b':
150 			if ((bufsize = atoi(optarg)) <= 0) {
151 				fprintf(stderr, "bufsize must be > 0\n");
152 				prg_usage();
153 			}
154 			if (bufsize % 4096 != 0) {
155 				fprintf(stderr,
156 					"bufsize must be multiple of 4k\n");
157 				prg_usage();
158 			}
159 			break;
160 		case 'o':
161 			if ((offset = atoi(optarg)) <= 0) {
162 				fprintf(stderr, "offset must be > 0\n");
163 				prg_usage();
164 			}
165 			break;
166 		case 'i':
167 			if ((iter = atoi(optarg)) <= 0) {
168 				fprintf(stderr, "iterations must be > 0\n");
169 				prg_usage();
170 			}
171 			break;
172 		case 'f':
173 			strcpy(filename, optarg);
174 			break;
175 		default:
176 			prg_usage();
177 		}
178 	}
179 
180 	setup();
181 
182 	/* Testblock-1: Read with Direct IO, Write without */
183 	action = READ_DIRECT;
184 	if ((fd_w = open(filename, O_WRONLY | O_CREAT, 0666)) < 0)
185 		tst_brkm(TBROK | TERRNO, cleanup,
186 			 "open(%s, O_WRONLY..) failed", filename);
187 	if ((fd_r = open(filename, O_DIRECT | O_RDONLY, 0666)) < 0)
188 		tst_brkm(TBROK | TERRNO, cleanup,
189 			 "open(%s, O_DIRECT|O_RDONLY..) failed", filename);
190 	if (runtest(fd_r, fd_w, iter, offset, action) < 0) {
191 		failed = TRUE;
192 		fail_count++;
193 		tst_resm(TFAIL, "Read with Direct IO, Write without");
194 	} else
195 		tst_resm(TPASS, "Read with Direct IO, Write without");
196 	close(fd_w);
197 	close(fd_r);
198 	unlink(filename);
199 	total++;
200 
201 	/* Testblock-2: Write with Direct IO, Read without */
202 	action = WRITE_DIRECT;
203 	if ((fd_w = open(filename, O_DIRECT | O_WRONLY | O_CREAT, 0666)) == -1)
204 		tst_brkm(TBROK | TERRNO, cleanup,
205 			 "open(%s, O_DIRECT|O_WRONLY..) failed", filename);
206 	if ((fd_r = open(filename, O_RDONLY | O_CREAT, 0666)) == -1)
207 		tst_brkm(TBROK | TERRNO, cleanup,
208 			 "open(%s, O_RDONLY..) failed", filename);
209 	if (runtest(fd_r, fd_w, iter, offset, action) < 0) {
210 		failed = TRUE;
211 		fail_count++;
212 		tst_resm(TFAIL, "Write with Direct IO, Read without");
213 	} else
214 		tst_resm(TPASS, "Write with Direct IO, Read without");
215 	close(fd_w);
216 	close(fd_r);
217 	unlink(filename);
218 	total++;
219 
220 	/* Testblock-3: Read, Write with Direct IO. */
221 	action = RDWR_DIRECT;
222 	if ((fd_w = open(filename, O_DIRECT | O_WRONLY | O_CREAT, 0666)) == -1)
223 		tst_brkm(TBROK | TERRNO, cleanup,
224 			 "open(%s, O_DIRECT|O_WRONLY|O_CREAT, ..) failed",
225 			 filename);
226 	if ((fd_r = open(filename, O_DIRECT | O_RDONLY | O_CREAT, 0666)) == -1)
227 		tst_brkm(TBROK | TERRNO, cleanup,
228 			 "open(%s, O_DIRECT|O_RDONLY|O_CREAT, ..) failed",
229 			 filename);
230 	if (runtest(fd_r, fd_w, iter, offset, action) < 0) {
231 		failed = TRUE;
232 		fail_count++;
233 		tst_resm(TFAIL, "Read, Write with Direct IO");
234 	} else
235 		tst_resm(TPASS, "Read, Write with Direct IO");
236 	close(fd_w);
237 	close(fd_r);
238 	unlink(filename);
239 	total++;
240 
241 	if (failed)
242 		tst_resm(TINFO, "%d/%d testblocks failed", fail_count, total);
243 	else
244 		tst_resm(TINFO, "%d testblocks %d iterations completed",
245 			 total, iter);
246 	cleanup();
247 
248 	tst_exit();
249 
250 }
251 
setup(void)252 static void setup(void)
253 {
254 	tst_tmpdir();
255 
256 	if ((fd1 = open(filename, O_CREAT | O_EXCL, 0600)) == -1)
257 		tst_brkm(TBROK | TERRNO, cleanup,
258 			 "open(%s, O_CREAT|O_EXCL, ..) failed", filename);
259 	close(fd1);
260 
261 	/* Test for filesystem support of O_DIRECT */
262 	if ((fd1 = open(filename, O_DIRECT, 0600)) == -1)
263 		tst_brkm(TCONF | TERRNO, cleanup,
264 			 "open(%s, O_DIRECT, ..) failed", filename);
265 	close(fd1);
266 
267 }
268 
cleanup(void)269 static void cleanup(void)
270 {
271 	if (fd1 != -1)
272 		unlink(filename);
273 
274 	tst_rmdir();
275 
276 }
277 
278 #else /* O_DIRECT */
main()279 int main()
280 {
281 	tst_brkm(TCONF, NULL, "O_DIRECT is not defined.");
282 }
283 #endif /* O_DIRECT */
284