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