]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - io/pwrite.c
libxfs/linux.c: Replace use of ustat by stat
[thirdparty/xfsprogs-dev.git] / io / pwrite.c
CommitLineData
e246ba5f 1/*
da23017d
NS
2 * Copyright (c) 2003-2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
dfc130f3 4 *
da23017d
NS
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
e246ba5f 7 * published by the Free Software Foundation.
dfc130f3 8 *
da23017d
NS
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.
dfc130f3 13 *
da23017d
NS
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
e246ba5f
NS
17 */
18
64a93371 19#include <sys/uio.h>
6b803e5a
CH
20#include "command.h"
21#include "input.h"
e246ba5f 22#include "init.h"
48c46ee3 23#include "io.h"
e246ba5f
NS
24
25static cmdinfo_t pwrite_cmd;
26
27static void
28pwrite_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"
48c46ee3 35" 'pwrite 512 20' - writes 20 bytes at 512 bytes into the open file\n"
e246ba5f
NS
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"
e246ba5f 39" The writes are performed in sequential blocks starting at offset, with the\n"
8fb2237e
NS
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" -R -- write at random offsets in the specified range of bytes\n"
51" -Z N -- zeed the random number generator (used when writing randomly)\n"
52" (heh, zorry, the -s/-S arguments were already in use in pwrite)\n"
197d5828 53#ifdef HAVE_PWRITEV
10899f17 54" -V N -- use vectored IO with N iovecs of blocksize each (pwritev)\n"
197d5828 55#endif
e246ba5f
NS
56"\n"));
57}
58
197d5828 59#ifdef HAVE_PWRITEV
10899f17 60static int
197d5828 61do_pwritev(
10899f17
DC
62 int fd,
63 off64_t offset,
64 ssize_t count,
65 ssize_t buffer_size)
66{
197d5828
ES
67 int vecs = 0;
68 ssize_t oldlen = 0;
69 ssize_t bytes = 0;
10899f17
DC
70
71 /* trim the iovec if necessary */
72 if (count < buffersize) {
73 size_t len = 0;
74 while (len + iov[vecs].iov_len < count) {
75 len += iov[vecs].iov_len;
76 vecs++;
77 }
78 oldlen = iov[vecs].iov_len;
79 iov[vecs].iov_len = count - len;
80 vecs++;
81 } else {
82 vecs = vectors;
83 }
84 bytes = pwritev(fd, iov, vectors, offset);
85
86 /* restore trimmed iov */
87 if (oldlen)
88 iov[vecs - 1].iov_len = oldlen;
89
90 return bytes;
91}
197d5828
ES
92#else
93#define do_pwritev(fd, offset, count, buffer_size) (0)
94#endif
95
96static int
97do_pwrite(
98 int fd,
99 off64_t offset,
100 ssize_t count,
101 ssize_t buffer_size)
102{
103 if (!vectors)
104 return pwrite64(fd, buffer, min(count, buffer_size), offset);
105
106 return do_pwritev(fd, offset, count, buffer_size);
107}
108
8fb2237e
NS
109static int
110write_random(
111 off64_t offset,
112 long long count,
113 unsigned int seed,
114 long long *total)
115{
116 off64_t off, range;
117 ssize_t bytes;
118 int ops = 0;
119
120 srandom(seed);
121 if ((bytes = (offset % buffersize)))
122 offset -= bytes;
123 offset = max(0, offset);
124 if ((bytes = (count % buffersize)))
125 count += bytes;
126 count = max(buffersize, count);
127 range = count - buffersize;
128
129 *total = 0;
130 while (count > 0) {
2ab8ecbe
DM
131 if (range)
132 off = ((offset + (random() % range)) / buffersize) *
133 buffersize;
134 else
135 off = offset;
10899f17 136 bytes = do_pwrite(file->fd, off, buffersize, buffersize);
8fb2237e
NS
137 if (bytes == 0)
138 break;
139 if (bytes < 0) {
140 perror("pwrite64");
141 return -1;
142 }
143 ops++;
144 *total += bytes;
145 if (bytes < buffersize)
146 break;
147 count -= bytes;
148 }
149 return ops;
150}
151
152static int
153write_backward(
154 off64_t offset,
155 long long *count,
156 long long *total)
157{
158 off64_t end, off = offset;
159 ssize_t bytes = 0, bytes_requested;
160 long long cnt = *count;
161 int ops = 0;
162
163 if ((end = off - cnt) < 0) {
164 cnt += end; /* subtraction, end is negative */
165 end = 0;
166 }
167 *total = 0;
168 *count = cnt;
169
170 /* Do initial unaligned write if needed */
171 if ((bytes_requested = (off % buffersize))) {
172 bytes_requested = min(cnt, bytes_requested);
173 off -= bytes_requested;
10899f17 174 bytes = do_pwrite(file->fd, off, bytes_requested, buffersize);
8fb2237e
NS
175 if (bytes == 0)
176 return ops;
177 if (bytes < 0) {
178 perror("pwrite64");
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) {
190 bytes_requested = min(cnt, buffersize);
191 off -= bytes_requested;
10899f17 192 bytes = do_pwrite(file->fd, off, cnt, buffersize);
8fb2237e
NS
193 if (bytes == 0)
194 break;
195 if (bytes < 0) {
196 perror("pwrite64");
197 return -1;
198 }
199 ops++;
200 *total += bytes;
201 if (bytes < bytes_requested)
202 break;
203 cnt -= bytes;
204 }
205 return ops;
206}
207
e246ba5f
NS
208static int
209write_buffer(
210 off64_t offset,
92d9b902 211 long long count,
2c2f6d79 212 size_t bs,
e246ba5f
NS
213 int fd,
214 off64_t skip,
92d9b902 215 long long *total)
e246ba5f 216{
2c2f6d79 217 ssize_t bytes;
92d9b902
NS
218 long long bar = min(bs, count);
219 int ops = 0;
e246ba5f
NS
220
221 *total = 0;
8e2153bf 222 while (count >= 0) {
e246ba5f 223 if (fd > 0) { /* input file given, read buffer first */
92d9b902 224 if (read_buffer(fd, skip + *total, bs, &bar, 0, 1) < 0)
e246ba5f
NS
225 break;
226 }
10899f17 227 bytes = do_pwrite(file->fd, offset, count, bar);
e246ba5f
NS
228 if (bytes == 0)
229 break;
230 if (bytes < 0) {
231 perror("pwrite64");
92d9b902 232 return -1;
e246ba5f 233 }
92d9b902 234 ops++;
e246ba5f 235 *total += bytes;
10899f17 236 if (bytes < min(count, bar))
e246ba5f
NS
237 break;
238 offset += bytes;
239 count -= bytes;
8e2153bf
ES
240 if (count == 0)
241 break;
e246ba5f 242 }
92d9b902 243 return ops;
e246ba5f
NS
244}
245
246static int
247pwrite_f(
248 int argc,
249 char **argv)
250{
8fb2237e 251 size_t bsize;
e246ba5f 252 off64_t offset, skip = 0;
2c2f6d79 253 long long count, total, tmp;
8fb2237e 254 unsigned int zeed = 0, seed = 0xcdcdcdcd;
d026b19e 255 size_t fsblocksize, fssectsize;
92d9b902 256 struct timeval t1, t2;
e246ba5f 257 char *sp, *infile = NULL;
d347f827 258 int Cflag, qflag, uflag, dflag, wflag, Wflag;
8fb2237e 259 int direction = IO_FORWARD;
5c7bef67 260 int c, fd = -1;
e246ba5f 261
d347f827 262 Cflag = qflag = uflag = dflag = wflag = Wflag = 0;
8fb2237e
NS
263 init_cvtnum(&fsblocksize, &fssectsize);
264 bsize = fsblocksize;
265
00d50425 266 while ((c = getopt(argc, argv, "b:BCdf:Fi:qRs:S:uV:wWZ:")) != EOF) {
e246ba5f
NS
267 switch (c) {
268 case 'b':
8fb2237e 269 tmp = cvtnum(fsblocksize, fssectsize, optarg);
2c2f6d79 270 if (tmp < 0) {
e246ba5f
NS
271 printf(_("non-numeric bsize -- %s\n"), optarg);
272 return 0;
273 }
8fb2237e 274 bsize = tmp;
e246ba5f 275 break;
5c7bef67
NS
276 case 'C':
277 Cflag = 1;
278 break;
8fb2237e
NS
279 case 'F':
280 direction = IO_FORWARD;
281 break;
282 case 'B':
283 direction = IO_BACKWARD;
284 break;
285 case 'R':
286 direction = IO_RANDOM;
287 break;
e246ba5f
NS
288 case 'd':
289 dflag = 1;
290 break;
291 case 'f':
292 case 'i':
293 infile = optarg;
294 break;
295 case 's':
8fb2237e 296 skip = cvtnum(fsblocksize, fssectsize, optarg);
638473d8 297 if (skip < 0) {
e246ba5f
NS
298 printf(_("non-numeric skip -- %s\n"), optarg);
299 return 0;
300 }
301 break;
302 case 'S':
303 seed = strtoul(optarg, &sp, 0);
304 if (!sp || sp == optarg) {
305 printf(_("non-numeric seed -- %s\n"), optarg);
306 return 0;
307 }
308 break;
d347f827
NS
309 case 'q':
310 qflag = 1;
311 break;
48c46ee3
NS
312 case 'u':
313 uflag = 1;
314 break;
10899f17
DC
315 case 'V':
316 vectors = strtoul(optarg, &sp, 0);
317 if (!sp || sp == optarg) {
197d5828 318 printf(_("non-numeric vector count == %s\n"),
10899f17
DC
319 optarg);
320 return 0;
321 }
322 break;
5ecb3de2
NS
323 case 'w':
324 wflag = 1;
325 break;
326 case 'W':
327 Wflag = 1;
328 break;
8fb2237e
NS
329 case 'Z':
330 zeed = strtoul(optarg, &sp, 0);
331 if (!sp || sp == optarg) {
332 printf(_("non-numeric seed -- %s\n"), optarg);
333 return 0;
334 }
335 break;
e246ba5f 336 default:
48c46ee3 337 return command_usage(&pwrite_cmd);
e246ba5f
NS
338 }
339 }
8fb2237e 340 if (((skip || dflag) && !infile) || (optind != argc - 2))
48c46ee3 341 return command_usage(&pwrite_cmd);
8fb2237e
NS
342 if (infile && direction != IO_FORWARD)
343 return command_usage(&pwrite_cmd);
344 offset = cvtnum(fsblocksize, fssectsize, argv[optind]);
638473d8 345 if (offset < 0) {
e246ba5f
NS
346 printf(_("non-numeric offset argument -- %s\n"), argv[optind]);
347 return 0;
348 }
349 optind++;
8fb2237e 350 count = cvtnum(fsblocksize, fssectsize, argv[optind]);
638473d8 351 if (count < 0) {
e246ba5f
NS
352 printf(_("non-numeric length argument -- %s\n"), argv[optind]);
353 return 0;
354 }
355
8fb2237e 356 if (alloc_buffer(bsize, uflag, seed) < 0)
e246ba5f
NS
357 return 0;
358
24cd0fec 359 c = IO_READONLY | (dflag ? IO_DIRECT : 0);
48c46ee3 360 if (infile && ((fd = openfile(infile, NULL, c, 0)) < 0))
e246ba5f
NS
361 return 0;
362
92d9b902 363 gettimeofday(&t1, NULL);
8fb2237e
NS
364 switch (direction) {
365 case IO_RANDOM:
366 if (!zeed) /* srandom seed */
367 zeed = time(NULL);
368 c = write_random(offset, count, zeed, &total);
369 break;
370 case IO_FORWARD:
371 c = write_buffer(offset, count, bsize, fd, skip, &total);
372 break;
373 case IO_BACKWARD:
374 c = write_backward(offset, &count, &total);
375 break;
376 default:
9234d416 377 total = 0;
8fb2237e
NS
378 ASSERT(0);
379 }
d347f827
NS
380 if (c < 0)
381 goto done;
5ecb3de2
NS
382 if (Wflag)
383 fsync(file->fd);
384 if (wflag)
385 fdatasync(file->fd);
d347f827
NS
386 if (qflag)
387 goto done;
92d9b902
NS
388 gettimeofday(&t2, NULL);
389 t2 = tsub(t2, t1);
390
a9b61ce9
DW
391 report_io_times("wrote", &t2, (long long)offset, count, total, c,
392 Cflag);
d347f827 393done:
886578b4
LM
394 if (infile)
395 close(fd);
e246ba5f
NS
396 return 0;
397}
398
399void
400pwrite_init(void)
401{
ad765595
AM
402 pwrite_cmd.name = "pwrite";
403 pwrite_cmd.altname = "w";
e246ba5f
NS
404 pwrite_cmd.cfunc = pwrite_f;
405 pwrite_cmd.argmin = 2;
406 pwrite_cmd.argmax = -1;
48c46ee3 407 pwrite_cmd.flags = CMD_NOMAP_OK | CMD_FOREIGN_OK;
e246ba5f 408 pwrite_cmd.args =
10899f17 409_("[-i infile [-d] [-s skip]] [-b bs] [-S seed] [-wW] [-FBR [-Z N]] [-V N] off len");
e246ba5f
NS
410 pwrite_cmd.oneline =
411 _("writes a number of bytes at a specified offset");
412 pwrite_cmd.help = pwrite_help;
413
414 add_command(&pwrite_cmd);
415}