]>
git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/pread.c
1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2003-2005 Silicon Graphics, Inc.
8 #define _DEFAULT_SOURCE
16 static cmdinfo_t pread_cmd
;
23 " reads a range of bytes in a specified block size from the given offset\n"
26 " 'pread -v 512 20' - dumps 20 bytes read from 512 bytes into the file\n"
28 " Reads a segment of the currently open file, optionally dumping it to the\n"
29 " standard output stream (with -v option) for subsequent inspection.\n"
30 " The reads are performed in sequential blocks starting at offset, with the\n"
31 " blocksize tunable using the -b option (default blocksize is 4096 bytes),\n"
32 " unless a different pattern is requested.\n"
33 " -q -- quiet mode, do not write anything to standard output.\n"
34 " -B -- read backwards through the range from offset (backwards N bytes)\n"
35 " -F -- read forwards through the range of bytes from offset (default)\n"
36 " -v -- be verbose, dump out buffers (used when reading forwards)\n"
37 " -R -- read at random offsets in the range of bytes\n"
38 " -Z N -- zeed the random number generator (used when reading randomly)\n"
39 " (heh, zorry, the -s/-S arguments were already in use in pwrite)\n"
40 " -V N -- use vectored IO with N iovecs of blocksize each (preadv)\n"
42 " -U -- Perform the preadv2() with RWF_DONTCACHE\n"
45 " When in \"random\" mode, the number of read operations will equal the\n"
46 " number required to do a complete forward/backward scan of the range.\n"
47 " Note that the offset within the range is chosen at random each time\n"
48 " (an offset may be read more than once when operating in this mode).\n"
66 iov
= calloc(vectors
, sizeof(struct iovec
));
71 for (i
= 0; i
< vectors
; i
++) {
72 iov
[i
].iov_base
= memalign(pagesize
, bsize
);
73 if (!iov
[i
].iov_base
) {
77 iov
[i
].iov_len
= bsize
;
79 memset(iov
[i
].iov_base
, seed
, bsize
);
81 io_buffersize
= bsize
* vectors
;
85 free(iov
[i
].iov_base
);
98 return alloc_iovec(bsize
, uflag
, seed
);
100 if (bsize
> highwater
) {
103 io_buffer
= memalign(pagesize
, bsize
);
106 highwater
= io_buffersize
= 0;
111 io_buffersize
= bsize
;
113 memset(io_buffer
, seed
, io_buffersize
);
126 for (i
= 0, p
= (char *)buf
; i
< len
; i
+= 16) {
129 printf("%08llx: ", (unsigned long long)offset
+ i
);
130 for (j
= 0; j
< 16 && i
+ j
< len
; j
++, p
++)
133 for (j
= 0; j
< 16 && i
+ j
< len
; j
++, s
++) {
134 if (isalnum((int)*s
))
151 __dump_buffer(io_buffer
, offset
, len
);
155 for (i
= 0; len
> 0 && i
< vectors
; i
++) {
156 l
= min(len
, iov
[i
].iov_len
);
158 __dump_buffer(iov
[i
].iov_base
, offset
, l
);
175 /* trim the iovec if necessary */
176 if (count
< io_buffersize
) {
178 while (len
+ iov
[vecs
].iov_len
< count
) {
179 len
+= iov
[vecs
].iov_len
;
182 oldlen
= iov
[vecs
].iov_len
;
183 iov
[vecs
].iov_len
= count
- len
;
190 bytes
= preadv2(fd
, iov
, vectors
, offset
, preadv2_flags
);
192 bytes
= preadv(fd
, iov
, vectors
, offset
);
194 bytes
= preadv(fd
, iov
, vectors
, offset
);
196 /* restore trimmed iov */
198 iov
[vecs
- 1].iov_len
= oldlen
;
212 return pread(fd
, io_buffer
, min(count
, buffer_size
), offset
);
214 return do_preadv(fd
, offset
, count
, preadv2_flags
);
227 off_t end
, off
, range
;
232 end
= lseek(fd
, 0, SEEK_END
);
233 offset
= (eof
|| offset
> end
) ? end
: offset
;
234 if ((bytes
= (offset
% io_buffersize
)))
236 offset
= max(0, offset
);
237 if ((bytes
= (count
% io_buffersize
)))
239 count
= max(io_buffersize
, count
);
240 range
= count
- io_buffersize
;
245 off
= ((offset
+ (random() % range
)) / io_buffersize
) *
249 bytes
= do_pread(fd
, off
, io_buffersize
, io_buffersize
, preadv2_flags
);
258 if (bytes
< io_buffersize
)
274 off_t end
, off
= *offset
;
275 ssize_t bytes
= 0, bytes_requested
;
276 long long cnt
= *count
;
279 end
= lseek(fd
, 0, SEEK_END
);
280 off
= eof
? end
: min(end
, lseek(fd
, off
, SEEK_SET
));
281 if ((end
= off
- cnt
) < 0) {
282 cnt
+= end
; /* subtraction, end is negative */
289 /* Do initial unaligned read if needed */
290 if ((bytes_requested
= (off
% io_buffersize
))) {
291 off
-= bytes_requested
;
292 bytes
= do_pread(fd
, off
, bytes_requested
, io_buffersize
, preadv2_flags
);
301 if (bytes
< bytes_requested
)
306 /* Iterate backward through the rest of the range */
308 bytes_requested
= min(cnt
, io_buffersize
);
309 off
-= bytes_requested
;
310 bytes
= do_pread(fd
, off
, cnt
, io_buffersize
, preadv2_flags
);
319 if (bytes
< bytes_requested
)
341 while (count
> 0 || eof
) {
342 bytes
= do_pread(fd
, offset
, count
, io_buffersize
, preadv2_flags
);
351 dump_buffer(offset
, bytes
);
353 if (onlyone
|| bytes
< min(count
, io_buffersize
))
370 return read_forward(fd
, offset
, count
, total
, verbose
, onlyone
, 0, 0);
380 unsigned int zeed
= 0;
381 long long count
, total
, tmp
;
382 size_t fsblocksize
, fssectsize
;
383 struct timeval t1
, t2
;
385 int Cflag
, qflag
, uflag
, vflag
;
386 int eof
= 0, direction
= IO_FORWARD
;
388 int preadv2_flags
= 0;
390 Cflag
= qflag
= uflag
= vflag
= 0;
391 init_cvtnum(&fsblocksize
, &fssectsize
);
394 while ((c
= getopt(argc
, argv
, "b:BCFRquUvV:Z:")) != EOF
) {
397 tmp
= cvtnum(fsblocksize
, fssectsize
, optarg
);
399 printf(_("non-numeric bsize -- %s\n"), optarg
);
409 direction
= IO_FORWARD
;
412 direction
= IO_BACKWARD
;
415 direction
= IO_RANDOM
;
425 preadv2_flags
|= RWF_DONTCACHE
;
432 vectors
= strtoul(optarg
, &sp
, 0);
433 if (!sp
|| sp
== optarg
) {
434 printf(_("non-numeric vector count == %s\n"),
441 zeed
= strtoul(optarg
, &sp
, 0);
442 if (!sp
|| sp
== optarg
) {
443 printf(_("non-numeric seed -- %s\n"), optarg
);
450 return command_usage(&pread_cmd
);
453 if (optind
!= argc
- 2) {
455 return command_usage(&pread_cmd
);
457 if (preadv2_flags
!= 0 && vectors
== 0) {
458 printf(_("preadv2 flags require vectored I/O (-V)\n"));
460 return command_usage(&pread_cmd
);
463 offset
= cvtnum(fsblocksize
, fssectsize
, argv
[optind
]);
464 if (offset
< 0 && (direction
& (IO_RANDOM
|IO_BACKWARD
))) {
465 eof
= -1; /* read from EOF */
466 } else if (offset
< 0) {
467 printf(_("non-numeric length argument -- %s\n"), argv
[optind
]);
472 count
= cvtnum(fsblocksize
, fssectsize
, argv
[optind
]);
473 if (count
< 0 && (direction
& (IO_RANDOM
|IO_FORWARD
))) {
474 eof
= -1; /* read to EOF */
475 } else if (count
< 0) {
476 printf(_("non-numeric length argument -- %s\n"), argv
[optind
]);
481 if (alloc_buffer(bsize
, uflag
, 0xabababab) < 0) {
486 gettimeofday(&t1
, NULL
);
489 if (!zeed
) /* srandom seed */
491 c
= read_random(file
->fd
, offset
, count
, &total
, zeed
, eof
,
495 c
= read_forward(file
->fd
, offset
, count
, &total
, vflag
, 0, eof
,
501 c
= read_backward(file
->fd
, &offset
, &count
, &total
, eof
,
514 gettimeofday(&t2
, NULL
);
517 report_io_times("read", &t2
, (long long)offset
, count
, total
, c
, Cflag
);
524 pread_cmd
.name
= "pread";
525 pread_cmd
.altname
= "r";
526 pread_cmd
.cfunc
= pread_f
;
527 pread_cmd
.argmin
= 2;
528 pread_cmd
.argmax
= -1;
529 pread_cmd
.flags
= CMD_NOMAP_OK
| CMD_FOREIGN_OK
;
530 pread_cmd
.args
= _("[-b bs] [-qUv] [-i N] [-FBR [-Z N]] off len");
531 pread_cmd
.oneline
= _("reads a number of bytes at a specified offset");
532 pread_cmd
.help
= pread_help
;
534 add_command(&pread_cmd
);