2022-06-03 19:15:11 +00:00
|
|
|
/* SPDX-License-Identifier: BSD-3-Clause
|
2022-11-01 20:26:26 +00:00
|
|
|
* Copyright (C) 2022 Intel Corporation.
|
2022-03-12 16:06:09 +00:00
|
|
|
* All rights reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "spdk/stdinc.h"
|
|
|
|
|
|
|
|
#include "spdk/nvme.h"
|
|
|
|
#include "spdk/env.h"
|
|
|
|
#include "spdk/string.h"
|
|
|
|
#include "spdk/log.h"
|
|
|
|
|
|
|
|
static struct spdk_nvme_ctrlr *g_ctrlr;
|
|
|
|
static struct spdk_nvme_ns *g_ns;
|
|
|
|
static struct spdk_nvme_qpair *g_qpair;
|
|
|
|
static struct spdk_nvme_transport_id g_trid = {};
|
|
|
|
static uint32_t g_outstanding;
|
|
|
|
|
|
|
|
static void
|
|
|
|
io_complete(void *arg, const struct spdk_nvme_cpl *cpl)
|
|
|
|
{
|
|
|
|
if (spdk_nvme_cpl_is_error(cpl)) {
|
|
|
|
spdk_nvme_print_completion(spdk_nvme_qpair_get_id(g_qpair),
|
|
|
|
(struct spdk_nvme_cpl *)cpl);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_outstanding--;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define WRITE_BLOCKS 128
|
|
|
|
#define FUSED_BLOCKS 1
|
|
|
|
|
|
|
|
static void
|
|
|
|
fused_ordering(uint32_t poll_count)
|
|
|
|
{
|
|
|
|
void *cw_buf, *large_buf;
|
|
|
|
int rc;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
g_qpair = spdk_nvme_ctrlr_alloc_io_qpair(g_ctrlr, NULL, 0);
|
|
|
|
if (g_qpair == NULL) {
|
|
|
|
printf("ERROR: spdk_nvme_ctrlr_alloc_io_qpair() failed\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
cw_buf = spdk_zmalloc(FUSED_BLOCKS * 4096, 0x1000, NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
|
|
|
|
if (cw_buf == NULL) {
|
|
|
|
printf("ERROR: buffer allocation failed\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
large_buf = spdk_zmalloc(WRITE_BLOCKS * 4096, 0x1000, NULL, SPDK_ENV_SOCKET_ID_ANY,
|
|
|
|
SPDK_MALLOC_DMA);
|
|
|
|
if (large_buf == NULL) {
|
|
|
|
printf("ERROR: buffer allocation failed\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Issue a bunch of relatively large writes - big enough that the data will not fit
|
|
|
|
* in-capsule - followed by the compare command. Then poll the completion queue a number of
|
|
|
|
* times matching the poll_count variable. This adds a variable amount of delay between
|
|
|
|
* the compare and the subsequent fused write submission.
|
|
|
|
*
|
|
|
|
* GitHub issue #2428 showed a problem where once the non-in-capsule data had been fetched from
|
|
|
|
* the host, that request could get sent to the target layer between the two fused commands. This
|
|
|
|
* variable delay would eventually induce this condition before the fix.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < 8; i++) {
|
|
|
|
rc = spdk_nvme_ns_cmd_write(g_ns, g_qpair, large_buf, 0, WRITE_BLOCKS, io_complete, NULL, 0);
|
|
|
|
if (rc != 0) {
|
|
|
|
fprintf(stderr, "starting write I/O failed\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
g_outstanding++;
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = spdk_nvme_ns_cmd_compare(g_ns, g_qpair, cw_buf, 0, FUSED_BLOCKS, io_complete, NULL,
|
|
|
|
SPDK_NVME_IO_FLAGS_FUSE_FIRST);
|
|
|
|
if (rc != 0) {
|
|
|
|
fprintf(stderr, "starting compare I/O failed\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
g_outstanding++;
|
|
|
|
while (poll_count--) {
|
|
|
|
spdk_nvme_qpair_process_completions(g_qpair, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
rc = spdk_nvme_ns_cmd_write(g_ns, g_qpair, cw_buf, 0, FUSED_BLOCKS, io_complete, NULL,
|
|
|
|
SPDK_NVME_IO_FLAGS_FUSE_SECOND);
|
|
|
|
if (rc != 0) {
|
|
|
|
fprintf(stderr, "starting write I/O failed\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
g_outstanding++;
|
|
|
|
|
|
|
|
while (g_outstanding) {
|
|
|
|
spdk_nvme_qpair_process_completions(g_qpair, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
spdk_nvme_ctrlr_free_io_qpair(g_qpair);
|
|
|
|
spdk_free(cw_buf);
|
|
|
|
spdk_free(large_buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
usage(const char *program_name)
|
|
|
|
{
|
|
|
|
printf("%s [options]", program_name);
|
|
|
|
printf("\t\n");
|
|
|
|
printf("options:\n");
|
|
|
|
printf("\t[-r remote NVMe over Fabrics target address]\n");
|
|
|
|
#ifdef DEBUG
|
|
|
|
printf("\t[-L enable debug logging]\n");
|
|
|
|
#else
|
2022-09-02 07:32:46 +00:00
|
|
|
printf("\t[-L enable debug logging (flag disabled, must reconfigure with --enable-debug)]\n");
|
2022-03-12 16:06:09 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
parse_args(int argc, char **argv, struct spdk_env_opts *env_opts)
|
|
|
|
{
|
|
|
|
int op, rc;
|
|
|
|
|
|
|
|
while ((op = getopt(argc, argv, "r:L:")) != -1) {
|
|
|
|
switch (op) {
|
|
|
|
case 'r':
|
|
|
|
if (spdk_nvme_transport_id_parse(&g_trid, optarg) != 0) {
|
|
|
|
fprintf(stderr, "Error parsing transport address\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'L':
|
|
|
|
rc = spdk_log_set_flag(optarg);
|
|
|
|
if (rc < 0) {
|
|
|
|
fprintf(stderr, "unknown flag\n");
|
|
|
|
usage(argv[0]);
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
spdk_log_set_print_level(SPDK_LOG_DEBUG);
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
usage(argv[0]);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-06-22 21:35:04 +00:00
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
2022-03-12 16:06:09 +00:00
|
|
|
{
|
|
|
|
int rc, i;
|
|
|
|
struct spdk_env_opts opts;
|
|
|
|
struct spdk_nvme_ctrlr_opts ctrlr_opts;
|
|
|
|
int nsid;
|
|
|
|
|
|
|
|
spdk_env_opts_init(&opts);
|
|
|
|
spdk_log_set_print_level(SPDK_LOG_NOTICE);
|
|
|
|
rc = parse_args(argc, argv, &opts);
|
|
|
|
if (rc != 0) {
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
opts.name = "fused_ordering";
|
|
|
|
if (spdk_env_init(&opts) < 0) {
|
|
|
|
fprintf(stderr, "Unable to initialize SPDK env\n");
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
spdk_nvme_ctrlr_get_default_ctrlr_opts(&ctrlr_opts, sizeof(ctrlr_opts));
|
|
|
|
ctrlr_opts.keep_alive_timeout_ms = 60 * 1000;
|
|
|
|
g_ctrlr = spdk_nvme_connect(&g_trid, &ctrlr_opts, sizeof(ctrlr_opts));
|
|
|
|
if (g_ctrlr == NULL) {
|
|
|
|
fprintf(stderr, "spdk_nvme_connect() failed\n");
|
|
|
|
rc = 1;
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
|
|
|
|
printf("Attached to %s\n", g_trid.subnqn);
|
|
|
|
|
|
|
|
nsid = spdk_nvme_ctrlr_get_first_active_ns(g_ctrlr);
|
|
|
|
if (nsid == 0) {
|
|
|
|
perror("No active namespaces");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
g_ns = spdk_nvme_ctrlr_get_ns(g_ctrlr, nsid);
|
|
|
|
|
|
|
|
printf(" Namespace ID: %d size: %juGB\n", spdk_nvme_ns_get_id(g_ns),
|
|
|
|
spdk_nvme_ns_get_size(g_ns) / 1000000000);
|
|
|
|
|
|
|
|
for (i = 0; i < 1024; i++) {
|
|
|
|
printf("fused_ordering(%d)\n", i);
|
|
|
|
fused_ordering(i);
|
|
|
|
}
|
|
|
|
|
|
|
|
exit:
|
|
|
|
spdk_nvme_detach(g_ctrlr);
|
|
|
|
spdk_env_fini();
|
|
|
|
return rc;
|
|
|
|
}
|