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