Commit 450ee009 authored by Changpeng Liu's avatar Changpeng Liu Committed by Jim Harris
Browse files

examples/perf: add application verification for e2e data protection tests



For end-to-end data protection tests with extended lba format, when
Protection Information Action bit was cleared to 0, the perf
application can do some comparison based on the flags we used
for writes. For the unexptected protection information value, print
a notice for users.

Change-Id: I9851ce6338030f9b57180cd5e46368e0c94bc212
Signed-off-by: default avatarChangpeng Liu <changpeng.liu@intel.com>
Reviewed-on: https://review.gerrithub.io/394158


Reviewed-by: default avatarDaniel Verkamp <daniel.verkamp@intel.com>
Reviewed-by: default avatarJim Harris <james.r.harris@intel.com>
Reviewed-by: default avatarShuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Tested-by: default avatarSPDK Automated Test System <sys_sgsw@intel.com>
parent f35f395b
Loading
Loading
Loading
Loading
+86 −4
Original line number Diff line number Diff line
@@ -137,6 +137,8 @@ struct perf_task {
	uint64_t		submit_tsc;
	uint16_t		appmask;
	uint16_t		apptag;
	uint64_t		lba;
	bool			is_read;
#if HAVE_LIBAIO
	struct iocb		iocb;
#endif
@@ -539,6 +541,72 @@ task_extended_lba_setup_pi(struct ns_entry *entry, struct perf_task *task, uint6
	}
}

static void
task_extended_lba_pi_verify(struct ns_entry *entry, struct perf_task *task,
			    uint64_t lba, uint32_t lba_count)
{
	struct spdk_nvme_protection_info *pi;
	uint32_t i, md_size, sector_size, pi_offset, ref_tag;
	uint16_t crc16, guard, app_tag;
	const struct spdk_nvme_ns_data *nsdata;

	if (spdk_nvme_ns_get_pi_type(entry->u.nvme.ns) ==
	    SPDK_NVME_FMT_NVM_PROTECTION_DISABLE) {
		return;
	}

	sector_size = spdk_nvme_ns_get_sector_size(entry->u.nvme.ns);
	md_size = spdk_nvme_ns_get_md_size(entry->u.nvme.ns);
	nsdata = spdk_nvme_ns_get_data(entry->u.nvme.ns);

	/* PI locates at the first 8 bytes of metadata,
	 * doesn't support now
	 */
	if (nsdata->dps.md_start) {
		return;
	}

	for (i = 0; i < lba_count; i++) {
		pi_offset = ((sector_size + md_size) * (i + 1)) - 8;
		pi = (struct spdk_nvme_protection_info *)(task->buf + pi_offset);

		if (entry->io_flags & SPDK_NVME_IO_FLAGS_PRCHK_GUARD) {
			/* CRC buffer should not include last 8 bytes of PI */
			crc16 = spdk_crc16_t10dif(task->buf + (sector_size + md_size) * i,
						  sector_size + md_size - 8);
			to_be16(&guard, crc16);
			if (pi->guard != guard) {
				fprintf(stdout, "Get Guard Error LBA 0x%16.16"PRIx64","
					" Preferred 0x%04x but returned with 0x%04x,"
					" may read the LBA without write it first\n",
					lba + i, guard, pi->guard);
			}

		}
		if (entry->io_flags & SPDK_NVME_IO_FLAGS_PRCHK_APPTAG) {
			/* Previously we used the number of lbas as
			 * application tag for writes
			 */
			to_be16(&app_tag, lba_count);
			if (pi->app_tag != app_tag) {
				fprintf(stdout, "Get Application Tag Error LBA 0x%16.16"PRIx64","
					" Preferred 0x%04x but returned with 0x%04x,"
					" may read the LBA without write it first\n",
					lba + i, app_tag, pi->app_tag);
			}
		}
		if (entry->io_flags & SPDK_NVME_IO_FLAGS_PRCHK_REFTAG) {
			to_be32(&ref_tag, (uint32_t)lba + i);
			if (pi->ref_tag != ref_tag) {
				fprintf(stdout, "Get Reference Tag Error LBA 0x%16.16"PRIx64","
					" Preferred 0x%08x but returned with 0x%08x,"
					" may read the LBA without write it first\n",
					lba + i, ref_tag, pi->ref_tag);
			}
		}
	}
}

static void io_complete(void *ctx, const struct spdk_nvme_cpl *completion);

static __thread unsigned int seed = 0;
@@ -560,7 +628,9 @@ submit_single_io(struct perf_task *task)
		}
	}

	task->is_read = false;
	task->submit_tsc = spdk_get_ticks();
	task->lba = offset_in_ios * entry->io_size_blocks;

	if ((g_rw_percentage == 100) ||
	    (g_rw_percentage != 0 && ((rand_r(&seed) % 100) < g_rw_percentage))) {
@@ -571,12 +641,13 @@ submit_single_io(struct perf_task *task)
		} else
#endif
		{
			task_extended_lba_setup_pi(entry, task, offset_in_ios * entry->io_size_blocks,
			task_extended_lba_setup_pi(entry, task, task->lba,
						   entry->io_size_blocks, false);
			task->is_read = true;

			rc = spdk_nvme_ns_cmd_read_with_md(entry->u.nvme.ns, ns_ctx->u.nvme.qpair,
							   task->buf, NULL,
							   offset_in_ios * entry->io_size_blocks,
							   task->lba,
							   entry->io_size_blocks, io_complete,
							   task, entry->io_flags,
							   task->appmask, task->apptag);
@@ -589,12 +660,12 @@ submit_single_io(struct perf_task *task)
		} else
#endif
		{
			task_extended_lba_setup_pi(entry, task, offset_in_ios * entry->io_size_blocks,
			task_extended_lba_setup_pi(entry, task, task->lba,
						   entry->io_size_blocks, true);

			rc = spdk_nvme_ns_cmd_write_with_md(entry->u.nvme.ns, ns_ctx->u.nvme.qpair,
							    task->buf, NULL,
							    offset_in_ios * entry->io_size_blocks,
							    task->lba,
							    entry->io_size_blocks, io_complete,
							    task, entry->io_flags,
							    task->appmask, task->apptag);
@@ -613,8 +684,10 @@ task_complete(struct perf_task *task)
{
	struct ns_worker_ctx	*ns_ctx;
	uint64_t		tsc_diff;
	struct ns_entry		*entry;

	ns_ctx = task->ns_ctx;
	entry = ns_ctx->entry;
	ns_ctx->current_queue_depth--;
	ns_ctx->io_completed++;
	tsc_diff = spdk_get_ticks() - task->submit_tsc;
@@ -629,6 +702,15 @@ task_complete(struct perf_task *task)
		spdk_histogram_data_tally(ns_ctx->histogram, tsc_diff);
	}

	/* add application level verification for end-to-end data protection */
	if (entry->type == ENTRY_TYPE_NVME_NS) {
		if (spdk_nvme_ns_supports_extended_lba(entry->u.nvme.ns) &&
		    task->is_read && !g_metacfg_pract_flag) {
			task_extended_lba_pi_verify(entry, task, task->lba,
						    entry->io_size_blocks);
		}
	}

	/*
	 * is_draining indicates when time has expired for the test run
	 * and we are just waiting for the previously submitted I/O