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: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-on: https://review.gerrithub.io/394158
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
This commit is contained in:
Changpeng Liu 2018-01-10 20:25:19 +08:00 committed by Jim Harris
parent f35f395b82
commit 450ee00944

View File

@ -137,6 +137,8 @@ struct perf_task {
uint64_t submit_tsc; uint64_t submit_tsc;
uint16_t appmask; uint16_t appmask;
uint16_t apptag; uint16_t apptag;
uint64_t lba;
bool is_read;
#if HAVE_LIBAIO #if HAVE_LIBAIO
struct iocb iocb; struct iocb iocb;
#endif #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 void io_complete(void *ctx, const struct spdk_nvme_cpl *completion);
static __thread unsigned int seed = 0; 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->submit_tsc = spdk_get_ticks();
task->lba = offset_in_ios * entry->io_size_blocks;
if ((g_rw_percentage == 100) || if ((g_rw_percentage == 100) ||
(g_rw_percentage != 0 && ((rand_r(&seed) % 100) < g_rw_percentage))) { (g_rw_percentage != 0 && ((rand_r(&seed) % 100) < g_rw_percentage))) {
@ -571,12 +641,13 @@ submit_single_io(struct perf_task *task)
} else } else
#endif #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); 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, rc = spdk_nvme_ns_cmd_read_with_md(entry->u.nvme.ns, ns_ctx->u.nvme.qpair,
task->buf, NULL, task->buf, NULL,
offset_in_ios * entry->io_size_blocks, task->lba,
entry->io_size_blocks, io_complete, entry->io_size_blocks, io_complete,
task, entry->io_flags, task, entry->io_flags,
task->appmask, task->apptag); task->appmask, task->apptag);
@ -589,12 +660,12 @@ submit_single_io(struct perf_task *task)
} else } else
#endif #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); entry->io_size_blocks, true);
rc = spdk_nvme_ns_cmd_write_with_md(entry->u.nvme.ns, ns_ctx->u.nvme.qpair, rc = spdk_nvme_ns_cmd_write_with_md(entry->u.nvme.ns, ns_ctx->u.nvme.qpair,
task->buf, NULL, task->buf, NULL,
offset_in_ios * entry->io_size_blocks, task->lba,
entry->io_size_blocks, io_complete, entry->io_size_blocks, io_complete,
task, entry->io_flags, task, entry->io_flags,
task->appmask, task->apptag); task->appmask, task->apptag);
@ -613,8 +684,10 @@ task_complete(struct perf_task *task)
{ {
struct ns_worker_ctx *ns_ctx; struct ns_worker_ctx *ns_ctx;
uint64_t tsc_diff; uint64_t tsc_diff;
struct ns_entry *entry;
ns_ctx = task->ns_ctx; ns_ctx = task->ns_ctx;
entry = ns_ctx->entry;
ns_ctx->current_queue_depth--; ns_ctx->current_queue_depth--;
ns_ctx->io_completed++; ns_ctx->io_completed++;
tsc_diff = spdk_get_ticks() - task->submit_tsc; 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); 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 * is_draining indicates when time has expired for the test run
* and we are just waiting for the previously submitted I/O * and we are just waiting for the previously submitted I/O