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 * diotest3.c
23 *
24 * DESCRIPTION
25 * Fork given number of children. Each child opens the same file, but
26 * uses its own file descriptiors. The child does writes and reads from
27 * its segment in the file. The segment to which the child writes is
28 * determined by childnumber * bufsize. There is no need to use any locks.
29 * Program tests the combinations of buffered/buffered read(), write()
30 * calls.
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 * diotest3 [-b bufsize] [-o offset] [-n numchild]
38 * [-i iterations [-f filename]
39 *
40 * History
41 * 04/22/2002 Narasimha Sharoff nsharoff@us.ibm.com
42 *
43 * RESTRICTIONS
44 * None
45 */
46
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <unistd.h>
50 #include <string.h>
51 #include <sys/file.h>
52 #include <sys/fcntl.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 = "diotest03"; /* 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 static int iter = 100; /* Iterations. Default 100 */
73 static int bufsize = BUFSIZE; /* Buffersize. Default 4k */
74 static int offset = 0; /* Offset. Default 0 */
75 static char filename[LEN];
76
77 /*
78 * prg_usage: display the program usage
79 */
prg_usage()80 void prg_usage()
81 {
82 fprintf(stderr,
83 "Usage: diotest3 [-b bufsize] [-o offset] [-n numchild] [-i iterations] [-f filename]\n");
84 exit(1);
85 }
86
87 /*
88 * runtest: write the data to the file. Read the data from the file and compare.
89 * For each iteration, write data starting at offse+iter*bufsize
90 * location in the file and read from there.
91 *
92 * XXX (garrcoop): shouldn't use libltp APIs because it runs forked.
93 */
runtest(int fd_r,int fd_w,int childnum,int action)94 int runtest(int fd_r, int fd_w, int childnum, int action)
95 {
96 char *buf1;
97 char *buf2;
98 off_t seekoff;
99 int bufsize = BUFSIZE;
100 int i;
101
102 /* Allocate for buffers */
103 seekoff = offset + bufsize * childnum;
104 if ((buf1 = valloc(bufsize)) == 0) {
105 tst_resm(TFAIL | TERRNO, "valloc for buf1 failed");
106 return (-1);
107 }
108 if ((buf2 = valloc(bufsize)) == 0) {
109 tst_resm(TFAIL | TERRNO, "valloc for buf2 failed");
110 return (-1);
111 }
112
113 /* seek, write, read and verify */
114 for (i = 0; i < iter; i++) {
115 fillbuf(buf1, bufsize, childnum + i);
116 if (lseek(fd_w, seekoff, SEEK_SET) < 0) {
117 tst_resm(TFAIL | TERRNO, "lseek (fd_w, ..) failed");
118 return (-1);
119 }
120 if (write(fd_w, buf1, bufsize) < bufsize) {
121 tst_resm(TFAIL | TERRNO, "write failed");
122 return (-1);
123 }
124 if (action == READ_DIRECT) {
125 /* Make sure data is on to disk before read */
126 if (fsync(fd_w) < 0) {
127 tst_resm(TFAIL | TERRNO, "fsync failed");
128 return (-1);
129 }
130 }
131 if (lseek(fd_r, seekoff, SEEK_SET) < 0) {
132 tst_resm(TFAIL | TERRNO, "lseek(fd_r, ..) failed");
133 return (-1);
134 }
135 if (read(fd_r, buf2, bufsize) < bufsize) {
136 tst_resm(TFAIL | TERRNO, "read failed");
137 return (-1);
138 }
139 if (bufcmp(buf1, buf2, bufsize) != 0) {
140 tst_resm(TFAIL,
141 "comparsion failed; child=%d offset=%d",
142 childnum, (int)seekoff);
143 return (-1);
144 }
145 }
146 tst_exit();
147 }
148
149 /*
150 * child_function: open the file for read and write. Call the runtest routine.
151 */
child_function(int childnum,int action)152 int child_function(int childnum, int action)
153 {
154 int fd_w, fd_r;
155
156 switch (action) {
157 case READ_DIRECT:
158 if ((fd_w = open(filename, O_WRONLY | O_CREAT, 0666)) < 0) {
159 tst_resm(TFAIL | TERRNO,
160 "open(%s, O_WRONLY|O_CREAT, ..) failed",
161 filename);
162 return (-1);
163 }
164 if ((fd_r = open(filename, O_DIRECT | O_RDONLY, 0666)) < 0) {
165 tst_resm(TFAIL | TERRNO,
166 "open(%s, O_DIRECT|O_RDONLY, ..) failed",
167 filename);
168 close(fd_w);
169 return (-1);
170 }
171 if (runtest(fd_r, fd_w, childnum, action) == -1) {
172 tst_resm(TFAIL, "Read Direct-child %d failed",
173 childnum);
174 close(fd_w);
175 close(fd_r);
176 return (-1);
177 }
178 break;
179 case WRITE_DIRECT:
180 if ((fd_w =
181 open(filename, O_DIRECT | O_WRONLY | O_CREAT, 0666)) < 0) {
182 tst_resm(TFAIL, "fd_w open failed for %s: %s", filename,
183 strerror(errno));
184 return (-1);
185 }
186 if ((fd_r = open(filename, O_RDONLY, 0666)) < 0) {
187 tst_resm(TFAIL, "fd_r open failed for %s: %s",
188 filename, strerror(errno));
189 close(fd_w);
190 return (-1);
191 }
192 if (runtest(fd_r, fd_w, childnum, action) == -1) {
193 tst_resm(TFAIL, "Write Direct-child %d failed",
194 childnum);
195 close(fd_w);
196 close(fd_r);
197 return (-1);
198 }
199 break;
200 case RDWR_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_DIRECT | O_RDONLY, 0666)) < 0) {
208 tst_resm(TFAIL, "fd_r open failed for %s: %s",
209 filename, strerror(errno));
210 close(fd_w);
211 return (-1);
212 }
213 if (runtest(fd_r, fd_w, childnum, action) == -1) {
214 tst_resm(TFAIL, "RDWR Direct-child %d failed",
215 childnum);
216 close(fd_w);
217 close(fd_r);
218 return (-1);
219 }
220 break;
221 default:
222 fprintf(stderr, "Invalid Action Value\n");
223 return (-1);
224 }
225 close(fd_w);
226 close(fd_r);
227 exit(0);
228 }
229
230 static void setup(void);
231 static void cleanup(void);
232 static int fd1 = -1;
233
main(int argc,char * argv[])234 int main(int argc, char *argv[])
235 {
236 int *pidlst;
237 int numchild = 1; /* Number of children. Default 5 */
238 int i, fail_count = 0, failed = 0, total = 0;
239
240 /* Options */
241 sprintf(filename, "testdata-3.%ld", syscall(__NR_gettid));
242 while ((i = getopt(argc, argv, "b:o:i:n:f:")) != -1) {
243 switch (i) {
244 case 'b':
245 if ((bufsize = atoi(optarg)) <= 0) {
246 fprintf(stderr, "bufsize must be > 0\n");
247 prg_usage();
248 }
249 if (bufsize % 4096 != 0) {
250 fprintf(stderr,
251 "bufsize must be multiple of 4k\n");
252 prg_usage();
253 }
254 break;
255 case 'o':
256 if ((offset = atoi(optarg)) <= 0) {
257 fprintf(stderr, "offset must be > 0\n");
258 prg_usage();
259 }
260 break;
261 case 'i':
262 if ((iter = atoi(optarg)) <= 0) {
263 fprintf(stderr, "iterations must be > 0\n");
264 prg_usage();
265 }
266 break;
267 case 'n':
268 if ((numchild = atoi(optarg)) <= 0) {
269 fprintf(stderr, "no of children must be > 0\n");
270 prg_usage();
271 }
272 break;
273 case 'f':
274 strcpy(filename, optarg);
275 break;
276 default:
277 prg_usage();
278 }
279 }
280
281 setup();
282
283 /* Testblock-1: Read with Direct IO, Write without */
284 if (forkchldrn(&pidlst, numchild, READ_DIRECT, child_function) < 0) {
285 failed = TRUE;
286 fail_count++;
287 tst_resm(TFAIL, "Read with Direct IO, Write without");
288 } else {
289 if (waitchldrn(&pidlst, numchild) < 0) {
290 failed = TRUE;
291 fail_count++;
292 tst_resm(TFAIL, "Read with Direct IO, Write without");
293 } else
294 tst_resm(TPASS, "Read with Direct IO, Write without");
295
296 }
297 unlink(filename);
298 free(pidlst);
299 total++;
300
301 /* Testblock-2: Write with Direct IO, Read without */
302 if (forkchldrn(&pidlst, numchild, WRITE_DIRECT, child_function) < 0) {
303 failed = TRUE;
304 fail_count++;
305 tst_resm(TFAIL, "Write with Direct IO, Read without");
306 } else {
307 if (waitchldrn(&pidlst, numchild) < 0) {
308 failed = TRUE;
309 fail_count++;
310 tst_resm(TFAIL, "Write with Direct IO, Read without");
311 } else
312 tst_resm(TPASS, "Write with Direct IO, Read without");
313 }
314 unlink(filename);
315 free(pidlst);
316 total++;
317
318 /* Testblock-3: Read, Write with Direct IO. */
319 if (forkchldrn(&pidlst, numchild, RDWR_DIRECT, child_function) < 0) {
320 failed = TRUE;
321 fail_count++;
322 tst_resm(TFAIL, "Read, Write with Direct IO");
323 } else {
324 if (waitchldrn(&pidlst, numchild) < 0) {
325 failed = TRUE;
326 fail_count++;
327 tst_resm(TFAIL, "Read, Write with Direct IO");
328 } else
329 tst_resm(TPASS, "Read, Write with Direct IO");
330 }
331 unlink(filename);
332 free(pidlst);
333 total++;
334
335 if (failed)
336 tst_resm(TINFO, "%d/%d testblocks failed", fail_count, total);
337 else
338 tst_resm(TINFO,
339 "%d testblocks %d iterations with %d children completed",
340 total, iter, numchild);
341 cleanup();
342
343 tst_exit();
344
345 }
346
setup(void)347 static void setup(void)
348 {
349 tst_tmpdir();
350
351 if ((fd1 = open(filename, O_CREAT | O_EXCL, 0600)) < 0)
352 tst_brkm(TBROK | TERRNO, cleanup,
353 "open(%s, O_CREAT|O_EXCL, ..) failed", filename);
354 close(fd1);
355
356 /* Test for filesystem support of O_DIRECT */
357 if ((fd1 = open(filename, O_DIRECT, 0600)) < 0)
358 tst_brkm(TCONF, cleanup, "open(%s, O_DIRECT, ..) failed",
359 filename);
360 close(fd1);
361 }
362
cleanup(void)363 static void cleanup(void)
364 {
365 if (fd1 != -1)
366 unlink(filename);
367
368 tst_rmdir();
369
370 }
371 #else /* O_DIRECT */
372
main()373 int main()
374 {
375 tst_brkm(TCONF, NULL, "O_DIRECT is not defined.");
376 }
377 #endif /* O_DIRECT */
378