// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2000-2001 Silicon Graphics, Inc. * All Rights Reserved. */ #include "global.h" int verbose; /* print lots of debugging info */ void usage(char *progname); void writeblks(int fd, long filesize, int blocksize, int interleave, int base, int rev); int readblks(int fd, long filesize, int blocksize, int interleave, int count); void usage(char *progname) { fprintf(stderr, "usage: %s [-l filesize] [-b blocksize] [-i interleave]\n" "\t\t[-c count] [-r(everse)] [-v(erbose)] filename\n", progname); exit(1); } int main(int argc, char *argv[]) { int interleave, blocksize, count, rev, i, ch, fd; long filesize; char *filename = NULL; int errs; filesize = 1024*1024; blocksize = 4096; count = interleave = 4; rev = verbose = 0; while ((ch = getopt(argc, argv, "b:l:i:c:rv")) != EOF) { switch(ch) { case 'b': blocksize = atoi(optarg); break; case 'c': count = atoi(optarg); break; case 'i': interleave = atoi(optarg); break; case 'l': filesize = atol(optarg); break; case 'v': verbose++; break; case 'r': rev++; break; default: usage(argv[0]); break; } } if (optind == argc-1) filename = argv[optind]; else usage(argv[0]); if ((filesize % (blocksize*interleave)) != 0) { filesize -= filesize % (blocksize * interleave); printf("filesize not a multiple of blocksize*interleave,\n"); printf("reducing filesize to %ld\n", filesize); } if (count > interleave) { count = interleave; printf("count of passes is too large, setting to %d\n", count); } else if (count < 1) { count = 1; printf("count of passes is too small, setting to %d\n", count); } if ((fd = open(filename, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) { perror("open"); return 1; } /* * Avoid allocation patterns being perturbed by different speculative * preallocation beyond EOF configurations by first truncating the file * to the expected maximum file size. */ if (ftruncate(fd, filesize) < 0) { perror("ftruncate"); exit(EXIT_FAILURE); } for (i = 0; i < count; i++) { writeblks(fd, filesize, blocksize, interleave, i, rev); } errs=readblks(fd, filesize, blocksize, interleave, count); if (close(fd) < 0) { perror("close"); return 1; } if (errs) { printf("%d errors detected during readback\n", errs); return 1; } return 0; } void writeblks(int fd, long filesize, int blocksize, int interleave, int base, int rev) { long offset; char *buffer; if ((buffer = calloc(1, blocksize)) == NULL) { perror("malloc"); exit(1); } if (rev) { offset = (filesize-blocksize) - (base * blocksize); } else { offset = base * blocksize; } for (;;) { if (lseek(fd, offset, SEEK_SET) < 0) { perror("lseek"); exit(1); } *(long *)buffer = *(long *)(buffer+256) = offset; if (write(fd, buffer, blocksize) < blocksize) { perror("write"); exit(1); } if (verbose) { printf("writing data at offset=%ld, delta=%d, value 0x%lx and 0x%lx\n", offset-base*blocksize, base, *(long *)buffer, *(long *)(buffer+256)); } if (rev) { offset -= interleave*blocksize; if (offset < 0) break; } else { offset += interleave*blocksize; if (offset >= filesize) break; } } { /* pad file out to full length */ char *zero=""; if (lseek(fd, filesize-1, SEEK_SET)<0) { perror("lseek"); exit(1); } if (write(fd, zero, 1)!=1) { perror("write"); exit(1); } } free(buffer); } int readblks(int fd, long filesize, int blocksize, int interleave, int count) { long offset; char *buffer, *tmp; int xfer, i; int errs=0; if ((buffer = calloc(interleave, blocksize)) == NULL) { perror("malloc"); exit(1); } xfer = interleave * blocksize; if (lseek(fd, (long)0, SEEK_SET) < 0) { perror("lseek"); exit(1); } for (offset = 0; offset < filesize; offset += xfer) { if ((i = read(fd, buffer, xfer) < xfer)) { if (i == 0) break; if (i < 0) perror("read"); printf("short read: %d of %d bytes read\n", i, xfer); exit(1); } for (tmp = buffer, i = 0; i < count; i++, tmp += blocksize) { if ( (*(long *)tmp != (offset+i*blocksize)) || (*(long *)(tmp+256) != (offset+i*blocksize)) ) { printf("mismatched data at offset=%ld, delta=%d, expected 0x%lx, got 0x%lx and 0x%lx\n", offset, i, offset+i*blocksize, *(long *)tmp, *(long *)(tmp+256)); errs++; } } } free(buffer); return errs; }