#define _LARGEFILE64_SOURCE #include #include #include #include #include #include #include #include #include #include #include #ifndef O_DIRECT #define O_DIRECT 00040000 #endif #define PREALLOC 1024*1024*1024 long blocks; long *blocklist; int blocksize; char *buffer; int fd; long interval = 0; off64_t filesize = PREALLOC; int otrunc = 0; int odirect = 0; int osync = 0; int prealloc = 0; int removefile = 0; char *filename; void usage(void) { fprintf (stderr, "usage: extent [options] \n"); fprintf (stderr, " -d use direct I/O\n"); fprintf (stderr, " -i progress interval\n"); fprintf (stderr, " -l file length (default %ld)\n", filesize); fprintf (stderr, " -p preallocate file\n"); fprintf (stderr, " -r remove file after each test\n"); fprintf (stderr, " -s synchronous I/O\n"); fprintf (stderr, " -t truncate on open\n"); } void preallocate(void) { struct flock f; if (ftruncate(fd, 0) < 0) { perror("ftruncate"); exit(1); } f.l_start = 0; f.l_whence = 0; while (f.l_start < filesize) { f.l_len = PREALLOC; if (f.l_len > (filesize - f.l_start)) f.l_len = filesize - f.l_start; if (ioctl(fd, XFS_IOC_RESVSP64, &f) < 0) { perror("fcntl"); exit(1); } f.l_start += f.l_len; } if (ftruncate(fd, filesize) < 0) { perror("ftruncate"); exit(1); } } void open_file(char *filename) { fd = open(filename, O_WRONLY|O_CREAT|(otrunc ? O_TRUNC : 0)|(osync ? O_SYNC : 0)|(odirect ? O_DIRECT : 0), 0666); if (fd < 0) { perror("open"); exit(1); } } void close_file(void) { if (removefile) { if (unlink(filename) < 0) perror("unlink"); } close(fd); } void do_write(void) { int ret; long i; off64_t offset; for (i = 0; i < blocks; i++) { if (interval && (i % interval) == 0) { printf("\rwriting record %ld of %ld, %f%%", i, blocks, ((float)i * 100) / (float)blocks); fflush(stdout); fdatasync(fd); } offset = (off64_t)blocklist[i] * (off64_t)blocksize; if (lseek64(fd, offset, SEEK_SET) < 0) perror("lseek"); ret = write(fd, buffer, blocksize); if (ret < 0) perror("write"); else if (ret < blocksize) printf("short write\n"); } if (interval) printf("\rwriting record %ld of %ld, %f%%\n", i, blocks, ((float)i * 100) / (float)blocks); } void do_read(void) { int i; int ret; off64_t offset = 0; if (lseek64(fd, 0, SEEK_SET) < 0) { perror("lseek"); exit(1); } for (;;) { ret = read(fd, buffer, blocksize); if (ret < 0) { perror("read"); exit(1); } if (ret == 0) break; for (i = 0; i < ret; i++) { if (buffer[i] != 'x') printf("corruption detected at offset %ld\n", offset); } offset += ret; } } int main(int argc, char **argv) { struct stat buf; long temp; long i; long j; int c; while ((c = getopt(argc, argv, "di:l:prst")) != EOF) { switch (c) { case 'd': odirect = 1; break; case 'i': interval = strtoul(optarg, NULL, 0); break; case 'l': filesize = strtoll(optarg, NULL, 0); break; case 'p': prealloc = 1; break; case 'r': removefile = 1; break; case 's': osync = 1; break; case 't': otrunc = 1; break; default: usage(); exit(1); break; } } if (optind == argc) { usage(); exit(1); } filename = argv[optind]; open_file(filename); if (fstat(fd, &buf) < 0) { perror("fstat"); exit(1); } close_file(); srandom(time(NULL)); blocksize = buf.st_blksize; blocks = filesize / blocksize; printf("blocksize: %d\n", blocksize); printf("blocks: %ld\n", blocks); buffer = memalign(getpagesize(), blocksize); if (!buffer) { perror("malloc"); exit(1); } memset(buffer, 'x', blocksize); blocklist = malloc(sizeof(blocklist[0]) * blocks); if (!blocklist) { perror("malloc"); exit(1); } open_file(filename); if (prealloc) preallocate(); printf("forward sequential write...\n"); for (i = 0; i < blocks; i++) blocklist[i] = i; do_write(); close_file(); open_file(filename); if (prealloc) preallocate(); printf("backward sequential write...\n"); for (i = 0; i < blocks; i++) blocklist[i] = blocks - i - 1; do_write(); close_file(); open_file(filename); if (prealloc) preallocate(); printf("stride write...\n"); for (i = 0, j = 0; i < (blocks / 2); i++, j += 2) blocklist[i] = j; for (j = 1; i < blocks; i++, j += 2) blocklist[i] = j; do_write(); close_file(); open_file(filename); if (prealloc) preallocate(); printf("backward stride write...\n"); for (i = 0, j = blocks - 1; i < (blocks / 2); i++, j -= 2) blocklist[i] = j; for (j = blocks - 2; i < blocks; i++, j -= 2) blocklist[i] = j; do_write(); close_file(); open_file(filename); if (prealloc) preallocate(); printf("inverted stride write...\n"); for (i = 0, j = 0; i < (blocks / 2); i++, j += 2) blocklist[i] = j; for (j = blocks - 1; i < blocks; i++, j -= 2) blocklist[i] = j; do_write(); close_file(); open_file(filename); if (prealloc) preallocate(); printf("parallel write...\n"); for (i = 0, j = 0; i < blocks; i += 2, j++) blocklist[i] = j; for (i = 1; i < blocks; i += 2, j++) blocklist[i] = j; do_write(); close_file(); open_file(filename); if (prealloc) preallocate(); printf("converge write...\n"); for (i = 0, j = 0; i < blocks; i += 2, j++) blocklist[i] = j; for (i = 1, j = blocks - 1; i < blocks; i += 2, j--) blocklist[i] = j; do_write(); close_file(); open_file(filename); if (prealloc) preallocate(); printf("diverge write...\n"); for (i = 0, j = (blocks / 2) - 1; i < blocks; i += 2, j--) blocklist[i] = j; for (i = 1, j = (blocks / 2); i < blocks; i += 2, j++) blocklist[i] = j; do_write(); close_file(); open_file(filename); if (prealloc) preallocate(); printf("random write...\n"); for (i = 0; i < blocks; i++) blocklist[i] = i; for (i = 0; i < blocks; i++) { j = random() % blocks; temp = blocklist[i]; blocklist[i] = blocklist[j]; blocklist[j] = temp; } do_write(); close_file(); free(blocklist); free(buffer); exit(0); }