env: Move DPDK intialization into the env library.

Change-Id: Ie3a324f1523ffa0ddb0bd6a24a9a3cd0acbf64b0
Signed-off-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
Ben Walker 2017-01-12 11:25:17 -07:00 committed by Daniel Verkamp
parent 25270f1d7c
commit 18d26e42a3
27 changed files with 480 additions and 550 deletions

View File

@ -372,9 +372,8 @@ This is the main file.
\msc \msc
c_runtime [label="C Runtime"], dpdk [label="DPDK"], nvmf [label="NVMf target"]; c_runtime [label="C Runtime"], nvmf [label="NVMf target"];
c_runtime=>nvmf [label="main()"]; c_runtime=>nvmf [label="main()"];
nvmf=> [label="rte_eal_init()"];
nvmf=>nvmf [label="spdk_app_init()"]; nvmf=>nvmf [label="spdk_app_init()"];
nvmf=>nvmf [label="spdk_event_allocate()"]; nvmf=>nvmf [label="spdk_event_allocate()"];
nvmf=>nvmf [label="spdk_app_start()"]; nvmf=>nvmf [label="spdk_app_start()"];

View File

@ -398,22 +398,12 @@ work_fn(void *arg)
static int static int
init(void) init(void)
{ {
char *core_mask_conf; struct spdk_env_opts opts;
core_mask_conf = spdk_sprintf_alloc("-c %s", g_user_config.core_mask); spdk_env_opts_init(&opts);
if (!core_mask_conf) { opts.name = "perf";
return 1; opts.core_mask = g_user_config.core_mask;
} spdk_env_init(&opts);
char *ealargs[] = {"perf", core_mask_conf, "-n 4"};
if (rte_eal_init(sizeof(ealargs) / sizeof(ealargs[0]), ealargs) < 0) {
free(core_mask_conf);
fprintf(stderr, "Could not init eal\n");
return 1;
}
free(core_mask_conf);
return 0; return 0;
} }

View File

