Home | History | Annotate | Download | only in direct_io
      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 (at) 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 */
     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 */
    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 
    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 
    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 
    269 static void cleanup(void)
    270 {
    271 	if (fd1 != -1)
    272 		unlink(filename);
    273 
    274 	tst_rmdir();
    275 
    276 }
    277 
    278 #else /* O_DIRECT */
    279 int main()
    280 {
    281 	tst_brkm(TCONF, NULL, "O_DIRECT is not defined.");
    282 }
    283 #endif /* O_DIRECT */
    284