The following changes since commit 2fa0ab21c5726d8242a820ff688de019cc4d2fe2: engines/nvme: cast __u64 to unsigned long long for printing (2023-03-21 08:40:14 -0600) are available in the Git repository at: git://git.kernel.dk/fio.git master for you to fetch changes up to d86ac3e9f4c703b7d7c9add96e69f2d02affdc65: Merge branch 'trim-support' of https://github.com/ankit-sam/fio (2023-03-27 13:21:25 -0600) ---------------------------------------------------------------- Ankit Kumar (2): fdp: drop expensive modulo operation io_uring_cmd: suppport for trim operation Jens Axboe (1): Merge branch 'trim-support' of https://github.com/ankit-sam/fio engines/io_uring.c | 31 ++++++++++++++++++++++++++++++- engines/nvme.c | 34 ++++++++++++++++++++++++++++++++++ engines/nvme.h | 12 ++++++++++++ fdp.c | 5 ++++- stat.c | 2 +- 5 files changed, 81 insertions(+), 3 deletions(-) --- Diff of recent changes: diff --git a/engines/io_uring.c b/engines/io_uring.c index 54fdf7f3..f10a4593 100644 --- a/engines/io_uring.c +++ b/engines/io_uring.c @@ -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; diff --git a/engines/nvme.c b/engines/nvme.c index 3f6b64a8..ac908687 100644 --- a/engines/nvme.c +++ b/engines/nvme.c @@ -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) { diff --git a/engines/nvme.h b/engines/nvme.h index 1c0e526b..408594d5 100644 --- a/engines/nvme.h +++ b/engines/nvme.h @@ -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/fdp.c b/fdp.c index 84e04fce..d92dbc67 100644 --- a/fdp.c +++ b/fdp.c @@ -119,7 +119,10 @@ void fdp_fill_dspec_data(struct thread_data *td, struct io_u *io_u) return; } - dspec = ruhs->plis[ruhs->pli_loc++ % ruhs->nr_ruhs]; + if (ruhs->pli_loc >= ruhs->nr_ruhs) + ruhs->pli_loc = 0; + + dspec = ruhs->plis[ruhs->pli_loc++]; io_u->dtype = 2; io_u->dspec = dspec; } diff --git a/stat.c b/stat.c index d779a90f..015b8e28 100644 --- 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;