nvme/fio_plugin: add fdp support to fio plugin

This adds support for FDP device described by TP4146.

spdk_fio_fdp_fetch_ruhs() fetches the reclaim unit handle
descriptors, used by fio for placement identifiers. This function
also informs fio whether device has fdp capability or not.

spdk_fio_queue() has been modified to submit write with
extended IO arguments. This can only work if sgl is enabled.

Note, a guard FIO_HAS_FDP checks for the required io-engine ops
version.

Change-Id: I91d0d02d3147357a66a831ef9fb82e6b7250be3d
Signed-off-by: Ankit Kumar <ankit.kumar@samsung.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/17605
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
Ankit Kumar 2023-04-18 00:32:53 +05:30 committed by Ben Walker
parent 76f4b77726
commit 86bc8a5f13
2 changed files with 97 additions and 0 deletions

View File

@ -200,3 +200,17 @@ smalloc: OOM. Consider using --alloc-size to increase the shared memory availabl
This is because fio needs to allocate memory for the zone-report, that is, retrieve the state of This is because fio needs to allocate memory for the zone-report, that is, retrieve the state of
zones on the device including auxiliary accounting information. To solve this, then you can follow zones on the device including auxiliary accounting information. To solve this, then you can follow
fio's advice and increase ``--alloc-size``. fio's advice and increase ``--alloc-size``.
## FDP
To use FDP enabled device build and run the io-engine against fio version >= 3.34 and add:
```bash
fdp=1
```
to your fio-script, also have a look at script-example provided with fio:
```bash
fio/examples/uring-cmd-fdp.fio
```

View File