@ -379,21 +379,12 @@ init_src_buffer(void)
static int static int
init(void) init(void)
{ {
char *core_mask_conf; struct spdk_env_opts opts;
core_mask_conf = spdk_sprintf_alloc("-c %s", g_user_config.core_mask); spdk_env_opts_init(&opts);
if (!core_mask_conf) { opts.name = "verify";
return 1; opts.core_mask = g_user_config.core_mask;
} spdk_env_init(&opts);
char *ealargs[] = {"verify", core_mask_conf, "-n 4"};
if (rte_eal_init(sizeof(ealargs) / sizeof(ealargs[0]), ealargs) < 0) {
free(core_mask_conf);
fprintf(stderr, "Could not init eal\n");
return 1;
}
free(core_mask_conf);
if (init_src_buffer() != 0) { if (init_src_buffer() != 0) {
fprintf(stderr, "Could not init src buffer\n"); fprintf(stderr, "Could not init src buffer\n");

View File

@ -133,6 +133,7 @@ static struct arb_context g_arbitration = {
.arbitration_config = 0, .arbitration_config = 0,
.io_size_bytes = 131072, .io_size_bytes = 131072,
.max_completions = 0, .max_completions = 0,
/* Default 4 cores for urgent/high/medium/low */
.core_mask = "0xf", .core_mask = "0xf",
.workload_type = "randrw", .workload_type = "randrw",
}; };
@ -1080,18 +1081,6 @@ set_arb_feature(struct spdk_nvme_ctrlr *ctrlr)
return 0; return 0;
} }
static char *ealargs[] = {
"arb",
"-c 0xf", /* This must be the second parameter. It is overwritten by index in main(). */
"-n 4",
"--proc-type=auto",
#ifdef __linux__
"--base-virtaddr=0x1000000000",
"", /* May be replaced by --file-prefix */
#endif
};
int int
main(int argc, char **argv) main(int argc, char **argv)
{ {
@ -1099,45 +1088,18 @@ main(int argc, char **argv)
struct worker_thread *worker; struct worker_thread *worker;
char task_pool_name[30]; char task_pool_name[30];
uint32_t task_count; uint32_t task_count;
size_t argcount; struct spdk_env_opts opts;
char *core_mask = NULL;
char *file_prefix = NULL;
rc = parse_args(argc, argv); rc = parse_args(argc, argv);
if (rc != 0) { if (rc != 0) {
return rc; return rc;
} }
/* Default 4 cores for (urgent / high / medium / low) 4 kinds of queues respectively */ spdk_env_opts_init(&opts);
ealargs[1] = core_mask = spdk_sprintf_alloc("-c %s", g_arbitration.core_mask); opts.name = "arb";
if (ealargs[1] == NULL) { opts.core_mask = g_arbitration.core_mask;
perror("ealargs spdk_sprintf_alloc"); opts.shm_id = g_arbitration.shm_id;
return 1; spdk_env_init(&opts);
}
argcount = (sizeof(ealargs) / sizeof(ealargs[0])) - 1;
#ifdef __linux__
if (g_arbitration.shm_id >= 0) {
ealargs[5] = file_prefix = spdk_sprintf_alloc("--file-prefix=spdk%d",
g_arbitration.shm_id);
argcount++;
}
#endif
rc = rte_eal_init(argcount, ealargs);
free(core_mask);
if (file_prefix) {
free(file_prefix);
}
if (rc < 0) {
fprintf(stderr, "could not initialize dpdk\n");
return 1;
}
g_arbitration.tsc_rate = spdk_get_ticks_hz(); g_arbitration.tsc_rate = spdk_get_ticks_hz();

View File

@ -37,9 +37,6 @@
#include <assert.h> #include <assert.h>
#include <pthread.h> #include <pthread.h>
#include "rte_config.h"
#include "rte_eal.h"
#include "spdk/nvme.h" #include "spdk/nvme.h"
#include "spdk/env.h" #include "spdk/env.h"
#include "spdk/string.h" #include "spdk/string.h"
@ -175,19 +172,13 @@ attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
} }
} }
static char *ealargs[] = {
"fio",
"-n 4",
"--proc-type=auto",
};
/* Called once at initialization. This is responsible for gathering the size of /* Called once at initialization. This is responsible for gathering the size of
* each "file", which in our case are in the form * each "file", which in our case are in the form
* "05:00.0/0" (PCI bus:device.function/NVMe NSID) */ * "05:00.0/0" (PCI bus:device.function/NVMe NSID) */
static int spdk_fio_setup(struct thread_data *td) static int spdk_fio_setup(struct thread_data *td)
{ {
int rc;
struct spdk_fio_thread *fio_thread; struct spdk_fio_thread *fio_thread;
struct spdk_env_opts opts;
fio_thread = calloc(1, sizeof(*fio_thread)); fio_thread = calloc(1, sizeof(*fio_thread));
assert(fio_thread != NULL); assert(fio_thread != NULL);
@ -198,11 +189,9 @@ static int spdk_fio_setup(struct thread_data *td)
fio_thread->iocq = calloc(td->o.iodepth + 1, sizeof(struct io_u *)); fio_thread->iocq = calloc(td->o.iodepth + 1, sizeof(struct io_u *));
assert(fio_thread->iocq != NULL); assert(fio_thread->iocq != NULL);
rc = rte_eal_init(sizeof(ealargs) / sizeof(ealargs[0]), ealargs); spdk_env_opts_init(&opts);
if (rc < 0) { opts.name = "fio";
fprintf(stderr, "could not initialize dpdk\n"); spdk_env_init(&opts);
return 1;
}
/* Enumerate all of the controllers */ /* Enumerate all of the controllers */
if (spdk_nvme_probe(NULL, td, probe_cb, attach_cb, NULL) != 0) { if (spdk_nvme_probe(NULL, td, probe_cb, attach_cb, NULL) != 0) {

View File

@ -36,9 +36,6 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <rte_config.h>
#include <rte_eal.h>
#include "spdk/nvme.h" #include "spdk/nvme.h"
#include "spdk/env.h" #include "spdk/env.h"
@ -304,32 +301,20 @@ cleanup(void)
} }
} }
static char *ealargs[] = {
"hello_world",
"-c 0x1",
"-n 4",
"--proc-type=auto",
};
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int rc; int rc;
struct spdk_env_opts opts;
/* /*
* By default, the SPDK NVMe driver uses DPDK for huge page-based * SPDK relies on an abstraction around the local environment
* memory management and NVMe request buffer pools. Huge pages can * named env that handles memory allocation and PCI device operations.
* be either 2MB or 1GB in size (instead of 4KB) and are pinned in * This library must be initialized first.
* memory. Pinned memory is important to ensure DMA operations
* never target swapped out memory.
* *
* So first we must initialize DPDK. "-c 0x1" indicates to only use
* core 0.
*/ */
rc = rte_eal_init(sizeof(ealargs) / sizeof(ealargs[0]), ealargs); spdk_env_opts_init(&opts);
if (rc < 0) { opts.name = "hello_world";
fprintf(stderr, "could not initialize dpdk\n"); spdk_env_init(&opts);
return 1;
}
printf("Initializing NVMe Controllers\n"); printf("Initializing NVMe Controllers\n");

View File

