xref: /aosp_15_r20/external/autotest/client/tests/disktest/src/disktest.c (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1*9c5db199SXin Li // Copyright Martin J. Bligh & Google. <[email protected]>.
2*9c5db199SXin Li // New Year's Eve, 2006
3*9c5db199SXin Li // Released under the GPL v2.
4*9c5db199SXin Li //
5*9c5db199SXin Li // Compile with -D_FILE_OFFSET_BITS=64 -D _GNU_SOURCE
6*9c5db199SXin Li 
7*9c5db199SXin Li #include <stdio.h>
8*9c5db199SXin Li #include <stdlib.h>
9*9c5db199SXin Li #include <unistd.h>
10*9c5db199SXin Li #include <sys/types.h>
11*9c5db199SXin Li #include <sys/wait.h>
12*9c5db199SXin Li #include <sys/stat.h>
13*9c5db199SXin Li #include <fcntl.h>
14*9c5db199SXin Li #include <time.h>
15*9c5db199SXin Li #include <getopt.h>
16*9c5db199SXin Li #include <errno.h>
17*9c5db199SXin Li #include <malloc.h>
18*9c5db199SXin Li #include <string.h>
19*9c5db199SXin Li 
20*9c5db199SXin Li struct pattern {
21*9c5db199SXin Li 	unsigned int sector;
22*9c5db199SXin Li 	unsigned int signature;
23*9c5db199SXin Li };
24*9c5db199SXin Li 
25*9c5db199SXin Li #define SECTOR_SIZE 512
26*9c5db199SXin Li #define PATTERN_PER_SECTOR  (SECTOR_SIZE / sizeof(struct pattern))
27*9c5db199SXin Li 
28*9c5db199SXin Li char *filename = "testfile";
29*9c5db199SXin Li volatile int stop = 0;
30*9c5db199SXin Li int init_only = 0;
31*9c5db199SXin Li int verify_only = 0;
32*9c5db199SXin Li unsigned int megabytes = 1;
33*9c5db199SXin Li unsigned int skip_mb = 0;
34*9c5db199SXin Li unsigned int start_block = 0;
35*9c5db199SXin Li unsigned int blocksize = 4096;
36*9c5db199SXin Li unsigned int seconds = 15;
37*9c5db199SXin Li unsigned int linear_tasks = 1;
38*9c5db199SXin Li unsigned int random_tasks = 4;
39*9c5db199SXin Li unsigned int blocks;
40*9c5db199SXin Li unsigned int sectors_per_block;
41*9c5db199SXin Li unsigned int signature = 0;
42*9c5db199SXin Li unsigned int stop_on_error = 0;
43*9c5db199SXin Li 
die(char * error)44*9c5db199SXin Li void die(char *error)
45*9c5db199SXin Li {
46*9c5db199SXin Li 	fprintf(stderr, "%s\n", error);
47*9c5db199SXin Li 	exit(1);
48*9c5db199SXin Li }
49*9c5db199SXin Li 
50*9c5db199SXin Li /*
51*9c5db199SXin Li  * Fill a block with it's own sector number
52*9c5db199SXin Li  * buf must be at least blocksize
53*9c5db199SXin Li  */
write_block(int fd,unsigned int block,struct pattern * buffer)54*9c5db199SXin Li void write_block(int fd, unsigned int block, struct pattern *buffer)
55*9c5db199SXin Li {
56*9c5db199SXin Li 	unsigned int i, sec_offset, sector;
57*9c5db199SXin Li 	off_t offset;
58*9c5db199SXin Li 	struct pattern *sector_buffer;
59*9c5db199SXin Li 
60*9c5db199SXin Li 	for (sec_offset = 0; sec_offset < sectors_per_block; sec_offset++) {
61*9c5db199SXin Li 		sector = (block * sectors_per_block) + sec_offset;
62*9c5db199SXin Li 		sector_buffer = &buffer[sec_offset * PATTERN_PER_SECTOR];
63*9c5db199SXin Li 
64*9c5db199SXin Li 		for (i = 0; i < PATTERN_PER_SECTOR; i++) {
65*9c5db199SXin Li 			sector_buffer[i].sector = sector;
66*9c5db199SXin Li 			sector_buffer[i].signature = signature;
67*9c5db199SXin Li 		}
68*9c5db199SXin Li 	}
69*9c5db199SXin Li 
70*9c5db199SXin Li 	offset = block; offset *= blocksize;   // careful of overflow
71*9c5db199SXin Li 	lseek(fd, offset, SEEK_SET);
72*9c5db199SXin Li 	if (write(fd, buffer, blocksize) != blocksize) {
73*9c5db199SXin Li 		fprintf(stderr, "Write failed : file %s : block %d\n", filename, block);
74*9c5db199SXin Li 		exit(1);
75*9c5db199SXin Li 	}
76*9c5db199SXin Li }
77*9c5db199SXin Li 
78*9c5db199SXin Li /*
79*9c5db199SXin Li  * Verify a block contains the correct signature and sector numbers for
80*9c5db199SXin Li  * each sector within that block. We check every copy within the sector
81*9c5db199SXin Li  * and count how many were wrong.
82*9c5db199SXin Li  *
83*9c5db199SXin Li  * buf must be at least blocksize
84*9c5db199SXin Li  */
verify_block(int fd,unsigned int block,struct pattern * buffer,char * err)85*9c5db199SXin Li int verify_block(int fd, unsigned int block, struct pattern *buffer, char *err)
86*9c5db199SXin Li {
87*9c5db199SXin Li 	unsigned int sec_offset, sector;
88*9c5db199SXin Li 	off_t offset;
89*9c5db199SXin Li 	int i, errors = 0;
90*9c5db199SXin Li 	struct pattern *sector_buffer;
91*9c5db199SXin Li 
92*9c5db199SXin Li 	offset = block; offset *= blocksize;   // careful of overflow
93*9c5db199SXin Li 	lseek(fd, offset, SEEK_SET);
94*9c5db199SXin Li 	if (read(fd, buffer, blocksize) != blocksize) {
95*9c5db199SXin Li 		fprintf(stderr, "read failed: block %d (errno: %d) filename %s %s\n", block, errno, filename, err);
96*9c5db199SXin Li 		exit(1);
97*9c5db199SXin Li 	}
98*9c5db199SXin Li 
99*9c5db199SXin Li 	for (sec_offset = 0; sec_offset < sectors_per_block; sec_offset++) {
100*9c5db199SXin Li 		unsigned int read_sector = 0, read_signature = 0;
101*9c5db199SXin Li 		unsigned int sector_errors = 0, signature_errors = 0;
102*9c5db199SXin Li 
103*9c5db199SXin Li 		sector = (block * sectors_per_block) + sec_offset;
104*9c5db199SXin Li 		sector_buffer = &buffer[sec_offset * PATTERN_PER_SECTOR];
105*9c5db199SXin Li 
106*9c5db199SXin Li 		for (i = 0; i < PATTERN_PER_SECTOR; i++) {
107*9c5db199SXin Li 			if (sector_buffer[i].sector != sector) {
108*9c5db199SXin Li 				read_sector = sector_buffer[i].sector;
109*9c5db199SXin Li 				sector_errors++;
110*9c5db199SXin Li 				errors++;
111*9c5db199SXin Li 			}
112*9c5db199SXin Li 			if (sector_buffer[i].signature != signature) {
113*9c5db199SXin Li 				read_signature = sector_buffer[i].signature;
114*9c5db199SXin Li 				signature_errors++;
115*9c5db199SXin Li 				errors++;
116*9c5db199SXin Li 			}
117*9c5db199SXin Li 		}
118*9c5db199SXin Li 		if (sector_errors)
119*9c5db199SXin Li 			printf("Block %d (from %d to %d) sector %08x has wrong sector number %08x (%d/%lu) filename %s %s\n",
120*9c5db199SXin Li 					block, start_block, start_block+blocks,
121*9c5db199SXin Li 					sector, read_sector,
122*9c5db199SXin Li 					sector_errors, PATTERN_PER_SECTOR,
123*9c5db199SXin Li 					filename, err);
124*9c5db199SXin Li 		if (signature_errors)
125*9c5db199SXin Li 			printf("Block %d (from %d to %d) sector %08x signature is %08x should be %08x (%d/%lu) filename %s %s\n",
126*9c5db199SXin Li 				block, start_block, start_block+blocks,
127*9c5db199SXin Li 				sector, read_signature, signature,
128*9c5db199SXin Li 				signature_errors, PATTERN_PER_SECTOR,
129*9c5db199SXin Li 				filename, err);
130*9c5db199SXin Li 
131*9c5db199SXin Li 	}
132*9c5db199SXin Li 	return errors;
133*9c5db199SXin Li }
134*9c5db199SXin Li 
write_file(unsigned int end_time,int random_access)135*9c5db199SXin Li void write_file(unsigned int end_time, int random_access)
136*9c5db199SXin Li {
137*9c5db199SXin Li 	int fd, pid;
138*9c5db199SXin Li 	unsigned int block;
139*9c5db199SXin Li 	void *buffer;
140*9c5db199SXin Li 
141*9c5db199SXin Li 	fflush(stdout); fflush(stderr);
142*9c5db199SXin Li 	pid = fork();
143*9c5db199SXin Li 
144*9c5db199SXin Li 	if (pid < 0)
145*9c5db199SXin Li 		die ("error forking child");
146*9c5db199SXin Li 	if (pid != 0)			// parent
147*9c5db199SXin Li 		return;
148*9c5db199SXin Li 
149*9c5db199SXin Li 	fd = open(filename, O_RDWR, 0666);
150*9c5db199SXin Li 	buffer = malloc(blocksize);
151*9c5db199SXin Li 
152*9c5db199SXin Li 	if (random_access) {
153*9c5db199SXin Li 		srandom(time(NULL) - getpid());
154*9c5db199SXin Li 		while(time(NULL) < end_time) {
155*9c5db199SXin Li 			block = start_block + (unsigned int)(random() % blocks);
156*9c5db199SXin Li 			write_block(fd, block, buffer);
157*9c5db199SXin Li 		}
158*9c5db199SXin Li 	} else {
159*9c5db199SXin Li 		while(time(NULL) < end_time)
160*9c5db199SXin Li 			for (block = start_block; block < start_block + blocks; block++)
161*9c5db199SXin Li 				write_block(fd, block, buffer);
162*9c5db199SXin Li 	}
163*9c5db199SXin Li 	free(buffer);
164*9c5db199SXin Li 	exit(0);
165*9c5db199SXin Li }
166*9c5db199SXin Li 
verify_file(unsigned int end_time,int random_access,int direct)167*9c5db199SXin Li void verify_file(unsigned int end_time, int random_access, int direct)
168*9c5db199SXin Li {
169*9c5db199SXin Li 	int pid, error = 0;
170*9c5db199SXin Li 	char err_msg[40];
171*9c5db199SXin Li 	char *err = err_msg;
172*9c5db199SXin Li 	fflush(stdout); fflush(stderr);
173*9c5db199SXin Li 	pid = fork();
174*9c5db199SXin Li 
175*9c5db199SXin Li 	if (pid < 0)
176*9c5db199SXin Li 		die ("error forking child");
177*9c5db199SXin Li 	if (pid != 0)			// parent
178*9c5db199SXin Li 		return;
179*9c5db199SXin Li 
180*9c5db199SXin Li 	int fd;
181*9c5db199SXin Li 	unsigned int block;
182*9c5db199SXin Li 	unsigned int align = (blocksize > 4096) ? blocksize : 4096;
183*9c5db199SXin Li 	void *buffer = memalign(align, blocksize);
184*9c5db199SXin Li 
185*9c5db199SXin Li 	if (direct) {
186*9c5db199SXin Li 		fd = open(filename, O_RDONLY | O_DIRECT);
187*9c5db199SXin Li 		strcpy(err, "direct");
188*9c5db199SXin Li 		err += 6;
189*9c5db199SXin Li 	} else {
190*9c5db199SXin Li 		fd = open(filename, O_RDONLY);
191*9c5db199SXin Li 		strcpy(err, "cached");
192*9c5db199SXin Li 		err += 6;
193*9c5db199SXin Li 	}
194*9c5db199SXin Li 
195*9c5db199SXin Li 	if (random_access) {
196*9c5db199SXin Li 		strcpy(err, ",random");
197*9c5db199SXin Li 		srandom(time(NULL) - getpid());
198*9c5db199SXin Li 		while(time(NULL) < end_time) {
199*9c5db199SXin Li 			block = start_block + (unsigned int)(random() % blocks);
200*9c5db199SXin Li 			if (verify_block(fd, block, buffer, err_msg))
201*9c5db199SXin Li 				error = 1;
202*9c5db199SXin Li 		}
203*9c5db199SXin Li 	} else {
204*9c5db199SXin Li 		strcpy(err, ",linear");
205*9c5db199SXin Li 		while(time(NULL) < end_time)
206*9c5db199SXin Li 			for (block = start_block; block < start_block + blocks; block++)
207*9c5db199SXin Li 				if (verify_block(fd, block, buffer, err_msg))
208*9c5db199SXin Li 					error = 1;
209*9c5db199SXin Li 	}
210*9c5db199SXin Li 	free(buffer);
211*9c5db199SXin Li 	exit(error);
212*9c5db199SXin Li }
213*9c5db199SXin Li 
usage(void)214*9c5db199SXin Li void usage(void)
215*9c5db199SXin Li {
216*9c5db199SXin Li 	printf("Usage: disktest\n");
217*9c5db199SXin Li 	printf("    [-f filename]        filename to use     (testfile)\n");
218*9c5db199SXin Li 	printf("    [-s seconds]         seconds to run for  (15)\n");
219*9c5db199SXin Li 	printf("    [-m megabytes]       megabytes to use    (1)\n");
220*9c5db199SXin Li 	printf("    [-M megabytes]       megabytes to skip   (0)\n");
221*9c5db199SXin Li 	printf("    [-b blocksize]	 blocksize           (4096)\n");
222*9c5db199SXin Li 	printf("    [-l linear tasks]    linear access tasks (4)\n");
223*9c5db199SXin Li 	printf("    [-r random tasks]    random access tasks (4)\n");
224*9c5db199SXin Li 	printf("    [-v]                 verify pre-existing file\n");
225*9c5db199SXin Li 	printf("    [-i]                 only do init phase\n");
226*9c5db199SXin Li 	printf("    [-S]                 stop immediately on error\n");
227*9c5db199SXin Li 	printf("\n");
228*9c5db199SXin Li }
229*9c5db199SXin Li 
double_verify(int fd,void * buffer,char * err)230*9c5db199SXin Li unsigned int double_verify(int fd, void *buffer, char *err)
231*9c5db199SXin Li {
232*9c5db199SXin Li 	unsigned int block, errors = 0;
233*9c5db199SXin Li 
234*9c5db199SXin Li 	for (block = start_block; block < start_block + blocks; block++) {
235*9c5db199SXin Li 		if (verify_block(fd, block, buffer, err)) {
236*9c5db199SXin Li 			if (stop_on_error)
237*9c5db199SXin Li 				return 1;
238*9c5db199SXin Li 			errors++;
239*9c5db199SXin Li 		}
240*9c5db199SXin Li 	}
241*9c5db199SXin Li 	return errors;
242*9c5db199SXin Li }
243*9c5db199SXin Li 
main(int argc,char * argv[])244*9c5db199SXin Li int main(int argc, char *argv[])
245*9c5db199SXin Li {
246*9c5db199SXin Li 	unsigned int block;
247*9c5db199SXin Li 	time_t start_time, end_time;
248*9c5db199SXin Li 	int tasks, opt, retcode, pid;
249*9c5db199SXin Li 	void *init_buffer;
250*9c5db199SXin Li 
251*9c5db199SXin Li 	/* Parse all input options */
252*9c5db199SXin Li 	while ((opt = getopt(argc, argv, "vf:s:m:M:b:l:r:iS")) != -1) {
253*9c5db199SXin Li 		switch (opt) {
254*9c5db199SXin Li 			case 'v':
255*9c5db199SXin Li 				verify_only = 1;
256*9c5db199SXin Li 				break;
257*9c5db199SXin Li 			case 'f':
258*9c5db199SXin Li 				filename = optarg;
259*9c5db199SXin Li 				break;
260*9c5db199SXin Li 			case 's':
261*9c5db199SXin Li 				seconds = atoi(optarg);
262*9c5db199SXin Li 				break;
263*9c5db199SXin Li 			case 'm':
264*9c5db199SXin Li 				megabytes = atoi(optarg);
265*9c5db199SXin Li 				break;
266*9c5db199SXin Li 			case 'M':
267*9c5db199SXin Li 				skip_mb = atoi(optarg);
268*9c5db199SXin Li 				break;
269*9c5db199SXin Li 			case 'b':
270*9c5db199SXin Li 				blocksize = atoi(optarg);
271*9c5db199SXin Li 				break;
272*9c5db199SXin Li 			case 'l':
273*9c5db199SXin Li 				linear_tasks = atoi(optarg);
274*9c5db199SXin Li 				break;
275*9c5db199SXin Li 			case 'r':
276*9c5db199SXin Li 				random_tasks = atoi(optarg);
277*9c5db199SXin Li 				break;
278*9c5db199SXin Li 			case 'i':
279*9c5db199SXin Li 				init_only = 1;
280*9c5db199SXin Li 				break;
281*9c5db199SXin Li 			case 'S':
282*9c5db199SXin Li 				stop_on_error = 1;
283*9c5db199SXin Li 				break;
284*9c5db199SXin Li 			default:
285*9c5db199SXin Li 				usage();
286*9c5db199SXin Li 				exit(1);
287*9c5db199SXin Li 		}
288*9c5db199SXin Li 	}
289*9c5db199SXin Li 	argc -= optind;
290*9c5db199SXin Li 	argv += optind;
291*9c5db199SXin Li 
292*9c5db199SXin Li 	/* blocksize must be < 1MB, and a divisor. Tough */
293*9c5db199SXin Li 	blocks = megabytes * (1024 * 1024 / blocksize);
294*9c5db199SXin Li 	start_block = skip_mb * (1024 * 1024 / blocksize);
295*9c5db199SXin Li 	sectors_per_block = blocksize / SECTOR_SIZE;
296*9c5db199SXin Li 	init_buffer = malloc(blocksize);
297*9c5db199SXin Li 
298*9c5db199SXin Li 	if (verify_only) {
299*9c5db199SXin Li 		struct stat stat_buf;
300*9c5db199SXin Li 
301*9c5db199SXin Li 		printf("Verifying %s\n", filename);
302*9c5db199SXin Li 		int fd = open(filename, O_RDONLY);
303*9c5db199SXin Li 		if (fd < 0)
304*9c5db199SXin Li 			die("open failed");
305*9c5db199SXin Li 
306*9c5db199SXin Li 		if (fstat(fd, &stat_buf) != 0)
307*9c5db199SXin Li 			die("fstat failed");
308*9c5db199SXin Li 		megabytes = stat_buf.st_size / (1024 * 1024);
309*9c5db199SXin Li 		blocks = megabytes * (1024 * 1024 / blocksize);
310*9c5db199SXin Li 		if (read(fd, init_buffer, SECTOR_SIZE) != SECTOR_SIZE) {
311*9c5db199SXin Li 			fprintf(stderr, "read failed of initial sector (errno: %d) filename %s\n", errno, filename);
312*9c5db199SXin Li 			exit(1);
313*9c5db199SXin Li 		}
314*9c5db199SXin Li 		lseek(fd, 0, SEEK_SET);
315*9c5db199SXin Li 		signature = ((struct pattern *)init_buffer)->signature;
316*9c5db199SXin Li 
317*9c5db199SXin Li 		printf("Checking %d megabytes using signature %08x\n",
318*9c5db199SXin Li 							megabytes, signature);
319*9c5db199SXin Li 		if (double_verify(fd, init_buffer, "init1"))
320*9c5db199SXin Li 			exit(1);
321*9c5db199SXin Li 		else
322*9c5db199SXin Li 			exit(0);
323*9c5db199SXin Li 	}
324*9c5db199SXin Li 
325*9c5db199SXin Li 	signature = (getpid() << 16) + ((unsigned int) time(NULL) & 0xffff);
326*9c5db199SXin Li 
327*9c5db199SXin Li 	/* Initialise file */
328*9c5db199SXin Li 	int fd = open(filename, O_RDWR | O_TRUNC | O_CREAT, 0666);
329*9c5db199SXin Li 	if (fd < 0)
330*9c5db199SXin Li 		die("open failed");
331*9c5db199SXin Li 
332*9c5db199SXin Li 	start_time = time(NULL);
333*9c5db199SXin Li 
334*9c5db199SXin Li 	printf("Ininitializing block %d to %d in file %s (signature %08x)\n", start_block, start_block+blocks, filename, signature);
335*9c5db199SXin Li 	/* Initialise all file data to correct blocks */
336*9c5db199SXin Li 	for (block = start_block; block < start_block+blocks; block++)
337*9c5db199SXin Li 		write_block(fd, block, init_buffer);
338*9c5db199SXin Li 	if(fsync(fd) != 0)
339*9c5db199SXin Li 		die("fsync failed");
340*9c5db199SXin Li 	if (double_verify(fd, init_buffer, "init1")) {
341*9c5db199SXin Li 		if (!stop_on_error) {
342*9c5db199SXin Li 			printf("First verify failed. Repeating for posterity\n");
343*9c5db199SXin Li 			double_verify(fd, init_buffer, "init2");
344*9c5db199SXin Li 		}
345*9c5db199SXin Li 		exit(1);
346*9c5db199SXin Li 	}
347*9c5db199SXin Li 
348*9c5db199SXin Li 	printf("Wrote %d MB to %s (%d seconds)\n", megabytes, filename, (int) (time(NULL) - start_time));
349*9c5db199SXin Li 
350*9c5db199SXin Li 	free(init_buffer);
351*9c5db199SXin Li 	if (init_only)
352*9c5db199SXin Li 		exit(0);
353*9c5db199SXin Li 
354*9c5db199SXin Li 	end_time = time(NULL) + seconds;
355*9c5db199SXin Li 
356*9c5db199SXin Li 	/* Fork off all linear access pattern tasks */
357*9c5db199SXin Li 	for (tasks = 0; tasks < linear_tasks; tasks++)
358*9c5db199SXin Li 		write_file(end_time, 0);
359*9c5db199SXin Li 
360*9c5db199SXin Li 	/* Fork off all random access pattern tasks */
361*9c5db199SXin Li 	for (tasks = 0; tasks < random_tasks; tasks++)
362*9c5db199SXin Li 		write_file(end_time, 1);
363*9c5db199SXin Li 
364*9c5db199SXin Li 	/* Verify in all four possible ways */
365*9c5db199SXin Li 	verify_file(end_time, 0, 0);
366*9c5db199SXin Li 	verify_file(end_time, 0, 1);
367*9c5db199SXin Li 	verify_file(end_time, 1, 0);
368*9c5db199SXin Li 	verify_file(end_time, 1, 1);
369*9c5db199SXin Li 
370*9c5db199SXin Li 	for (tasks = 0; tasks < linear_tasks + random_tasks + 4; tasks++) {
371*9c5db199SXin Li 		pid = wait(&retcode);
372*9c5db199SXin Li 		if (retcode != 0) {
373*9c5db199SXin Li 			printf("pid %d exited with status %d\n", pid, retcode);
374*9c5db199SXin Li 			exit(1);
375*9c5db199SXin Li 		}
376*9c5db199SXin Li 	}
377*9c5db199SXin Li 	return 0;
378*9c5db199SXin Li }
379