]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - io/pread.c
configure: don't check for preadv and pwritev
[thirdparty/xfsprogs-dev.git] / io / pread.c
CommitLineData
959ef981 1// SPDX-License-Identifier: GPL-2.0
e246ba5f 2/*
da23017d
NS
3 * Copyright (c) 2003-2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
e246ba5f
NS
5 */
6
c1436573
LR
7#define _BSD_SOURCE
8#define _DEFAULT_SOURCE
64a93371 9#include <sys/uio.h>
6b803e5a
CH
10#include "command.h"
11#include "input.h"
e246ba5f 12#include <ctype.h>
e246ba5f 13#include "init.h"
48c46ee3 14#include "io.h"
e246ba5f
NS
15
16static cmdinfo_t pread_cmd;
17
18static void
19pread_help(void)
20{
21 printf(_(
22"\n"
23" reads a range of bytes in a specified block size from the given offset\n"
24"\n"
25" Example:\n"
48c46ee3 26" 'pread -v 512 20' - dumps 20 bytes read from 512 bytes into the file\n"
e246ba5f
NS
27"\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"
8fb2237e
NS
31" blocksize tunable using the -b option (default blocksize is 4096 bytes),\n"
32" unless a different pattern is requested.\n"
0388cfb1 33" -q -- quiet mode, do not write anything to standard output.\n"
8fb2237e
NS
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"
e115d3b2
DC
40" -V N -- use vectored IO with N iovecs of blocksize each (preadv)\n"
41"\n"
8fb2237e
NS
42" When in \"random\" mode, the number of read operations will equal the\n"
43" number required to do a complete forward/backward scan of the range.\n"
44" Note that the offset within the range is chosen at random each time\n"
45" (an offset may be read more than once when operating in this mode).\n"
e246ba5f
NS
46"\n"));
47}
48
86715ccb 49void *io_buffer;
2c2f6d79 50size_t highwater;
86715ccb 51size_t io_buffersize;
e115d3b2
DC
52int vectors;
53struct iovec *iov;
54
55static int
56alloc_iovec(
57 size_t bsize,
58 int uflag,
59 unsigned int seed)
60{
61 int i;
62
63 iov = calloc(vectors, sizeof(struct iovec));
64 if (!iov)
65 return -1;
66
86715ccb 67 io_buffersize = 0;
e115d3b2
DC
68 for (i = 0; i < vectors; i++) {
69 iov[i].iov_base = memalign(pagesize, bsize);
09bd34dd 70 if (!iov[i].iov_base) {
e115d3b2
DC
71 perror("memalign");
72 goto unwind;
73 }
74 iov[i].iov_len = bsize;
75 if (!uflag)
76 memset(iov[i].iov_base, seed, bsize);
77 }
86715ccb 78 io_buffersize = bsize * vectors;
e115d3b2
DC
79 return 0;
80unwind:
81 for( ; i >= 0; i--)
82 free(iov[i].iov_base);
83 free(iov);
84 iov = NULL;
85 return -1;
86}
e246ba5f
NS
87
88int
89alloc_buffer(
2c2f6d79 90 size_t bsize,
48c46ee3 91 int uflag,
e246ba5f
NS
92 unsigned int seed)
93{
e115d3b2
DC
94 if (vectors)
95 return alloc_iovec(bsize, uflag, seed);
96
105f2cc2 97 if (bsize > highwater) {
86715ccb
ES
98 if (io_buffer)
99 free(io_buffer);
100 io_buffer = memalign(pagesize, bsize);
101 if (!io_buffer) {
ae8d6a95 102 perror("memalign");
86715ccb 103 highwater = io_buffersize = 0;
48c46ee3 104 return -1;
e246ba5f 105 }
105f2cc2 106 highwater = bsize;
e246ba5f 107 }
86715ccb 108 io_buffersize = bsize;
48c46ee3 109 if (!uflag)
86715ccb 110 memset(io_buffer, seed, io_buffersize);
48c46ee3 111 return 0;
e246ba5f
NS
112}
113
b6fef47a 114static void
e115d3b2
DC
115__dump_buffer(
116 void *buf,
9e726740 117 off_t offset,
e246ba5f
NS
118 ssize_t len)
119{
120 int i, j;
121 char *p;
122
09bd34dd 123 for (i = 0, p = (char *)buf; i < len; i += 16) {
e246ba5f
NS
124 char *s = p;
125
638473d8 126 printf("%08llx: ", (unsigned long long)offset + i);
e246ba5f
NS
127 for (j = 0; j < 16 && i + j < len; j++, p++)
128 printf("%02x ", *p);
129 printf(" ");
130 for (j = 0; j < 16 && i + j < len; j++, s++) {
93d9f139 131 if (isalnum((int)*s))
e246ba5f
NS
132 printf("%c", *s);
133 else
134 printf(".");
135 }
136 printf("\n");
137 }
138}
139
e115d3b2
DC
140void
141dump_buffer(
9e726740 142 off_t offset,
e115d3b2
DC
143 ssize_t len)
144{
145 int i, l;
146
147 if (!vectors) {
86715ccb 148 __dump_buffer(io_buffer, offset, len);
e115d3b2
DC
149 return;
150 }
151
152 for (i = 0; len > 0 && i < vectors; i++) {
153 l = min(len, iov[i].iov_len);
154
155 __dump_buffer(iov[i].iov_base, offset, l);
156 len -= l;
157 offset += l;
158 }
159}
160
421c9220 161static ssize_t
197d5828 162do_preadv(
e115d3b2 163 int fd,
9e726740 164 off_t offset,
4eafc4d3 165 long long count)
e115d3b2
DC
166{
167 int vecs = 0;
168 ssize_t oldlen = 0;
169 ssize_t bytes = 0;
170
e115d3b2 171 /* trim the iovec if necessary */
86715ccb 172 if (count < io_buffersize) {
e115d3b2
DC
173 size_t len = 0;
174 while (len + iov[vecs].iov_len < count) {
175 len += iov[vecs].iov_len;
176 vecs++;
177 }
178 oldlen = iov[vecs].iov_len;
179 iov[vecs].iov_len = count - len;
180 vecs++;
181 } else {
182 vecs = vectors;
183 }
184 bytes = preadv(fd, iov, vectors, offset);
185
186 /* restore trimmed iov */
187 if (oldlen)
188 iov[vecs - 1].iov_len = oldlen;
189
190 return bytes;
191}
197d5828 192
421c9220 193static ssize_t
197d5828
ES
194do_pread(
195 int fd,
9e726740 196 off_t offset,
4eafc4d3 197 long long count,
421c9220 198 size_t buffer_size)
197d5828
ES
199{
200 if (!vectors)
86715ccb 201 return pread(fd, io_buffer, min(count, buffer_size), offset);
197d5828 202
248b6f9a 203 return do_preadv(fd, offset, count);
197d5828 204}
e115d3b2 205
8fb2237e
NS
206static int
207read_random(
208 int fd,
9e726740 209 off_t offset,
8fb2237e
NS
210 long long count,
211 long long *total,
212 unsigned int seed,
213 int eof)
214{
9e726740 215 off_t end, off, range;
8fb2237e
NS
216 ssize_t bytes;
217 int ops = 0;
218
219 srandom(seed);
dc8878f4 220 end = lseek(fd, 0, SEEK_END);
8fb2237e 221 offset = (eof || offset > end) ? end : offset;
86715ccb 222 if ((bytes = (offset % io_buffersize)))
8fb2237e
NS
223 offset -= bytes;
224 offset = max(0, offset);
86715ccb 225 if ((bytes = (count % io_buffersize)))
8fb2237e 226 count += bytes;
86715ccb
ES
227 count = max(io_buffersize, count);
228 range = count - io_buffersize;
8fb2237e
NS
229
230 *total = 0;
231 while (count > 0) {
2ab8ecbe 232 if (range)
86715ccb
ES
233 off = ((offset + (random() % range)) / io_buffersize) *
234 io_buffersize;
2ab8ecbe
DM
235 else
236 off = offset;
86715ccb 237 bytes = do_pread(fd, off, io_buffersize, io_buffersize);
8fb2237e
NS
238 if (bytes == 0)
239 break;
240 if (bytes < 0) {
2f9a125c 241 perror("pread");
8fb2237e
NS
242 return -1;
243 }
244 ops++;
245 *total += bytes;
86715ccb 246 if (bytes < io_buffersize)
8fb2237e
NS
247 break;
248 count -= bytes;
249 }
250 return ops;
251}
252
253static int
254read_backward(
255 int fd,
9e726740 256 off_t *offset,
8fb2237e
NS
257 long long *count,
258 long long *total,
259 int eof)
260{
9e726740 261 off_t end, off = *offset;
8fb2237e
NS
262 ssize_t bytes = 0, bytes_requested;
263 long long cnt = *count;
264 int ops = 0;
265
dc8878f4
FJ
266 end = lseek(fd, 0, SEEK_END);
267 off = eof ? end : min(end, lseek(fd, off, SEEK_SET));
8fb2237e
NS
268 if ((end = off - cnt) < 0) {
269 cnt += end; /* subtraction, end is negative */
270 end = 0;
271 }
272 *total = 0;
273 *count = cnt;
274 *offset = off;
275
276 /* Do initial unaligned read if needed */
86715ccb 277 if ((bytes_requested = (off % io_buffersize))) {
8fb2237e 278 off -= bytes_requested;
86715ccb 279 bytes = do_pread(fd, off, bytes_requested, io_buffersize);
8fb2237e
NS
280 if (bytes == 0)
281 return ops;
282 if (bytes < 0) {
2f9a125c 283 perror("pread");
8fb2237e
NS
284 return -1;
285 }
286 ops++;
287 *total += bytes;
288 if (bytes < bytes_requested)
289 return ops;
290 cnt -= bytes;
291 }
292
293 /* Iterate backward through the rest of the range */
294 while (cnt > end) {
86715ccb 295 bytes_requested = min(cnt, io_buffersize);
8fb2237e 296 off -= bytes_requested;
86715ccb 297 bytes = do_pread(fd, off, cnt, io_buffersize);
8fb2237e
NS
298 if (bytes == 0)
299 break;
300 if (bytes < 0) {
2f9a125c 301 perror("pread");
8fb2237e
NS
302 return -1;
303 }
304 ops++;
305 *total += bytes;
306 if (bytes < bytes_requested)
307 break;
308 cnt -= bytes;
309 }
310 return ops;
311}
312
313static int
314read_forward(
e246ba5f 315 int fd,
9e726740 316 off_t offset,
92d9b902
NS
317 long long count,
318 long long *total,
e246ba5f 319 int verbose,
8fb2237e
NS
320 int onlyone,
321 int eof)
e246ba5f 322{
2c2f6d79 323 ssize_t bytes;
92d9b902 324 int ops = 0;
e246ba5f
NS
325
326 *total = 0;
8fb2237e 327 while (count > 0 || eof) {
86715ccb 328 bytes = do_pread(fd, offset, count, io_buffersize);
e246ba5f
NS
329 if (bytes == 0)
330 break;
331 if (bytes < 0) {
2f9a125c 332 perror("pread");
92d9b902 333 return -1;
e246ba5f 334 }
92d9b902 335 ops++;
e246ba5f
NS
336 if (verbose)
337 dump_buffer(offset, bytes);
338 *total += bytes;
86715ccb 339 if (onlyone || bytes < min(count, io_buffersize))
e246ba5f
NS
340 break;
341 offset += bytes;
342 count -= bytes;
343 }
92d9b902 344 return ops;
e246ba5f
NS
345}
346
8fb2237e
NS
347int
348read_buffer(
349 int fd,
9e726740 350 off_t offset,
8fb2237e
NS
351 long long count,
352 long long *total,
353 int verbose,
354 int onlyone)
355{
356 return read_forward(fd, offset, count, total, verbose, onlyone, 0);
357}
358
e246ba5f
NS
359static int
360pread_f(
361 int argc,
362 char **argv)
363{
8fb2237e 364 size_t bsize;
9e726740 365 off_t offset;
8fb2237e 366 unsigned int zeed = 0;
2c2f6d79 367 long long count, total, tmp;
d026b19e 368 size_t fsblocksize, fssectsize;
92d9b902 369 struct timeval t1, t2;
8fb2237e 370 char *sp;
d347f827 371 int Cflag, qflag, uflag, vflag;
8fb2237e 372 int eof = 0, direction = IO_FORWARD;
e246ba5f
NS
373 int c;
374
d347f827 375 Cflag = qflag = uflag = vflag = 0;
8fb2237e
NS
376 init_cvtnum(&fsblocksize, &fssectsize);
377 bsize = fsblocksize;
378
e115d3b2 379 while ((c = getopt(argc, argv, "b:BCFRquvV:Z:")) != EOF) {
e246ba5f
NS
380 switch (c) {
381 case 'b':
8fb2237e 382 tmp = cvtnum(fsblocksize, fssectsize, optarg);
2c2f6d79 383 if (tmp < 0) {
e246ba5f 384 printf(_("non-numeric bsize -- %s\n"), optarg);
9e1595e6 385 exitcode = 1;
e246ba5f
NS
386 return 0;
387 }
8fb2237e 388 bsize = tmp;
e246ba5f 389 break;
5c7bef67
NS
390 case 'C':
391 Cflag = 1;
392 break;
8fb2237e
NS
393 case 'F':
394 direction = IO_FORWARD;
395 break;
396 case 'B':
397 direction = IO_BACKWARD;
398 break;
399 case 'R':
400 direction = IO_RANDOM;
401 break;
d347f827
NS
402 case 'q':
403 qflag = 1;
404 break;
48c46ee3
NS
405 case 'u':
406 uflag = 1;
407 break;
e246ba5f
NS
408 case 'v':
409 vflag = 1;
410 break;
e115d3b2
DC
411 case 'V':
412 vectors = strtoul(optarg, &sp, 0);
413 if (!sp || sp == optarg) {
197d5828 414 printf(_("non-numeric vector count == %s\n"),
e115d3b2 415 optarg);
9e1595e6 416 exitcode = 1;
e115d3b2
DC
417 return 0;
418 }
419 break;
8fb2237e
NS
420 case 'Z':
421 zeed = strtoul(optarg, &sp, 0);
422 if (!sp || sp == optarg) {
423 printf(_("non-numeric seed -- %s\n"), optarg);
9e1595e6 424 exitcode = 1;
8fb2237e
NS
425 return 0;
426 }
427 break;
e246ba5f 428 default:
9e1595e6 429 exitcode = 1;
48c46ee3 430 return command_usage(&pread_cmd);
e246ba5f
NS
431 }
432 }
9e1595e6
DC
433 if (optind != argc - 2) {
434 exitcode = 1;
48c46ee3 435 return command_usage(&pread_cmd);
9e1595e6 436 }
48c46ee3 437
8fb2237e
NS
438 offset = cvtnum(fsblocksize, fssectsize, argv[optind]);
439 if (offset < 0 && (direction & (IO_RANDOM|IO_BACKWARD))) {
440 eof = -1; /* read from EOF */
441 } else if (offset < 0) {
442 printf(_("non-numeric length argument -- %s\n"), argv[optind]);
9e1595e6 443 exitcode = 1;
e246ba5f
NS
444 return 0;
445 }
446 optind++;
8fb2237e
NS
447 count = cvtnum(fsblocksize, fssectsize, argv[optind]);
448 if (count < 0 && (direction & (IO_RANDOM|IO_FORWARD))) {
449 eof = -1; /* read to EOF */
450 } else if (count < 0) {
e246ba5f 451 printf(_("non-numeric length argument -- %s\n"), argv[optind]);
9e1595e6 452 exitcode = 1;
e246ba5f
NS
453 return 0;
454 }
d347f827 455
9e1595e6
DC
456 if (alloc_buffer(bsize, uflag, 0xabababab) < 0) {
457 exitcode = 1;
e246ba5f 458 return 0;
9e1595e6 459 }
e246ba5f 460
92d9b902 461 gettimeofday(&t1, NULL);
8fb2237e
NS
462 switch (direction) {
463 case IO_RANDOM:
464 if (!zeed) /* srandom seed */
465 zeed = time(NULL);
466 c = read_random(file->fd, offset, count, &total, zeed, eof);
467 break;
468 case IO_FORWARD:
469 c = read_forward(file->fd, offset, count, &total, vflag, 0, eof);
470 if (eof)
471 count = total;
472 break;
473 case IO_BACKWARD:
474 c = read_backward(file->fd, &offset, &count, &total, eof);
475 break;
476 default:
477 ASSERT(0);
478 }
9e1595e6
DC
479 if (c < 0) {
480 exitcode = 1;
e246ba5f 481 return 0;
9e1595e6
DC
482 }
483
d347f827
NS
484 if (qflag)
485 return 0;
92d9b902
NS
486 gettimeofday(&t2, NULL);
487 t2 = tsub(t2, t1);
e246ba5f 488
a9b61ce9 489 report_io_times("read", &t2, (long long)offset, count, total, c, Cflag);
e246ba5f
NS
490 return 0;
491}
492
493void
494pread_init(void)
495{
ad765595
AM
496 pread_cmd.name = "pread";
497 pread_cmd.altname = "r";
e246ba5f
NS
498 pread_cmd.cfunc = pread_f;
499 pread_cmd.argmin = 2;
500 pread_cmd.argmax = -1;
48c46ee3 501 pread_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
0388cfb1 502 pread_cmd.args = _("[-b bs] [-qv] [-i N] [-FBR [-Z N]] off len");
e246ba5f
NS
503 pread_cmd.oneline = _("reads a number of bytes at a specified offset");
504 pread_cmd.help = pread_help;
505
506 add_command(&pread_cmd);
507}