engines/io_uring: add multi range dsm support
authorAnkit Kumar <ankit.kumar@samsung.com>
Thu, 15 Feb 2024 15:18:12 +0000 (20:48 +0530)
committerJens Axboe <axboe@kernel.dk>
Thu, 15 Feb 2024 15:38:39 +0000 (08:38 -0700)
Update the io_uring_cmd ioengine to support multiple ranges for trim.
This includes allocating buffer for multiple ranges, and changes to
the nvme trim helper functions.
Add an example on how to use multi range trim.

Signed-off-by: Ankit Kumar <ankit.kumar@samsung.com>
Link: https://lore.kernel.org/r/20240215151812.138370-4-ankit.kumar@samsung.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
engines/io_uring.c
engines/nvme.c
engines/nvme.h
examples/uring-cmd-trim-multi-range.fio [new file with mode: 0644]

index c0cb5a78f7bdaac645d23dada975b271c363b7ec..9069fa3e81a5caaf03c038481f072c25fcca3385 100644 (file)
@@ -81,7 +81,7 @@ struct ioring_data {
 
        struct cmdprio cmdprio;
 
-       struct nvme_dsm_range *dsm;
+       struct nvme_dsm *dsm;
 };
 
 struct ioring_options {
@@ -385,6 +385,9 @@ static int fio_ioring_cmd_prep(struct thread_data *td, struct io_u *io_u)
        struct fio_file *f = io_u->file;
        struct nvme_uring_cmd *cmd;
        struct io_uring_sqe *sqe;
+       struct nvme_dsm *dsm;
+       void *ptr = ld->dsm;
+       unsigned int dsm_size;
 
        /* only supports nvme_uring_cmd */
        if (o->cmd_type != FIO_URING_CMD_NVME)
@@ -423,9 +426,13 @@ static int fio_ioring_cmd_prep(struct thread_data *td, struct io_u *io_u)
        }
 
        cmd = (struct nvme_uring_cmd *)sqe->cmd;
+       dsm_size = sizeof(*ld->dsm) + td->o.num_range * sizeof(struct nvme_dsm_range);
+       ptr += io_u->index * dsm_size;
+       dsm = (struct nvme_dsm *)ptr;
+
        return fio_nvme_uring_cmd_prep(cmd, io_u,
                        o->nonvectored ? NULL : &ld->iovecs[io_u->index],
-                       &ld->dsm[io_u->index]);
+                       dsm);
 }
 
 static struct io_u *fio_ioring_event(struct thread_data *td, int event)
@@ -1133,8 +1140,11 @@ static int fio_ioring_init(struct thread_data *td)
 {
        struct ioring_options *o = td->eo;
        struct ioring_data *ld;
+       struct nvme_dsm *dsm;
+       void *ptr;
+       unsigned int dsm_size;
        unsigned long long md_size;
-       int ret;
+       int ret, i;
 
        /* sqthread submission requires registered files */
        if (o->sqpoll_thread)
@@ -1195,10 +1205,19 @@ static int fio_ioring_init(struct thread_data *td)
         * in zbd mode where trim means zone reset.
         */
        if (!strcmp(td->io_ops->name, "io_uring_cmd") && td_trim(td) &&
-           td->o.zone_mode == ZONE_MODE_ZBD)
+           td->o.zone_mode == ZONE_MODE_ZBD) {
                td->io_ops->flags |= FIO_ASYNCIO_SYNC_TRIM;
-       else
-               ld->dsm = calloc(td->o.iodepth, sizeof(*ld->dsm));
+       } else {
+               dsm_size = sizeof(*ld->dsm) +
+                       td->o.num_range * sizeof(struct nvme_dsm_range);
+               ld->dsm = calloc(td->o.iodepth, dsm_size);
+               ptr = ld->dsm;
+               for (i = 0; i < td->o.iodepth; i++) {
+                       dsm = (struct nvme_dsm *)ptr;
+                       dsm->nr_ranges = td->o.num_range;
+                       ptr += dsm_size;
+               }
+       }
 
        return 0;
 }