@ -11,6 +11,7 @@
#include "spdk/env.h" #include "spdk/env.h"
#include "spdk/string.h" #include "spdk/string.h"
#include "spdk/log.h" #include "spdk/log.h"
#include "spdk/likely.h"
#include "spdk/endian.h" #include "spdk/endian.h"
#include "spdk/dif.h" #include "spdk/dif.h"
#include "spdk/util.h" #include "spdk/util.h"
@ -21,8 +22,10 @@
#ifdef for_each_rw_ddir #ifdef for_each_rw_ddir
#define FIO_HAS_ZBD (FIO_IOOPS_VERSION >= 26) #define FIO_HAS_ZBD (FIO_IOOPS_VERSION >= 26)
#define FIO_HAS_FDP (FIO_IOOPS_VERSION >= 32)
#else #else
#define FIO_HAS_ZBD (0) #define FIO_HAS_ZBD (0)
#define FIO_HAS_FDP (0)
#endif #endif
/* FreeBSD is missing CLOCK_MONOTONIC_RAW, /* FreeBSD is missing CLOCK_MONOTONIC_RAW,
@ -1020,6 +1023,9 @@ spdk_fio_queue(struct thread_data *td, struct io_u *io_u)
struct spdk_nvme_ns *ns = NULL; struct spdk_nvme_ns *ns = NULL;
void *md_buf = NULL; void *md_buf = NULL;
struct spdk_dif_ctx *dif_ctx = &fio_req->dif_ctx; struct spdk_dif_ctx *dif_ctx = &fio_req->dif_ctx;
#if FIO_HAS_FDP
struct spdk_nvme_ns_cmd_ext_io_opts ext_opts;
#endif
uint32_t block_size; uint32_t block_size;
uint64_t lba; uint64_t lba;
uint32_t lba_count; uint32_t lba_count;
@ -1039,6 +1045,15 @@ spdk_fio_queue(struct thread_data *td, struct io_u *io_u)
lba = io_u->offset / block_size; lba = io_u->offset / block_size;
lba_count = io_u->xfer_buflen / block_size; lba_count = io_u->xfer_buflen / block_size;
#if FIO_HAS_FDP
/* Only SGL support for write command with directives */
if (io_u->ddir == DDIR_WRITE && io_u->dtype && !g_spdk_enable_sgl) {
log_err("spdk/nvme: queue() directives require SGL to be enabled\n");
io_u->error = -EINVAL;
return FIO_Q_COMPLETED;
}
#endif
/* TODO: considering situations that fio will randomize and verify io_u */ /* TODO: considering situations that fio will randomize and verify io_u */
if (fio_qpair->nvme_pi_enabled) { if (fio_qpair->nvme_pi_enabled) {
if (fio_qpair->extended_lba) { if (fio_qpair->extended_lba) {
@ -1081,6 +1096,19 @@ spdk_fio_queue(struct thread_data *td, struct io_u *io_u)
} }
} else { } else {
if (!fio_qpair->zone_append_enabled) { if (!fio_qpair->zone_append_enabled) {
#if FIO_HAS_FDP
if (spdk_unlikely(io_u->dtype)) {
ext_opts.io_flags = fio_qpair->io_flags | (io_u->dtype << 20);
ext_opts.metadata = md_buf;
ext_opts.cdw13 = (io_u->dspec << 16);
ext_opts.apptag = dif_ctx->app_tag;
ext_opts.apptag_mask = dif_ctx->apptag_mask;
rc = spdk_nvme_ns_cmd_writev_ext(ns, fio_qpair->qpair, lba, lba_count,
spdk_fio_completion_cb, fio_req,
spdk_nvme_io_reset_sgl, spdk_nvme_io_next_sge, &ext_opts);
break;
}
#endif
rc = spdk_nvme_ns_cmd_writev_with_md(ns, fio_qpair->qpair, lba, rc = spdk_nvme_ns_cmd_writev_with_md(ns, fio_qpair->qpair, lba,
lba_count, spdk_fio_completion_cb, fio_req, fio_qpair->io_flags, lba_count, spdk_fio_completion_cb, fio_req, fio_qpair->io_flags,
spdk_nvme_io_reset_sgl, spdk_nvme_io_next_sge, md_buf, spdk_nvme_io_reset_sgl, spdk_nvme_io_next_sge, md_buf,
@ -1419,6 +1447,58 @@ spdk_fio_get_max_open_zones(struct thread_data *td, struct fio_file *f,
} }
#endif #endif
#if FIO_HAS_FDP
static int
spdk_fio_fdp_fetch_ruhs(struct thread_data *td, struct fio_file *f,
struct fio_ruhs_info *fruhs_info)
{
struct spdk_fio_thread *fio_thread = td->io_ops_data;
struct spdk_fio_qpair *fio_qpair = NULL;
struct spdk_nvme_qpair *tmp_qpair;
struct {
struct spdk_nvme_fdp_ruhs ruhs;
struct spdk_nvme_fdp_ruhs_desc desc[128];
} fdp_ruhs;
uint16_t idx;
int completed = 0, err;
fio_qpair = get_fio_qpair(fio_thread, f);
if (!fio_qpair) {
log_err("spdk/nvme: no ns/qpair or file_name: '%s'\n", f->file_name);
return -ENODEV;
}
/* qpair has not been allocated yet (it gets allocated in spdk_fio_open()).
* Create a temporary qpair in order to perform report zones.
*/
assert(!fio_qpair->qpair);
tmp_qpair = spdk_nvme_ctrlr_alloc_io_qpair(fio_qpair->fio_ctrlr->ctrlr, NULL, 0);
if (!tmp_qpair) {
log_err("spdk/nvme: cannot allocate a temporary qpair\n");
return -EIO;
}
err = spdk_nvme_ns_cmd_io_mgmt_recv(fio_qpair->ns, tmp_qpair, &fdp_ruhs, sizeof(fdp_ruhs),
SPDK_NVME_FDP_IO_MGMT_RECV_RUHS, 0, pcu_cb, &completed);
if (err || pcu(tmp_qpair, &completed) || completed < 0) {
log_err("spdk/nvme: fetch_ruhs(): err: %d, cpl: %d\n", err, completed);
err = err ? err : -EIO;
goto exit;
}
fruhs_info->nr_ruhs = fdp_ruhs.ruhs.nruhsd;
for (idx = 0; idx < fdp_ruhs.ruhs.nruhsd; idx++) {
fruhs_info->plis[idx] = fdp_ruhs.desc[idx].pid;
}
exit:
spdk_nvme_ctrlr_free_io_qpair(tmp_qpair);
return err;
}
#endif
static void static void
spdk_fio_cleanup(struct thread_data *td) spdk_fio_cleanup(struct thread_data *td)
{ {
@ -1722,6 +1802,9 @@ struct ioengine_ops ioengine = {
#endif #endif
#if FIO_IOOPS_VERSION >= 30 #if FIO_IOOPS_VERSION >= 30
.get_max_open_zones = spdk_fio_get_max_open_zones, .get_max_open_zones = spdk_fio_get_max_open_zones,
#endif
#if FIO_HAS_FDP
.fdp_fetch_ruhs = spdk_fio_fdp_fetch_ruhs,
#endif #endif
.flags = FIO_RAWIO | FIO_NOEXTEND | FIO_NODISKUTIL | FIO_MEMALIGN, .flags = FIO_RAWIO | FIO_NOEXTEND | FIO_NODISKUTIL | FIO_MEMALIGN,
.options = options, .options = options,