Home | History | Annotate | Download | only in writetest
      1 /*
      2  *
      3  *   Copyright (c) CHANG Industry, Inc., 2004
      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  *  FILE        : writetest.c
     22  *  DESCRIPTION : The purpose of this test is to verify that writes to
     23  *                disk occur without corruption.  It writes one 1MB
     24  *                buffer at a time, where each byte in the buffer is
     25  *                generated from a random number.  Once done
     26  *                completed, the file is re-opened, the random number
     27  *                generator is re-seeded, and the file is verified.
     28  *
     29  *  HISTORY:
     30  *   05/12/2004 : Written by Danny Sung <dannys (at) changind.com> to
     31  *                verify integrity of disk writes.
     32  *
     33  */
     34 
     35 #include <fcntl.h>
     36 #include <getopt.h>
     37 #include <stdarg.h>
     38 #include <stdint.h>
     39 #include <stdio.h>
     40 #include <stdlib.h>
     41 #include <string.h>
     42 #include <time.h>
     43 #include <unistd.h>
     44 
     45 #include "test.h"
     46 
     47 #define BLOCKSIZE (1024*1024)
     48 #define FILE_OUT    "fileout"
     49 #define FILE_MODE   0644
     50 #define MAX_FILENAME_LEN 1024
     51 
     52 int Verbosity = 0;
     53 int DefaultSeed = 0;
     54 char Filename[MAX_FILENAME_LEN] = FILE_OUT;
     55 off_t NumBlocks = 1;
     56 char *TCID = "writetest";
     57 int TST_TOTAL = 2;
     58 
     59 void buf_init(void)
     60 {
     61 	static int seed = 0;
     62 	if (seed == 0)
     63 		seed = DefaultSeed;
     64 	srand(seed);
     65 }
     66 
     67 void buf_fill(uint8_t * buf)
     68 {
     69 	int i;
     70 	for (i = 0; i < BLOCKSIZE; i++) {
     71 		*buf = (rand() & 0xff);
     72 		buf++;
     73 	}
     74 }
     75 
     76 int write_file(off_t num_blocks, const char *filename)
     77 {
     78 	int fd;
     79 	int ret = 0;
     80 	off_t block;
     81 	uint8_t buf[BLOCKSIZE];
     82 
     83 	fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_LARGEFILE,
     84 		  FILE_MODE);
     85 	if (fd < 0) {
     86 		perror(TCID);
     87 		return (-1);
     88 	}
     89 	for (block = 0; block < num_blocks; block++) {
     90 		int rv;
     91 		if (Verbosity > 2)
     92 			tst_resm(TINFO, "Block: %lld/%lld  (%3lld%%)\r",
     93 				 (long long int)block,
     94 				 (long long int)num_blocks,
     95 				 (long long int)(block * 100 / num_blocks));
     96 		buf_fill(buf);
     97 		rv = write(fd, buf, BLOCKSIZE);
     98 		if (rv != BLOCKSIZE) {
     99 			ret = -1;
    100 			break;
    101 		}
    102 	}
    103 	if (Verbosity > 2)
    104 		tst_resm(TINFO, "Block: %lld/%lld  (%3lld%%)\r",
    105 			 (long long int)block, (long long int)num_blocks,
    106 			 (long long int)(block * 100 / num_blocks));
    107 	close(fd);
    108 	return (ret);
    109 }
    110 
    111 int verify_file(off_t num_blocks, const char *filename)
    112 {
    113 	int fd;
    114 	int ret = 0;
    115 	off_t block;
    116 	uint8_t buf_actual[BLOCKSIZE];
    117 	char buf_read[BLOCKSIZE];
    118 
    119 	fd = open(filename, O_RDONLY);
    120 	if (fd < 0) {
    121 		perror(TCID);
    122 		return (-1);
    123 	}
    124 	for (block = 0; block < num_blocks; block++) {
    125 		int rv;
    126 		int n;
    127 		if (Verbosity > 2)
    128 			tst_resm(TINFO, "Block: %lld/%lld  (%3lld%%)\r",
    129 				 (long long int)block,
    130 				 (long long int)num_blocks,
    131 				 (long long int)(block * 100 / num_blocks));
    132 		buf_fill(buf_actual);
    133 		rv = read(fd, buf_read, BLOCKSIZE);
    134 		if (rv != BLOCKSIZE) {
    135 			ret = -1;
    136 			break;
    137 		}
    138 		for (n = 0; n < BLOCKSIZE; n++) {
    139 			int ba, br;
    140 			ba = buf_actual[n] & 0xff;
    141 			br = buf_read[n] & 0xff;
    142 			if (ba != br) {
    143 				if (Verbosity > 2)
    144 					tst_resm(TINFO,
    145 						 "Mismatch: block=%lld +%d bytes offset=%lld read: %02xh actual: %02xh\n",
    146 						 (long long int)block, n,
    147 						 (long long
    148 						  int)((block * BLOCKSIZE) + n),
    149 						 br, ba);
    150 				ret++;
    151 			}
    152 		}
    153 	}
    154 	close(fd);
    155 	if (Verbosity > 2)
    156 		tst_resm(TINFO, "Block: %lld/%lld  (%3lld%%)\r",
    157 			 (long long int)block, (long long int)num_blocks,
    158 			 (long long int)(block * 100 / num_blocks));
    159 	return (ret);
    160 }
    161 
    162 void usage(void)
    163 {
    164 	printf("%s [-v] [-b blocks] [-s seed] [-o filename]\n", TCID);
    165 	printf("\n"
    166 	       "   -v          - increase verbosity level\n"
    167 	       "   blocks      - number of blocks to write\n"
    168 	       "   seed        - seed to use (0 to use timestamp)\n"
    169 	       "   filename    - name of output file\n");
    170 }
    171 
    172 void parse_args(int argc, char **argv)
    173 {
    174 	int c;
    175 	TCID = argv[0];
    176 
    177 	while (1) {
    178 		int option_index = 0;
    179 		static struct option long_options[] = {
    180 			{"blocks", 1, 0, 'b'},
    181 			{"out", 1, 0, 'o'},
    182 			{"seed", 1, 0, 's'},
    183 			{"verbose", 0, 0, 'v'},
    184 			{"help", 0, 0, 'h'},
    185 			{0, 0, 0, 0}
    186 		};
    187 		c = getopt_long(argc, argv, "hvb:o:s:", long_options,
    188 				&option_index);
    189 		if (c == -1)
    190 			break;
    191 		switch (c) {
    192 		case 'b':
    193 			NumBlocks = strtoul(optarg, NULL, 0);
    194 			break;
    195 		case 'o':
    196 			strncpy(Filename, optarg, MAX_FILENAME_LEN);
    197 			break;
    198 		case 's':
    199 			DefaultSeed = strtoul(optarg, NULL, 0);
    200 			break;
    201 		case 'v':
    202 			Verbosity++;
    203 			break;
    204 		case 'h':
    205 		default:
    206 			usage();
    207 			exit(-1);
    208 		}
    209 	}
    210 }
    211 
    212 void setup()
    213 {
    214 	tst_tmpdir();
    215 
    216 }
    217 
    218 void cleanup(void)
    219 {
    220 	tst_rmdir();
    221 	tst_exit();
    222 }
    223 
    224 int main(int argc, char *argv[])
    225 {
    226 	int rv;
    227 
    228 	setup();
    229 
    230 	DefaultSeed = time(NULL);
    231 	parse_args(argc, argv);
    232 	tst_resm(TINFO, "Blocks:       %lld\n", (long long int)NumBlocks);
    233 	tst_resm(TINFO, "Seed:         %d\n", DefaultSeed);
    234 	tst_resm(TINFO, "Output file: '%s'\n", Filename);
    235 
    236 	tst_resm(TINFO, "Writing %lld blocks of %d bytes to '%s'\n",
    237 		 (long long int)NumBlocks, BLOCKSIZE, Filename);
    238 	buf_init();
    239 	rv = write_file(NumBlocks, Filename);
    240 	if (rv == 0) {
    241 		tst_resm(TPASS, "Write: Success");
    242 	} else {
    243 		tst_resm(TFAIL, "Write: Failure");
    244 	}
    245 
    246 	tst_resm(TINFO, "Verifying %lld blocks in '%s'\n",
    247 		 (long long int)NumBlocks, Filename);
    248 	buf_init();
    249 	rv = verify_file(NumBlocks, Filename);
    250 	if (rv == 0) {
    251 		tst_resm(TPASS, "Verify: Success\n");
    252 	} else {
    253 		tst_resm(TFAIL, "Verify: Failure");
    254 		tst_resm(TINFO, "Total mismatches: %d bytes\n", rv);
    255 	}
    256 
    257 	cleanup();
    258 	return 0;
    259 }
    260