@ -81,6 +81,7 @@ static int g_expected_insert_times = -1;
static int g_expected_removal_times = -1; static int g_expected_removal_times = -1;
static int g_insert_times; static int g_insert_times;
static int g_removal_times; static int g_removal_times;
static int g_shm_id = -1;
static void static void
task_complete(struct perf_task *task); task_complete(struct perf_task *task);
@ -376,7 +377,8 @@ static void usage(char *program_name)
{ {
printf("%s options", program_name); printf("%s options", program_name);
printf("\n"); printf("\n");
printf("\t[-i expected hot insert times]\n"); printf("\t[-i shm id (optional)]\n");
printf("\t[-n expected hot insert times]\n");
printf("\t[-r expected hot removal times]\n"); printf("\t[-r expected hot removal times]\n");
printf("\t[-t time in seconds]\n"); printf("\t[-t time in seconds]\n");
} }
@ -389,9 +391,12 @@ parse_args(int argc, char **argv)
/* default value*/ /* default value*/
g_time_in_sec = 0; g_time_in_sec = 0;
while ((op = getopt(argc, argv, "i:r:t:")) != -1) { while ((op = getopt(argc, argv, "i:n:r:t:")) != -1) {
switch (op) { switch (op) {
case 'i': case 'i':
g_shm_id = atoi(optarg);
break;
case 'n':
g_expected_insert_times = atoi(optarg); g_expected_insert_times = atoi(optarg);
break; break;
case 'r': case 'r':
@ -430,26 +435,23 @@ register_controllers(void)
return 0; return 0;
} }
static char *ealargs[] = {
"hotplug",
"-c 0x1",
"-n 4",
};
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int rc; int rc;
struct spdk_env_opts opts;
rc = parse_args(argc, argv); rc = parse_args(argc, argv);
if (rc != 0) { if (rc != 0) {
return rc; return rc;
} }
rc = rte_eal_init(sizeof(ealargs) / sizeof(ealargs[0]), ealargs); spdk_env_opts_init(&opts);
if (rc < 0) { opts.name = "hotplug";
fprintf(stderr, "could not initialize dpdk\n"); opts.core_mask = "0x1";
return 1; if (g_shm_id > -1) {
opts.shm_id = g_shm_id;
} }
spdk_env_init(&opts);
task_pool = rte_mempool_create("task_pool", 8192, task_pool = rte_mempool_create("task_pool", 8192,
sizeof(struct perf_task), sizeof(struct perf_task),

View File

@ -950,31 +950,21 @@ attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
spdk_nvme_detach(ctrlr); spdk_nvme_detach(ctrlr);
} }
static const char *ealargs[] = {
"identify",
"-c 0x1",
"-n 4",
"-m 512",
"--proc-type=auto",
};
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int rc; int rc;
struct spdk_env_opts opts;
spdk_env_opts_init(&opts);
opts.name = "identify";
opts.core_mask = "0x1";
spdk_env_init(&opts);
rc = parse_args(argc, argv); rc = parse_args(argc, argv);
if (rc != 0) { if (rc != 0) {
return rc; return rc;
} }
rc = rte_eal_init(sizeof(ealargs) / sizeof(ealargs[0]),
(char **)(void *)(uintptr_t)ealargs);
if (rc < 0) {
fprintf(stderr, "could not initialize dpdk\n");
exit(1);
}
rc = 0; rc = 0;
if (spdk_nvme_probe(&g_trid, NULL, probe_cb, attach_cb, NULL) != 0) { if (spdk_nvme_probe(&g_trid, NULL, probe_cb, attach_cb, NULL) != 0) {
fprintf(stderr, "spdk_nvme_probe() failed\n"); fprintf(stderr, "spdk_nvme_probe() failed\n");

View File

@ -138,13 +138,6 @@ attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
} }
} }
static const char *ealargs[] = {
"nvme_manage",
"-c 0x1",
"-n 4",
"--proc-type=auto",
};
static void usage(void) static void usage(void)
{ {
printf("NVMe Management Options"); printf("NVMe Management Options");
@ -843,15 +836,13 @@ update_firmware_image(void)
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int rc, i; int i;
struct spdk_env_opts opts;
rc = rte_eal_init(sizeof(ealargs) / sizeof(ealargs[0]), spdk_env_opts_init(&opts);
(char **)(void *)(uintptr_t)ealargs); opts.name = "nvme_manage";
opts.core_mask = "0x1";
if (rc < 0) { spdk_env_init(&opts);
fprintf(stderr, "could not initialize dpdk\n");
exit(1);
}
if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) { if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) {
fprintf(stderr, "spdk_nvme_probe() failed\n"); fprintf(stderr, "spdk_nvme_probe() failed\n");
@ -917,5 +908,5 @@ int main(int argc, char **argv)
spdk_nvme_detach(dev->ctrlr); spdk_nvme_detach(dev->ctrlr);
} }
return rc; return 0;
} }

View File

@ -1193,71 +1193,30 @@ associate_workers_with_ns(void)
return 0; return 0;
} }
static char *ealargs[] = {
"perf",
"-c 0x1", /* This must be the second parameter. It is overwritten by index in main(). */
"-n 4",
"-m 512", /* This can be overwritten by index in main(). */
"--proc-type=auto",
#ifdef __linux__
"--base-virtaddr=0x1000000000",
"", /* May be replaced by --file-prefix */
#endif
};
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int rc; int rc;
struct worker_thread *worker; struct worker_thread *worker;
char task_pool_name[30]; char task_pool_name[30];
uint32_t task_count; uint32_t task_count;
size_t argcount; struct spdk_env_opts opts;
char *core_mask = NULL;
char *mem_size = NULL;
char *file_prefix = NULL;
rc = parse_args(argc, argv); rc = parse_args(argc, argv);
if (rc != 0) { if (rc != 0) {
return rc; return rc;
} }
ealargs[1] = core_mask = spdk_sprintf_alloc("-c %s", g_core_mask ? g_core_mask : "0x1"); spdk_env_opts_init(&opts);
if (ealargs[1] == NULL) { opts.name = "perf";
perror("ealargs spdk_sprintf_alloc"); opts.shm_id = g_shm_id;
return 1; if (g_core_mask) {
opts.core_mask = g_core_mask;
} }
ealargs[3] = mem_size = spdk_sprintf_alloc("-m %d", g_dpdk_mem ? g_dpdk_mem : 512); if (g_dpdk_mem) {
if (ealargs[3] == NULL) { opts.dpdk_mem_size = g_dpdk_mem;
free(ealargs[1]);
perror("ealargs spdk_sprintf_alloc");
return 1;
}
argcount = (sizeof(ealargs) / sizeof(ealargs[0])) - 1;
#ifdef __linux__
if (g_shm_id >= 0) {
ealargs[6] = file_prefix = spdk_sprintf_alloc("--file-prefix=spdk%d",
g_shm_id);
argcount++;
}
#endif
rc = rte_eal_init(argcount, ealargs);
free(core_mask);
free(mem_size);
if (file_prefix) {
free(file_prefix);
}
if (rc < 0) {
fprintf(stderr, "could not initialize dpdk\n");
return 1;
} }
spdk_env_init(&opts);
g_tsc_rate = spdk_get_ticks_hz(); g_tsc_rate = spdk_get_ticks_hz();

View File

