1 /* 2 * Copyright (c) International Business Machines Corp., 2002 3 * 04/30/2002 Narasimha Sharoff nsharoff (at) 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 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 */ 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 */ 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 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 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 388 static void cleanup(void) 389 { 390 if (fd1 != -1) 391 unlink(filename); 392 393 tst_rmdir(); 394 } 395 396 #else /* O_DIRECT */ 397 398 int main(void) 399 { 400 tst_brkm(TCONF, NULL, "O_DIRECT is not defined."); 401 } 402 403 #endif /* O_DIRECT */ 404