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 * diotest5.c 23 * 24 * DESCRIPTION 25 * The programs test buffered and direct IO with vector arrays using 26 * readv() and writev() calls. 27 * Test blocks 28 * [1] Direct readv, Buffered writev 29 * [2] Direct writev, Buffered readv 30 * [3] Direct readv, Direct writev 31 * The bufsize should be in n*4k size for direct readv, writev. The offset 32 * value marks the starting position in file from where to start the 33 * write and read. (Using larger offset, larger files can be tested). 34 * The nvector gives vector array size. Test data file can be 35 * specified through commandline and is useful for running test with 36 * raw devices as a file. 37 * 38 * USAGE 39 * diotest5 [-b bufsize] [-o offset] [-i iterations] 40 * [-v nvector] [-f filename] 41 * 42 * History 43 * 04/29/2002 Narasimha Sharoff nsharoff@us.ibm.com 44 * 45 * RESTRICTIONS 46 * None 47*/ 48 49#include <stdio.h> 50#include <stdlib.h> 51#include <unistd.h> 52#include <string.h> 53#include <sys/file.h> 54#include <fcntl.h> 55#include <sys/syscall.h> 56#include <sys/uio.h> 57#include <errno.h> 58 59#include "diotest_routines.h" 60 61#include "test.h" 62 63char *TCID = "diotest05"; /* Test program identifier. */ 64int TST_TOTAL = 3; /* Total number of test conditions */ 65 66#ifdef O_DIRECT 67 68#define BUFSIZE 4096 69#define TRUE 1 70#define LEN 30 71#define READ_DIRECT 1 72#define WRITE_DIRECT 2 73#define RDWR_DIRECT 3 74 75static int bufsize = BUFSIZE; /* Buffer size. Default 4k */ 76static int iter = 20; /* Iterations. Default 20 */ 77static int nvector = 20; /* Vector array. Default 20 */ 78static off64_t offset = 0; /* Start offset. Default 0 */ 79static char filename[LEN]; /* Test data file */ 80static int fd1 = -1; 81/* 82 * runtest: Write the data in vector array to the file. Read the data 83 * from the file into another vectory array and verify. Repeat the test. 84*/ 85int runtest(int fd_r, int fd_w, int iter, off64_t offset, int action) 86{ 87 int i; 88 struct iovec *iov1, *iov2, *iovp; 89 90 /* Allocate for buffers and data pointers */ 91 if ((iov1 = 92 (struct iovec *)valloc(sizeof(struct iovec) * nvector)) == NULL) { 93 tst_resm(TFAIL, "valloc() buf1 failed: %s", strerror(errno)); 94 return (-1); 95 } 96 if ((iov2 = 97 (struct iovec *)valloc(sizeof(struct iovec) * nvector)) == NULL) { 98 tst_resm(TFAIL, "valloc buf2 failed: %s", strerror(errno)); 99 return (-1); 100 } 101 for (i = 0, iovp = iov1; i < nvector; iovp++, i++) { 102 if ((iovp->iov_base = valloc(bufsize)) == NULL) { 103 tst_resm(TFAIL, "valloc for iovp->iov_base: %s", 104 strerror(errno)); 105 return (-1); 106 } 107 iovp->iov_len = bufsize; 108 } 109 for (i = 0, iovp = iov2; i < nvector; iovp++, i++) { 110 if ((iovp->iov_base = valloc(bufsize)) == NULL) { 111 tst_resm(TFAIL, "valloc, iov2 for iovp->iov_base: %s", 112 strerror(errno)); 113 return (-1); 114 } 115 iovp->iov_len = bufsize; 116 } 117 118 /* Test */ 119 for (i = 0; i < iter; i++) { 120 vfillbuf(iov1, nvector, i); 121 vfillbuf(iov2, nvector, i + 1); 122 if (lseek(fd_w, offset, SEEK_SET) < 0) { 123 tst_resm(TFAIL, "lseek before writev failed: %s", 124 strerror(errno)); 125 return (-1); 126 } 127 if (writev(fd_w, iov1, nvector) < 0) { 128 tst_resm(TFAIL, "writev failed: %s", strerror(errno)); 129 return (-1); 130 } 131 if (lseek(fd_r, offset, SEEK_SET) < 0) { 132 tst_resm(TFAIL, "lseek before readv failed: %s", 133 strerror(errno)); 134 return (-1); 135 } 136 if (readv(fd_r, iov2, nvector) < 0) { 137 tst_resm(TFAIL, "readv failed: %s", strerror(errno)); 138 return (-1); 139 } 140 if (vbufcmp(iov1, iov2, nvector) != 0) { 141 tst_resm(TFAIL, "readv/writev comparision failed"); 142 return (-1); 143 } 144 } 145 146 /* Cleanup */ 147 for (i = 0, iovp = iov1; i < nvector; iovp++, i++) { 148 free(iovp->iov_base); 149 } 150 for (i = 0, iovp = iov2; i < nvector; iovp++, i++) { 151 free(iovp->iov_base); 152 } 153 free(iov1); 154 free(iov2); 155 return 0; 156} 157 158static void prg_usage(void) 159{ 160 fprintf(stderr, 161 "Usage: diotest5 [-b bufsize] [-o offset] [ -i iteration] [ -v nvector] [-f filename]\n"); 162 exit(1); 163} 164 165static void setup(void); 166static void cleanup(void); 167 168int main(int argc, char *argv[]) 169{ 170 int i, action, fd_r, fd_w; 171 int fail_count = 0, total = 0, failed = 0; 172 173 /* Options */ 174 sprintf(filename, "testdata-5.%ld", syscall(__NR_gettid)); 175 while ((i = getopt(argc, argv, "b:o:i:v:f:")) != -1) { 176 switch (i) { 177 case 'b': 178 if ((bufsize = atoi(optarg)) <= 0) { 179 fprintf(stderr, "bufsize must be > 0"); 180 prg_usage(); 181 } 182 if (bufsize % 4096 != 0) { 183 fprintf(stderr, "bufsize must be > 0"); 184 prg_usage(); 185 } 186 break; 187 case 'o': 188 if ((offset = atoll(optarg)) <= 0) { 189 fprintf(stderr, "offset must be > 0"); 190 prg_usage(); 191 } 192 break; 193 case 'i': 194 if ((iter = atoi(optarg)) <= 0) { 195 fprintf(stderr, "iterations must be > 0"); 196 prg_usage(); 197 } 198 break; 199 case 'v': 200 if ((nvector = atoi(optarg)) <= 0) { 201 fprintf(stderr, "vector array must be > 0"); 202 prg_usage(); 203 } 204 break; 205 case 'f': 206 strcpy(filename, optarg); 207 break; 208 default: 209 prg_usage(); 210 } 211 } 212 213 setup(); 214 215 /* Testblock-1: Read with Direct IO, Write without */ 216 action = READ_DIRECT; 217 if ((fd_w = open(filename, O_WRONLY | O_CREAT, 0666)) < 0) { 218 tst_brkm(TBROK, cleanup, "fd_w open failed for %s: %s", 219 filename, strerror(errno)); 220 } 221 if ((fd_r = open64(filename, O_DIRECT | O_RDONLY | O_CREAT, 0666)) < 0) { 222 tst_brkm(TBROK, cleanup, "fd_r open failed for %s: %s", 223 filename, strerror(errno)); 224 } 225 if (runtest(fd_r, fd_w, iter, offset, action) < 0) { 226 failed = TRUE; 227 fail_count++; 228 tst_resm(TFAIL, "Read with Direct IO, Write without"); 229 } else 230 tst_resm(TPASS, "Read with Direct IO, Write without"); 231 232 unlink(filename); 233 close(fd_r); 234 close(fd_w); 235 total++; 236 237 /* Testblock-2: Write with Direct IO, Read without */ 238 action = WRITE_DIRECT; 239 if ((fd_w = open(filename, O_DIRECT | O_WRONLY | O_CREAT, 0666)) < 0) { 240 tst_brkm(TBROK, cleanup, "fd_w open failed for %s: %s", 241 filename, strerror(errno)); 242 } 243 if ((fd_r = open64(filename, O_RDONLY | O_CREAT, 0666)) < 0) { 244 tst_brkm(TBROK, cleanup, "fd_r open failed for %s: %s", 245 filename, strerror(errno)); 246 } 247 if (runtest(fd_r, fd_w, iter, offset, action) < 0) { 248 failed = TRUE; 249 fail_count++; 250 tst_resm(TFAIL, "Write with Direct IO, Read without"); 251 } else 252 tst_resm(TPASS, "Write with Direct IO, Read without"); 253 unlink(filename); 254 close(fd_r); 255 close(fd_w); 256 total++; 257 258 /* Testblock-3: Read, Write with Direct IO */ 259 action = RDWR_DIRECT; 260 if ((fd_w = open(filename, O_DIRECT | O_WRONLY | O_CREAT, 0666)) < 0) { 261 tst_brkm(TBROK, cleanup, "fd_w open failed for %s: %s", 262 filename, strerror(errno)); 263 } 264 if ((fd_r = open64(filename, O_DIRECT | O_RDONLY | O_CREAT, 0666)) < 0) { 265 tst_brkm(TBROK, cleanup, "fd_r open failed for %s: %s", 266 filename, strerror(errno)); 267 } 268 if (runtest(fd_r, fd_w, iter, offset, action) < 0) { 269 failed = TRUE; 270 fail_count++; 271 tst_resm(TFAIL, "Read, Write with Direct IO"); 272 } else 273 tst_resm(TPASS, "Read, Write with Direct IO"); 274 unlink(filename); 275 close(fd_r); 276 close(fd_w); 277 total++; 278 279 if (failed) 280 tst_resm(TINFO, "%d/%d testblocks failed", fail_count, total); 281 else 282 tst_resm(TINFO, 283 "%d testblocks %d iterations with %d vector array completed", 284 total, iter, nvector); 285 286 cleanup(); 287 288 tst_exit(); 289} 290 291static void setup(void) 292{ 293 tst_tmpdir(); 294 295 if ((fd1 = open(filename, O_CREAT | O_EXCL, 0600)) < 0) { 296 tst_brkm(TBROK, cleanup, "Couldn't create test file %s: %s", 297 filename, strerror(errno)); 298 } 299 close(fd1); 300 301 /* Test for filesystem support of O_DIRECT */ 302 if ((fd1 = open(filename, O_DIRECT, 0600)) < 0) { 303 tst_brkm(TCONF, cleanup, 304 "O_DIRECT is not supported by this filesystem. %s", 305 strerror(errno)); 306 } 307 close(fd1); 308} 309 310static void cleanup(void) 311{ 312 if (fd1 != -1) 313 unlink(filename); 314 315 tst_rmdir(); 316 317} 318#else /* O_DIRECT */ 319 320int main() 321{ 322 323 tst_resm(TCONF, "O_DIRECT is not defined."); 324 return 0; 325} 326#endif /* O_DIRECT */ 327