@ -380,25 +380,16 @@ attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
dev->ctrlr = ctrlr; dev->ctrlr = ctrlr;
} }
static const char *ealargs[] = {
"reserve",
"-c 0x1",
"-n 4",
"--proc-type=auto",
};
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
struct dev *iter; struct dev *iter;
int rc, i; int rc, i;
struct spdk_env_opts opts;
rc = rte_eal_init(sizeof(ealargs) / sizeof(ealargs[0]), spdk_env_opts_init(&opts);
(char **)(void *)(uintptr_t)ealargs); opts.name = "reserve";
opts.core_mask = "0x1";
if (rc < 0) { spdk_env_init(&opts);
fprintf(stderr, "could not initialize dpdk\n");
exit(1);
}
if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) { if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) {
fprintf(stderr, "spdk_nvme_probe() failed\n"); fprintf(stderr, "spdk_nvme_probe() failed\n");

View File

@ -51,6 +51,29 @@ extern "C" {
struct spdk_pci_device; struct spdk_pci_device;
/**
* \brief Environment initialization options
*/
struct spdk_env_opts {
const char *name;
const char *core_mask;
int shm_id;
int dpdk_mem_channel;
int dpdk_master_core;
int dpdk_mem_size;
};
/**
* \brief Initialize the default value of opts
*/
void spdk_env_opts_init(struct spdk_env_opts *opts);
/**
* \brief Initialize the environment library. This must be called prior to using
* any other functions in this library.
*/
void spdk_env_init(const struct spdk_env_opts *opts);
/** /**
* Allocate a pinned, physically contiguous memory buffer with the * Allocate a pinned, physically contiguous memory buffer with the
* given size and alignment. * given size and alignment.

View File

@ -81,8 +81,8 @@ struct spdk_app_opts {
spdk_sighandler_t usr1_handler; spdk_sighandler_t usr1_handler;
bool enable_coredump; bool enable_coredump;
uint32_t dpdk_mem_channel; int dpdk_mem_channel;
uint32_t dpdk_master_core; int dpdk_master_core;
int dpdk_mem_size; int dpdk_mem_size;
/* The maximum latency allowed when passing an event /* The maximum latency allowed when passing an event
@ -98,11 +98,6 @@ struct spdk_app_opts {
*/ */
void spdk_app_opts_init(struct spdk_app_opts *opts); void spdk_app_opts_init(struct spdk_app_opts *opts);
/**
* \brief Initialize DPDK via opts.
*/
void spdk_dpdk_framework_init(struct spdk_app_opts *opts);
/** /**
* \brief Initialize an application to use the event framework. This must be called prior to using * \brief Initialize an application to use the event framework. This must be called prior to using
* any other functions in this library. * any other functions in this library.

View File

@ -34,8 +34,8 @@
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..) SPDK_ROOT_DIR := $(abspath $(CURDIR)/../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
CFLAGS += $(DPDK_INC) CFLAGS += $(ENV_CFLAGS)
C_SRCS = env.c pci.c vtophys.c C_SRCS = env.c pci.c vtophys.c init.c
C_SRCS += pci_nvme.c pci_ioat.c C_SRCS += pci_nvme.c pci_ioat.c
LIBNAME = env_dpdk LIBNAME = env_dpdk

312
lib/env_dpdk/init.c Normal file
View File

@ -0,0 +1,312 @@
/*-
* BSD LICENSE
*
* Copyright (c) Intel Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "spdk/env.h"
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <rte_config.h>
#include <rte_eal.h>
#define SPDK_ENV_DPDK_DEFAULT_NAME "spdk"
#define SPDK_ENV_DPDK_DEFAULT_SHM_ID -1
#define SPDK_ENV_DPDK_DEFAULT_MEM_SIZE -1
#define SPDK_ENV_DPDK_DEFAULT_MASTER_CORE -1
#define SPDK_ENV_DPDK_DEFAULT_MEM_CHANNEL -1
#define SPDK_ENV_DPDK_DEFAULT_CORE_MASK "0x1"
static char *
_sprintf_alloc(const char *format, ...)
{
va_list args;
va_list args_copy;
char *buf;
size_t bufsize;
int rc;
va_start(args, format);
/* Try with a small buffer first. */
bufsize = 32;
/* Limit maximum buffer size to something reasonable so we don't loop forever. */
while (bufsize <= 1024 * 1024) {
buf = malloc(bufsize);
if (buf == NULL) {
va_end(args);
return NULL;
}
va_copy(args_copy, args);
rc = vsnprintf(buf, bufsize, format, args_copy);
va_end(args_copy);
/*
* If vsnprintf() returned a count within our current buffer size, we are done.
* The count does not include the \0 terminator, so rc == bufsize is not OK.
*/
if (rc >= 0 && (size_t)rc < bufsize) {
va_end(args);
return buf;
}
/*
* vsnprintf() should return the required space, but some libc versions do not
* implement this correctly, so just double the buffer size and try again.
*
* We don't need the data in buf, so rather than realloc(), use free() and malloc()
* again to avoid a copy.
*/
free(buf);
bufsize *= 2;
}
va_end(args);
return NULL;
}
void
spdk_env_opts_init(struct spdk_env_opts *opts)
{
if (!opts) {
return;
}
memset(opts, 0, sizeof(*opts));
opts->name = SPDK_ENV_DPDK_DEFAULT_NAME;
opts->core_mask = SPDK_ENV_DPDK_DEFAULT_CORE_MASK;
opts->shm_id = SPDK_ENV_DPDK_DEFAULT_SHM_ID;
opts->dpdk_mem_size = SPDK_ENV_DPDK_DEFAULT_MEM_SIZE;
opts->dpdk_master_core = SPDK_ENV_DPDK_DEFAULT_MASTER_CORE;
opts->dpdk_mem_channel = SPDK_ENV_DPDK_DEFAULT_MEM_CHANNEL;
}
static void
spdk_free_args(char **args, int argcount)
{
int i;
assert(args != NULL);
for (i = 0; i < argcount; i++) {
assert(args[i] != NULL);
free(args[i]);
}
free(args);
}
static char **
spdk_push_arg(char *args[], int *argcount, char *arg)
{
char **tmp;
if (arg == NULL) {
return NULL;
}
tmp = realloc(args, sizeof(char *) * (*argcount + 1));
if (tmp == NULL) {
spdk_free_args(args, *argcount);
return NULL;
}
tmp[*argcount] = arg;
(*argcount)++;
return tmp;
}
static unsigned long long
spdk_get_coremask(const char *coremask)
{
unsigned long long core_mask, max_coremask = 0;
int num_cores_online;
num_cores_online = sysconf(_SC_NPROCESSORS_ONLN);
if (num_cores_online > 0) {
if (num_cores_online > RTE_MAX_LCORE) {
num_cores_online = RTE_MAX_LCORE;
}
if (num_cores_online >= 64) {
max_coremask = ~0ULL;
} else {
max_coremask = (1ULL << num_cores_online) - 1;
}
}
core_mask = strtoull(coremask, NULL, 16);
core_mask &= max_coremask;
return core_mask;
}
static int
spdk_build_eal_cmdline(const struct spdk_env_opts *opts, char **out[])
{
unsigned long long core_mask;
int argcount = 0;
char **args;
if (out == NULL) {
return -1;
}
*out = NULL;
args = NULL;
/* set the program name */
args = spdk_push_arg(args, &argcount, _sprintf_alloc("%s", opts->name));
if (args == NULL) {
return -1;
}
/* set the coremask */
core_mask = spdk_get_coremask(opts->core_mask);
if (core_mask == 0) {
spdk_free_args(args, argcount);
return -1;
}
args = spdk_push_arg(args, &argcount, _sprintf_alloc("-c %llx", core_mask));
if (args == NULL) {
return -1;
}
/* set the memory channel number */
if (opts->dpdk_mem_channel > 0) {
args = spdk_push_arg(args, &argcount, _sprintf_alloc("-n %d", opts->dpdk_mem_channel));
if (args == NULL) {
return -1;
}
}
/* set the memory size */
if (opts->dpdk_mem_size > 0) {
args = spdk_push_arg(args, &argcount, _sprintf_alloc("-m %d", opts->dpdk_mem_size));
if (args == NULL) {
return -1;
}
}
/* set the master core */
if (opts->dpdk_master_core > 0) {
args = spdk_push_arg(args, &argcount, _sprintf_alloc("--master-lcore=%d",
opts->dpdk_master_core));
if (args == NULL) {
return -1;
}
}
#ifdef __linux__
if (opts->shm_id < 0) {
args = spdk_push_arg(args, &argcount, _sprintf_alloc("--file-prefix=spdk_pid%d",
getpid()));
if (args == NULL) {
return -1;
}
} else {
args = spdk_push_arg(args, &argcount, _sprintf_alloc("--file-prefix=spdk%d",
opts->shm_id));
if (args == NULL) {
return -1;
}
}
/* set the base virtual address */
args = spdk_push_arg(args, &argcount, _sprintf_alloc("--base-virtaddr=0x1000000000"));
if (args == NULL) {
return -1;
}
/* set the process type */
args = spdk_push_arg(args, &argcount, _sprintf_alloc("--proc-type=auto"));
if (args == NULL) {
return -1;
}
#endif
*out = args;
return argcount;
}
void spdk_env_init(const struct spdk_env_opts *opts)
{
char **args = NULL;
char **dpdk_args = NULL;
int argcount, i, rc;
argcount = spdk_build_eal_cmdline(opts, &args);
if (argcount <= 0) {
fprintf(stderr, "Invalid arguments to initialize DPDK\n");
exit(-1);
}
printf("Starting Intel(R) DPDK initialization ... \n");
printf("[ DPDK EAL parameters: ");
for (i = 0; i < argcount; i++) {
printf("%s ", args[i]);
}
printf("]\n");
/* DPDK rearranges the array we pass to it, so make a copy
* before passing so we can still free the individual strings
* correctly.
*/
dpdk_args = calloc(argcount, sizeof(char *));
memcpy(dpdk_args, args, sizeof(char *) * argcount);
fflush(stdout);
rc = rte_eal_init(argcount, dpdk_args);
spdk_free_args(args, argcount);
free(dpdk_args);
if (rc < 0) {
fprintf(stderr, "Failed to initialize DPDK\n");
exit(-1);
}
}

View File

@ -38,7 +38,6 @@
#include <pthread.h> #include <pthread.h>
#include <rte_config.h> #include <rte_config.h>
#include <rte_eal.h>
#include <rte_eal_memconfig.h> #include <rte_eal_memconfig.h>
#include "spdk/env.h" #include "spdk/env.h"

View File

@ -36,7 +36,7 @@ include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
CFLAGS += $(ENV_CFLAGS) CFLAGS += $(ENV_CFLAGS)
LIBNAME = event LIBNAME = event
C_SRCS = app.c dpdk_init.c reactor.c subsystem.c C_SRCS = app.c reactor.c subsystem.c
DIRS-y = rpc DIRS-y = rpc

View File

@ -49,6 +49,7 @@
#include <rte_config.h> #include <rte_config.h>
#include <rte_lcore.h> #include <rte_lcore.h>
#include "spdk/env.h"
#include "spdk/log.h" #include "spdk/log.h"
#include "spdk/conf.h" #include "spdk/conf.h"
#include "spdk/trace.h" #include "spdk/trace.h"
@ -56,9 +57,9 @@
#define SPDK_APP_DEFAULT_LOG_FACILITY "local7" #define SPDK_APP_DEFAULT_LOG_FACILITY "local7"
#define SPDK_APP_DEFAULT_LOG_PRIORITY "info" #define SPDK_APP_DEFAULT_LOG_PRIORITY "info"
#define SPDK_APP_DPDK_DEFAULT_MEM_SIZE 2048 #define SPDK_APP_DPDK_DEFAULT_MEM_SIZE -1
#define SPDK_APP_DPDK_DEFAULT_MASTER_CORE 0 #define SPDK_APP_DPDK_DEFAULT_MASTER_CORE -1
#define SPDK_APP_DPDK_DEFAULT_MEM_CHANNEL 4 #define SPDK_APP_DPDK_DEFAULT_MEM_CHANNEL -1
#define SPDK_APP_DPDK_DEFAULT_CORE_MASK "0x1" #define SPDK_APP_DPDK_DEFAULT_CORE_MASK "0x1"
/* Add enough here to append ".pid" plus 2 digit instance ID */ /* Add enough here to append ".pid" plus 2 digit instance ID */
@ -243,6 +244,7 @@ spdk_app_init(struct spdk_app_opts *opts)
int rc; int rc;
uint64_t tpoint_group_mask; uint64_t tpoint_group_mask;
char *end; char *end;
struct spdk_env_opts env_opts = {};
if (opts->enable_coredump) { if (opts->enable_coredump) {
struct rlimit core_limits; struct rlimit core_limits;
@ -279,6 +281,13 @@ spdk_app_init(struct spdk_app_opts *opts)
opts->shm_id = getpid(); opts->shm_id = getpid();
} }
if (opts->shm_id == -1) {
sp = spdk_conf_find_section(config, "Global");
if (sp != NULL) {
opts->shm_id = spdk_conf_section_get_intval(sp, "MultiprocessGroupID");
}
}
memset(&g_spdk_app, 0, sizeof(g_spdk_app)); memset(&g_spdk_app, 0, sizeof(g_spdk_app));
g_spdk_app.config = config; g_spdk_app.config = config;
g_spdk_app.shm_id = opts->shm_id; g_spdk_app.shm_id = opts->shm_id;
@ -324,7 +333,16 @@ spdk_app_init(struct spdk_app_opts *opts)
} }
} }
spdk_dpdk_framework_init(opts); spdk_env_opts_init(&env_opts);
env_opts.name = opts->name;
env_opts.core_mask = opts->reactor_mask;
env_opts.shm_id = opts->shm_id;
env_opts.dpdk_mem_channel = opts->dpdk_mem_channel;
env_opts.dpdk_master_core = opts->dpdk_master_core;
env_opts.dpdk_mem_size = opts->dpdk_mem_size;
spdk_env_init(&env_opts);
/* /*
* If mask not specified on command line or in configuration file, * If mask not specified on command line or in configuration file,

View File

@ -1,211 +0,0 @@
/*-
* BSD LICENSE
*
* Copyright (c) Intel Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "spdk/event.h"
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <rte_config.h>
#include <rte_per_lcore.h>
#include <rte_eal.h>
#include <rte_launch.h>
#include <rte_common.h>
#include "spdk/string.h"
enum dpdk_eal_args {
EAL_PROGNAME_ARG = 0,
EAL_COREMASK_ARG,
EAL_MEMCHAN_ARG,
EAL_MEMSIZE_ARG,
EAL_MASTER_CORE_ARG,
EAL_FILE_PREFIX_ARG,
EAL_PROC_TYPE_ARG,
EAL_ARG_COUNT
};
/* g_arg_strings contains the original pointers allocated via
* spdk_sprintf_alloc(). These pointers are copied to g_ealargs
* for passing to DPDK rte_eal_init(). Since DPDK may modify the
* pointer values, we use g_arg_strings() to free the strings after
* rte_eal_init() completes.
*/
static char *g_arg_strings[EAL_ARG_COUNT];
static char *g_ealargs[EAL_ARG_COUNT];
static void
spdk_free_ealargs(void)
{
int i;
for (i = 0; i < EAL_ARG_COUNT; i++)
free(g_arg_strings[i]);
}
static unsigned long long
spdk_get_eal_coremask(const char *coremask)
{
unsigned long long core_mask, max_coremask = 0;
int num_cores_online;
num_cores_online = sysconf(_SC_NPROCESSORS_ONLN);
if (num_cores_online > 0) {
if (num_cores_online > RTE_MAX_LCORE) {
num_cores_online = RTE_MAX_LCORE;
}
if (num_cores_online >= 64) {
max_coremask = ~0ULL;
} else {
max_coremask = (1ULL << num_cores_online) - 1;
}
}
core_mask = strtoull(coremask, NULL, 16);
core_mask &= max_coremask;
return core_mask;
}
static void
spdk_build_eal_cmdline(struct spdk_app_opts *opts)
{
unsigned long long core_mask;
/* set the program name */
g_arg_strings[EAL_PROGNAME_ARG] = spdk_sprintf_alloc("%s", opts->name);
if (g_arg_strings[EAL_PROGNAME_ARG] == NULL) {
rte_exit(EXIT_FAILURE, "g_arg_strings spdk_sprintf_alloc");
}
/*set the coremask */
core_mask = spdk_get_eal_coremask(opts->reactor_mask);
g_arg_strings[EAL_COREMASK_ARG] = spdk_sprintf_alloc("-c %llx", core_mask);
if (g_arg_strings[EAL_COREMASK_ARG] == NULL) {
spdk_free_ealargs();
rte_exit(EXIT_FAILURE, "g_arg_strings spdk_sprintf_alloc");
}
/* set the memory channel number */
g_arg_strings[EAL_MEMCHAN_ARG] = spdk_sprintf_alloc("-n %d", opts->dpdk_mem_channel);
if (g_arg_strings[EAL_MEMCHAN_ARG] == NULL) {
spdk_free_ealargs();
rte_exit(EXIT_FAILURE, "g_arg_strings spdk_sprintf_alloc");
}
/* set the memory size */
g_arg_strings[EAL_MEMSIZE_ARG] = spdk_sprintf_alloc("-m %d", opts->dpdk_mem_size);
if (g_arg_strings[EAL_MEMSIZE_ARG] == NULL) {
spdk_free_ealargs();
rte_exit(EXIT_FAILURE, "g_arg_strings spdk_sprintf_alloc");
}
/* set the master core */
g_arg_strings[EAL_MASTER_CORE_ARG] = spdk_sprintf_alloc("--master-lcore=%d",
opts->dpdk_master_core);
if (g_arg_strings[EAL_MASTER_CORE_ARG] == NULL) {
spdk_free_ealargs();
rte_exit(EXIT_FAILURE, "g_arg_strings spdk_sprintf_alloc");
}
#ifdef __linux__
/* set the hugepage file prefix */
g_arg_strings[EAL_FILE_PREFIX_ARG] = spdk_sprintf_alloc("--file-prefix=spdk%d",
opts->shm_id);
#else
/* --file-prefix is not required on FreeBSD */
g_arg_strings[EAL_FILE_PREFIX_ARG] = strdup("");
#endif
if (g_arg_strings[EAL_FILE_PREFIX_ARG] == NULL) {
spdk_free_ealargs();
rte_exit(EXIT_FAILURE, "ealargs spdk_sprintf_alloc");
}
#ifdef __linux__
/* set the process type */
g_arg_strings[EAL_PROC_TYPE_ARG] = spdk_sprintf_alloc("--proc-type=auto");
#else
/* --proc-type is not required on FreeBSD */
/* TODO: to enable the support on FreeBSD once it supports process shared mutex */
g_arg_strings[EAL_PROC_TYPE_ARG] = strdup("");
#endif
if (g_arg_strings[EAL_PROC_TYPE_ARG] == NULL) {
spdk_free_ealargs();
rte_exit(EXIT_FAILURE, "ealargs spdk_sprintf_alloc");
}
memcpy(g_ealargs, g_arg_strings, sizeof(g_arg_strings));
}
static void
spdk_init_dpdk(struct spdk_app_opts *opts)
{
int i, rc;
static bool g_dpdk_initialized = false;
/* to make sure DPDK is only initialized once */
if (g_dpdk_initialized)
rte_exit(EXIT_FAILURE, "DPDK is already initialized\n");
spdk_build_eal_cmdline(opts);
printf("Starting Intel(R) DPDK initialization ... \n");
printf("[ DPDK EAL parameters: ");
for (i = 0; i < EAL_ARG_COUNT; i++) {
printf("%s ", g_ealargs[i]);
}
printf("]\n");
fflush(stdout);
rc = rte_eal_init(EAL_ARG_COUNT, g_ealargs);
spdk_free_ealargs();
if (rc < 0)
rte_exit(EXIT_FAILURE, "Invalid EAL arguments for DPDK\n");
g_dpdk_initialized = true;
printf("done.\n");
}
__attribute__((weak))
void spdk_dpdk_framework_init(struct spdk_app_opts *opts)
{
spdk_init_dpdk(opts);
}

