Allow more flexibility in zone start and span
[fio.git] / engines / sync.c
CommitLineData
2866c82d 1/*
a31041ea 2 * sync/psync engine
da751ca9
JA
3 *
4 * IO engine that does regular read(2)/write(2) with lseek(2) to transfer
a31041ea 5 * data and IO engine that does regular pread(2)/pwrite(2) to transfer data.
2866c82d
JA
6 *
7 */
8#include <stdio.h>
9#include <stdlib.h>
10#include <unistd.h>
5921e80c 11#include <sys/uio.h>
2866c82d 12#include <errno.h>
5f350952
JA
13
14#include "../fio.h"
2cafffbe 15#include "../optgroup.h"
a0679ce5 16#include "../lib/rand.h"
2866c82d 17
ef5f5a3a
JA
18/*
19 * Sync engine uses engine_data to store last offset
20 */
710bf9c5 21#define LAST_POS(f) ((f)->engine_pos)
ef5f5a3a 22
1d2af02a
JA
23struct syncio_data {
24 struct iovec *iovecs;
25 struct io_u **io_us;
26 unsigned int queued;
e51cf72c 27 unsigned int events;
1d2af02a
JA
28 unsigned long queued_bytes;
29
30 unsigned long long last_offset;
31 struct fio_file *last_file;
32 enum fio_ddir last_ddir;
a0679ce5
SB
33
34 struct frand_state rand_state;
1d2af02a
JA
35};
36
6562685f 37#ifdef FIO_HAVE_PWRITEV2
2cafffbe
JA
38struct psyncv2_options {
39 void *pad;
40 unsigned int hipri;
a0679ce5 41 unsigned int hipri_percentage;
bb707dff 42 unsigned int uncached;
2cafffbe
JA
43};
44
45static struct fio_option options[] = {
46 {
47 .name = "hipri",
48 .lname = "RWF_HIPRI",
49 .type = FIO_OPT_STR_SET,
50 .off1 = offsetof(struct psyncv2_options, hipri),
51 .help = "Set RWF_HIPRI for pwritev2/preadv2",
52 .category = FIO_OPT_C_ENGINE,
53 .group = FIO_OPT_G_INVALID,
54 },
a0679ce5
SB
55 {
56 .name = "hipri_percentage",
57 .lname = "RWF_HIPRI_PERCENTAGE",
58 .type = FIO_OPT_INT,
59 .off1 = offsetof(struct psyncv2_options, hipri_percentage),
60 .minval = 0,
61 .maxval = 100,
62 .def = "100",
63 .help = "Probabilistically set RWF_HIPRI for pwritev2/preadv2",
64 .category = FIO_OPT_C_ENGINE,
65 .group = FIO_OPT_G_INVALID,
66 },
bb707dff
JA
67 {
68 .name = "uncached",
69 .lname = "Uncached",
70 .type = FIO_OPT_INT,
71 .off1 = offsetof(struct psyncv2_options, uncached),
72 .help = "Use RWF_UNCACHED for buffered read/writes",
73 .category = FIO_OPT_C_ENGINE,
74 .group = FIO_OPT_G_INVALID,
75 },
2cafffbe
JA
76 {
77 .name = NULL,
78 },
79};
80#endif
81
2866c82d
JA
82static int fio_syncio_prep(struct thread_data *td, struct io_u *io_u)
83{
53cdc686
JA
84 struct fio_file *f = io_u->file;
85
ff58fced 86 if (!ddir_rw(io_u->ddir))
87dc1ab1
JA
87 return 0;
88
ef5f5a3a 89 if (LAST_POS(f) != -1ULL && LAST_POS(f) == io_u->offset)
e943b878
JA
90 return 0;
91
53cdc686 92 if (lseek(f->fd, io_u->offset, SEEK_SET) == -1) {
e1161c32 93 td_verror(td, errno, "lseek");
2866c82d
JA
94 return 1;
95 }
96
97 return 0;
98}
99
2bd3eabc 100static int fio_io_end(struct thread_data *td, struct io_u *io_u, int ret)
2866c82d 101{
ff58fced 102 if (io_u->file && ret >= 0 && ddir_rw(io_u->ddir))
ef5f5a3a 103 LAST_POS(io_u->file) = io_u->offset + ret;
e943b878 104
cec6b55d 105 if (ret != (int) io_u->xfer_buflen) {
22819ec2 106 if (ret >= 0) {
cec6b55d
JA
107 io_u->resid = io_u->xfer_buflen - ret;
108 io_u->error = 0;
36167d82 109 return FIO_Q_COMPLETED;
2866c82d
JA
110 } else
111 io_u->error = errno;
112 }
113
bfd197cb
JA
114 if (io_u->error) {
115 io_u_log_error(td, io_u);
e1161c32 116 td_verror(td, io_u->error, "xfer");
bfd197cb 117 }
2866c82d 118
36167d82 119 return FIO_Q_COMPLETED;
2866c82d
JA
120}
121
07fc0acd 122#ifdef CONFIG_PWRITEV
2e4ef4fb
JA
123static enum fio_q_status fio_pvsyncio_queue(struct thread_data *td,
124 struct io_u *io_u)
07fc0acd 125{
565e784d 126 struct syncio_data *sd = td->io_ops_data;
07fc0acd
JA
127 struct iovec *iov = &sd->iovecs[0];
128 struct fio_file *f = io_u->file;
129 int ret;
130
131 fio_ro_check(td, io_u);
132
133 iov->iov_base = io_u->xfer_buf;
134 iov->iov_len = io_u->xfer_buflen;
135
136 if (io_u->ddir == DDIR_READ)
137 ret = preadv(f->fd, iov, 1, io_u->offset);
138 else if (io_u->ddir == DDIR_WRITE)
139 ret = pwritev(f->fd, iov, 1, io_u->offset);
140 else if (io_u->ddir == DDIR_TRIM) {
141 do_io_u_trim(td, io_u);
142 return FIO_Q_COMPLETED;
143 } else
144 ret = do_io_u_sync(td, io_u);
145
146 return fio_io_end(td, io_u, ret);
147}
148#endif
149
6562685f 150#ifdef FIO_HAVE_PWRITEV2
2e4ef4fb
JA
151static enum fio_q_status fio_pvsyncio2_queue(struct thread_data *td,
152 struct io_u *io_u)
2cafffbe 153{
565e784d 154 struct syncio_data *sd = td->io_ops_data;
2cafffbe
JA
155 struct psyncv2_options *o = td->eo;
156 struct iovec *iov = &sd->iovecs[0];
157 struct fio_file *f = io_u->file;
158 int ret, flags = 0;
159
160 fio_ro_check(td, io_u);
161
a0679ce5 162 if (o->hipri &&
1bd5d213 163 (rand_between(&sd->rand_state, 1, 100) <= o->hipri_percentage))
2cafffbe 164 flags |= RWF_HIPRI;
bb707dff
JA
165 if (!td->o.odirect && o->uncached)
166 flags |= RWF_UNCACHED;
2cafffbe
JA
167
168 iov->iov_base = io_u->xfer_buf;
169 iov->iov_len = io_u->xfer_buflen;
170
171 if (io_u->ddir == DDIR_READ)
172 ret = preadv2(f->fd, iov, 1, io_u->offset, flags);
173 else if (io_u->ddir == DDIR_WRITE)
174 ret = pwritev2(f->fd, iov, 1, io_u->offset, flags);
175 else if (io_u->ddir == DDIR_TRIM) {
176 do_io_u_trim(td, io_u);
177 return FIO_Q_COMPLETED;
178 } else
179 ret = do_io_u_sync(td, io_u);
180
181 return fio_io_end(td, io_u, ret);
182}
183#endif
184
2e4ef4fb
JA
185static enum fio_q_status fio_psyncio_queue(struct thread_data *td,
186 struct io_u *io_u)
a31041ea 187{
2bd3eabc
JA
188 struct fio_file *f = io_u->file;
189 int ret;
190
191 fio_ro_check(td, io_u);
192
193 if (io_u->ddir == DDIR_READ)
194 ret = pread(f->fd, io_u->xfer_buf, io_u->xfer_buflen, io_u->offset);
195 else if (io_u->ddir == DDIR_WRITE)
196 ret = pwrite(f->fd, io_u->xfer_buf, io_u->xfer_buflen, io_u->offset);
6eaf09d6
SL
197 else if (io_u->ddir == DDIR_TRIM) {
198 do_io_u_trim(td, io_u);
199 return FIO_Q_COMPLETED;
200 } else
0a28ecda 201 ret = do_io_u_sync(td, io_u);
2bd3eabc
JA
202
203 return fio_io_end(td, io_u, ret);
204}
205
2e4ef4fb
JA
206static enum fio_q_status fio_syncio_queue(struct thread_data *td,
207 struct io_u *io_u)
2bd3eabc
JA
208{
209 struct fio_file *f = io_u->file;
210 int ret;
211
212 fio_ro_check(td, io_u);
213
214 if (io_u->ddir == DDIR_READ)
215 ret = read(f->fd, io_u->xfer_buf, io_u->xfer_buflen);
216 else if (io_u->ddir == DDIR_WRITE)
217 ret = write(f->fd, io_u->xfer_buf, io_u->xfer_buflen);
6eaf09d6
SL
218 else if (io_u->ddir == DDIR_TRIM) {
219 do_io_u_trim(td, io_u);
220 return FIO_Q_COMPLETED;
221 } else
0a28ecda 222 ret = do_io_u_sync(td, io_u);
2bd3eabc
JA
223
224 return fio_io_end(td, io_u, ret);
a31041ea 225}
226
1d2af02a
JA
227static int fio_vsyncio_getevents(struct thread_data *td, unsigned int min,
228 unsigned int max,
1f440ece 229 const struct timespec fio_unused *t)
1d2af02a 230{
565e784d 231 struct syncio_data *sd = td->io_ops_data;
1d2af02a
JA
232 int ret;
233
234 if (min) {
e51cf72c
JA
235 ret = sd->events;
236 sd->events = 0;
1d2af02a
JA
237 } else
238 ret = 0;
239
240 dprint(FD_IO, "vsyncio_getevents: min=%d,max=%d: %d\n", min, max, ret);
241 return ret;
242}
243
244static struct io_u *fio_vsyncio_event(struct thread_data *td, int event)
245{
565e784d 246 struct syncio_data *sd = td->io_ops_data;
1d2af02a
JA
247
248 return sd->io_us[event];
249}
250
251static int fio_vsyncio_append(struct thread_data *td, struct io_u *io_u)
252{
565e784d 253 struct syncio_data *sd = td->io_ops_data;
1d2af02a 254
5f9099ea 255 if (ddir_sync(io_u->ddir))
1d2af02a
JA
256 return 0;
257
258 if (io_u->offset == sd->last_offset && io_u->file == sd->last_file &&
259 io_u->ddir == sd->last_ddir)
260 return 1;
261
262 return 0;
263}
264
265static void fio_vsyncio_set_iov(struct syncio_data *sd, struct io_u *io_u,
2b13e716 266 int idx)
1d2af02a 267{
2b13e716
JA
268 sd->io_us[idx] = io_u;
269 sd->iovecs[idx].iov_base = io_u->xfer_buf;
270 sd->iovecs[idx].iov_len = io_u->xfer_buflen;
1d2af02a
JA
271 sd->last_offset = io_u->offset + io_u->xfer_buflen;
272 sd->last_file = io_u->file;
273 sd->last_ddir = io_u->ddir;
274 sd->queued_bytes += io_u->xfer_buflen;
275 sd->queued++;
276}
277
2e4ef4fb
JA
278static enum fio_q_status fio_vsyncio_queue(struct thread_data *td,
279 struct io_u *io_u)
1d2af02a 280{
565e784d 281 struct syncio_data *sd = td->io_ops_data;
1d2af02a
JA
282
283 fio_ro_check(td, io_u);
284
285 if (!fio_vsyncio_append(td, io_u)) {
286 dprint(FD_IO, "vsyncio_queue: no append (%d)\n", sd->queued);
287 /*
288 * If we can't append and have stuff queued, tell fio to
289 * commit those first and then retry this io
290 */
291 if (sd->queued)
292 return FIO_Q_BUSY;
0a28ecda
JA
293 if (ddir_sync(io_u->ddir)) {
294 int ret = do_io_u_sync(td, io_u);
295
296 return fio_io_end(td, io_u, ret);
297 }
cc9159c3 298
1d2af02a
JA
299 sd->queued = 0;
300 sd->queued_bytes = 0;
301 fio_vsyncio_set_iov(sd, io_u, 0);
302 } else {
303 if (sd->queued == td->o.iodepth) {
304 dprint(FD_IO, "vsyncio_queue: max depth %d\n", sd->queued);
305 return FIO_Q_BUSY;
306 }
307
308 dprint(FD_IO, "vsyncio_queue: append\n");
309 fio_vsyncio_set_iov(sd, io_u, sd->queued);
310 }
311
312 dprint(FD_IO, "vsyncio_queue: depth now %d\n", sd->queued);
313 return FIO_Q_QUEUED;
314}
315
316/*
317 * Check that we transferred all bytes, or saw an error, etc
318 */
319static int fio_vsyncio_end(struct thread_data *td, ssize_t bytes)
320{
565e784d 321 struct syncio_data *sd = td->io_ops_data;
1d2af02a
JA
322 struct io_u *io_u;
323 unsigned int i;
324 int err;
325
326 /*
327 * transferred everything, perfect
328 */
329 if (bytes == sd->queued_bytes)
330 return 0;
331
332 err = errno;
333 for (i = 0; i < sd->queued; i++) {
334 io_u = sd->io_us[i];
335
336 if (bytes == -1) {
337 io_u->error = err;
338 } else {
339 unsigned int this_io;
340
341 this_io = bytes;
342 if (this_io > io_u->xfer_buflen)
343 this_io = io_u->xfer_buflen;
344
345 io_u->resid = io_u->xfer_buflen - this_io;
346 io_u->error = 0;
347 bytes -= this_io;
348 }
349 }
350
351 if (bytes == -1) {
352 td_verror(td, err, "xfer vsync");
353 return -err;
354 }
355
356 return 0;
357}
358
359static int fio_vsyncio_commit(struct thread_data *td)
360{
565e784d 361 struct syncio_data *sd = td->io_ops_data;
1d2af02a
JA
362 struct fio_file *f;
363 ssize_t ret;
364
365 if (!sd->queued)
366 return 0;
367
838bc709 368 io_u_mark_submit(td, sd->queued);
1d2af02a
JA
369 f = sd->last_file;
370
371 if (lseek(f->fd, sd->io_us[0]->offset, SEEK_SET) == -1) {
372 int err = -errno;
373
374 td_verror(td, errno, "lseek");
375 return err;
376 }
377
378 if (sd->last_ddir == DDIR_READ)
379 ret = readv(f->fd, sd->iovecs, sd->queued);
380 else
381 ret = writev(f->fd, sd->iovecs, sd->queued);
382
383 dprint(FD_IO, "vsyncio_commit: %d\n", (int) ret);
e51cf72c
JA
384 sd->events = sd->queued;
385 sd->queued = 0;
1d2af02a
JA
386 return fio_vsyncio_end(td, ret);
387}
388
389static int fio_vsyncio_init(struct thread_data *td)
390{
391 struct syncio_data *sd;
392
393 sd = malloc(sizeof(*sd));
394 memset(sd, 0, sizeof(*sd));
395 sd->last_offset = -1ULL;
396 sd->iovecs = malloc(td->o.iodepth * sizeof(struct iovec));
397 sd->io_us = malloc(td->o.iodepth * sizeof(struct io_u *));
a0679ce5 398 init_rand(&sd->rand_state, 0);
1d2af02a 399
565e784d 400 td->io_ops_data = sd;
1d2af02a
JA
401 return 0;
402}
403
404static void fio_vsyncio_cleanup(struct thread_data *td)
405{
565e784d 406 struct syncio_data *sd = td->io_ops_data;
1d2af02a 407
02a3d83f
TK
408 if (sd) {
409 free(sd->iovecs);
410 free(sd->io_us);
411 free(sd);
412 }
1d2af02a
JA
413}
414
a31041ea 415static struct ioengine_ops ioengine_rw = {
2866c82d
JA
416 .name = "sync",
417 .version = FIO_IOOPS_VERSION,
2866c82d
JA
418 .prep = fio_syncio_prep,
419 .queue = fio_syncio_queue,
b5af8293
JA
420 .open_file = generic_open_file,
421 .close_file = generic_close_file,
df9c26b1 422 .get_file_size = generic_get_file_size,
2866c82d
JA
423 .flags = FIO_SYNCIO,
424};
5f350952 425
a31041ea 426static struct ioengine_ops ioengine_prw = {
427 .name = "psync",
428 .version = FIO_IOOPS_VERSION,
2bd3eabc 429 .queue = fio_psyncio_queue,
a31041ea 430 .open_file = generic_open_file,
431 .close_file = generic_close_file,
df9c26b1 432 .get_file_size = generic_get_file_size,
a31041ea 433 .flags = FIO_SYNCIO,
434};
435
1d2af02a
JA
436static struct ioengine_ops ioengine_vrw = {
437 .name = "vsync",
438 .version = FIO_IOOPS_VERSION,
439 .init = fio_vsyncio_init,
440 .cleanup = fio_vsyncio_cleanup,
441 .queue = fio_vsyncio_queue,
442 .commit = fio_vsyncio_commit,
443 .event = fio_vsyncio_event,
444 .getevents = fio_vsyncio_getevents,
445 .open_file = generic_open_file,
446 .close_file = generic_close_file,
df9c26b1 447 .get_file_size = generic_get_file_size,
1d2af02a
JA
448 .flags = FIO_SYNCIO,
449};
450
07fc0acd
JA
451#ifdef CONFIG_PWRITEV
452static struct ioengine_ops ioengine_pvrw = {
453 .name = "pvsync",
454 .version = FIO_IOOPS_VERSION,
455 .init = fio_vsyncio_init,
456 .cleanup = fio_vsyncio_cleanup,
457 .queue = fio_pvsyncio_queue,
458 .open_file = generic_open_file,
459 .close_file = generic_close_file,
460 .get_file_size = generic_get_file_size,
461 .flags = FIO_SYNCIO,
462};
463#endif
464
6562685f 465#ifdef FIO_HAVE_PWRITEV2
2cafffbe
JA
466static struct ioengine_ops ioengine_pvrw2 = {
467 .name = "pvsync2",
468 .version = FIO_IOOPS_VERSION,
469 .init = fio_vsyncio_init,
470 .cleanup = fio_vsyncio_cleanup,
471 .queue = fio_pvsyncio2_queue,
472 .open_file = generic_open_file,
473 .close_file = generic_close_file,
474 .get_file_size = generic_get_file_size,
475 .flags = FIO_SYNCIO,
476 .options = options,
477 .option_struct_size = sizeof(struct psyncv2_options),
478};
479#endif
480
5f350952
JA
481static void fio_init fio_syncio_register(void)
482{
a31041ea 483 register_ioengine(&ioengine_rw);
484 register_ioengine(&ioengine_prw);
1d2af02a 485 register_ioengine(&ioengine_vrw);
9a0ced5a 486#ifdef CONFIG_PWRITEV
07fc0acd 487 register_ioengine(&ioengine_pvrw);
9a0ced5a 488#endif
6562685f 489#ifdef FIO_HAVE_PWRITEV2
526c403d
JD
490 register_ioengine(&ioengine_pvrw2);
491#endif
5f350952
JA
492}
493
494static void fio_exit fio_syncio_unregister(void)
495{
a31041ea 496 unregister_ioengine(&ioengine_rw);
497 unregister_ioengine(&ioengine_prw);
1d2af02a 498 unregister_ioengine(&ioengine_vrw);
9a0ced5a 499#ifdef CONFIG_PWRITEV
07fc0acd 500 unregister_ioengine(&ioengine_pvrw);
9a0ced5a 501#endif
6562685f 502#ifdef FIO_HAVE_PWRITEV2
526c403d
JD
503 unregister_ioengine(&ioengine_pvrw2);
504#endif
5f350952 505}