aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnkit Kumar <ankit.kumar@samsung.com>2023-08-14 20:27:44 +0530
committerVincent Fu <vincent.fu@samsung.com>2023-08-14 10:27:33 -0400
commit5163f35e362419c6f2ea23dcb9c48a8044608171 (patch)
treef6b1c21daac84c3e36390f9d6ab0053e8693e5bc
parentea13c4a7ec39ae1c4b9227af61fcb8cc45d93841 (diff)
downloadfio-5163f35e362419c6f2ea23dcb9c48a8044608171.tar.gz
engines:io_uring: generate and verify pi for 16b guard
Generate and verify protection information for 16 bit guard format, for the nvme backend of io_uring_cmd ioengine. The support is there for both the cases where metadata is transferred in separate buffer, or transferred at the end of logical block creating an extended logical block. This support also takes into consideration when protection information resides in last or first 8 bytes of metadata. Signed-off-by: Ankit Kumar <ankit.kumar@samsung.com> Link: https://lore.kernel.org/r/20230814145747.114725-8-ankit.kumar@samsung.com Signed-off-by: Vincent Fu <vincent.fu@samsung.com>
-rw-r--r--engines/io_uring.c34
-rw-r--r--engines/nvme.c173
-rw-r--r--engines/nvme.h12
3 files changed, 219 insertions, 0 deletions
diff --git a/engines/io_uring.c b/engines/io_uring.c
index 376a2a270..7ac7c755b 100644
--- a/engines/io_uring.c
+++ b/engines/io_uring.c
@@ -456,7 +456,9 @@ static struct io_u *fio_ioring_cmd_event(struct thread_data *td, int event)
struct ioring_options *o = td->eo;
struct io_uring_cqe *cqe;
struct io_u *io_u;
+ struct nvme_data *data;
unsigned index;
+ int ret;
index = (event + ld->cq_ring_off) & ld->cq_ring_mask;
if (o->cmd_type == FIO_URING_CMD_NVME)
@@ -470,6 +472,15 @@ static struct io_u *fio_ioring_cmd_event(struct thread_data *td, int event)
else
io_u->error = 0;
+ if (o->cmd_type == FIO_URING_CMD_NVME) {
+ data = FILE_ENG_DATA(io_u->file);
+ if (data->pi_type && (io_u->ddir == DDIR_READ) && !o->pi_act) {
+ ret = fio_nvme_pi_verify(data, io_u);
+ if (ret)
+ io_u->error = ret;
+ }
+ }
+
return io_u;
}
@@ -1190,6 +1201,7 @@ static int fio_ioring_io_u_init(struct thread_data *td, struct io_u *io_u)
{
struct ioring_data *ld = td->io_ops_data;
struct ioring_options *o = td->eo;
+ struct nvme_pi_data *pi_data;
char *p;
ld->io_u_index[io_u->index] = io_u;
@@ -1198,11 +1210,32 @@ static int fio_ioring_io_u_init(struct thread_data *td, struct io_u *io_u)
p = PTR_ALIGN(ld->md_buf, page_mask) + td->o.mem_align;
p += o->md_per_io_size * io_u->index;
io_u->mmap_data = p;
+
+ if (!o->pi_act) {
+ pi_data = calloc(1, sizeof(*pi_data));
+ pi_data->io_flags |= o->prchk;
+ pi_data->apptag_mask = o->apptag_mask;
+ pi_data->apptag = o->apptag;
+ io_u->engine_data = pi_data;
+ }
}
return 0;
}
+static void fio_ioring_io_u_free(struct thread_data *td, struct io_u *io_u)
+{
+ struct ioring_options *o = td->eo;
+ struct nvme_pi *pi;
+
+ if (!strcmp(td->io_ops->name, "io_uring_cmd") &&
+ (o->cmd_type == FIO_URING_CMD_NVME)) {
+ pi = io_u->engine_data;
+ free(pi);
+ io_u->engine_data = NULL;
+ }
+}
+
static int fio_ioring_open_file(struct thread_data *td, struct fio_file *f)
{
struct ioring_data *ld = td->io_ops_data;
@@ -1411,6 +1444,7 @@ static struct ioengine_ops ioengine_uring_cmd = {
.init = fio_ioring_init,
.post_init = fio_ioring_cmd_post_init,
.io_u_init = fio_ioring_io_u_init,
+ .io_u_free = fio_ioring_io_u_free,
.prep = fio_ioring_cmd_prep,
.queue = fio_ioring_queue,
.commit = fio_ioring_commit,
diff --git a/engines/nvme.c b/engines/nvme.c
index 8793d7423..6896dfc06 100644
--- a/engines/nvme.c
+++ b/engines/nvme.c
@@ -4,6 +4,7 @@
*/
#include "nvme.h"
+#include "../crc/crc-t10dif.h"
static inline __u64 get_slba(struct nvme_data *data, struct io_u *io_u)
{
@@ -21,6 +22,158 @@ static inline __u32 get_nlb(struct nvme_data *data, struct io_u *io_u)
return (io_u->xfer_buflen >> data->lba_shift) - 1;
}
+static void fio_nvme_generate_pi_16b_guard(struct nvme_data *data,
+ struct io_u *io_u,
+ struct nvme_cmd_ext_io_opts *opts)
+{
+ struct nvme_pi_data *pi_data = io_u->engine_data;
+ struct nvme_16b_guard_pif *pi;
+ unsigned char *buf = io_u->xfer_buf;
+ unsigned char *md_buf = io_u->mmap_data;
+ __u64 slba = get_slba(data, io_u);
+ __u32 nlb = get_nlb(data, io_u) + 1;
+ __u32 lba_num = 0;
+ __u16 guard = 0;
+
+ if (data->pi_loc) {
+ if (data->lba_ext)
+ pi_data->interval = data->lba_ext - data->ms;
+ else
+ pi_data->interval = 0;
+ } else {
+ if (data->lba_ext)
+ pi_data->interval = data->lba_ext - sizeof(struct nvme_16b_guard_pif);
+ else
+ pi_data->interval = data->ms - sizeof(struct nvme_16b_guard_pif);
+ }
+
+ if (io_u->ddir != DDIR_WRITE)
+ return;
+
+ while (lba_num < nlb) {
+ if (data->lba_ext)
+ pi = (struct nvme_16b_guard_pif *)(buf + pi_data->interval);
+ else
+ pi = (struct nvme_16b_guard_pif *)(md_buf + pi_data->interval);
+
+ if (opts->io_flags & NVME_IO_PRINFO_PRCHK_GUARD) {
+ if (data->lba_ext) {
+ guard = fio_crc_t10dif(0, buf, pi_data->interval);
+ } else {
+ guard = fio_crc_t10dif(0, buf, data->lba_size);
+ guard = fio_crc_t10dif(guard, md_buf, pi_data->interval);
+ }
+ pi->guard = cpu_to_be16(guard);
+ }
+
+ if (opts->io_flags & NVME_IO_PRINFO_PRCHK_APP)
+ pi->apptag = cpu_to_be16(pi_data->apptag);
+
+ if (opts->io_flags & NVME_IO_PRINFO_PRCHK_REF) {
+ switch (data->pi_type) {
+ case NVME_NS_DPS_PI_TYPE1:
+ case NVME_NS_DPS_PI_TYPE2:
+ pi->srtag = cpu_to_be32((__u32)slba + lba_num);
+ break;
+ case NVME_NS_DPS_PI_TYPE3:
+ break;
+ }
+ }
+ if (data->lba_ext) {
+ buf += data->lba_ext;
+ } else {
+ buf += data->lba_size;
+ md_buf += data->ms;
+ }
+ lba_num++;
+ }
+}
+
+static int fio_nvme_verify_pi_16b_guard(struct nvme_data *data,
+ struct io_u *io_u)
+{
+ struct nvme_pi_data *pi_data = io_u->engine_data;
+ struct nvme_16b_guard_pif *pi;
+ struct fio_file *f = io_u->file;
+ unsigned char *buf = io_u->xfer_buf;
+ unsigned char *md_buf = io_u->mmap_data;
+ __u64 slba = get_slba(data, io_u);
+ __u32 nlb = get_nlb(data, io_u) + 1;
+ __u32 lba_num = 0;
+ __u16 unmask_app, unmask_app_exp, guard = 0;
+
+ while (lba_num < nlb) {
+ if (data->lba_ext)
+ pi = (struct nvme_16b_guard_pif *)(buf + pi_data->interval);
+ else
+ pi = (struct nvme_16b_guard_pif *)(md_buf + pi_data->interval);
+
+ if (data->pi_type == NVME_NS_DPS_PI_TYPE3) {
+ if (pi->apptag == NVME_PI_APP_DISABLE &&
+ pi->srtag == NVME_PI_REF_DISABLE)
+ goto next;
+ } else if (data->pi_type == NVME_NS_DPS_PI_TYPE1 ||
+ data->pi_type == NVME_NS_DPS_PI_TYPE2) {
+ if (pi->apptag == NVME_PI_APP_DISABLE)
+ goto next;
+ }
+
+ if (pi_data->io_flags & NVME_IO_PRINFO_PRCHK_GUARD) {
+ if (data->lba_ext) {
+ guard = fio_crc_t10dif(0, buf, pi_data->interval);
+ } else {
+ guard = fio_crc_t10dif(0, buf, data->lba_size);
+ guard = fio_crc_t10dif(guard, md_buf, pi_data->interval);
+ }
+ if (be16_to_cpu(pi->guard) != guard) {
+ log_err("%s: Guard compare error: LBA: %llu Expected=%x, Actual=%x\n",
+ f->file_name, (unsigned long long)slba,
+ guard, be16_to_cpu(pi->guard));
+ return -EIO;
+ }
+ }
+
+ if (pi_data->io_flags & NVME_IO_PRINFO_PRCHK_APP) {
+ unmask_app = be16_to_cpu(pi->apptag) & pi_data->apptag_mask;
+ unmask_app_exp = pi_data->apptag & pi_data->apptag_mask;
+ if (unmask_app != unmask_app_exp) {
+ log_err("%s: APPTAG compare error: LBA: %llu Expected=%x, Actual=%x\n",
+ f->file_name, (unsigned long long)slba,
+ unmask_app_exp, unmask_app);
+ return -EIO;
+ }
+ }
+
+ if (pi_data->io_flags & NVME_IO_PRINFO_PRCHK_REF) {
+ switch (data->pi_type) {
+ case NVME_NS_DPS_PI_TYPE1:
+ case NVME_NS_DPS_PI_TYPE2:
+ if (be32_to_cpu(pi->srtag) !=
+ ((__u32)slba + lba_num)) {
+ log_err("%s: REFTAG compare error: LBA: %llu Expected=%x, Actual=%x\n",
+ f->file_name, (unsigned long long)slba,
+ (__u32)slba + lba_num,
+ be32_to_cpu(pi->srtag));
+ return -EIO;
+ }
+ break;
+ case NVME_NS_DPS_PI_TYPE3:
+ break;
+ }
+ }
+next:
+ if (data->lba_ext) {
+ buf += data->lba_ext;
+ } else {
+ buf += data->lba_size;
+ md_buf += data->ms;
+ }
+ lba_num++;
+ }
+
+ return 0;
+}
+
void fio_nvme_uring_cmd_trim_prep(struct nvme_uring_cmd *cmd, struct io_u *io_u,
struct nvme_dsm_range *dsm)
{
@@ -96,6 +249,11 @@ void fio_nvme_pi_fill(struct nvme_uring_cmd *cmd, struct io_u *io_u,
slba = get_slba(data, io_u);
cmd->cdw12 |= opts->io_flags;
+ if (data->pi_type && !(opts->io_flags & NVME_IO_PRINFO_PRACT)) {
+ if (data->guard_type == NVME_NVM_NS_16B_GUARD)
+ fio_nvme_generate_pi_16b_guard(data, io_u, opts);
+ }
+
switch (data->pi_type) {
case NVME_NS_DPS_PI_TYPE1:
case NVME_NS_DPS_PI_TYPE2:
@@ -120,6 +278,21 @@ void fio_nvme_pi_fill(struct nvme_uring_cmd *cmd, struct io_u *io_u,
}
}
+int fio_nvme_pi_verify(struct nvme_data *data, struct io_u *io_u)
+{
+ int ret = 0;
+
+ switch (data->guard_type) {
+ case NVME_NVM_NS_16B_GUARD:
+ ret = fio_nvme_verify_pi_16b_guard(data, io_u);
+ break;
+ default:
+ break;
+ }
+
+ 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 f35983525..a1102dfe8 100644
--- a/engines/nvme.h
+++ b/engines/nvme.h
@@ -44,6 +44,9 @@ struct nvme_uring_cmd {
#define NVME_IDENTIFY_CSI_SHIFT 24
#define NVME_NQN_LENGTH 256
+#define NVME_PI_APP_DISABLE 0xFFFF
+#define NVME_PI_REF_DISABLE 0xFFFFFFFF
+
#define NVME_ZNS_ZRA_REPORT_ZONES 0
#define NVME_ZNS_ZRAS_FEAT_ERZ (1 << 16)
#define NVME_ZNS_ZSA_RESET 0x4
@@ -131,6 +134,13 @@ enum nvme_io_control_flags {
NVME_IO_PRINFO_PRACT = 1U << 29,
};
+struct nvme_pi_data {
+ __u32 interval;
+ __u32 io_flags;
+ __u16 apptag;
+ __u16 apptag_mask;
+};
+
struct nvme_lbaf {
__le16 ms;
__u8 ds;
@@ -415,6 +425,8 @@ int fio_nvme_uring_cmd_prep(struct nvme_uring_cmd *cmd, struct io_u *io_u,
void fio_nvme_pi_fill(struct nvme_uring_cmd *cmd, struct io_u *io_u,
struct nvme_cmd_ext_io_opts *opts);
+int fio_nvme_pi_verify(struct nvme_data *data, struct io_u *io_u);
+
int fio_nvme_get_zoned_model(struct thread_data *td, struct fio_file *f,
enum zbd_zoned_model *model);