View File

@ -36,17 +36,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <rte_config.h>
#include <rte_eal.h>
#include "spdk/env.h" #include "spdk/env.h"
static const char *ealargs[] = {
"vtophys",
"-c 0x1",
"-n 4",
};
static int static int
vtophys_negative_test(void) vtophys_negative_test(void)
{ {
@ -123,14 +114,12 @@ int
main(int argc, char **argv) main(int argc, char **argv)
{ {
int rc; int rc;
struct spdk_env_opts opts;
rc = rte_eal_init(sizeof(ealargs) / sizeof(ealargs[0]), spdk_env_opts_init(&opts);
(char **)(void *)(uintptr_t)ealargs); opts.name = "vtophys";
opts.core_mask = "0x1";
if (rc < 0) { spdk_env_init(&opts);
fprintf(stderr, "Could not init eal\n");
exit(1);
}
rc = vtophys_negative_test(); rc = vtophys_negative_test();
if (rc < 0) if (rc < 0)

View File

@ -38,7 +38,6 @@
#include <unistd.h> #include <unistd.h>
#include <rte_config.h> #include <rte_config.h>
#include <rte_eal.h>
#include <rte_ring.h> #include <rte_ring.h>
#include <rte_lcore.h> #include <rte_lcore.h>

View File

@ -216,27 +216,19 @@ attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
} }
} }
static const char *ealargs[] = {
"aer",
"-c 0x1",
"-n 4",
};
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
struct dev *dev; struct dev *dev;
int rc, i; int i;
struct spdk_env_opts opts;
spdk_env_opts_init(&opts);
opts.name = "aer";
opts.core_mask = "0x1";
spdk_env_init(&opts);
printf("Asynchronous Event Request test\n"); printf("Asynchronous Event Request test\n");
rc = rte_eal_init(sizeof(ealargs) / sizeof(ealargs[0]),
(char **)(void *)(uintptr_t)ealargs);
if (rc < 0) {
fprintf(stderr, "could not initialize dpdk\n");
exit(1);
}
if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) { if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) {
fprintf(stderr, "spdk_nvme_probe() failed\n"); fprintf(stderr, "spdk_nvme_probe() failed\n");
return 1; return 1;

View File

@ -631,28 +631,19 @@ attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
printf("Attached to %s\n", dev->name); printf("Attached to %s\n", dev->name);
} }
static const char *ealargs[] = {
"nvme_dp",
"-c 0x1",
"-n 4",
};
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
struct dev *iter; struct dev *iter;
int rc, i; int rc, i;
struct spdk_env_opts opts;
spdk_env_opts_init(&opts);
opts.name = "nvme_dp";
opts.core_mask = "0x1";
spdk_env_init(&opts);
printf("NVMe Write/Read with End-to-End data protection test\n"); printf("NVMe Write/Read with End-to-End data protection test\n");
rc = rte_eal_init(sizeof(ealargs) / sizeof(ealargs[0]),
(char **)(void *)(uintptr_t)ealargs);
if (rc < 0) {
fprintf(stderr, "could not initialize dpdk\n");
exit(1);
}
if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) { if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) {
fprintf(stderr, "nvme_probe() failed\n"); fprintf(stderr, "nvme_probe() failed\n");
exit(1); exit(1);

View File

@ -100,7 +100,7 @@ insert_devices
timing_enter hotplug_test timing_enter hotplug_test
ssh_vm "examples/nvme/hotplug/hotplug -t 10 -i 4 -r 8" & ssh_vm "examples/nvme/hotplug/hotplug -i 0 -t 10 -n 4 -r 8" &
example_pid=$! example_pid=$!
sleep 2 sleep 2

View File

@ -570,28 +570,21 @@ register_controllers(void)
return 0; return 0;
} }
static char *ealargs[] = {
"perf",
"-c 0x1",
"-n 4",
};
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int rc; int rc;
struct spdk_env_opts opts;
spdk_env_opts_init(&opts);
opts.name = "overhead";
opts.core_mask = "0x1";
spdk_env_init(&opts);
rc = parse_args(argc, argv); rc = parse_args(argc, argv);
if (rc != 0) { if (rc != 0) {
return rc; return rc;
} }
rc = rte_eal_init(sizeof(ealargs) / sizeof(ealargs[0]), ealargs);
if (rc < 0) {
fprintf(stderr, "could not initialize dpdk\n");
return 1;
}
g_task = spdk_zmalloc(sizeof(struct perf_task), 0, NULL); g_task = spdk_zmalloc(sizeof(struct perf_task), 0, NULL);
if (g_task == NULL) { if (g_task == NULL) {
fprintf(stderr, "g_task alloc failed\n"); fprintf(stderr, "g_task alloc failed\n");

View File

@ -612,29 +612,22 @@ run_nvme_reset_cycle(int retry_count)
return 0; return 0;
} }
static char *ealargs[] = {
"reset",
"-c 0x1",
"-n 4",
};
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
int rc; int rc;
int i; int i;
struct spdk_env_opts opts;
spdk_env_opts_init(&opts);
opts.name = "reset";
opts.core_mask = "0x1";
spdk_env_init(&opts);
rc = parse_args(argc, argv); rc = parse_args(argc, argv);
if (rc != 0) { if (rc != 0) {
return rc; return rc;
} }
rc = rte_eal_init(sizeof(ealargs) / sizeof(ealargs[0]), ealargs);
if (rc < 0) {
fprintf(stderr, "could not initialize dpdk\n");
return 1;
}
task_pool = rte_mempool_create("task_pool", 8192, task_pool = rte_mempool_create("task_pool", 8192,
sizeof(struct reset_task), sizeof(struct reset_task),
64, 0, NULL, NULL, task_ctor, NULL, 64, 0, NULL, NULL, task_ctor, NULL,

View File

@ -37,9 +37,6 @@
#include <inttypes.h> #include <inttypes.h>
#include <string.h> #include <string.h>
#include <rte_config.h>
#include <rte_eal.h>
#include "spdk/nvme.h" #include "spdk/nvme.h"
#include "spdk/env.h" #include "spdk/env.h"
@ -447,28 +444,19 @@ attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
printf("Attached to %s\n", dev->name); printf("Attached to %s\n", dev->name);
} }
static const char *ealargs[] = {
"nvme_sgl",
"-c 0x1",
"-n 4",
};
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
struct dev *iter; struct dev *iter;
int rc, i; int rc, i;
struct spdk_env_opts opts;
spdk_env_opts_init(&opts);
opts.name = "nvme_sgl";
opts.core_mask = "0x1";
spdk_env_init(&opts);
printf("NVMe Readv/Writev Request test\n"); printf("NVMe Readv/Writev Request test\n");
rc = rte_eal_init(sizeof(ealargs) / sizeof(ealargs[0]),
(char **)(void *)(uintptr_t)ealargs);
if (rc < 0) {
fprintf(stderr, "could not initialize dpdk\n");
exit(1);
}
if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) { if (spdk_nvme_probe(NULL, NULL, probe_cb, attach_cb, NULL) != 0) {
fprintf(stderr, "nvme_probe() failed\n"); fprintf(stderr, "nvme_probe() failed\n");
exit(1); exit(1);