2 * Copyright (c) 2000-2003 Silicon Graphics, Inc.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 unsigned char *valid; /* Bit-vector array showing which blocks have been written */
24 int nvalid; /* number of bytes in valid array */
25 #define SETBIT(ARRAY, N) ((ARRAY)[(N)/8] |= (1 << ((N)%8)))
26 #define BITVAL(ARRAY, N) ((ARRAY)[(N)/8] & (1 << ((N)%8)))
28 #define power_of_2(x) ((x) && !((x) & ((x) - 1)))
29 #define DEFAULT_FILESIZE ((__uint64_t) (256 * 1024 * 1024))
30 #define DEFAULT_BLOCKSIZE 512
34 unsigned int blocksize;
41 int extsize; /* used only for real-time */
44 __uint64_t fileoffset;
46 struct fsxattr rtattr;
48 #define READ_XFER 10 /* block to read at a time when checking */
51 * Define xfscntl() to mask the difference between the Linux
52 * and the Irix fcntl() interfaces to XFS for user space. The
53 * "cmd" argument is just the last part of the command, e.g.
54 * pass FSGETXATTR in place of either XFS_IOC_FSGETXATTR (Linux)
55 * F_FSGETXATTR (Irix).
58 #ifdef __sgi__ /* Irix */
59 # define xfscntl(filename, fd, cmd, arg) \
60 fcntl((fd), F_ ## cmd, (arg))
62 # define xfscntl(filename, fd, cmd, arg) \
63 xfsctl((filename), (fd), XFS_IOC_ ## cmd, (arg))
64 #endif /* ! __sgi__ */
70 "usage: %s [-l filesize] [-b blocksize] [-c count]\n"
71 "\t\t[-o write_offset] [-s seed] [-r [-x extentsize]]\n"
72 "\t\t[-w] [-v] [-d] [-a] [-p] [-t] filename\n\n",
74 fprintf(stderr, "\tdefault filesize is %" PRIu64 " bytes\n",
76 fprintf(stderr, "\tdefault blocksize is %u bytes\n",
78 fprintf(stderr, "\tdefault count is %d block-sized writes\n",
79 (int) (DEFAULT_FILESIZE / DEFAULT_BLOCKSIZE));
80 fprintf(stderr, "\tdefault write_offset is %" PRIu64 " bytes\n",
90 numblocks = filesize / blocksize;
91 block = random() % numblocks;
92 if (BITVAL(valid, block) == 0)
95 for ( ; BITVAL(valid, block) != 0; block++) {
96 if (block == (numblocks-1))
100 printf("returning block -1\n");
105 dumpblock(int *buffer, __uint64_t offset, int blocksize)
109 for (i = 0; i < (blocksize / 16); i++) {
110 printf("%llx: 0x%08x 0x%08x 0x%08x 0x%08x\n",
111 (unsigned long long)offset, *buffer, *(buffer + 1), *(buffer + 2),
119 writeblks(char *fname, int fd, size_t alignment)
129 if (posix_memalign((void **) &buffer, alignment, blocksize)) {
133 memset(buffer, 0, blocksize);
137 if (verbose && ((count % 100) == 0)) {
147 offset = (__uint64_t) block * blocksize;
151 fl.l_start = fileoffset + offset;
152 fl.l_len = blocksize;
155 if (xfscntl(fname, fd, RESVSP64, &fl) < 0) {
156 perror("xfsnctl(RESVSP64)");
161 SETBIT(valid, block);
163 if (lseek64(fd, fileoffset + offset, SEEK_SET) < 0) {
168 * Before writing, record offset at the base
169 * of the buffer and at offset 256 bytes
170 * into it. We'll verify this when we read
173 *(__uint64_t *) buffer = fileoffset + offset;
174 *(__uint64_t *) (buffer + 256) = fileoffset + offset;
176 if (write(fd, buffer, blocksize) < blocksize) {
182 printf("%swriting data at offset=%llx\n",
184 (unsigned long long) (fileoffset + offset));
192 readblks(int fd, size_t alignment)
194 unsigned long offset;
196 unsigned int xfer, block, i;
201 xfer = READ_XFER*blocksize;
202 if (posix_memalign((void **) &buffer, alignment, xfer)) {
206 memset(buffer, 0, xfer);
210 if (lseek64(fd, fileoffset, SEEK_SET) < 0) {
214 for (offset = 0, block = 0; offset < filesize; offset += xfer) {
215 if ((i = read(fd, buffer, xfer) < xfer)) {
221 for (tmp = buffer, i = 0; i < READ_XFER; i++, block++, tmp += blocksize) {
222 if (verbose && ((block % 100) == 0)) {
226 if (BITVAL(valid, block) == 0) {
227 if ((*(__uint64_t *)tmp != 0LL) ||
228 (*(__uint64_t *)(tmp+256) != 0LL)) {
229 printf("mismatched data at offset=%llx, expected 0x%llx, got 0x%llx and 0x%llx\n",
230 (unsigned long long)fileoffset + block * blocksize,
232 *(unsigned long long *)tmp,
233 *(unsigned long long *)(tmp+256));
237 if ( (*(__uint64_t *)tmp !=
238 fileoffset + block * blocksize) ||
239 (*(__uint64_t *)(tmp+256) !=
240 fileoffset + block * blocksize) ) {
241 printf("mismatched data at offset=%llx, "
242 "expected 0x%llx, got 0x%llx and 0x%llx\n",
243 (unsigned long long)fileoffset + block * blocksize,
244 (unsigned long long)fileoffset + block * blocksize,
245 *(unsigned long long *)tmp,
246 *(unsigned long long *)(tmp+256));
251 printf("block %d blocksize %d\n", block,
253 dumpblock((int *)tmp,
254 fileoffset + block * blocksize,
267 * Determine the memory alignment required for I/O buffers. For
268 * direct I/O we request the needed information from the file
269 * system; otherwise pointer alignment is fine. Returns the
270 * alignment multiple, or 0 if an error occurs.
273 get_alignment(char *filename, int fd)
275 struct dioattr dioattr;
278 return sizeof (void *);
280 memset(&dioattr, 0, sizeof dioattr);
281 if (xfscntl(filename, fd, DIOINFO, &dioattr) < 0) {
282 perror("xfscntl(FIOINFO)");
286 /* Make sure the alignment meets the needs of posix_memalign() */
288 if (dioattr.d_mem % sizeof (void *) || ! power_of_2(dioattr.d_mem)) {
294 * Also make sure user doesn't specify a block size that's
295 * incompatible with the underlying file system.
297 if (! dioattr.d_miniosz) {
298 perror("miniosz == 0!");
301 if (blocksize % dioattr.d_miniosz) {
302 fprintf(stderr, "blocksize %d must be a multiple of "
303 "%d for direct I/O\n", blocksize, dioattr.d_miniosz);
307 return (size_t) dioattr.d_mem;
311 main(int argc, char *argv[])
313 int seed, ch, fd, oflags;
314 char *filename = NULL;
318 filesize = DEFAULT_FILESIZE;
319 blocksize = DEFAULT_BLOCKSIZE;
320 count = (int) filesize / blocksize;
325 while ((ch = getopt(argc, argv, "b:l:s:c:o:x:vwdrapt")) != EOF) {
327 case 'b': blocksize = atoi(optarg); break;
328 case 'l': filesize = strtoull(optarg, NULL, 16); break;
329 case 's': seed = atoi(optarg); break;
330 case 'c': count = atoi(optarg); break;
331 case 'o': fileoffset = strtoull(optarg, NULL, 16); break;
332 case 'x': extsize = atoi(optarg); break;
333 case 'v': verbose++; break;
334 case 'w': wsync++; break;
335 case 'd': direct++; break;
336 case 'r': rt++; break;
337 case 'a': alloconly++; break;
338 case 'p': preserve++; break;
339 case 't': test++; preserve++; break;
340 default: usage(argv[0]); break;
343 if (optind == argc-1)
344 filename = argv[optind];
347 if ((filesize % blocksize) != 0) {
348 filesize -= filesize % blocksize;
349 printf("filesize not a multiple of blocksize, reducing filesize to %llu\n",
350 (unsigned long long)filesize);
352 if ((fileoffset % blocksize) != 0) {
353 fileoffset -= fileoffset % blocksize;
354 printf("fileoffset not a multiple of blocksize, reducing fileoffset to %llu\n",
355 (unsigned long long)fileoffset);
357 if (count > (filesize/blocksize)) {
358 count = (filesize/blocksize);
359 printf("count of blocks written is too large, setting to %d\n",
361 } else if (count < 1) {
363 printf("count of blocks written is too small, setting to %d\n",
366 printf("randholes: Seed = %d (use \"-s %d\" to re-execute this test)\n", seed, seed);
369 printf("randholes: blocksize=%d, filesize=%llu, seed=%d\n"
370 "randholes: count=%d, offset=%llu, extsize=%d\n",
371 blocksize, (unsigned long long)filesize, seed,
372 count, (unsigned long long)fileoffset, extsize);
373 printf("randholes: verbose=%d, wsync=%d, direct=%d, rt=%d, alloconly=%d, preserve=%d, test=%d\n",
374 verbose, wsync, direct, rt, alloconly, preserve, test);
377 * Open the file, write rand block in random places, read them all
378 * back to check for correctness, then close the file.
380 nvalid = (filesize / blocksize) / 8 + 1;
381 if ((valid = (unsigned char *)calloc(1, (unsigned)nvalid)) == NULL) {
388 oflags=test?(O_RDONLY):(O_RDWR | O_CREAT);
389 oflags |= (preserve ? 0 : O_TRUNC) |
390 (wsync ? O_SYNC : 0) |
391 (direct ? O_DIRECT : 0);
393 if ((fd = open(filename, oflags, 0666)) < 0) {
399 if (xfscntl(filename, fd, FSGETXATTR, &rtattr) < 0) {
400 perror("xfsnctl(FSGETXATTR)");
403 if ((rtattr.fsx_xflags & XFS_XFLAG_REALTIME) == 0 ||
404 (extsize && rtattr.fsx_extsize != extsize * blocksize)) {
405 rtattr.fsx_xflags |= XFS_XFLAG_REALTIME;
407 rtattr.fsx_extsize = extsize * blocksize;
408 if (xfscntl(filename, fd, FSSETXATTR, &rtattr) < 0) {
409 perror("xfscntl(FSSETXATTR)");
415 alignment = get_alignment(filename, fd);
419 printf(test?"write (skipped)\n":"write\n");
420 writeblks(filename, fd, alignment);
421 printf("readback\n");
422 r = readblks(fd, alignment);
430 printf("randholes: %d errors found during readback\n", r);
433 printf("randholes: ok\n");