]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - io/pwrite.c
configure: don't check for preadv and pwritev
[thirdparty/xfsprogs-dev.git] / io / pwrite.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
64a93371 7#include <sys/uio.h>
6b803e5a
CH
8#include "command.h"
9#include "input.h"
e246ba5f 10#include "init.h"
48c46ee3 11#include "io.h"
e246ba5f
NS
12
13static cmdinfo_t pwrite_cmd;
14
15static void
16pwrite_help(void)
17{
18 printf(_(
19"\n"
20" writes a range of bytes (in block size increments) from the given offset\n"
21"\n"
22" Example:\n"
48c46ee3 23" 'pwrite 512 20' - writes 20 bytes at 512 bytes into the open file\n"
e246ba5f
NS
24"\n"
25" Writes into a segment of the currently open file, using either a buffer\n"
26" filled with a set pattern (0xcdcdcdcd) or data read from an input file.\n"
e246ba5f 27" The writes are performed in sequential blocks starting at offset, with the\n"
8fb2237e
NS
28" blocksize tunable using the -b option (default blocksize is 4096 bytes),\n"
29" unless a different write pattern is requested.\n"
0388cfb1 30" -q -- quiet mode, do not write anything to standard output.\n"
8fb2237e
NS
31" -S -- use an alternate seed number for filling the write buffer\n"
32" -i -- input file, source of data to write (used when writing forward)\n"
33" -d -- open the input file for direct IO\n"
34" -s -- skip a number of bytes at the start of the input file\n"
35" -w -- call fdatasync(2) at the end (included in timing results)\n"
36" -W -- call fsync(2) at the end (included in timing results)\n"
37" -B -- write backwards through the range from offset (backwards N bytes)\n"
38" -F -- write forwards through the range of bytes from offset (default)\n"
43ba1d61 39" -O -- perform pwrite call once and return (maybe partial) bytes written\n"
8fb2237e
NS
40" -R -- write at random offsets in the specified range of bytes\n"
41" -Z N -- zeed the random number generator (used when writing randomly)\n"
42" (heh, zorry, the -s/-S arguments were already in use in pwrite)\n"
10899f17 43" -V N -- use vectored IO with N iovecs of blocksize each (pwritev)\n"
0799d5cf
GR
44#ifdef HAVE_PWRITEV2
45" -N -- Perform the pwritev2() with RWF_NOWAIT\n"
d9763825 46" -D -- Perform the pwritev2() with RWF_DSYNC\n"
0799d5cf 47#endif
e246ba5f
NS
48"\n"));
49}
50
421c9220 51static ssize_t
197d5828 52do_pwritev(
10899f17 53 int fd,
9e726740 54 off_t offset,
4eafc4d3
DW
55 long long count,
56 int pwritev2_flags)
10899f17 57{
197d5828
ES
58 int vecs = 0;
59 ssize_t oldlen = 0;
60 ssize_t bytes = 0;
10899f17
DC
61
62 /* trim the iovec if necessary */
86715ccb 63 if (count < io_buffersize) {
10899f17
DC
64 size_t len = 0;
65 while (len + iov[vecs].iov_len < count) {
66 len += iov[vecs].iov_len;
67 vecs++;
68 }
69 oldlen = iov[vecs].iov_len;
70 iov[vecs].iov_len = count - len;
71 vecs++;
72 } else {
73 vecs = vectors;
74 }
c5deeac9
GR
75#ifdef HAVE_PWRITEV2
76 if (pwritev2_flags)
77 bytes = pwritev2(fd, iov, vectors, offset, pwritev2_flags);
78 else
79 bytes = pwritev(fd, iov, vectors, offset);
80#else
10899f17 81 bytes = pwritev(fd, iov, vectors, offset);
c5deeac9 82#endif
10899f17
DC
83
84 /* restore trimmed iov */
85 if (oldlen)
86 iov[vecs - 1].iov_len = oldlen;
87
88 return bytes;
89}
197d5828 90
421c9220 91static ssize_t
197d5828
ES
92do_pwrite(
93 int fd,
9e726740 94 off_t offset,
4eafc4d3 95 long long count,
421c9220 96 size_t buffer_size,
c5deeac9 97 int pwritev2_flags)
197d5828
ES
98{
99 if (!vectors)
86715ccb 100 return pwrite(fd, io_buffer, min(count, buffer_size), offset);
197d5828 101
248b6f9a 102 return do_pwritev(fd, offset, count, pwritev2_flags);
197d5828
ES
103}
104
8fb2237e
NS
105static int
106write_random(
9e726740 107 off_t offset,
8fb2237e
NS
108 long long count,
109 unsigned int seed,
c5deeac9
GR
110 long long *total,
111 int pwritev2_flags)
8fb2237e 112{
9e726740 113 off_t off, range;
8fb2237e
NS
114 ssize_t bytes;
115 int ops = 0;
116
117 srandom(seed);
86715ccb 118 if ((bytes = (offset % io_buffersize)))
8fb2237e
NS
119 offset -= bytes;
120 offset = max(0, offset);
86715ccb 121 if ((bytes = (count % io_buffersize)))
8fb2237e 122 count += bytes;
86715ccb
ES
123 count = max(io_buffersize, count);
124 range = count - io_buffersize;
8fb2237e
NS
125
126 *total = 0;
127 while (count > 0) {
2ab8ecbe 128 if (range)
86715ccb
ES
129 off = ((offset + (random() % range)) / io_buffersize) *
130 io_buffersize;
2ab8ecbe
DM
131 else
132 off = offset;
86715ccb 133 bytes = do_pwrite(file->fd, off, io_buffersize, io_buffersize,
c5deeac9 134 pwritev2_flags);
8fb2237e
NS
135 if (bytes == 0)
136 break;
137 if (bytes < 0) {
2f9a125c 138 perror("pwrite");
8fb2237e
NS
139 return -1;
140 }
141 ops++;
142 *total += bytes;
86715ccb 143 if (bytes < io_buffersize)
8fb2237e
NS
144 break;
145 count -= bytes;
146 }
147 return ops;
148}
149
150static int
151write_backward(
9e726740 152 off_t offset,
8fb2237e 153 long long *count,
c5deeac9
GR
154 long long *total,
155 int pwritev2_flags)
8fb2237e 156{
9e726740 157 off_t end, off = offset;
8fb2237e
NS
158 ssize_t bytes = 0, bytes_requested;
159 long long cnt = *count;
160 int ops = 0;
161
162 if ((end = off - cnt) < 0) {
163 cnt += end; /* subtraction, end is negative */
164 end = 0;
165 }
166 *total = 0;
167 *count = cnt;
168
169 /* Do initial unaligned write if needed */
86715ccb 170 if ((bytes_requested = (off % io_buffersize))) {
8fb2237e
NS
171 bytes_requested = min(cnt, bytes_requested);
172 off -= bytes_requested;
86715ccb 173 bytes = do_pwrite(file->fd, off, bytes_requested, io_buffersize,
c5deeac9 174 pwritev2_flags);
8fb2237e
NS
175 if (bytes == 0)
176 return ops;
177 if (bytes < 0) {
2f9a125c 178 perror("pwrite");
8fb2237e
NS
179 return -1;
180 }
181 ops++;
182 *total += bytes;
183 if (bytes < bytes_requested)
184 return ops;
185 cnt -= bytes;
186 }
187
188 /* Iterate backward through the rest of the range */
189 while (cnt > end) {
86715ccb 190 bytes_requested = min(cnt, io_buffersize);
8fb2237e 191 off -= bytes_requested;
86715ccb 192 bytes = do_pwrite(file->fd, off, cnt, io_buffersize,
c5deeac9 193 pwritev2_flags);
8fb2237e
NS
194 if (bytes == 0)
195 break;
196 if (bytes < 0) {
2f9a125c 197 perror("pwrite");
8fb2237e
NS
198 return -1;
199 }
200 ops++;
201 *total += bytes;
202 if (bytes < bytes_requested)
203 break;
204 cnt -= bytes;
205 }
206 return ops;
207}
208
e246ba5f
NS
209static int
210write_buffer(
9e726740 211 off_t offset,
92d9b902 212 long long count,
2c2f6d79 213 size_t bs,
e246ba5f 214 int fd,
9e726740 215 off_t skip,
c5deeac9
GR
216 long long *total,
217 int pwritev2_flags)
e246ba5f 218{
2c2f6d79 219 ssize_t bytes;
92d9b902
NS
220 long long bar = min(bs, count);
221 int ops = 0;
e246ba5f
NS
222
223 *total = 0;
8e2153bf 224 while (count >= 0) {
e246ba5f 225 if (fd > 0) { /* input file given, read buffer first */
92d9b902 226 if (read_buffer(fd, skip + *total, bs, &bar, 0, 1) < 0)
e246ba5f
NS
227 break;
228 }
c5deeac9 229 bytes = do_pwrite(file->fd, offset, count, bar, pwritev2_flags);
e246ba5f
NS
230 if (bytes == 0)
231 break;
232 if (bytes < 0) {
2f9a125c 233 perror("pwrite");
92d9b902 234 return -1;
e246ba5f 235 }
92d9b902 236 ops++;
e246ba5f 237 *total += bytes;
10899f17 238 if (bytes < min(count, bar))
e246ba5f
NS
239 break;
240 offset += bytes;
241 count -= bytes;
8e2153bf
ES
242 if (count == 0)
243 break;
e246ba5f 244 }
92d9b902 245 return ops;
e246ba5f
NS
246}
247
43ba1d61
GR
248static int
249write_once(
9e726740 250 off_t offset,
43ba1d61
GR
251 long long count,
252 long long *total,
253 int pwritev2_flags)
254{
421c9220 255 ssize_t bytes;
43ba1d61 256 bytes = do_pwrite(file->fd, offset, count, count, pwritev2_flags);
99d6e84f
GR
257 if (bytes < 0) {
258 perror("pwrite");
43ba1d61 259 return -1;
99d6e84f 260 }
43ba1d61
GR
261 *total = bytes;
262 return 1;
263}
264
265
e246ba5f
NS
266static int
267pwrite_f(
268 int argc,
269 char **argv)
270{
8fb2237e 271 size_t bsize;
9e726740 272 off_t offset, skip = 0;
2c2f6d79 273 long long count, total, tmp;
8fb2237e 274 unsigned int zeed = 0, seed = 0xcdcdcdcd;
d026b19e 275 size_t fsblocksize, fssectsize;
92d9b902 276 struct timeval t1, t2;
e246ba5f 277 char *sp, *infile = NULL;
d347f827 278 int Cflag, qflag, uflag, dflag, wflag, Wflag;
8fb2237e 279 int direction = IO_FORWARD;
5c7bef67 280 int c, fd = -1;
c5deeac9 281 int pwritev2_flags = 0;
e246ba5f 282
d347f827 283 Cflag = qflag = uflag = dflag = wflag = Wflag = 0;
8fb2237e
NS
284 init_cvtnum(&fsblocksize, &fssectsize);
285 bsize = fsblocksize;
286
d9763825 287 while ((c = getopt(argc, argv, "b:BCdDf:Fi:NqRs:OS:uV:wWZ:")) != EOF) {
e246ba5f
NS
288 switch (c) {
289 case 'b':
8fb2237e 290 tmp = cvtnum(fsblocksize, fssectsize, optarg);
2c2f6d79 291 if (tmp < 0) {
e246ba5f 292 printf(_("non-numeric bsize -- %s\n"), optarg);
9e1595e6 293 exitcode = 1;
e246ba5f
NS
294 return 0;
295 }
8fb2237e 296 bsize = tmp;
e246ba5f 297 break;
5c7bef67
NS
298 case 'C':
299 Cflag = 1;
300 break;
8fb2237e
NS
301 case 'F':
302 direction = IO_FORWARD;
303 break;
304 case 'B':
305 direction = IO_BACKWARD;
306 break;
307 case 'R':
308 direction = IO_RANDOM;
309 break;
43ba1d61
GR
310 case 'O':
311 direction = IO_ONCE;
312 break;
e246ba5f
NS
313 case 'd':
314 dflag = 1;
315 break;
316 case 'f':
317 case 'i':
318 infile = optarg;
319 break;
0799d5cf
GR
320#ifdef HAVE_PWRITEV2
321 case 'N':
322 pwritev2_flags |= RWF_NOWAIT;
323 break;
d9763825
DC
324 case 'D':
325 pwritev2_flags |= RWF_DSYNC;
326 break;
0799d5cf 327#endif
e246ba5f 328 case 's':
8fb2237e 329 skip = cvtnum(fsblocksize, fssectsize, optarg);
638473d8 330 if (skip < 0) {
e246ba5f 331 printf(_("non-numeric skip -- %s\n"), optarg);
9e1595e6 332 exitcode = 1;
e246ba5f
NS
333 return 0;
334 }
335 break;
336 case 'S':
337 seed = strtoul(optarg, &sp, 0);
338 if (!sp || sp == optarg) {
339 printf(_("non-numeric seed -- %s\n"), optarg);
9e1595e6 340 exitcode = 1;
e246ba5f
NS
341 return 0;
342 }
343 break;
d347f827
NS
344 case 'q':
345 qflag = 1;
346 break;
48c46ee3
NS
347 case 'u':
348 uflag = 1;
349 break;
10899f17
DC
350 case 'V':
351 vectors = strtoul(optarg, &sp, 0);
352 if (!sp || sp == optarg) {
197d5828 353 printf(_("non-numeric vector count == %s\n"),
10899f17 354 optarg);
9e1595e6 355 exitcode = 1;
10899f17
DC
356 return 0;
357 }
358 break;
5ecb3de2
NS
359 case 'w':
360 wflag = 1;
361 break;
362 case 'W':
363 Wflag = 1;
364 break;
8fb2237e
NS
365 case 'Z':
366 zeed = strtoul(optarg, &sp, 0);
367 if (!sp || sp == optarg) {
368 printf(_("non-numeric seed -- %s\n"), optarg);
9e1595e6 369 exitcode = 1;
8fb2237e
NS
370 return 0;
371 }
372 break;
e246ba5f 373 default:
68c269ca 374 /* Handle ifdef'd-out options above */
9e1595e6 375 exitcode = 1;
68c269ca
GR
376 if (c != '?')
377 printf(_("%s: command -%c not supported\n"), argv[0], c);
378 else
379 command_usage(&pwrite_cmd);
380 return 0;
e246ba5f
NS
381 }
382 }
9e1595e6
DC
383 if (((skip || dflag) && !infile) || (optind != argc - 2)) {
384 exitcode = 1;
48c46ee3 385 return command_usage(&pwrite_cmd);
9e1595e6
DC
386 }
387 if (infile && direction != IO_FORWARD) {
388 exitcode = 1;
8fb2237e 389 return command_usage(&pwrite_cmd);
9e1595e6 390 }
8fb2237e 391 offset = cvtnum(fsblocksize, fssectsize, argv[optind]);
638473d8 392 if (offset < 0) {
e246ba5f 393 printf(_("non-numeric offset argument -- %s\n"), argv[optind]);
9e1595e6 394 exitcode = 1;
e246ba5f
NS
395 return 0;
396 }
397 optind++;
8fb2237e 398 count = cvtnum(fsblocksize, fssectsize, argv[optind]);
638473d8 399 if (count < 0) {
e246ba5f 400 printf(_("non-numeric length argument -- %s\n"), argv[optind]);
9e1595e6 401 exitcode = 1;
e246ba5f
NS
402 return 0;
403 }
404
9e1595e6
DC
405 if (alloc_buffer(bsize, uflag, seed) < 0) {
406 exitcode = 1;
e246ba5f 407 return 0;
9e1595e6 408 }
e246ba5f 409
24cd0fec 410 c = IO_READONLY | (dflag ? IO_DIRECT : 0);
9e1595e6
DC
411 if (infile && ((fd = openfile(infile, NULL, c, 0, NULL)) < 0)) {
412 exitcode = 1;
e246ba5f 413 return 0;
9e1595e6 414 }
e246ba5f 415
92d9b902 416 gettimeofday(&t1, NULL);
8fb2237e
NS
417 switch (direction) {
418 case IO_RANDOM:
419 if (!zeed) /* srandom seed */
420 zeed = time(NULL);
c5deeac9 421 c = write_random(offset, count, zeed, &total, pwritev2_flags);
8fb2237e
NS
422 break;
423 case IO_FORWARD:
c5deeac9
GR
424 c = write_buffer(offset, count, bsize, fd, skip, &total,
425 pwritev2_flags);
8fb2237e
NS
426 break;
427 case IO_BACKWARD:
c5deeac9 428 c = write_backward(offset, &count, &total, pwritev2_flags);
8fb2237e 429 break;
43ba1d61
GR
430 case IO_ONCE:
431 c = write_once(offset, count, &total, pwritev2_flags);
432 break;
8fb2237e 433 default:
9234d416 434 total = 0;
8fb2237e
NS
435 ASSERT(0);
436 }
9e1595e6
DC
437 if (c < 0) {
438 exitcode = 1;
d347f827 439 goto done;
9e1595e6 440 }
74919c4e
LB
441 if (Wflag) {
442 if (fsync(file->fd) < 0) {
443 perror("fsync");
9e1595e6 444 exitcode = 1;
74919c4e
LB
445 goto done;
446 }
447 }
448 if (wflag) {
449 if (fdatasync(file->fd) < 0) {
450 perror("fdatasync");
9e1595e6 451 exitcode = 1;
74919c4e
LB
452 goto done;
453 }
454 }
9e1595e6 455
d347f827
NS
456 if (qflag)
457 goto done;
92d9b902
NS
458 gettimeofday(&t2, NULL);
459 t2 = tsub(t2, t1);
460
a9b61ce9
DW
461 report_io_times("wrote", &t2, (long long)offset, count, total, c,
462 Cflag);
d347f827 463done:
886578b4
LM
464 if (infile)
465 close(fd);
e246ba5f
NS
466 return 0;
467}
468
469void
470pwrite_init(void)
471{
ad765595
AM
472 pwrite_cmd.name = "pwrite";
473 pwrite_cmd.altname = "w";
e246ba5f
NS
474 pwrite_cmd.cfunc = pwrite_f;
475 pwrite_cmd.argmin = 2;
476 pwrite_cmd.argmax = -1;
48c46ee3 477 pwrite_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
e246ba5f 478 pwrite_cmd.args =
0388cfb1 479_("[-i infile [-qdDwNOW] [-s skip]] [-b bs] [-S seed] [-FBR [-Z N]] [-V N] off len");
e246ba5f
NS
480 pwrite_cmd.oneline =
481 _("writes a number of bytes at a specified offset");
482 pwrite_cmd.help = pwrite_help;
483
484 add_command(&pwrite_cmd);
485}