@@ -1466,7 +1485,8 @@ static struct ioengine_ops ioengine_uring_cmd = {
        .name                   = "io_uring_cmd",
        .version                = FIO_IOOPS_VERSION,
        .flags                  = FIO_NO_OFFLOAD | FIO_MEMALIGN | FIO_RAWIO |
-                                       FIO_ASYNCIO_SETS_ISSUE_TIME,
+                                       FIO_ASYNCIO_SETS_ISSUE_TIME |
+                                       FIO_MULTI_RANGE_TRIM,
        .init                   = fio_ioring_init,
        .post_init              = fio_ioring_cmd_post_init,
        .io_u_init              = fio_ioring_io_u_init,
index 1933b9c812b8b389c6d050e2a5a27ef66b3ad64e..c6629e8644c67bef77c1d6deb399d4993b93831f 100644 (file)
@@ -329,24 +329,40 @@ next:
        return 0;
 }
 void fio_nvme_uring_cmd_trim_prep(struct nvme_uring_cmd *cmd, struct io_u *io_u,
-                                 struct nvme_dsm_range *dsm)
+                                 struct nvme_dsm *dsm)
 {
        struct nvme_data *data = FILE_ENG_DATA(io_u->file);
+       struct trim_range *range;
+       uint8_t *buf_point;
+       int i;
 
        cmd->opcode = nvme_cmd_dsm;
        cmd->nsid = data->nsid;
-       cmd->cdw10 = 0;
        cmd->cdw11 = NVME_ATTRIBUTE_DEALLOCATE;
-       cmd->addr = (__u64) (uintptr_t) dsm;
-       cmd->data_len = sizeof(*dsm);
-
-       dsm->slba = get_slba(data, io_u);
-       /* nlb is a 1-based value for deallocate */
-       dsm->nlb = get_nlb(data, io_u) + 1;
+       cmd->addr = (__u64) (uintptr_t) (&dsm->range[0]);
+
+       if (dsm->nr_ranges == 1) {
+               dsm->range[0].slba = get_slba(data, io_u->offset);
+               /* nlb is a 1-based value for deallocate */
+               dsm->range[0].nlb = get_nlb(data, io_u->xfer_buflen) + 1;
+               cmd->cdw10 = 0;
+               cmd->data_len = sizeof(struct nvme_dsm_range);
+       } else {
+               buf_point = io_u->xfer_buf;
+               for (i = 0; i < io_u->number_trim; i++) {
+                       range = (struct trim_range *)buf_point;
+                       dsm->range[i].slba = get_slba(data, range->start);
+                       /* nlb is a 1-based value for deallocate */
+                       dsm->range[i].nlb = get_nlb(data, range->len) + 1;
+                       buf_point += sizeof(struct trim_range);
+               }
+               cmd->cdw10 = io_u->number_trim - 1;
+               cmd->data_len = io_u->number_trim * sizeof(struct nvme_dsm_range);
+       }
 }
 
 int fio_nvme_uring_cmd_prep(struct nvme_uring_cmd *cmd, struct io_u *io_u,
-                           struct iovec *iov, struct nvme_dsm_range *dsm)
+                           struct iovec *iov, struct nvme_dsm *dsm)
 {
        struct nvme_data *data = FILE_ENG_DATA(io_u->file);
        __u64 slba;
index 792b35d830c5b82b137abdc1788e5b877c0d54ee..2d5204fc01f9c6ce050937d90a45078fa261b14b 100644 (file)
@@ -408,6 +408,11 @@ struct nvme_dsm_range {
        __le64  slba;
 };
 
+struct nvme_dsm {
+       __u32 nr_ranges;
+       struct nvme_dsm_range range[];
+};
+
 struct nvme_cmd_ext_io_opts {
        __u32 io_flags;
        __u16 apptag;
@@ -421,7 +426,7 @@ int fio_nvme_get_info(struct fio_file *f, __u64 *nlba, __u32 pi_act,
                      struct nvme_data *data);
 
 int fio_nvme_uring_cmd_prep(struct nvme_uring_cmd *cmd, struct io_u *io_u,
-                           struct iovec *iov, struct nvme_dsm_range *dsm);
+                           struct iovec *iov, struct nvme_dsm *dsm);
 
 void fio_nvme_pi_fill(struct nvme_uring_cmd *cmd, struct io_u *io_u,
                      struct nvme_cmd_ext_io_opts *opts);
diff --git a/examples/uring-cmd-trim-multi-range.fio b/examples/uring-cmd-trim-multi-range.fio
new file mode 100644 (file)
index 0000000..b376481
--- /dev/null
@@ -0,0 +1,21 @@
+# Multi-range trim command test with io_uring_cmd I/O engine for nvme-ns
+# generic character device.
+#
+[global]
+filename=/dev/ng0n1
+ioengine=io_uring_cmd
+cmd_type=nvme
+size=10M
+iodepth=32
+thread=1
+stonewall=1
+
+[write_bs]
+bs=4096
+rw=randtrim
+num_range=8
+
+[write_bssplit]
+bssplit=4k/10:64k/50:32k/40
+rw=trim
+num_range=8