io_uring_cmd: suppport for trim operation
authorAnkit Kumar <ankit.kumar@samsung.com>
Tue, 7 Mar 2023 14:21:06 +0000 (19:51 +0530)
committerAnkit Kumar <ankit.kumar@samsung.com>
Fri, 24 Mar 2023 15:43:57 +0000 (21:13 +0530)
Add support for trim operation to the io_uring_cmd
ioengine.
Print ZBD zone reset stats for trim operation.

Signed-off-by: Ankit Kumar <ankit.kumar@samsung.com>
engines/io_uring.c
engines/nvme.c
engines/nvme.h
stat.c

index 54fdf7f3af1f0f60823b308893d3a80deeb02306..f10a45933ff5bb1877b072538547ee2e637a69d5 100644 (file)
@@ -24,6 +24,7 @@
 #include "../lib/types.h"
 #include "../os/linux/io_uring.h"
 #include "cmdprio.h"
+#include "zbd.h"
 #include "nvme.h"
 
 #include <sys/stat.h>
@@ -409,6 +410,9 @@ static int fio_ioring_cmd_prep(struct thread_data *td, struct io_u *io_u)
        if (o->cmd_type != FIO_URING_CMD_NVME)
                return -EINVAL;
 
+       if (io_u->ddir == DDIR_TRIM)
+               return 0;
+
        sqe = &ld->sqes[(io_u->index) << 1];
 
        if (o->registerfiles) {
@@ -556,6 +560,27 @@ static inline void fio_ioring_cmdprio_prep(struct thread_data *td,
                ld->sqes[io_u->index].ioprio = io_u->ioprio;
 }
 
+static int fio_ioring_cmd_io_u_trim(const struct thread_data *td,
+                                   struct io_u *io_u)
+{
+       struct fio_file *f = io_u->file;
+       int ret;
+
+       if (td->o.zone_mode == ZONE_MODE_ZBD) {
+               ret = zbd_do_io_u_trim(td, io_u);
+               if (ret == io_u_completed)
+                       return io_u->xfer_buflen;
+               if (ret)
+                       goto err;
+       }
+
+       return fio_nvme_trim(td, f, io_u->offset, io_u->xfer_buflen);
+
+err:
+       io_u->error = ret;
+       return 0;
+}
+
 static enum fio_q_status fio_ioring_queue(struct thread_data *td,
                                          struct io_u *io_u)
 {
@@ -572,7 +597,11 @@ static enum fio_q_status fio_ioring_queue(struct thread_data *td,
                if (ld->queued)
                        return FIO_Q_BUSY;
 
-               do_io_u_trim(td, io_u);
+               if (!strcmp(td->io_ops->name, "io_uring_cmd"))
+                       fio_ioring_cmd_io_u_trim(td, io_u);
+               else
+                       do_io_u_trim(td, io_u);
+
                io_u_mark_submit(td, 1);
                io_u_mark_complete(td, 1);
                return FIO_Q_COMPLETED;
index 3f6b64a86fe5511cc77678a7a54f2fe696efc29c..ac9086876c24f11f105bcd7188d343c1684f1619 100644 (file)
@@ -43,6 +43,40 @@ int fio_nvme_uring_cmd_prep(struct nvme_uring_cmd *cmd, struct io_u *io_u,
        return 0;
 }
 
+static int nvme_trim(int fd, __u32 nsid, __u32 nr_range, __u32 data_len,
+                    void *data)
+{
+       struct nvme_passthru_cmd cmd = {
+               .opcode         = nvme_cmd_dsm,
+               .nsid           = nsid,
+               .addr           = (__u64)(uintptr_t)data,
+               .data_len       = data_len,
+               .cdw10          = nr_range - 1,
+               .cdw11          = NVME_ATTRIBUTE_DEALLOCATE,
+       };
+
+       return ioctl(fd, NVME_IOCTL_IO_CMD, &cmd);
+}
+
+int fio_nvme_trim(const struct thread_data *td, struct fio_file *f,
+                 unsigned long long offset, unsigned long long len)
+{
+       struct nvme_data *data = FILE_ENG_DATA(f);
+       struct nvme_dsm_range dsm;
+       int ret;
+
+       dsm.nlb = (len >> data->lba_shift);
+       dsm.slba = (offset >> data->lba_shift);
+
+       ret = nvme_trim(f->fd, data->nsid, 1, sizeof(struct nvme_dsm_range),
+                       &dsm);
+       if (ret)
+               log_err("%s: nvme_trim failed for offset %llu and len %llu, err=%d\n",
+                       f->file_name, offset, len, ret);
+
+       return ret;
+}
+
 static int nvme_identify(int fd, __u32 nsid, enum nvme_identify_cns cns,
                         enum nvme_csi csi, void *data)
 {
index 1c0e526b95edfe67e0c6fef4e34e5e098e96a1e7..408594d5509326b606c981cebbeea3e055eaeaf0 100644 (file)
@@ -48,6 +48,8 @@ struct nvme_uring_cmd {
 #define NVME_ZNS_ZSA_RESET 0x4
 #define NVME_ZONE_TYPE_SEQWRITE_REQ 0x2
 
+#define NVME_ATTRIBUTE_DEALLOCATE (1 << 2)
+
 enum nvme_identify_cns {
        NVME_IDENTIFY_CNS_NS            = 0x00,
        NVME_IDENTIFY_CNS_CSI_NS        = 0x05,
@@ -67,6 +69,7 @@ enum nvme_admin_opcode {
 enum nvme_io_opcode {
        nvme_cmd_write                  = 0x01,
        nvme_cmd_read                   = 0x02,
+       nvme_cmd_dsm                    = 0x09,
        nvme_cmd_io_mgmt_recv           = 0x12,
        nvme_zns_cmd_mgmt_send          = 0x79,
        nvme_zns_cmd_mgmt_recv          = 0x7a,
@@ -207,6 +210,15 @@ struct nvme_fdp_ruh_status {
        struct nvme_fdp_ruh_status_desc ruhss[];
 };
 
+struct nvme_dsm_range {
+       __le32  cattr;
+       __le32  nlb;
+       __le64  slba;
+};
+
+int fio_nvme_trim(const struct thread_data *td, struct fio_file *f,
+                 unsigned long long offset, unsigned long long len);
+
 int fio_nvme_iomgmt_ruhs(struct thread_data *td, struct fio_file *f,
                         struct nvme_fdp_ruh_status *ruhs, __u32 bytes);
 
diff --git a/stat.c b/stat.c
index d779a90f3209fccb413d80417ea75061a7955228..015b8e280ff27fec6174ae0d7f9c436867d64559 100644 (file)
--- a/stat.c
+++ b/stat.c
@@ -555,7 +555,7 @@ static void show_ddir_status(struct group_run_stats *rs, struct thread_stat *ts,
 
        iops = (1000 * (uint64_t)ts->total_io_u[ddir]) / runt;
        iops_p = num2str(iops, ts->sig_figs, 1, 0, N2S_NONE);
-       if (ddir == DDIR_WRITE)
+       if (ddir == DDIR_WRITE || ddir == DDIR_TRIM)
                post_st = zbd_write_status(ts);
        else if (ddir == DDIR_READ && ts->cachehit && ts->cachemiss) {
                uint64_t total;