engines:io_uring: uring_cmd add support for protection info
[fio.git] / engines / io_uring.c
1 /*
2  * io_uring engine
3  *
4  * IO engine using the new native Linux aio io_uring interface. See:
5  *
6  * http://git.kernel.dk/cgit/linux-block/log/?h=io_uring
7  *
8  */
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <errno.h>
12 #include <sys/time.h>
13 #include <sys/resource.h>
14
15 #include "../fio.h"
16 #include "../lib/pow2.h"
17 #include "../optgroup.h"
18 #include "../lib/memalign.h"
19 #include "../lib/fls.h"
20 #include "../lib/roundup.h"
21
22 #ifdef ARCH_HAVE_IOURING
23
24 #include "../lib/types.h"
25 #include "../os/linux/io_uring.h"
26 #include "cmdprio.h"
27 #include "zbd.h"
28 #include "nvme.h"
29
30 #include <sys/stat.h>
31
32 enum uring_cmd_type {
33         FIO_URING_CMD_NVME = 1,
34 };
35
36 struct io_sq_ring {
37         unsigned *head;
38         unsigned *tail;
39         unsigned *ring_mask;
40         unsigned *ring_entries;
41         unsigned *flags;
42         unsigned *array;
43 };
44
45 struct io_cq_ring {
46         unsigned *head;
47         unsigned *tail;
48         unsigned *ring_mask;
49         unsigned *ring_entries;
50         struct io_uring_cqe *cqes;
51 };
52
53 struct ioring_mmap {
54         void *ptr;
55         size_t len;
56 };
57
58 struct ioring_data {
59         int ring_fd;
60
61         struct io_u **io_u_index;
62         char *md_buf;
63
64         int *fds;
65
66         struct io_sq_ring sq_ring;
67         struct io_uring_sqe *sqes;
68         struct iovec *iovecs;
69         unsigned sq_ring_mask;
70
71         struct io_cq_ring cq_ring;
72         unsigned cq_ring_mask;
73
74         int queued;
75         int cq_ring_off;
76         unsigned iodepth;
77         int prepped;
78
79         struct ioring_mmap mmap[3];
80
81         struct cmdprio cmdprio;
82
83         struct nvme_dsm_range *dsm;
84 };
85
86 struct ioring_options {
87         struct thread_data *td;
88         unsigned int hipri;
89         struct cmdprio_options cmdprio_options;
90         unsigned int fixedbufs;
91         unsigned int registerfiles;
92         unsigned int sqpoll_thread;
93         unsigned int sqpoll_set;
94         unsigned int sqpoll_cpu;
95         unsigned int nonvectored;
96         unsigned int uncached;
97         unsigned int nowait;
98         unsigned int force_async;
99         unsigned int md_per_io_size;
100         unsigned int pi_act;
101         unsigned int apptag;
102         unsigned int apptag_mask;
103         unsigned int prchk;
104         char *pi_chk;
105         enum uring_cmd_type cmd_type;
106 };
107
108 static const int ddir_to_op[2][2] = {
109         { IORING_OP_READV, IORING_OP_READ },
110         { IORING_OP_WRITEV, IORING_OP_WRITE }
111 };
112
113 static const int fixed_ddir_to_op[2] = {
114         IORING_OP_READ_FIXED,
115         IORING_OP_WRITE_FIXED
116 };
117
118 static int fio_ioring_sqpoll_cb(void *data, unsigned long long *val)
119 {
120         struct ioring_options *o = data;
121
122         o->sqpoll_cpu = *val;
123         o->sqpoll_set = 1;
124         return 0;
125 }
126
127 static struct fio_option options[] = {
128         {
129                 .name   = "hipri",
130                 .lname  = "High Priority",
131                 .type   = FIO_OPT_STR_SET,
132                 .off1   = offsetof(struct ioring_options, hipri),
133                 .help   = "Use polled IO completions",
134                 .category = FIO_OPT_C_ENGINE,
135                 .group  = FIO_OPT_G_IOURING,
136         },
137         {
138                 .name   = "fixedbufs",
139                 .lname  = "Fixed (pre-mapped) IO buffers",
140                 .type   = FIO_OPT_STR_SET,
141                 .off1   = offsetof(struct ioring_options, fixedbufs),
142                 .help   = "Pre map IO buffers",
143                 .category = FIO_OPT_C_ENGINE,
144                 .group  = FIO_OPT_G_IOURING,
145         },
146         {
147                 .name   = "registerfiles",
148                 .lname  = "Register file set",
149                 .type   = FIO_OPT_STR_SET,
150                 .off1   = offsetof(struct ioring_options, registerfiles),
151                 .help   = "Pre-open/register files",
152                 .category = FIO_OPT_C_ENGINE,
153                 .group  = FIO_OPT_G_IOURING,
154         },
155         {
156                 .name   = "sqthread_poll",
157                 .lname  = "Kernel SQ thread polling",
158                 .type   = FIO_OPT_STR_SET,
159                 .off1   = offsetof(struct ioring_options, sqpoll_thread),
160                 .help   = "Offload submission/completion to kernel thread",
161                 .category = FIO_OPT_C_ENGINE,
162                 .group  = FIO_OPT_G_IOURING,
163         },
164         {
165                 .name   = "sqthread_poll_cpu",
166                 .lname  = "SQ Thread Poll CPU",
167                 .type   = FIO_OPT_INT,
168                 .cb     = fio_ioring_sqpoll_cb,
169                 .help   = "What CPU to run SQ thread polling on",
170                 .category = FIO_OPT_C_ENGINE,
171                 .group  = FIO_OPT_G_IOURING,
172         },
173         {
174                 .name   = "nonvectored",
175                 .lname  = "Non-vectored",
176                 .type   = FIO_OPT_INT,
177                 .off1   = offsetof(struct ioring_options, nonvectored),
178                 .def    = "-1",
179                 .help   = "Use non-vectored read/write commands",
180                 .category = FIO_OPT_C_ENGINE,
181                 .group  = FIO_OPT_G_IOURING,
182         },
183         {
184                 .name   = "uncached",
185                 .lname  = "Uncached",
186                 .type   = FIO_OPT_INT,
187                 .off1   = offsetof(struct ioring_options, uncached),
188                 .help   = "Use RWF_UNCACHED for buffered read/writes",
189                 .category = FIO_OPT_C_ENGINE,
190                 .group  = FIO_OPT_G_IOURING,
191         },
192         {
193                 .name   = "nowait",
194                 .lname  = "RWF_NOWAIT",
195                 .type   = FIO_OPT_BOOL,
196                 .off1   = offsetof(struct ioring_options, nowait),
197                 .help   = "Use RWF_NOWAIT for reads/writes",
198                 .category = FIO_OPT_C_ENGINE,
199                 .group  = FIO_OPT_G_IOURING,
200         },
201         {
202                 .name   = "force_async",
203                 .lname  = "Force async",
204                 .type   = FIO_OPT_INT,
205                 .off1   = offsetof(struct ioring_options, force_async),
206                 .help   = "Set IOSQE_ASYNC every N requests",
207                 .category = FIO_OPT_C_ENGINE,
208                 .group  = FIO_OPT_G_IOURING,
209         },
210         {
211                 .name   = "cmd_type",
212                 .lname  = "Uring cmd type",
213                 .type   = FIO_OPT_STR,
214                 .off1   = offsetof(struct ioring_options, cmd_type),
215                 .help   = "Specify uring-cmd type",
216                 .def    = "nvme",
217                 .posval = {
218                           { .ival = "nvme",
219                             .oval = FIO_URING_CMD_NVME,
220                             .help = "Issue nvme-uring-cmd",
221                           },
222                 },
223                 .category = FIO_OPT_C_ENGINE,
224                 .group  = FIO_OPT_G_IOURING,
225         },
226         CMDPRIO_OPTIONS(struct ioring_options, FIO_OPT_G_IOURING),
227         {
228                 .name   = "md_per_io_size",
229                 .lname  = "Separate Metadata Buffer Size per I/O",
230                 .type   = FIO_OPT_INT,
231                 .off1   = offsetof(struct ioring_options, md_per_io_size),
232                 .def    = "0",
233                 .help   = "Size of separate metadata buffer per I/O (Default: 0)",
234                 .category = FIO_OPT_C_ENGINE,
235                 .group  = FIO_OPT_G_IOURING,
236         },
237         {
238                 .name   = "pi_act",
239                 .lname  = "Protection Information Action",
240                 .type   = FIO_OPT_BOOL,
241                 .off1   = offsetof(struct ioring_options, pi_act),
242                 .def    = "1",
243                 .help   = "Protection Information Action bit (pi_act=1 or pi_act=0)",
244                 .category = FIO_OPT_C_ENGINE,
245                 .group  = FIO_OPT_G_IOURING,
246         },
247         {
248                 .name   = "pi_chk",
249                 .lname  = "Protection Information Check",
250                 .type   = FIO_OPT_STR_STORE,
251                 .off1   = offsetof(struct ioring_options, pi_chk),
252                 .def    = NULL,
253                 .help   = "Control of Protection Information Checking (pi_chk=GUARD,REFTAG,APPTAG)",
254                 .category = FIO_OPT_C_ENGINE,
255                 .group  = FIO_OPT_G_IOURING,
256         },
257         {
258                 .name   = "apptag",
259                 .lname  = "Application Tag used in Protection Information",
260                 .type   = FIO_OPT_INT,
261                 .off1   = offsetof(struct ioring_options, apptag),
262                 .def    = "0x1234",
263                 .help   = "Application Tag used in Protection Information field (Default: 0x1234)",
264                 .category = FIO_OPT_C_ENGINE,
265                 .group  = FIO_OPT_G_IOURING,
266         },
267         {
268                 .name   = "apptag_mask",
269                 .lname  = "Application Tag Mask",
270                 .type   = FIO_OPT_INT,
271                 .off1   = offsetof(struct ioring_options, apptag_mask),
272                 .def    = "0xffff",
273                 .help   = "Application Tag Mask used with Application Tag (Default: 0xffff)",
274                 .category = FIO_OPT_C_ENGINE,
275                 .group  = FIO_OPT_G_IOURING,
276         },
277         {
278                 .name   = NULL,
279         },
280 };
281
282 static int io_uring_enter(struct ioring_data *ld, unsigned int to_submit,
283                          unsigned int min_complete, unsigned int flags)
284 {
285 #ifdef FIO_ARCH_HAS_SYSCALL
286         return __do_syscall6(__NR_io_uring_enter, ld->ring_fd, to_submit,
287                                 min_complete, flags, NULL, 0);
288 #else
289         return syscall(__NR_io_uring_enter, ld->ring_fd, to_submit,
290                         min_complete, flags, NULL, 0);
291 #endif
292 }
293
294 static int fio_ioring_prep(struct thread_data *td, struct io_u *io_u)
295 {
296         struct ioring_data *ld = td->io_ops_data;
297         struct ioring_options *o = td->eo;
298         struct fio_file *f = io_u->file;
299         struct io_uring_sqe *sqe;
300
301         sqe = &ld->sqes[io_u->index];
302
303         if (o->registerfiles) {
304                 sqe->fd = f->engine_pos;
305                 sqe->flags = IOSQE_FIXED_FILE;
306         } else {
307                 sqe->fd = f->fd;
308                 sqe->flags = 0;
309         }
310
311         if (io_u->ddir == DDIR_READ || io_u->ddir == DDIR_WRITE) {
312                 if (o->fixedbufs) {
313                         sqe->opcode = fixed_ddir_to_op[io_u->ddir];
314                         sqe->addr = (unsigned long) io_u->xfer_buf;
315                         sqe->len = io_u->xfer_buflen;
316                         sqe->buf_index = io_u->index;
317                 } else {
318                         struct iovec *iov = &ld->iovecs[io_u->index];
319
320                         /*
321                          * Update based on actual io_u, requeue could have
322                          * adjusted these
323                          */
324                         iov->iov_base = io_u->xfer_buf;
325                         iov->iov_len = io_u->xfer_buflen;
326
327                         sqe->opcode = ddir_to_op[io_u->ddir][!!o->nonvectored];
328                         if (o->nonvectored) {
329                                 sqe->addr = (unsigned long) iov->iov_base;
330                                 sqe->len = iov->iov_len;
331                         } else {
332                                 sqe->addr = (unsigned long) iov;
333                                 sqe->len = 1;
334                         }
335                 }
336                 sqe->rw_flags = 0;
337                 if (!td->o.odirect && o->uncached)
338                         sqe->rw_flags |= RWF_UNCACHED;
339                 if (o->nowait)
340                         sqe->rw_flags |= RWF_NOWAIT;
341
342                 /*
343                  * Since io_uring can have a submission context (sqthread_poll)
344                  * that is different from the process context, we cannot rely on
345                  * the IO priority set by ioprio_set() (options prio, prioclass,
346                  * and priohint) to be inherited.
347                  * td->ioprio will have the value of the "default prio", so set
348                  * this unconditionally. This value might get overridden by
349                  * fio_ioring_cmdprio_prep() if the option cmdprio_percentage or
350                  * cmdprio_bssplit is used.
351                  */
352                 sqe->ioprio = td->ioprio;
353                 sqe->off = io_u->offset;
354         } else if (ddir_sync(io_u->ddir)) {
355                 sqe->ioprio = 0;
356                 if (io_u->ddir == DDIR_SYNC_FILE_RANGE) {
357                         sqe->off = f->first_write;
358                         sqe->len = f->last_write - f->first_write;
359                         sqe->sync_range_flags = td->o.sync_file_range;
360                         sqe->opcode = IORING_OP_SYNC_FILE_RANGE;
361                 } else {
362                         sqe->off = 0;
363                         sqe->addr = 0;
364                         sqe->len = 0;
365                         if (io_u->ddir == DDIR_DATASYNC)
366                                 sqe->fsync_flags |= IORING_FSYNC_DATASYNC;
367                         sqe->opcode = IORING_OP_FSYNC;
368                 }
369         }
370
371         if (o->force_async && ++ld->prepped == o->force_async) {
372                 ld->prepped = 0;
373                 sqe->flags |= IOSQE_ASYNC;
374         }
375
376         sqe->user_data = (unsigned long) io_u;
377         return 0;
378 }
379
380 static int fio_ioring_cmd_prep(struct thread_data *td, struct io_u *io_u)
381 {
382         struct ioring_data *ld = td->io_ops_data;
383         struct ioring_options *o = td->eo;
384         struct fio_file *f = io_u->file;
385         struct nvme_uring_cmd *cmd;
386         struct io_uring_sqe *sqe;
387
388         /* only supports nvme_uring_cmd */
389         if (o->cmd_type != FIO_URING_CMD_NVME)
390                 return -EINVAL;
391
392         if (io_u->ddir == DDIR_TRIM && td->io_ops->flags & FIO_ASYNCIO_SYNC_TRIM)
393                 return 0;
394
395         sqe = &ld->sqes[(io_u->index) << 1];
396
397         if (o->registerfiles) {
398                 sqe->fd = f->engine_pos;
399                 sqe->flags = IOSQE_FIXED_FILE;
400         } else {
401                 sqe->fd = f->fd;
402         }
403         sqe->rw_flags = 0;
404         if (!td->o.odirect && o->uncached)
405                 sqe->rw_flags |= RWF_UNCACHED;
406         if (o->nowait)
407                 sqe->rw_flags |= RWF_NOWAIT;
408
409         sqe->opcode = IORING_OP_URING_CMD;
410         sqe->user_data = (unsigned long) io_u;
411         if (o->nonvectored)
412                 sqe->cmd_op = NVME_URING_CMD_IO;
413         else
414                 sqe->cmd_op = NVME_URING_CMD_IO_VEC;
415         if (o->force_async && ++ld->prepped == o->force_async) {
416                 ld->prepped = 0;
417                 sqe->flags |= IOSQE_ASYNC;
418         }
419         if (o->fixedbufs) {
420                 sqe->uring_cmd_flags = IORING_URING_CMD_FIXED;
421                 sqe->buf_index = io_u->index;
422         }
423
424         cmd = (struct nvme_uring_cmd *)sqe->cmd;
425         return fio_nvme_uring_cmd_prep(cmd, io_u,
426                         o->nonvectored ? NULL : &ld->iovecs[io_u->index],
427                         &ld->dsm[io_u->index]);
428 }
429
430 static struct io_u *fio_ioring_event(struct thread_data *td, int event)
431 {
432         struct ioring_data *ld = td->io_ops_data;
433         struct io_uring_cqe *cqe;
434         struct io_u *io_u;
435         unsigned index;
436
437         index = (event + ld->cq_ring_off) & ld->cq_ring_mask;
438
439         cqe = &ld->cq_ring.cqes[index];
440         io_u = (struct io_u *) (uintptr_t) cqe->user_data;
441
442         if (cqe->res != io_u->xfer_buflen) {
443                 if (cqe->res > io_u->xfer_buflen)
444                         io_u->error = -cqe->res;
445                 else
446                         io_u->resid = io_u->xfer_buflen - cqe->res;
447         } else
448                 io_u->error = 0;
449
450         return io_u;
451 }
452
453 static struct io_u *fio_ioring_cmd_event(struct thread_data *td, int event)
454 {
455         struct ioring_data *ld = td->io_ops_data;
456         struct ioring_options *o = td->eo;
457         struct io_uring_cqe *cqe;
458         struct io_u *io_u;
459         unsigned index;
460
461         index = (event + ld->cq_ring_off) & ld->cq_ring_mask;
462         if (o->cmd_type == FIO_URING_CMD_NVME)
463                 index <<= 1;
464
465         cqe = &ld->cq_ring.cqes[index];
466         io_u = (struct io_u *) (uintptr_t) cqe->user_data;
467
468         if (cqe->res != 0)
469                 io_u->error = -cqe->res;
470         else
471                 io_u->error = 0;
472
473         return io_u;
474 }
475
476 static int fio_ioring_cqring_reap(struct thread_data *td, unsigned int events,
477                                    unsigned int max)
478 {
479         struct ioring_data *ld = td->io_ops_data;
480         struct io_cq_ring *ring = &ld->cq_ring;
481         unsigned head, reaped = 0;
482
483         head = *ring->head;
484         do {
485                 if (head == atomic_load_acquire(ring->tail))
486                         break;
487                 reaped++;
488                 head++;
489         } while (reaped + events < max);
490
491         if (reaped)
492                 atomic_store_release(ring->head, head);
493
494         return reaped;
495 }
496
497 static int fio_ioring_getevents(struct thread_data *td, unsigned int min,
498                                 unsigned int max, const struct timespec *t)
499 {
500         struct ioring_data *ld = td->io_ops_data;
501         unsigned actual_min = td->o.iodepth_batch_complete_min == 0 ? 0 : min;
502         struct ioring_options *o = td->eo;
503         struct io_cq_ring *ring = &ld->cq_ring;
504         unsigned events = 0;
505         int r;
506
507         ld->cq_ring_off = *ring->head;
508         do {
509                 r = fio_ioring_cqring_reap(td, events, max);
510                 if (r) {
511                         events += r;
512                         max -= r;
513                         if (actual_min != 0)
514                                 actual_min -= r;
515                         continue;
516                 }
517
518                 if (!o->sqpoll_thread) {
519                         r = io_uring_enter(ld, 0, actual_min,
520                                                 IORING_ENTER_GETEVENTS);
521                         if (r < 0) {
522                                 if (errno == EAGAIN || errno == EINTR)
523                                         continue;
524                                 r = -errno;
525                                 td_verror(td, errno, "io_uring_enter");
526                                 break;
527                         }
528                 }
529         } while (events < min);
530
531         return r < 0 ? r : events;
532 }
533
534 static inline void fio_ioring_cmd_nvme_pi(struct thread_data *td,
535                                           struct io_u *io_u)
536 {
537         struct ioring_data *ld = td->io_ops_data;
538         struct ioring_options *o = td->eo;
539         struct nvme_uring_cmd *cmd;
540         struct io_uring_sqe *sqe;
541         struct nvme_cmd_ext_io_opts ext_opts = {0};
542         struct nvme_data *data = FILE_ENG_DATA(io_u->file);
543
544         if (io_u->ddir == DDIR_TRIM)
545                 return;
546
547         sqe = &ld->sqes[(io_u->index) << 1];
548         cmd = (struct nvme_uring_cmd *)sqe->cmd;
549
550         if (data->pi_type) {
551                 if (o->pi_act)
552                         ext_opts.io_flags |= NVME_IO_PRINFO_PRACT;
553                 ext_opts.io_flags |= o->prchk;
554                 ext_opts.apptag = o->apptag;
555                 ext_opts.apptag_mask = o->apptag_mask;
556         }
557
558         fio_nvme_pi_fill(cmd, io_u, &ext_opts);
559 }
560
561 static inline void fio_ioring_cmdprio_prep(struct thread_data *td,
562                                            struct io_u *io_u)
563 {
564         struct ioring_data *ld = td->io_ops_data;
565         struct cmdprio *cmdprio = &ld->cmdprio;
566
567         if (fio_cmdprio_set_ioprio(td, cmdprio, io_u))
568                 ld->sqes[io_u->index].ioprio = io_u->ioprio;
569 }
570
571 static enum fio_q_status fio_ioring_queue(struct thread_data *td,
572                                           struct io_u *io_u)
573 {
574         struct ioring_data *ld = td->io_ops_data;
575         struct ioring_options *o = td->eo;
576         struct io_sq_ring *ring = &ld->sq_ring;
577         unsigned tail, next_tail;
578
579         fio_ro_check(td, io_u);
580
581         if (ld->queued == ld->iodepth)
582                 return FIO_Q_BUSY;
583
584         if (io_u->ddir == DDIR_TRIM && td->io_ops->flags & FIO_ASYNCIO_SYNC_TRIM) {
585                 if (ld->queued)
586                         return FIO_Q_BUSY;
587
588                 do_io_u_trim(td, io_u);
589
590                 io_u_mark_submit(td, 1);
591                 io_u_mark_complete(td, 1);
592                 return FIO_Q_COMPLETED;
593         }
594
595         tail = *ring->tail;
596         next_tail = tail + 1;
597         if (next_tail == atomic_load_relaxed(ring->head))
598                 return FIO_Q_BUSY;
599
600         if (ld->cmdprio.mode != CMDPRIO_MODE_NONE)
601                 fio_ioring_cmdprio_prep(td, io_u);
602
603         if (!strcmp(td->io_ops->name, "io_uring_cmd") &&
604                 o->cmd_type == FIO_URING_CMD_NVME)
605                 fio_ioring_cmd_nvme_pi(td, io_u);
606
607         ring->array[tail & ld->sq_ring_mask] = io_u->index;
608         atomic_store_release(ring->tail, next_tail);
609
610         ld->queued++;
611         return FIO_Q_QUEUED;
612 }
613
614 static void fio_ioring_queued(struct thread_data *td, int start, int nr)
615 {
616         struct ioring_data *ld = td->io_ops_data;
617         struct timespec now;
618
619         if (!fio_fill_issue_time(td))
620                 return;
621
622         fio_gettime(&now, NULL);
623
624         while (nr--) {
625                 struct io_sq_ring *ring = &ld->sq_ring;
626                 int index = ring->array[start & ld->sq_ring_mask];
627                 struct io_u *io_u = ld->io_u_index[index];
628
629                 memcpy(&io_u->issue_time, &now, sizeof(now));
630                 io_u_queued(td, io_u);
631
632                 start++;
633         }
634
635         /*
636          * only used for iolog
637          */
638         if (td->o.read_iolog_file)
639                 memcpy(&td->last_issue, &now, sizeof(now));
640 }
641
642 static int fio_ioring_commit(struct thread_data *td)
643 {
644         struct ioring_data *ld = td->io_ops_data;
645         struct ioring_options *o = td->eo;
646         int ret;
647
648         if (!ld->queued)
649                 return 0;
650
651         /*
652          * Kernel side does submission. just need to check if the ring is
653          * flagged as needing a kick, if so, call io_uring_enter(). This
654          * only happens if we've been idle too long.
655          */
656         if (o->sqpoll_thread) {
657                 struct io_sq_ring *ring = &ld->sq_ring;
658                 unsigned start = *ld->sq_ring.tail - ld->queued;
659                 unsigned flags;
660
661                 flags = atomic_load_relaxed(ring->flags);
662                 if (flags & IORING_SQ_NEED_WAKEUP)
663                         io_uring_enter(ld, ld->queued, 0,
664                                         IORING_ENTER_SQ_WAKEUP);
665                 fio_ioring_queued(td, start, ld->queued);
666                 io_u_mark_submit(td, ld->queued);
667
668                 ld->queued = 0;
669                 return 0;
670         }
671
672         do {
673                 unsigned start = *ld->sq_ring.head;
674                 long nr = ld->queued;
675
676                 ret = io_uring_enter(ld, nr, 0, IORING_ENTER_GETEVENTS);
677                 if (ret > 0) {
678                         fio_ioring_queued(td, start, ret);
679                         io_u_mark_submit(td, ret);
680
681                         ld->queued -= ret;
682                         ret = 0;
683                 } else if (!ret) {
684                         io_u_mark_submit(td, ret);
685                         continue;
686                 } else {
687                         if (errno == EAGAIN || errno == EINTR) {
688                                 ret = fio_ioring_cqring_reap(td, 0, ld->queued);
689                                 if (ret)
690                                         continue;
691                                 /* Shouldn't happen */
692                                 usleep(1);
693                                 continue;
694                         }
695                         ret = -errno;
696                         td_verror(td, errno, "io_uring_enter submit");
697                         break;
698                 }
699         } while (ld->queued);
700
701         return ret;
702 }
703
704 static void fio_ioring_unmap(struct ioring_data *ld)
705 {
706         int i;
707
708         for (i = 0; i < FIO_ARRAY_SIZE(ld->mmap); i++)
709                 munmap(ld->mmap[i].ptr, ld->mmap[i].len);
710         close(ld->ring_fd);
711 }
712
713 static void fio_ioring_cleanup(struct thread_data *td)
714 {
715         struct ioring_data *ld = td->io_ops_data;
716
717         if (ld) {
718                 if (!(td->flags & TD_F_CHILD))
719                         fio_ioring_unmap(ld);
720
721                 fio_cmdprio_cleanup(&ld->cmdprio);
722                 free(ld->io_u_index);
723                 free(ld->md_buf);
724                 free(ld->iovecs);
725                 free(ld->fds);
726                 free(ld->dsm);
727                 free(ld);
728         }
729 }
730
731 static int fio_ioring_mmap(struct ioring_data *ld, struct io_uring_params *p)
732 {
733         struct io_sq_ring *sring = &ld->sq_ring;
734         struct io_cq_ring *cring = &ld->cq_ring;
735         void *ptr;
736
737         ld->mmap[0].len = p->sq_off.array + p->sq_entries * sizeof(__u32);
738         ptr = mmap(0, ld->mmap[0].len, PROT_READ | PROT_WRITE,
739                         MAP_SHARED | MAP_POPULATE, ld->ring_fd,
740                         IORING_OFF_SQ_RING);
741         ld->mmap[0].ptr = ptr;
742         sring->head = ptr + p->sq_off.head;
743         sring->tail = ptr + p->sq_off.tail;
744         sring->ring_mask = ptr + p->sq_off.ring_mask;
745         sring->ring_entries = ptr + p->sq_off.ring_entries;
746         sring->flags = ptr + p->sq_off.flags;
747         sring->array = ptr + p->sq_off.array;
748         ld->sq_ring_mask = *sring->ring_mask;
749
750         if (p->flags & IORING_SETUP_SQE128)
751                 ld->mmap[1].len = 2 * p->sq_entries * sizeof(struct io_uring_sqe);
752         else
753                 ld->mmap[1].len = p->sq_entries * sizeof(struct io_uring_sqe);
754         ld->sqes = mmap(0, ld->mmap[1].len, PROT_READ | PROT_WRITE,
755                                 MAP_SHARED | MAP_POPULATE, ld->ring_fd,
756                                 IORING_OFF_SQES);
757         ld->mmap[1].ptr = ld->sqes;
758
759         if (p->flags & IORING_SETUP_CQE32) {
760                 ld->mmap[2].len = p->cq_off.cqes +
761                                         2 * p->cq_entries * sizeof(struct io_uring_cqe);
762         } else {
763                 ld->mmap[2].len = p->cq_off.cqes +
764                                         p->cq_entries * sizeof(struct io_uring_cqe);
765         }
766         ptr = mmap(0, ld->mmap[2].len, PROT_READ | PROT_WRITE,
767                         MAP_SHARED | MAP_POPULATE, ld->ring_fd,
768                         IORING_OFF_CQ_RING);
769         ld->mmap[2].ptr = ptr;
770         cring->head = ptr + p->cq_off.head;
771         cring->tail = ptr + p->cq_off.tail;
772         cring->ring_mask = ptr + p->cq_off.ring_mask;
773         cring->ring_entries = ptr + p->cq_off.ring_entries;
774         cring->cqes = ptr + p->cq_off.cqes;
775         ld->cq_ring_mask = *cring->ring_mask;
776         return 0;
777 }
778
779 static void fio_ioring_probe(struct thread_data *td)
780 {
781         struct ioring_data *ld = td->io_ops_data;
782         struct ioring_options *o = td->eo;
783         struct io_uring_probe *p;
784         int ret;
785
786         /* already set by user, don't touch */
787         if (o->nonvectored != -1)
788                 return;
789
790         /* default to off, as that's always safe */
791         o->nonvectored = 0;
792
793         p = calloc(1, sizeof(*p) + 256 * sizeof(struct io_uring_probe_op));
794         if (!p)
795                 return;
796
797         ret = syscall(__NR_io_uring_register, ld->ring_fd,
798                         IORING_REGISTER_PROBE, p, 256);
799         if (ret < 0)
800                 goto out;
801
802         if (IORING_OP_WRITE > p->ops_len)
803                 goto out;
804
805         if ((p->ops[IORING_OP_READ].flags & IO_URING_OP_SUPPORTED) &&
806             (p->ops[IORING_OP_WRITE].flags & IO_URING_OP_SUPPORTED))
807                 o->nonvectored = 1;
808 out:
809         free(p);
810 }
811
812 static int fio_ioring_queue_init(struct thread_data *td)
813 {
814         struct ioring_data *ld = td->io_ops_data;
815         struct ioring_options *o = td->eo;
816         int depth = td->o.iodepth;
817         struct io_uring_params p;
818         int ret;
819
820         memset(&p, 0, sizeof(p));
821
822         if (o->hipri)
823                 p.flags |= IORING_SETUP_IOPOLL;
824         if (o->sqpoll_thread) {
825                 p.flags |= IORING_SETUP_SQPOLL;
826                 if (o->sqpoll_set) {
827                         p.flags |= IORING_SETUP_SQ_AFF;
828                         p.sq_thread_cpu = o->sqpoll_cpu;
829                 }
830
831                 /*
832                  * Submission latency for sqpoll_thread is just the time it
833                  * takes to fill in the SQ ring entries, and any syscall if
834                  * IORING_SQ_NEED_WAKEUP is set, we don't need to log that time
835                  * separately.
836                  */
837                 td->o.disable_slat = 1;
838         }
839
840         /*
841          * Clamp CQ ring size at our SQ ring size, we don't need more entries
842          * than that.
843          */
844         p.flags |= IORING_SETUP_CQSIZE;
845         p.cq_entries = depth;
846
847         /*
848          * Setup COOP_TASKRUN as we don't need to get IPI interrupted for
849          * completing IO operations.
850          */
851         p.flags |= IORING_SETUP_COOP_TASKRUN;
852
853         /*
854          * io_uring is always a single issuer, and we can defer task_work
855          * runs until we reap events.
856          */
857         p.flags |= IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN;
858
859 retry:
860         ret = syscall(__NR_io_uring_setup, depth, &p);
861         if (ret < 0) {
862                 if (errno == EINVAL && p.flags & IORING_SETUP_DEFER_TASKRUN) {
863                         p.flags &= ~IORING_SETUP_DEFER_TASKRUN;
864                         p.flags &= ~IORING_SETUP_SINGLE_ISSUER;
865                         goto retry;
866                 }
867                 if (errno == EINVAL && p.flags & IORING_SETUP_COOP_TASKRUN) {
868                         p.flags &= ~IORING_SETUP_COOP_TASKRUN;
869                         goto retry;
870                 }
871                 if (errno == EINVAL && p.flags & IORING_SETUP_CQSIZE) {
872                         p.flags &= ~IORING_SETUP_CQSIZE;
873                         goto retry;
874                 }
875                 return ret;
876         }
877
878         ld->ring_fd = ret;
879
880         fio_ioring_probe(td);
881
882         if (o->fixedbufs) {
883                 ret = syscall(__NR_io_uring_register, ld->ring_fd,
884                                 IORING_REGISTER_BUFFERS, ld->iovecs, depth);
885                 if (ret < 0)
886                         return ret;
887         }
888
889         return fio_ioring_mmap(ld, &p);
890 }
891
892 static int fio_ioring_cmd_queue_init(struct thread_data *td)
893 {
894         struct ioring_data *ld = td->io_ops_data;
895         struct ioring_options *o = td->eo;
896         int depth = td->o.iodepth;
897         struct io_uring_params p;
898         int ret;
899
900         memset(&p, 0, sizeof(p));
901
902         if (o->hipri)
903                 p.flags |= IORING_SETUP_IOPOLL;
904         if (o->sqpoll_thread) {
905                 p.flags |= IORING_SETUP_SQPOLL;
906                 if (o->sqpoll_set) {
907                         p.flags |= IORING_SETUP_SQ_AFF;
908                         p.sq_thread_cpu = o->sqpoll_cpu;
909                 }
910
911                 /*
912                  * Submission latency for sqpoll_thread is just the time it
913                  * takes to fill in the SQ ring entries, and any syscall if
914                  * IORING_SQ_NEED_WAKEUP is set, we don't need to log that time
915                  * separately.
916                  */
917                 td->o.disable_slat = 1;
918         }
919         if (o->cmd_type == FIO_URING_CMD_NVME) {
920                 p.flags |= IORING_SETUP_SQE128;
921                 p.flags |= IORING_SETUP_CQE32;
922         }
923
924         /*
925          * Clamp CQ ring size at our SQ ring size, we don't need more entries
926          * than that.
927          */
928         p.flags |= IORING_SETUP_CQSIZE;
929         p.cq_entries = depth;
930
931         /*
932          * Setup COOP_TASKRUN as we don't need to get IPI interrupted for
933          * completing IO operations.
934          */
935         p.flags |= IORING_SETUP_COOP_TASKRUN;
936
937         /*
938          * io_uring is always a single issuer, and we can defer task_work
939          * runs until we reap events.
940          */
941         p.flags |= IORING_SETUP_SINGLE_ISSUER | IORING_SETUP_DEFER_TASKRUN;
942
943 retry:
944         ret = syscall(__NR_io_uring_setup, depth, &p);
945         if (ret < 0) {
946                 if (errno == EINVAL && p.flags & IORING_SETUP_DEFER_TASKRUN) {
947                         p.flags &= ~IORING_SETUP_DEFER_TASKRUN;
948                         p.flags &= ~IORING_SETUP_SINGLE_ISSUER;
949                         goto retry;
950                 }
951                 if (errno == EINVAL && p.flags & IORING_SETUP_COOP_TASKRUN) {
952                         p.flags &= ~IORING_SETUP_COOP_TASKRUN;
953                         goto retry;
954                 }
955                 if (errno == EINVAL && p.flags & IORING_SETUP_CQSIZE) {
956                         p.flags &= ~IORING_SETUP_CQSIZE;
957                         goto retry;
958                 }
959                 return ret;
960         }
961
962         ld->ring_fd = ret;
963
964         fio_ioring_probe(td);
965
966         if (o->fixedbufs) {
967                 ret = syscall(__NR_io_uring_register, ld->ring_fd,
968                                 IORING_REGISTER_BUFFERS, ld->iovecs, depth);
969                 if (ret < 0)
970                         return ret;
971         }
972
973         return fio_ioring_mmap(ld, &p);
974 }
975
976 static int fio_ioring_register_files(struct thread_data *td)
977 {
978         struct ioring_data *ld = td->io_ops_data;
979         struct fio_file *f;
980         unsigned int i;
981         int ret;
982
983         ld->fds = calloc(td->o.nr_files, sizeof(int));
984
985         for_each_file(td, f, i) {
986                 ret = generic_open_file(td, f);
987                 if (ret)
988                         goto err;
989                 ld->fds[i] = f->fd;
990                 f->engine_pos = i;
991         }
992
993         ret = syscall(__NR_io_uring_register, ld->ring_fd,
994                         IORING_REGISTER_FILES, ld->fds, td->o.nr_files);
995         if (ret) {
996 err:
997                 free(ld->fds);
998                 ld->fds = NULL;
999         }
1000
1001         /*
1002          * Pretend the file is closed again, and really close it if we hit
1003          * an error.
1004          */
1005         for_each_file(td, f, i) {
1006                 if (ret) {
1007                         int fio_unused ret2;
1008                         ret2 = generic_close_file(td, f);
1009                 } else
1010                         f->fd = -1;
1011         }
1012
1013         return ret;
1014 }
1015
1016 static int fio_ioring_post_init(struct thread_data *td)
1017 {
1018         struct ioring_data *ld = td->io_ops_data;
1019         struct ioring_options *o = td->eo;
1020         struct io_u *io_u;
1021         int err, i;
1022
1023         for (i = 0; i < td->o.iodepth; i++) {
1024                 struct iovec *iov = &ld->iovecs[i];
1025
1026                 io_u = ld->io_u_index[i];
1027                 iov->iov_base = io_u->buf;
1028                 iov->iov_len = td_max_bs(td);
1029         }
1030
1031         err = fio_ioring_queue_init(td);
1032         if (err) {
1033                 int init_err = errno;
1034
1035                 if (init_err == ENOSYS)
1036                         log_err("fio: your kernel doesn't support io_uring\n");
1037                 td_verror(td, init_err, "io_queue_init");
1038                 return 1;
1039         }
1040
1041         for (i = 0; i < td->o.iodepth; i++) {
1042                 struct io_uring_sqe *sqe;
1043
1044                 sqe = &ld->sqes[i];
1045                 memset(sqe, 0, sizeof(*sqe));
1046         }
1047
1048         if (o->registerfiles) {
1049                 err = fio_ioring_register_files(td);
1050                 if (err) {
1051                         td_verror(td, errno, "ioring_register_files");
1052                         return 1;
1053                 }
1054         }
1055
1056         return 0;
1057 }
1058
1059 static int fio_ioring_cmd_post_init(struct thread_data *td)
1060 {
1061         struct ioring_data *ld = td->io_ops_data;
1062         struct ioring_options *o = td->eo;
1063         struct io_u *io_u;
1064         int err, i;
1065
1066         for (i = 0; i < td->o.iodepth; i++) {
1067                 struct iovec *iov = &ld->iovecs[i];
1068
1069                 io_u = ld->io_u_index[i];
1070                 iov->iov_base = io_u->buf;
1071                 iov->iov_len = td_max_bs(td);
1072         }
1073
1074         err = fio_ioring_cmd_queue_init(td);
1075         if (err) {
1076                 int init_err = errno;
1077
1078                 td_verror(td, init_err, "io_queue_init");
1079                 return 1;
1080         }
1081
1082         for (i = 0; i < td->o.iodepth; i++) {
1083                 struct io_uring_sqe *sqe;
1084
1085                 if (o->cmd_type == FIO_URING_CMD_NVME) {
1086                         sqe = &ld->sqes[i << 1];
1087                         memset(sqe, 0, 2 * sizeof(*sqe));
1088                 } else {
1089                         sqe = &ld->sqes[i];
1090                         memset(sqe, 0, sizeof(*sqe));
1091                 }
1092         }
1093
1094         if (o->registerfiles) {
1095                 err = fio_ioring_register_files(td);
1096                 if (err) {
1097                         td_verror(td, errno, "ioring_register_files");
1098                         return 1;
1099                 }
1100         }
1101
1102         return 0;
1103 }
1104
1105 static void parse_prchk_flags(struct ioring_options *o)
1106 {
1107         if (!o->pi_chk)
1108                 return;
1109
1110         if (strstr(o->pi_chk, "GUARD") != NULL)
1111                 o->prchk = NVME_IO_PRINFO_PRCHK_GUARD;
1112         if (strstr(o->pi_chk, "REFTAG") != NULL)
1113                 o->prchk |= NVME_IO_PRINFO_PRCHK_REF;
1114         if (strstr(o->pi_chk, "APPTAG") != NULL)
1115                 o->prchk |= NVME_IO_PRINFO_PRCHK_APP;
1116 }
1117
1118 static int fio_ioring_init(struct thread_data *td)
1119 {
1120         struct ioring_options *o = td->eo;
1121         struct ioring_data *ld;
1122         unsigned long long md_size;
1123         int ret;
1124
1125         /* sqthread submission requires registered files */
1126         if (o->sqpoll_thread)
1127                 o->registerfiles = 1;
1128
1129         if (o->registerfiles && td->o.nr_files != td->o.open_files) {
1130                 log_err("fio: io_uring registered files require nr_files to "
1131                         "be identical to open_files\n");
1132                 return 1;
1133         }
1134
1135         ld = calloc(1, sizeof(*ld));
1136
1137         /* ring depth must be a power-of-2 */
1138         ld->iodepth = td->o.iodepth;
1139         td->o.iodepth = roundup_pow2(td->o.iodepth);
1140
1141         /* io_u index */
1142         ld->io_u_index = calloc(td->o.iodepth, sizeof(struct io_u *));
1143
1144         /*
1145          * metadata buffer for nvme command.
1146          * We are only supporting iomem=malloc / mem=malloc as of now.
1147          */
1148         if (!strcmp(td->io_ops->name, "io_uring_cmd") &&
1149             (o->cmd_type == FIO_URING_CMD_NVME) && o->md_per_io_size) {
1150                 md_size = (unsigned long long) o->md_per_io_size
1151                                 * (unsigned long long) td->o.iodepth;
1152                 md_size += page_mask + td->o.mem_align;
1153                 if (td->o.mem_align && td->o.mem_align > page_size)
1154                         md_size += td->o.mem_align - page_size;
1155                 if (td->o.mem_type == MEM_MALLOC) {
1156                         ld->md_buf = malloc(md_size);
1157                         if (!ld->md_buf)
1158                                 return 1;
1159                 } else {
1160                         log_err("fio: Only iomem=malloc or mem=malloc is supported\n");
1161                         return 1;
1162                 }
1163         }
1164         parse_prchk_flags(o);
1165
1166         ld->iovecs = calloc(td->o.iodepth, sizeof(struct iovec));
1167
1168         td->io_ops_data = ld;
1169
1170         ret = fio_cmdprio_init(td, &ld->cmdprio, &o->cmdprio_options);
1171         if (ret) {
1172                 td_verror(td, EINVAL, "fio_ioring_init");
1173                 return 1;
1174         }
1175
1176         /*
1177          * For io_uring_cmd, trims are async operations unless we are operating
1178          * in zbd mode where trim means zone reset.
1179          */
1180         if (!strcmp(td->io_ops->name, "io_uring_cmd") && td_trim(td) &&
1181             td->o.zone_mode == ZONE_MODE_ZBD)
1182                 td->io_ops->flags |= FIO_ASYNCIO_SYNC_TRIM;
1183         else
1184                 ld->dsm = calloc(ld->iodepth, sizeof(*ld->dsm));
1185
1186         return 0;
1187 }
1188
1189 static int fio_ioring_io_u_init(struct thread_data *td, struct io_u *io_u)
1190 {
1191         struct ioring_data *ld = td->io_ops_data;
1192         struct ioring_options *o = td->eo;
1193         char *p;
1194
1195         ld->io_u_index[io_u->index] = io_u;
1196
1197         if (!strcmp(td->io_ops->name, "io_uring_cmd")) {
1198                 p = PTR_ALIGN(ld->md_buf, page_mask) + td->o.mem_align;
1199                 p += o->md_per_io_size * io_u->index;
1200                 io_u->mmap_data = p;
1201         }
1202
1203         return 0;
1204 }
1205
1206 static int fio_ioring_open_file(struct thread_data *td, struct fio_file *f)
1207 {
1208         struct ioring_data *ld = td->io_ops_data;
1209         struct ioring_options *o = td->eo;
1210
1211         if (!ld || !o->registerfiles)
1212                 return generic_open_file(td, f);
1213
1214         f->fd = ld->fds[f->engine_pos];
1215         return 0;
1216 }
1217
1218 static int fio_ioring_cmd_open_file(struct thread_data *td, struct fio_file *f)
1219 {
1220         struct ioring_data *ld = td->io_ops_data;
1221         struct ioring_options *o = td->eo;
1222
1223         if (o->cmd_type == FIO_URING_CMD_NVME) {
1224                 struct nvme_data *data = NULL;
1225                 unsigned int lba_size = 0;
1226                 __u64 nlba = 0;
1227                 int ret;
1228
1229                 /* Store the namespace-id and lba size. */
1230                 data = FILE_ENG_DATA(f);
1231                 if (data == NULL) {
1232                         data = calloc(1, sizeof(struct nvme_data));
1233                         ret = fio_nvme_get_info(f, &nlba, o->pi_act, data);
1234                         if (ret) {
1235                                 free(data);
1236                                 return ret;
1237                         }
1238
1239                         FILE_SET_ENG_DATA(f, data);
1240                 }
1241
1242                 lba_size = data->lba_ext ? data->lba_ext : data->lba_size;
1243
1244                 for_each_rw_ddir(ddir) {
1245                         if (td->o.min_bs[ddir] % lba_size ||
1246                                 td->o.max_bs[ddir] % lba_size) {
1247                                 if (data->lba_ext)
1248                                         log_err("%s: block size must be a multiple of (LBA data size + Metadata size)\n",
1249                                                 f->file_name);
1250                                 else
1251                                         log_err("%s: block size must be a multiple of LBA data size\n",
1252                                                 f->file_name);
1253                                 td_verror(td, EINVAL, "fio_ioring_cmd_open_file");
1254                                 return 1;
1255                         }
1256                         if (data->ms && !data->lba_ext && ddir != DDIR_TRIM &&
1257                             (o->md_per_io_size < ((td->o.max_bs[ddir] / data->lba_size) *
1258                                                   data->ms))) {
1259                                 log_err("%s: md_per_io_size should be at least %llu bytes\n",
1260                                         f->file_name,
1261                                         ((td->o.max_bs[ddir] / data->lba_size) * data->ms));
1262                                 td_verror(td, EINVAL, "fio_ioring_cmd_open_file");
1263                                 return 1;
1264                         }
1265                 }
1266         }
1267         if (!ld || !o->registerfiles)
1268                 return generic_open_file(td, f);
1269
1270         f->fd = ld->fds[f->engine_pos];
1271         return 0;
1272 }
1273
1274 static int fio_ioring_close_file(struct thread_data *td, struct fio_file *f)
1275 {
1276         struct ioring_data *ld = td->io_ops_data;
1277         struct ioring_options *o = td->eo;
1278
1279         if (!ld || !o->registerfiles)
1280                 return generic_close_file(td, f);
1281
1282         f->fd = -1;
1283         return 0;
1284 }
1285
1286 static int fio_ioring_cmd_close_file(struct thread_data *td,
1287                                      struct fio_file *f)
1288 {
1289         struct ioring_data *ld = td->io_ops_data;
1290         struct ioring_options *o = td->eo;
1291
1292         if (o->cmd_type == FIO_URING_CMD_NVME) {
1293                 struct nvme_data *data = FILE_ENG_DATA(f);
1294
1295                 FILE_SET_ENG_DATA(f, NULL);
1296                 free(data);
1297         }
1298         if (!ld || !o->registerfiles)
1299                 return generic_close_file(td, f);
1300
1301         f->fd = -1;
1302         return 0;
1303 }
1304
1305 static int fio_ioring_cmd_get_file_size(struct thread_data *td,
1306                                         struct fio_file *f)
1307 {
1308         struct ioring_options *o = td->eo;
1309
1310         if (fio_file_size_known(f))
1311                 return 0;
1312
1313         if (o->cmd_type == FIO_URING_CMD_NVME) {
1314                 struct nvme_data *data = NULL;
1315                 __u64 nlba = 0;
1316                 int ret;
1317
1318                 data = calloc(1, sizeof(struct nvme_data));
1319                 ret = fio_nvme_get_info(f, &nlba, o->pi_act, data);
1320                 if (ret) {
1321                         free(data);
1322                         return ret;
1323                 }
1324
1325                 f->real_file_size = data->lba_size * nlba;
1326                 fio_file_set_size_known(f);
1327
1328                 FILE_SET_ENG_DATA(f, data);
1329                 return 0;
1330         }
1331         return generic_get_file_size(td, f);
1332 }
1333
1334 static int fio_ioring_cmd_get_zoned_model(struct thread_data *td,
1335                                           struct fio_file *f,
1336                                           enum zbd_zoned_model *model)
1337 {
1338         return fio_nvme_get_zoned_model(td, f, model);
1339 }
1340
1341 static int fio_ioring_cmd_report_zones(struct thread_data *td,
1342                                        struct fio_file *f, uint64_t offset,
1343                                        struct zbd_zone *zbdz,
1344                                        unsigned int nr_zones)
1345 {
1346         return fio_nvme_report_zones(td, f, offset, zbdz, nr_zones);
1347 }
1348
1349 static int fio_ioring_cmd_reset_wp(struct thread_data *td, struct fio_file *f,
1350                                    uint64_t offset, uint64_t length)
1351 {
1352         return fio_nvme_reset_wp(td, f, offset, length);
1353 }
1354
1355 static int fio_ioring_cmd_get_max_open_zones(struct thread_data *td,
1356                                              struct fio_file *f,
1357                                              unsigned int *max_open_zones)
1358 {
1359         return fio_nvme_get_max_open_zones(td, f, max_open_zones);
1360 }
1361
1362 static int fio_ioring_cmd_fetch_ruhs(struct thread_data *td, struct fio_file *f,
1363                                      struct fio_ruhs_info *fruhs_info)
1364 {
1365         struct nvme_fdp_ruh_status *ruhs;
1366         int bytes, ret, i;
1367
1368         bytes = sizeof(*ruhs) + FDP_MAX_RUHS * sizeof(struct nvme_fdp_ruh_status_desc);
1369         ruhs = scalloc(1, bytes);
1370         if (!ruhs)
1371                 return -ENOMEM;
1372
1373         ret = fio_nvme_iomgmt_ruhs(td, f, ruhs, bytes);
1374         if (ret)
1375                 goto free;
1376
1377         fruhs_info->nr_ruhs = le16_to_cpu(ruhs->nruhsd);
1378         for (i = 0; i < fruhs_info->nr_ruhs; i++)
1379                 fruhs_info->plis[i] = le16_to_cpu(ruhs->ruhss[i].pid);
1380 free:
1381         sfree(ruhs);
1382         return ret;
1383 }
1384
1385 static struct ioengine_ops ioengine_uring = {
1386         .name                   = "io_uring",
1387         .version                = FIO_IOOPS_VERSION,
1388         .flags                  = FIO_ASYNCIO_SYNC_TRIM | FIO_NO_OFFLOAD |
1389                                         FIO_ASYNCIO_SETS_ISSUE_TIME,
1390         .init                   = fio_ioring_init,
1391         .post_init              = fio_ioring_post_init,
1392         .io_u_init              = fio_ioring_io_u_init,
1393         .prep                   = fio_ioring_prep,
1394         .queue                  = fio_ioring_queue,
1395         .commit                 = fio_ioring_commit,
1396         .getevents              = fio_ioring_getevents,
1397         .event                  = fio_ioring_event,
1398         .cleanup                = fio_ioring_cleanup,
1399         .open_file              = fio_ioring_open_file,
1400         .close_file             = fio_ioring_close_file,
1401         .get_file_size          = generic_get_file_size,
1402         .options                = options,
1403         .option_struct_size     = sizeof(struct ioring_options),
1404 };
1405
1406 static struct ioengine_ops ioengine_uring_cmd = {
1407         .name                   = "io_uring_cmd",
1408         .version                = FIO_IOOPS_VERSION,
1409         .flags                  = FIO_NO_OFFLOAD | FIO_MEMALIGN | FIO_RAWIO |
1410                                         FIO_ASYNCIO_SETS_ISSUE_TIME,
1411         .init                   = fio_ioring_init,
1412         .post_init              = fio_ioring_cmd_post_init,
1413         .io_u_init              = fio_ioring_io_u_init,
1414         .prep                   = fio_ioring_cmd_prep,
1415         .queue                  = fio_ioring_queue,
1416         .commit                 = fio_ioring_commit,
1417         .getevents              = fio_ioring_getevents,
1418         .event                  = fio_ioring_cmd_event,
1419         .cleanup                = fio_ioring_cleanup,
1420         .open_file              = fio_ioring_cmd_open_file,
1421         .close_file             = fio_ioring_cmd_close_file,
1422         .get_file_size          = fio_ioring_cmd_get_file_size,
1423         .get_zoned_model        = fio_ioring_cmd_get_zoned_model,
1424         .report_zones           = fio_ioring_cmd_report_zones,
1425         .reset_wp               = fio_ioring_cmd_reset_wp,
1426         .get_max_open_zones     = fio_ioring_cmd_get_max_open_zones,
1427         .options                = options,
1428         .option_struct_size     = sizeof(struct ioring_options),
1429         .fdp_fetch_ruhs         = fio_ioring_cmd_fetch_ruhs,
1430 };
1431
1432 static void fio_init fio_ioring_register(void)
1433 {
1434         register_ioengine(&ioengine_uring);
1435         register_ioengine(&ioengine_uring_cmd);
1436 }
1437
1438 static void fio_exit fio_ioring_unregister(void)
1439 {
1440         unregister_ioengine(&ioengine_uring);
1441         unregister_ioengine(&ioengine_uring_cmd);
1442 }
1443 #endif