Compare commits
34 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
a26adb0d6c | ||
|
a73286870e | ||
|
ad82ba685e | ||
|
e5d26ecc2a | ||
|
658d7df6a7 | ||
|
ba9c5abe86 | ||
|
8a0f9cf3a7 | ||
|
2209decef9 | ||
|
81e12ff27e | ||
|
3c42afe400 | ||
|
034d7cc9d7 | ||
|
807019734e | ||
|
ede2227a7c | ||
|
d3b788e9ab | ||
|
c64c931c52 | ||
|
52d31fe78d | ||
|
3421560144 | ||
|
bfd7d22df5 | ||
|
9c93d81be3 | ||
|
3a3cfb3292 | ||
|
8c6c009fce | ||
|
4e9a9c4a22 | ||
|
fc9ae4f30f | ||
|
ea364da638 | ||
|
0e70cb48ab | ||
|
494848e3a9 | ||
|
623d5cc456 | ||
|
0bcafaea56 | ||
|
b5005497db | ||
|
839af8867e | ||
|
bf602f12ca | ||
|
ad97082bd0 | ||
|
05216cb7bf | ||
|
69b16a000f |
17
CHANGELOG.md
17
CHANGELOG.md
@ -1,6 +1,8 @@
|
||||
# Changelog
|
||||
|
||||
## v20.10: (Upcoming Release)
|
||||
## v20.10.1: (Upcoming Release)
|
||||
|
||||
## v20.10: NVMe-oF multipath, NVMe ZNS, iSCSI login redirection
|
||||
|
||||
### accel
|
||||
|
||||
@ -38,6 +40,19 @@ Removed `spdk_subsystem_config` callback for submodules as part of legacy config
|
||||
Removed `spdk_app_get_running_config` function that printed configuration in legacy format,
|
||||
and removed `usr1_handler` from `struct spdk_app_opts` callback that was used to call it.
|
||||
|
||||
Added SPDK thread scheduler framework which is used to rebalance load among CPU cores.
|
||||
The scheduler implementation is pluggable and two schedulers are added first, `static` scheduler
|
||||
and `gscheduler` scheduler.
|
||||
|
||||
`static` scheduler is used by default and does not reschedule threads and keeps the initial
|
||||
assignments.
|
||||
|
||||
CPU frequency governor framework and implementation are also added.
|
||||
`dpdk_governor` is the first implementation and is based on rte_power library of DPDK.
|
||||
`gscheduler` scheduler utilizes the CPU frequency governor.
|
||||
|
||||
Scheduler and governor frameworks are experimental features.
|
||||
|
||||
### fio
|
||||
|
||||
Bdev fio_plugin no longer supports legacy configuration files. Options `spdk_conf` and
|
||||
|
@ -208,7 +208,7 @@ if [ $SPDK_RUN_FUNCTIONAL_TEST -eq 1 ]; then
|
||||
# enabled, it catches SEGV earlier than our handler which
|
||||
# breaks the hotplug logic.
|
||||
if [ $SPDK_RUN_ASAN -eq 0 ]; then
|
||||
run_test "nvme_hotplug" test/nvme/hotplug.sh intel
|
||||
run_test "nvme_hotplug" test/nvme/hotplug.sh root
|
||||
fi
|
||||
fi
|
||||
|
||||
|
2
dpdk
2
dpdk
@ -1 +1 @@
|
||||
Subproject commit c3fae14048afdb5cc43c2d2a5364631ae7669493
|
||||
Subproject commit 7d8b8e4efe4833631f9a03f18d14e7c642927b8b
|
@ -116,3 +116,33 @@ To your fio-script, also have a look at script-examples provided with fio:
|
||||
|
||||
fio/examples/zbd-seq-read.fio
|
||||
fio/examples/zbd-rand-write.fio
|
||||
|
||||
## Maximum Open Zones
|
||||
|
||||
Zoned Namespaces has a resource constraint on the amount of zones which can be in an opened state at
|
||||
any point in time. You can control how many zones fio will keep in an open state by using the
|
||||
``--max_open_zones`` option.
|
||||
|
||||
The SPDK/NVMe fio io-engine will set a default value if you do not provide one.
|
||||
|
||||
## Maximum Active Zones
|
||||
|
||||
Zoned Namespaces has a resource constraint on the number of zones that can be active at any point in
|
||||
time. Unlike ``max_open_zones``, then fio currently do not manage this constraint, and there is thus
|
||||
no option to limit it either.
|
||||
|
||||
When running with the SPDK/NVMe fio io-engine you can be exposed to error messages, in the form of
|
||||
completion errors, with the NVMe status code of 0xbd ("Too Many Active Zones"). To work around this,
|
||||
then you can reset all zones before fio start running its jobs by using the engine option:
|
||||
|
||||
--initial_zone_reset=1
|
||||
|
||||
## Shared Memory Increase
|
||||
|
||||
If your device has a lot of zones, fio can give you errors such as:
|
||||
|
||||
smalloc: OOM. Consider using --alloc-size to increase the shared memory available.
|
||||
|
||||
This is because fio needs to allocate memory for the zone-report, that is, retrieve the state of
|
||||
zones on the device including auxiliary accounting information. To solve this, then you can follow
|
||||
fio's advice and increase ``--alloc-size``.
|
||||
|
@ -92,6 +92,7 @@ struct spdk_fio_options {
|
||||
int apptag_mask;
|
||||
char *digest_enable;
|
||||
int enable_vmd;
|
||||
int initial_zone_reset;
|
||||
};
|
||||
|
||||
struct spdk_fio_request {
|
||||
@ -254,6 +255,36 @@ get_fio_qpair(struct spdk_fio_thread *fio_thread, struct fio_file *f)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function to use while processing completions until completion-indicator turns non-zero
|
||||
*/
|
||||
static void
|
||||
pcu_cb(void *ctx, const struct spdk_nvme_cpl *cpl)
|
||||
{
|
||||
int *completed = ctx;
|
||||
|
||||
*completed = spdk_nvme_cpl_is_error(cpl) ? -1 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process Completions Until the given 'completed' indicator turns non-zero or an error occurs
|
||||
*/
|
||||
static int32_t
|
||||
pcu(struct spdk_nvme_qpair *qpair, int *completed)
|
||||
{
|
||||
int32_t ret;
|
||||
|
||||
while (!*completed) {
|
||||
ret = spdk_nvme_qpair_process_completions(qpair, 1);
|
||||
if (ret < 0) {
|
||||
log_err("spdk/nvme: process_compl(): ret: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
@ -558,6 +589,34 @@ static int spdk_fio_setup(struct thread_data *td)
|
||||
g_td_count++;
|
||||
pthread_mutex_unlock(&g_mutex);
|
||||
|
||||
if (fio_options->initial_zone_reset == 1) {
|
||||
#if FIO_HAS_ZBD
|
||||
struct spdk_fio_qpair *fio_qpair;
|
||||
|
||||
TAILQ_FOREACH(fio_qpair, &fio_thread->fio_qpair, link) {
|
||||
const struct spdk_nvme_zns_ns_data *zns_data;
|
||||
int completed = 0, err;
|
||||
|
||||
if (!fio_qpair->ns) {
|
||||
continue;
|
||||
}
|
||||
zns_data = spdk_nvme_zns_ns_get_data(fio_qpair->ns);
|
||||
if (!zns_data) {
|
||||
continue;
|
||||
}
|
||||
|
||||
err = spdk_nvme_zns_reset_zone(fio_qpair->ns, fio_qpair->qpair, 0x0, true,
|
||||
pcu_cb, &completed);
|
||||
if (err || pcu(fio_qpair->qpair, &completed) || completed < 0) {
|
||||
log_err("spdk/nvme: warn: initial_zone_reset: err: %d, cpl: %d\n",
|
||||
err, completed);
|
||||
}
|
||||
}
|
||||
#else
|
||||
log_err("spdk/nvme: ZBD/ZNS is not supported\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -1019,6 +1078,7 @@ spdk_fio_get_zoned_model(struct thread_data *td, struct fio_file *f, enum zbd_zo
|
||||
{
|
||||
struct spdk_fio_thread *fio_thread = td->io_ops_data;
|
||||
struct spdk_fio_qpair *fio_qpair = NULL;
|
||||
const struct spdk_nvme_zns_ns_data *zns_data = NULL;
|
||||
|
||||
*model = ZBD_IGNORE;
|
||||
|
||||
@ -1045,48 +1105,43 @@ spdk_fio_get_zoned_model(struct thread_data *td, struct fio_file *f, enum zbd_zo
|
||||
return -ENOSYS;
|
||||
|
||||
case SPDK_NVME_CSI_ZNS:
|
||||
if (!spdk_nvme_zns_ns_get_data(fio_qpair->ns)) {
|
||||
zns_data = spdk_nvme_zns_ns_get_data(fio_qpair->ns);
|
||||
if (!zns_data) {
|
||||
log_err("spdk/nvme: file_name: '%s', ZNS is not enabled\n", f->file_name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
*model = ZBD_HOST_MANAGED;
|
||||
|
||||
/** Unlimited open resources, skip checking 'max_open_zones' */
|
||||
if (0xFFFFFFFF == zns_data->mor) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!td->o.max_open_zones) {
|
||||
td->o.max_open_zones = spdk_min(ZBD_MAX_OPEN_ZONES, zns_data->mor + 1);
|
||||
log_info("spdk/nvme: parameter 'max_open_zones' was unset; assigned: %d.\n",
|
||||
td->o.max_open_zones);
|
||||
} else if (td->o.max_open_zones < 0) {
|
||||
log_err("spdk/nvme: invalid parameter 'max_open_zones': %d\n",
|
||||
td->o.max_open_zones);
|
||||
return -EINVAL;
|
||||
} else if (td->o.max_open_zones > ZBD_MAX_OPEN_ZONES) {
|
||||
log_err("spdk/nvme: parameter 'max_open_zones': %d exceeds fio-limit: %d\n",
|
||||
td->o.max_open_zones, ZBD_MAX_OPEN_ZONES);
|
||||
return -EINVAL;
|
||||
} else if ((uint32_t)td->o.max_open_zones > (zns_data->mor + 1)) {
|
||||
log_err("spdk/nvme: parameter 'max_open_zones': %d exceeds dev-limit: %u\n",
|
||||
td->o.max_open_zones, zns_data->mor + 1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function to use while processing completions until completion-indicator turns non-zero
|
||||
*/
|
||||
static void
|
||||
pcu_cb(void *ctx, const struct spdk_nvme_cpl *cpl)
|
||||
{
|
||||
int *completed = ctx;
|
||||
|
||||
*completed = spdk_nvme_cpl_is_error(cpl) ? -1 : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process Completions Until the given 'completed' indicator turns non-zero or an error occurs
|
||||
*/
|
||||
static int32_t
|
||||
pcu(struct spdk_nvme_qpair *qpair, int *completed)
|
||||
{
|
||||
int32_t ret;
|
||||
|
||||
while (!*completed) {
|
||||
ret = spdk_nvme_qpair_process_completions(qpair, 1);
|
||||
if (ret < 0) {
|
||||
log_err("spdk/nvme: process_compl(): ret: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint64_t
|
||||
spdk_fio_qpair_mdts_nbytes(struct spdk_fio_qpair *fio_qpair)
|
||||
{
|
||||
@ -1139,13 +1194,14 @@ spdk_fio_report_zones(struct thread_data *td, struct fio_file *f, uint64_t offse
|
||||
}
|
||||
|
||||
err = spdk_nvme_zns_report_zones(fio_qpair->ns, fio_qpair->qpair, report, report_nbytes,
|
||||
offset / lba_nbytes, SPDK_NVME_ZRA_LIST_ALL, false, pcu_cb,
|
||||
offset / lba_nbytes, SPDK_NVME_ZRA_LIST_ALL, true, pcu_cb,
|
||||
&completed);
|
||||
if (err || pcu(fio_qpair->qpair, &completed) || completed < 0) {
|
||||
log_err("spdk/nvme: report_zones(): err: %d, cpl: %d\n", err, completed);
|
||||
err = err ? err : -EIO;
|
||||
goto exit;
|
||||
}
|
||||
assert(report->nr_zones <= report_nzones_max);
|
||||
report_nzones = report->nr_zones;
|
||||
|
||||
for (uint64_t idx = 0; idx < report->nr_zones; ++idx) {
|
||||
@ -1162,7 +1218,7 @@ spdk_fio_report_zones(struct thread_data *td, struct fio_file *f, uint64_t offse
|
||||
break;
|
||||
|
||||
default:
|
||||
log_err("%s: invalid zone-type: 0x%x\n", f->file_name, zdesc->zt);
|
||||
log_err("spdk/nvme: %s: inv. zone-type: 0x%x\n", f->file_name, zdesc->zt);
|
||||
err = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
@ -1191,7 +1247,7 @@ spdk_fio_report_zones(struct thread_data *td, struct fio_file *f, uint64_t offse
|
||||
break;
|
||||
|
||||
default:
|
||||
log_err("%s: invalid zone-state: 0x%x\n", f->file_name, zdesc->zs);
|
||||
log_err("spdk/nvme: %s: inv. zone-state: 0x%x\n", f->file_name, zdesc->zs);
|
||||
err = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
@ -1210,7 +1266,6 @@ spdk_fio_reset_wp(struct thread_data *td, struct fio_file *f, uint64_t offset, u
|
||||
struct spdk_fio_qpair *fio_qpair = NULL;
|
||||
const struct spdk_nvme_zns_ns_data *zns = NULL;
|
||||
uint64_t zsze_nbytes, lba_nbytes;
|
||||
int completed = 0;
|
||||
int err = 0;
|
||||
|
||||
fio_qpair = get_fio_qpair(fio_thread, f);
|
||||
@ -1226,11 +1281,19 @@ spdk_fio_reset_wp(struct thread_data *td, struct fio_file *f, uint64_t offset, u
|
||||
zsze_nbytes = spdk_nvme_zns_ns_get_zone_size(fio_qpair->ns);
|
||||
lba_nbytes = spdk_nvme_ns_get_sector_size(fio_qpair->ns);
|
||||
|
||||
/** check the assumption that offset is valid zone-start lba */
|
||||
if (offset % zsze_nbytes) {
|
||||
log_err("spdk/nvme: offset: %zu is not a valid zslba\n", offset);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (uint64_t cur = offset; cur < offset + length; cur += zsze_nbytes) {
|
||||
err = spdk_nvme_zns_reset_zone(fio_qpair->ns, fio_qpair->qpair, offset / lba_nbytes,
|
||||
int completed = 0;
|
||||
|
||||
err = spdk_nvme_zns_reset_zone(fio_qpair->ns, fio_qpair->qpair, cur / lba_nbytes,
|
||||
false, pcu_cb, &completed);
|
||||
if (err || pcu(fio_qpair->qpair, &completed) || completed < 0) {
|
||||
log_err("spdk/nvme: report_zones(): err: %d, cpl: %d\n", err, completed);
|
||||
log_err("spdk/nvme: zns_reset_zone(): err: %d, cpl: %d\n", err, completed);
|
||||
err = err ? err : -EIO;
|
||||
break;
|
||||
}
|
||||
@ -1476,6 +1539,16 @@ static struct fio_option options[] = {
|
||||
.category = FIO_OPT_C_ENGINE,
|
||||
.group = FIO_OPT_G_INVALID,
|
||||
},
|
||||
{
|
||||
.name = "initial_zone_reset",
|
||||
.lname = "Reset Zones on initialization",
|
||||
.type = FIO_OPT_INT,
|
||||
.off1 = offsetof(struct spdk_fio_options, initial_zone_reset),
|
||||
.def = "0",
|
||||
.help = "Reset Zones on initialization (0=disable, 1=Reset All Zones)",
|
||||
.category = FIO_OPT_C_ENGINE,
|
||||
.group = FIO_OPT_G_INVALID,
|
||||
},
|
||||
{
|
||||
.name = NULL,
|
||||
},
|
||||
|
@ -775,11 +775,50 @@ print_zns_zone_report(void)
|
||||
g_zone_report = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
print_zns_ns_data(const struct spdk_nvme_zns_ns_data *nsdata_zns)
|
||||
{
|
||||
printf("ZNS Specific Namespace Data\n");
|
||||
printf("===========================\n");
|
||||
printf("Variable Zone Capacity: %s\n",
|
||||
nsdata_zns->zoc.variable_zone_capacity ? "Yes" : "No");
|
||||
printf("Zone Active Excursions: %s\n",
|
||||
nsdata_zns->zoc.zone_active_excursions ? "Yes" : "No");
|
||||
printf("Read Across Zone Boundaries: %s\n",
|
||||
nsdata_zns->ozcs.read_across_zone_boundaries ? "Yes" : "No");
|
||||
if (nsdata_zns->mar == 0xffffffff) {
|
||||
printf("Max Active Resources: No Limit\n");
|
||||
} else {
|
||||
printf("Max Active Resources: %"PRIu32"\n",
|
||||
nsdata_zns->mar + 1);
|
||||
}
|
||||
if (nsdata_zns->mor == 0xffffffff) {
|
||||
printf("Max Open Resources: No Limit\n");
|
||||
} else {
|
||||
printf("Max Open Resources: %"PRIu32"\n",
|
||||
nsdata_zns->mor + 1);
|
||||
}
|
||||
if (nsdata_zns->rrl == 0) {
|
||||
printf("Reset Recommended Limit: Not Reported\n");
|
||||
} else {
|
||||
printf("Reset Recommended Limit: %"PRIu32"\n",
|
||||
nsdata_zns->rrl);
|
||||
}
|
||||
if (nsdata_zns->frl == 0) {
|
||||
printf("Finish Recommended Limit: Not Reported\n");
|
||||
} else {
|
||||
printf("Finish Recommended Limit: %"PRIu32"\n",
|
||||
nsdata_zns->frl);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void
|
||||
print_namespace(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns)
|
||||
{
|
||||
const struct spdk_nvme_ctrlr_data *cdata;
|
||||
const struct spdk_nvme_ns_data *nsdata;
|
||||
const struct spdk_nvme_zns_ns_data *nsdata_zns;
|
||||
const struct spdk_uuid *uuid;
|
||||
uint32_t i;
|
||||
uint32_t flags;
|
||||
@ -788,6 +827,7 @@ print_namespace(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns)
|
||||
|
||||
cdata = spdk_nvme_ctrlr_get_data(ctrlr);
|
||||
nsdata = spdk_nvme_ns_get_data(ns);
|
||||
nsdata_zns = spdk_nvme_zns_ns_get_data(ns);
|
||||
flags = spdk_nvme_ns_get_flags(ns);
|
||||
|
||||
printf("Namespace ID:%d\n", spdk_nvme_ns_get_id(ns));
|
||||
@ -888,9 +928,15 @@ print_namespace(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns)
|
||||
printf("Number of LBA Formats: %d\n", nsdata->nlbaf + 1);
|
||||
printf("Current LBA Format: LBA Format #%02d\n",
|
||||
nsdata->flbas.format);
|
||||
for (i = 0; i <= nsdata->nlbaf; i++)
|
||||
for (i = 0; i <= nsdata->nlbaf; i++) {
|
||||
printf("LBA Format #%02d: Data Size: %5d Metadata Size: %5d\n",
|
||||
i, 1 << nsdata->lbaf[i].lbads, nsdata->lbaf[i].ms);
|
||||
if (spdk_nvme_ns_get_csi(ns) == SPDK_NVME_CSI_ZNS) {
|
||||
printf("LBA Format Extension #%02d: Zone Size (in LBAs): 0x%"PRIx64" Zone Descriptor Extension Size: %d bytes\n",
|
||||
i, nsdata_zns->lbafe[i].zsze, nsdata_zns->lbafe[i].zdes << 6);
|
||||
}
|
||||
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if (spdk_nvme_ctrlr_is_ocssd_supported(ctrlr)) {
|
||||
@ -904,6 +950,7 @@ print_namespace(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns)
|
||||
printf("ERROR: spdk_nvme_ctrlr_alloc_io_qpair() failed\n");
|
||||
exit(1);
|
||||
}
|
||||
print_zns_ns_data(nsdata_zns);
|
||||
get_zns_zone_report(ns, qpair);
|
||||
print_zns_zone_report();
|
||||
spdk_nvme_ctrlr_free_io_qpair(qpair);
|
||||
@ -1754,6 +1801,15 @@ print_controller(struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_transport
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (spdk_nvme_zns_ctrlr_get_data(ctrlr)) {
|
||||
printf("ZNS Specific Controller Data\n");
|
||||
printf("============================\n");
|
||||
printf("Zone Append Size Limit: %u\n",
|
||||
spdk_nvme_zns_ctrlr_get_data(ctrlr)->zasl);
|
||||
printf("\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
printf("Active Namespaces\n");
|
||||
printf("=================\n");
|
||||
for (nsid = spdk_nvme_ctrlr_get_first_active_ns(ctrlr);
|
||||
|
@ -1412,8 +1412,8 @@ static void usage(char *program_name)
|
||||
printf("\t");
|
||||
spdk_log_usage(stdout, "-T");
|
||||
printf("\t[-V enable VMD enumeration]\n");
|
||||
printf("\t[-z disable zero copy send for the given sock implementation]\n");
|
||||
printf("\t[-Z enable zero copy send for the given sock implementation. Default for posix impl]\n");
|
||||
printf("\t[-z disable zero copy send for the given sock implementation. Default for posix impl]\n");
|
||||
printf("\t[-Z enable zero copy send for the given sock implementation]\n");
|
||||
printf("\t[-A IO buffer alignment. Must be power of 2 and not less than cache line (%u)]\n",
|
||||
SPDK_CACHE_LINE_SIZE);
|
||||
printf("\t[-S set the default sock impl, e.g. \"posix\"]\n");
|
||||
|
@ -89,7 +89,7 @@ typedef void (*spdk_sighandler_t)(int signal);
|
||||
*/
|
||||
struct spdk_app_opts {
|
||||
const char *name;
|
||||
const char *config_file;
|
||||
const char *config_file; /* deprecated */
|
||||
const char *json_config_file;
|
||||
bool json_config_ignore_errors;
|
||||
const char *rpc_addr; /* Can be UNIX domain socket path or IP address + TCP port */
|
||||
|
@ -773,9 +773,16 @@ struct spdk_nvme_probe_ctx *spdk_nvme_probe_async(const struct spdk_nvme_transpo
|
||||
spdk_nvme_remove_cb remove_cb);
|
||||
|
||||
/**
|
||||
* Start controllers in the context list.
|
||||
* Proceed with attaching contollers associated with the probe context.
|
||||
*
|
||||
* Users may call the function util it returns True.
|
||||
* The probe context is one returned from a previous call to
|
||||
* spdk_nvme_probe_async(). Users must call this function on the
|
||||
* probe context until it returns 0.
|
||||
*
|
||||
* If any controllers fail to attach, there is no explicit notification.
|
||||
* Users can detect attachment failure by comparing attach_cb invocations
|
||||
* with the number of times where the user returned true for the
|
||||
* probe_cb.
|
||||
*
|
||||
* \param probe_ctx Context used to track probe actions.
|
||||
*
|
||||
@ -783,7 +790,6 @@ struct spdk_nvme_probe_ctx *spdk_nvme_probe_async(const struct spdk_nvme_transpo
|
||||
* is also freed and no longer valid.
|
||||
* \return -EAGAIN if there are still pending probe operations; user must call
|
||||
* spdk_nvme_probe_poll_async again to continue progress.
|
||||
* \return value other than 0 and -EAGAIN probe error with one controller.
|
||||
*/
|
||||
int spdk_nvme_probe_poll_async(struct spdk_nvme_probe_ctx *probe_ctx);
|
||||
|
||||
|
@ -54,7 +54,7 @@
|
||||
* Patch level is incremented on maintenance branch releases and reset to 0 for each
|
||||
* new major.minor release.
|
||||
*/
|
||||
#define SPDK_VERSION_PATCH 0
|
||||
#define SPDK_VERSION_PATCH 1
|
||||
|
||||
/**
|
||||
* Version string suffix.
|
||||
|
@ -43,7 +43,7 @@
|
||||
#define SPDK_NVME_TCP_DIGEST_ALIGNMENT 4
|
||||
#define SPDK_NVME_TCP_QPAIR_EXIT_TIMEOUT 30
|
||||
#define SPDK_NVMF_TCP_RECV_BUF_SIZE_FACTOR 8
|
||||
|
||||
#define SPDK_NVME_TCP_IN_CAPSULE_DATA_MAX_SIZE 8192u
|
||||
/*
|
||||
* Maximum number of SGL elements.
|
||||
*/
|
||||
|
@ -114,6 +114,9 @@ endif
|
||||
|
||||
ifeq ($(LINK_HASH),y)
|
||||
DPDK_LIB_LIST += rte_hash
|
||||
ifneq (, $(wildcard $(DPDK_ABS_DIR)/lib/librte_rcu.*))
|
||||
DPDK_LIB_LIST += rte_rcu
|
||||
endif
|
||||
endif
|
||||
|
||||
DPDK_SHARED_LIB = $(DPDK_LIB_LIST:%=$(DPDK_ABS_DIR)/lib/lib%.so)
|
||||
|
@ -60,7 +60,6 @@
|
||||
|
||||
struct spdk_vfio_dma_map {
|
||||
struct vfio_iommu_type1_dma_map map;
|
||||
struct vfio_iommu_type1_dma_unmap unmap;
|
||||
TAILQ_ENTRY(spdk_vfio_dma_map) tailq;
|
||||
};
|
||||
|
||||
@ -820,11 +819,6 @@ vtophys_iommu_map_dma(uint64_t vaddr, uint64_t iova, uint64_t size)
|
||||
dma_map->map.iova = iova;
|
||||
dma_map->map.size = size;
|
||||
|
||||
dma_map->unmap.argsz = sizeof(dma_map->unmap);
|
||||
dma_map->unmap.flags = 0;
|
||||
dma_map->unmap.iova = iova;
|
||||
dma_map->unmap.size = size;
|
||||
|
||||
pthread_mutex_lock(&g_vfio.mutex);
|
||||
if (g_vfio.device_ref == 0) {
|
||||
/* VFIO requires at least one device (IOMMU group) to be added to
|
||||
@ -865,6 +859,7 @@ vtophys_iommu_unmap_dma(uint64_t iova, uint64_t size)
|
||||
struct spdk_vfio_dma_map *dma_map;
|
||||
uint64_t refcount;
|
||||
int ret;
|
||||
struct vfio_iommu_type1_dma_unmap unmap = {};
|
||||
|
||||
pthread_mutex_lock(&g_vfio.mutex);
|
||||
TAILQ_FOREACH(dma_map, &g_vfio.maps, tailq) {
|
||||
@ -899,8 +894,11 @@ vtophys_iommu_unmap_dma(uint64_t iova, uint64_t size)
|
||||
goto out_remove;
|
||||
}
|
||||
|
||||
|
||||
ret = ioctl(g_vfio.fd, VFIO_IOMMU_UNMAP_DMA, &dma_map->unmap);
|
||||
unmap.argsz = sizeof(unmap);
|
||||
unmap.flags = 0;
|
||||
unmap.iova = dma_map->map.iova;
|
||||
unmap.size = dma_map->map.size;
|
||||
ret = ioctl(g_vfio.fd, VFIO_IOMMU_UNMAP_DMA, &unmap);
|
||||
if (ret) {
|
||||
DEBUG_PRINT("Cannot clear DMA mapping, error %d\n", errno);
|
||||
pthread_mutex_unlock(&g_vfio.mutex);
|
||||
@ -1383,7 +1381,12 @@ vtophys_pci_device_removed(struct rte_pci_device *pci_device)
|
||||
* of other, external factors.
|
||||
*/
|
||||
TAILQ_FOREACH(dma_map, &g_vfio.maps, tailq) {
|
||||
ret = ioctl(g_vfio.fd, VFIO_IOMMU_UNMAP_DMA, &dma_map->unmap);
|
||||
struct vfio_iommu_type1_dma_unmap unmap = {};
|
||||
unmap.argsz = sizeof(unmap);
|
||||
unmap.flags = 0;
|
||||
unmap.iova = dma_map->map.iova;
|
||||
unmap.size = dma_map->map.size;
|
||||
ret = ioctl(g_vfio.fd, VFIO_IOMMU_UNMAP_DMA, &unmap);
|
||||
if (ret) {
|
||||
DEBUG_PRINT("Cannot unmap DMA memory, error %d\n", errno);
|
||||
break;
|
||||
|
@ -40,6 +40,13 @@
|
||||
|
||||
#define SYSFS_PCI_DRIVERS "/sys/bus/pci/drivers"
|
||||
|
||||
/* Compatibility for versions < 20.11 */
|
||||
#if RTE_VERSION < RTE_VERSION_NUM(20, 11, 0, 0)
|
||||
#define RTE_DEV_ALLOWED RTE_DEV_WHITELISTED
|
||||
#define RTE_DEV_BLOCKED RTE_DEV_BLACKLISTED
|
||||
#define RTE_BUS_SCAN_ALLOWLIST RTE_BUS_SCAN_WHITELIST
|
||||
#endif
|
||||
|
||||
#define PCI_CFG_SIZE 256
|
||||
#define PCI_EXT_CAP_ID_SN 0x03
|
||||
|
||||
@ -340,7 +347,7 @@ _pci_env_init(void)
|
||||
{
|
||||
/* We assume devices were present on the bus for more than 2 seconds
|
||||
* before initializing SPDK and there's no need to wait more. We scan
|
||||
* the bus, but we don't blacklist any devices.
|
||||
* the bus, but we don't block any devices.
|
||||
*/
|
||||
scan_pci_bus(false);
|
||||
|
||||
@ -459,7 +466,7 @@ pci_device_fini(struct rte_pci_device *_dev)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* remove our whitelist_at option */
|
||||
/* remove our allowed_at option */
|
||||
if (_dev->device.devargs) {
|
||||
_dev->device.devargs->data = NULL;
|
||||
}
|
||||
@ -518,7 +525,7 @@ scan_pci_bus(bool delay_init)
|
||||
if (!da) {
|
||||
char devargs_str[128];
|
||||
|
||||
/* the device was never blacklisted or whitelisted */
|
||||
/* the device was never blocked or allowed */
|
||||
da = calloc(1, sizeof(*da));
|
||||
if (!da) {
|
||||
return -1;
|
||||
@ -535,21 +542,21 @@ scan_pci_bus(bool delay_init)
|
||||
}
|
||||
|
||||
if (da->data) {
|
||||
uint64_t whitelist_at = (uint64_t)(uintptr_t)da->data;
|
||||
uint64_t allowed_at = (uint64_t)(uintptr_t)da->data;
|
||||
|
||||
/* this device was seen by spdk before... */
|
||||
if (da->policy == RTE_DEV_BLACKLISTED && whitelist_at <= now) {
|
||||
da->policy = RTE_DEV_WHITELISTED;
|
||||
if (da->policy == RTE_DEV_BLOCKED && allowed_at <= now) {
|
||||
da->policy = RTE_DEV_ALLOWED;
|
||||
}
|
||||
} else if ((driver->driver.bus->bus.conf.scan_mode == RTE_BUS_SCAN_WHITELIST &&
|
||||
da->policy == RTE_DEV_WHITELISTED) || da->policy != RTE_DEV_BLACKLISTED) {
|
||||
/* override the policy only if not permanently blacklisted */
|
||||
} else if ((driver->driver.bus->bus.conf.scan_mode == RTE_BUS_SCAN_ALLOWLIST &&
|
||||
da->policy == RTE_DEV_ALLOWED) || da->policy != RTE_DEV_BLOCKED) {
|
||||
/* override the policy only if not permanently blocked */
|
||||
|
||||
if (delay_init) {
|
||||
da->policy = RTE_DEV_BLACKLISTED;
|
||||
da->policy = RTE_DEV_BLOCKED;
|
||||
da->data = (void *)(now + 2 * spdk_get_ticks_hz());
|
||||
} else {
|
||||
da->policy = RTE_DEV_WHITELISTED;
|
||||
da->policy = RTE_DEV_ALLOWED;
|
||||
da->data = (void *)(uintptr_t)now;
|
||||
}
|
||||
}
|
||||
@ -619,7 +626,7 @@ spdk_pci_device_attach(struct spdk_pci_driver *driver,
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* explicit attach ignores the whitelist, so if we blacklisted this
|
||||
/* explicit attach ignores the allowlist, so if we blocked this
|
||||
* device before let's enable it now - just for clarity.
|
||||
*/
|
||||
TAILQ_FOREACH(dev, &g_pci_devices, internal.tailq) {
|
||||
@ -633,7 +640,7 @@ spdk_pci_device_attach(struct spdk_pci_driver *driver,
|
||||
da = rte_dev->device.devargs;
|
||||
if (da && da->data) {
|
||||
da->data = (void *)(uintptr_t)spdk_get_ticks();
|
||||
da->policy = RTE_DEV_WHITELISTED;
|
||||
da->policy = RTE_DEV_ALLOWED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -401,6 +401,18 @@ spdk_app_start(struct spdk_app_opts *opts, spdk_msg_fn start_fn,
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (opts->config_file) {
|
||||
SPDK_ERRLOG("opts->config_file is deprecated. Use opts->json_config_file instead.\n");
|
||||
/* For now we will just treat config_file as json_config_file. But if both were
|
||||
* specified we will return an error here.
|
||||
*/
|
||||
if (opts->json_config_file) {
|
||||
SPDK_ERRLOG("Setting both opts->config_file and opts->json_config_file not allowed.\n");
|
||||
return 1;
|
||||
}
|
||||
opts->json_config_file = opts->config_file;
|
||||
}
|
||||
|
||||
if (!start_fn) {
|
||||
SPDK_ERRLOG("start_fn should not be NULL\n");
|
||||
return 1;
|
||||
@ -640,8 +652,6 @@ spdk_app_parse_args(int argc, char **argv, struct spdk_app_opts *opts,
|
||||
while ((ch = getopt_long(argc, argv, cmdline_short_opts, cmdline_options, &opt_idx)) != -1) {
|
||||
switch (ch) {
|
||||
case CONFIG_FILE_OPT_IDX:
|
||||
opts->config_file = optarg;
|
||||
break;
|
||||
case JSON_CONFIG_OPT_IDX:
|
||||
opts->json_config_file = optarg;
|
||||
break;
|
||||
@ -823,16 +833,6 @@ spdk_app_parse_args(int argc, char **argv, struct spdk_app_opts *opts,
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->config_file) {
|
||||
if (opts->json_config_file) {
|
||||
SPDK_ERRLOG("ERROR: --config and --json options can't be used together.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
opts->json_config_file = opts->config_file;
|
||||
opts->config_file = NULL;
|
||||
}
|
||||
|
||||
if (opts->json_config_file && opts->delay_subsystem_init) {
|
||||
SPDK_ERRLOG("JSON configuration file can't be used together with --wait-for-rpc.\n");
|
||||
goto out;
|
||||
|
@ -517,6 +517,18 @@ _reactors_scheduler_fini(void *arg1, void *arg2)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_reactors_scheduler_cancel(void *arg1, void *arg2)
|
||||
{
|
||||
struct spdk_reactor *reactor;
|
||||
uint32_t i;
|
||||
|
||||
SPDK_ENV_FOREACH_CORE(i) {
|
||||
reactor = spdk_reactor_get(i);
|
||||
reactor->flags.is_scheduling = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Phase 1 of thread scheduling is to gather metrics on the existing threads */
|
||||
static void
|
||||
_reactors_scheduler_gather_metrics(void *arg1, void *arg2)
|
||||
@ -551,6 +563,14 @@ _reactors_scheduler_gather_metrics(void *arg1, void *arg2)
|
||||
|
||||
if (core_info->threads_count > 0) {
|
||||
core_info->threads = calloc(core_info->threads_count, sizeof(struct spdk_lw_thread *));
|
||||
if (core_info->threads == NULL) {
|
||||
SPDK_ERRLOG("Failed to allocate memory when gathering metrics on %u\n", reactor->lcore);
|
||||
|
||||
/* Cancel this round of schedule work */
|
||||
evt = spdk_event_allocate(g_scheduling_reactor->lcore, _reactors_scheduler_cancel, NULL, NULL);
|
||||
spdk_event_call(evt);
|
||||
return;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
TAILQ_FOREACH(lw_thread, &reactor->threads, link) {
|
||||
|
@ -314,6 +314,14 @@ nvme_wait_for_completion_robust_lock_timeout(
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
if (qpair->ctrlr->trid.trtype == SPDK_NVME_TRANSPORT_PCIE) {
|
||||
union spdk_nvme_csts_register csts = spdk_nvme_ctrlr_get_regs_csts(qpair->ctrlr);
|
||||
if (csts.raw == SPDK_NVME_INVALID_REGISTER_VALUE) {
|
||||
status->cpl.status.sct = SPDK_NVME_SCT_GENERIC;
|
||||
status->cpl.status.sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status->done == false) {
|
||||
@ -688,11 +696,11 @@ nvme_ctrlr_probe(const struct spdk_nvme_transport_id *trid,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
static void
|
||||
nvme_ctrlr_poll_internal(struct spdk_nvme_ctrlr *ctrlr,
|
||||
struct spdk_nvme_probe_ctx *probe_ctx)
|
||||
{
|
||||
int rc = 0;
|
||||
int rc = 0;
|
||||
|
||||
rc = nvme_ctrlr_process_init(ctrlr);
|
||||
|
||||
@ -704,11 +712,11 @@ nvme_ctrlr_poll_internal(struct spdk_nvme_ctrlr *ctrlr,
|
||||
nvme_ctrlr_fail(ctrlr, false);
|
||||
nvme_robust_mutex_unlock(&ctrlr->ctrlr_lock);
|
||||
nvme_ctrlr_destruct(ctrlr);
|
||||
return rc;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctrlr->state != NVME_CTRLR_STATE_READY) {
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
STAILQ_INIT(&ctrlr->io_producers);
|
||||
@ -735,10 +743,7 @@ nvme_ctrlr_poll_internal(struct spdk_nvme_ctrlr *ctrlr,
|
||||
|
||||
if (probe_ctx->attach_cb) {
|
||||
probe_ctx->attach_cb(probe_ctx->cb_ctx, &ctrlr->trid, ctrlr, &ctrlr->opts);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1545,7 +1550,6 @@ spdk_nvme_probe_async(const struct spdk_nvme_transport_id *trid,
|
||||
int
|
||||
spdk_nvme_probe_poll_async(struct spdk_nvme_probe_ctx *probe_ctx)
|
||||
{
|
||||
int rc = 0;
|
||||
struct spdk_nvme_ctrlr *ctrlr, *ctrlr_tmp;
|
||||
|
||||
if (!spdk_process_is_primary() && probe_ctx->trid.trtype == SPDK_NVME_TRANSPORT_PCIE) {
|
||||
@ -1554,19 +1558,15 @@ spdk_nvme_probe_poll_async(struct spdk_nvme_probe_ctx *probe_ctx)
|
||||
}
|
||||
|
||||
TAILQ_FOREACH_SAFE(ctrlr, &probe_ctx->init_ctrlrs, tailq, ctrlr_tmp) {
|
||||
rc = nvme_ctrlr_poll_internal(ctrlr, probe_ctx);
|
||||
if (rc != 0) {
|
||||
rc = -EIO;
|
||||
break;
|
||||
}
|
||||
nvme_ctrlr_poll_internal(ctrlr, probe_ctx);
|
||||
}
|
||||
|
||||
if (rc != 0 || TAILQ_EMPTY(&probe_ctx->init_ctrlrs)) {
|
||||
if (TAILQ_EMPTY(&probe_ctx->init_ctrlrs)) {
|
||||
nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
|
||||
g_spdk_nvme_driver->initialized = true;
|
||||
nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
|
||||
free(probe_ctx);
|
||||
return rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EAGAIN;
|
||||
|
@ -3445,7 +3445,7 @@ union spdk_nvme_csts_register spdk_nvme_ctrlr_get_regs_csts(struct spdk_nvme_ctr
|
||||
union spdk_nvme_csts_register csts;
|
||||
|
||||
if (nvme_ctrlr_get_csts(ctrlr, &csts)) {
|
||||
csts.raw = 0xFFFFFFFFu;
|
||||
csts.raw = SPDK_NVME_INVALID_REGISTER_VALUE;
|
||||
}
|
||||
return csts;
|
||||
}
|
||||
|
@ -191,6 +191,9 @@ extern pid_t g_spdk_nvme_pid;
|
||||
#define NVME_FABRIC_CONNECT_COMMAND_TIMEOUT 500000
|
||||
#endif
|
||||
|
||||
/* This value indicates that a read from a PCIe register is invalid. This can happen when a device is no longer present */
|
||||
#define SPDK_NVME_INVALID_REGISTER_VALUE 0xFFFFFFFFu
|
||||
|
||||
enum nvme_payload_type {
|
||||
NVME_PAYLOAD_TYPE_INVALID = 0,
|
||||
|
||||
|
@ -667,7 +667,7 @@ nvme_qpair_resubmit_requests(struct spdk_nvme_qpair *qpair, uint32_t num_request
|
||||
STAILQ_REMOVE_HEAD(&qpair->queued_req, stailq);
|
||||
resubmit_rc = nvme_qpair_resubmit_request(qpair, req);
|
||||
if (spdk_unlikely(resubmit_rc != 0)) {
|
||||
SPDK_ERRLOG("Unable to resubmit as many requests as we completed.\n");
|
||||
SPDK_DEBUGLOG(nvme, "Unable to resubmit as many requests as we completed.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,6 @@
|
||||
#define NVME_TCP_HPDA_DEFAULT 0
|
||||
#define NVME_TCP_MAX_R2T_DEFAULT 1
|
||||
#define NVME_TCP_PDU_H2C_MIN_DATA_SIZE 4096
|
||||
#define NVME_TCP_IN_CAPSULE_DATA_MAX_SIZE 8192
|
||||
|
||||
/* NVMe TCP transport extensions for spdk_nvme_ctrlr */
|
||||
struct nvme_tcp_ctrlr {
|
||||
@ -518,7 +517,7 @@ nvme_tcp_req_init(struct nvme_tcp_qpair *tqpair, struct nvme_request *req,
|
||||
if (xfer == SPDK_NVME_DATA_HOST_TO_CONTROLLER) {
|
||||
max_incapsule_data_size = ctrlr->ioccsz_bytes;
|
||||
if ((req->cmd.opc == SPDK_NVME_OPC_FABRIC) || nvme_qpair_is_admin_queue(&tqpair->qpair)) {
|
||||
max_incapsule_data_size = NVME_TCP_IN_CAPSULE_DATA_MAX_SIZE;
|
||||
max_incapsule_data_size = SPDK_NVME_TCP_IN_CAPSULE_DATA_MAX_SIZE;
|
||||
}
|
||||
|
||||
if (req->payload_size <= max_incapsule_data_size) {
|
||||
@ -990,13 +989,13 @@ nvme_tcp_send_icreq_complete(void *cb_arg)
|
||||
{
|
||||
struct nvme_tcp_qpair *tqpair = cb_arg;
|
||||
|
||||
SPDK_DEBUGLOG(nvme, "Complete the icreq send for tqpair=%p\n", tqpair);
|
||||
SPDK_DEBUGLOG(nvme, "Complete the icreq send for tqpair=%p %u\n", tqpair, tqpair->qpair.id);
|
||||
|
||||
tqpair->flags.icreq_send_ack = true;
|
||||
|
||||
if (tqpair->state == NVME_TCP_QPAIR_STATE_INITIALIZING) {
|
||||
SPDK_DEBUGLOG(nvme, "qpair %u, finilize icresp\n", tqpair->qpair.id);
|
||||
nvme_tcp_icresp_handle(tqpair, &tqpair->recv_pdu);
|
||||
SPDK_DEBUGLOG(nvme, "tqpair %p %u, finilize icresp\n", tqpair, tqpair->qpair.id);
|
||||
tqpair->state = NVME_TCP_QPAIR_STATE_RUNNING;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1009,12 +1008,6 @@ nvme_tcp_icresp_handle(struct nvme_tcp_qpair *tqpair,
|
||||
enum spdk_nvme_tcp_term_req_fes fes;
|
||||
int recv_buf_size;
|
||||
|
||||
if (!tqpair->flags.icreq_send_ack) {
|
||||
tqpair->state = NVME_TCP_QPAIR_STATE_INITIALIZING;
|
||||
SPDK_DEBUGLOG(nvme, "qpair %u, waiting icreq ack\n", tqpair->qpair.id);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Only PFV 0 is defined currently */
|
||||
if (ic_resp->pfv != 0) {
|
||||
SPDK_ERRLOG("Expected ICResp PFV %u, got %u\n", 0u, ic_resp->pfv);
|
||||
@ -1065,8 +1058,15 @@ nvme_tcp_icresp_handle(struct nvme_tcp_qpair *tqpair,
|
||||
/* Not fatal. */
|
||||
}
|
||||
|
||||
tqpair->state = NVME_TCP_QPAIR_STATE_RUNNING;
|
||||
nvme_tcp_qpair_set_recv_state(tqpair, NVME_TCP_PDU_RECV_STATE_AWAIT_PDU_READY);
|
||||
|
||||
if (!tqpair->flags.icreq_send_ack) {
|
||||
tqpair->state = NVME_TCP_QPAIR_STATE_INITIALIZING;
|
||||
SPDK_DEBUGLOG(nvme, "tqpair %p %u, waiting icreq ack\n", tqpair, tqpair->qpair.id);
|
||||
return;
|
||||
}
|
||||
|
||||
tqpair->state = NVME_TCP_QPAIR_STATE_RUNNING;
|
||||
return;
|
||||
end:
|
||||
nvme_tcp_qpair_send_h2c_term_req(tqpair, pdu, fes, error_offset);
|
||||
|
@ -814,6 +814,10 @@ nvmf_ctrlr_cc_shn_done(struct spdk_io_channel_iter *i, int status)
|
||||
|
||||
/* After CC.EN transitions to 0 (due to shutdown or reset), the association
|
||||
* between the host and controller shall be preserved for at least 2 minutes */
|
||||
if (ctrlr->association_timer) {
|
||||
SPDK_DEBUGLOG(nvmf, "Association timer already set\n");
|
||||
nvmf_ctrlr_stop_association_timer(ctrlr);
|
||||
}
|
||||
ctrlr->association_timer = SPDK_POLLER_REGISTER(nvmf_ctrlr_association_remove, ctrlr,
|
||||
ctrlr->admin_qpair->transport->opts.association_timeout * 1000);
|
||||
}
|
||||
@ -834,6 +838,10 @@ nvmf_ctrlr_cc_reset_done(struct spdk_io_channel_iter *i, int status)
|
||||
|
||||
/* After CC.EN transitions to 0 (due to shutdown or reset), the association
|
||||
* between the host and controller shall be preserved for at least 2 minutes */
|
||||
if (ctrlr->association_timer) {
|
||||
SPDK_DEBUGLOG(nvmf, "Association timer already set\n");
|
||||
nvmf_ctrlr_stop_association_timer(ctrlr);
|
||||
}
|
||||
ctrlr->association_timer = SPDK_POLLER_REGISTER(nvmf_ctrlr_association_remove, ctrlr,
|
||||
ctrlr->admin_qpair->transport->opts.association_timeout * 1000);
|
||||
}
|
||||
|
140
lib/nvmf/tcp.c
140
lib/nvmf/tcp.c
@ -37,14 +37,14 @@
|
||||
#include "spdk/assert.h"
|
||||
#include "spdk/thread.h"
|
||||
#include "spdk/nvmf_transport.h"
|
||||
#include "spdk/sock.h"
|
||||
#include "spdk/string.h"
|
||||
#include "spdk/trace.h"
|
||||
#include "spdk/util.h"
|
||||
#include "spdk/log.h"
|
||||
|
||||
#include "spdk_internal/assert.h"
|
||||
#include "spdk/log.h"
|
||||
#include "spdk_internal/nvme_tcp.h"
|
||||
#include "spdk_internal/sock.h"
|
||||
|
||||
#include "nvmf_internal.h"
|
||||
|
||||
@ -254,12 +254,23 @@ struct spdk_nvmf_tcp_qpair {
|
||||
TAILQ_ENTRY(spdk_nvmf_tcp_qpair) link;
|
||||
};
|
||||
|
||||
struct spdk_nvmf_tcp_control_msg {
|
||||
STAILQ_ENTRY(spdk_nvmf_tcp_control_msg) link;
|
||||
};
|
||||
|
||||
struct spdk_nvmf_tcp_control_msg_list {
|
||||
void *msg_buf;
|
||||
STAILQ_HEAD(, spdk_nvmf_tcp_control_msg) free_msgs;
|
||||
};
|
||||
|
||||
struct spdk_nvmf_tcp_poll_group {
|
||||
struct spdk_nvmf_transport_poll_group group;
|
||||
struct spdk_sock_group *sock_group;
|
||||
|
||||
TAILQ_HEAD(, spdk_nvmf_tcp_qpair) qpairs;
|
||||
TAILQ_HEAD(, spdk_nvmf_tcp_qpair) await_req;
|
||||
|
||||
struct spdk_nvmf_tcp_control_msg_list *control_msg_list;
|
||||
};
|
||||
|
||||
struct spdk_nvmf_tcp_port {
|
||||
@ -295,6 +306,7 @@ static const struct spdk_json_object_decoder tcp_transport_opts_decoder[] = {
|
||||
|
||||
static bool nvmf_tcp_req_process(struct spdk_nvmf_tcp_transport *ttransport,
|
||||
struct spdk_nvmf_tcp_req *tcp_req);
|
||||
static void nvmf_tcp_poll_group_destroy(struct spdk_nvmf_transport_poll_group *group);
|
||||
|
||||
static void
|
||||
nvmf_tcp_req_set_state(struct spdk_nvmf_tcp_req *tcp_req,
|
||||
@ -1001,6 +1013,49 @@ nvmf_tcp_discover(struct spdk_nvmf_transport *transport,
|
||||
entry->tsas.tcp.sectype = SPDK_NVME_TCP_SECURITY_NONE;
|
||||
}
|
||||
|
||||
static struct spdk_nvmf_tcp_control_msg_list *
|
||||
nvmf_tcp_control_msg_list_create(uint16_t num_messages)
|
||||
{
|
||||
struct spdk_nvmf_tcp_control_msg_list *list;
|
||||
struct spdk_nvmf_tcp_control_msg *msg;
|
||||
uint16_t i;
|
||||
|
||||
list = calloc(1, sizeof(*list));
|
||||
if (!list) {
|
||||
SPDK_ERRLOG("Failed to allocate memory for list structure\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list->msg_buf = spdk_zmalloc(num_messages * SPDK_NVME_TCP_IN_CAPSULE_DATA_MAX_SIZE,
|
||||
NVMF_DATA_BUFFER_ALIGNMENT, NULL, SPDK_ENV_SOCKET_ID_ANY, SPDK_MALLOC_DMA);
|
||||
if (!list->msg_buf) {
|
||||
SPDK_ERRLOG("Failed to allocate memory for control message buffers\n");
|
||||
free(list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
STAILQ_INIT(&list->free_msgs);
|
||||
|
||||
for (i = 0; i < num_messages; i++) {
|
||||
msg = (struct spdk_nvmf_tcp_control_msg *)((char *)list->msg_buf + i *
|
||||
SPDK_NVME_TCP_IN_CAPSULE_DATA_MAX_SIZE);
|
||||
STAILQ_INSERT_TAIL(&list->free_msgs, msg, link);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static void
|
||||
nvmf_tcp_control_msg_list_free(struct spdk_nvmf_tcp_control_msg_list *list)
|
||||
{
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
|
||||
spdk_free(list->msg_buf);
|
||||
free(list);
|
||||
}
|
||||
|
||||
static struct spdk_nvmf_transport_poll_group *
|
||||
nvmf_tcp_poll_group_create(struct spdk_nvmf_transport *transport)
|
||||
{
|
||||
@ -1019,10 +1074,20 @@ nvmf_tcp_poll_group_create(struct spdk_nvmf_transport *transport)
|
||||
TAILQ_INIT(&tgroup->qpairs);
|
||||
TAILQ_INIT(&tgroup->await_req);
|
||||
|
||||
if (transport->opts.in_capsule_data_size < SPDK_NVME_TCP_IN_CAPSULE_DATA_MAX_SIZE) {
|
||||
SPDK_DEBUGLOG(nvmf_tcp, "ICD %u is less than min required for admin/fabric commands (%u). "
|
||||
"Creating control messages list\n", transport->opts.in_capsule_data_size,
|
||||
SPDK_NVME_TCP_IN_CAPSULE_DATA_MAX_SIZE);
|
||||
tgroup->control_msg_list = nvmf_tcp_control_msg_list_create(32);
|
||||
if (!tgroup->control_msg_list) {
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
return &tgroup->group;
|
||||
|
||||
cleanup:
|
||||
free(tgroup);
|
||||
nvmf_tcp_poll_group_destroy(&tgroup->group);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1049,6 +1114,9 @@ nvmf_tcp_poll_group_destroy(struct spdk_nvmf_transport_poll_group *group)
|
||||
|
||||
tgroup = SPDK_CONTAINEROF(group, struct spdk_nvmf_tcp_poll_group, group);
|
||||
spdk_sock_group_close(&tgroup->sock_group);
|
||||
if (tgroup->control_msg_list) {
|
||||
nvmf_tcp_control_msg_list_free(tgroup->control_msg_list);
|
||||
}
|
||||
|
||||
free(tgroup);
|
||||
}
|
||||
@ -1556,6 +1624,7 @@ nvmf_tcp_icreq_handle(struct spdk_nvmf_tcp_transport *ttransport,
|
||||
tqpair->recv_buf_size -= SPDK_NVME_TCP_DIGEST_LEN * SPDK_NVMF_TCP_RECV_BUF_SIZE_FACTOR;
|
||||
}
|
||||
|
||||
tqpair->recv_buf_size = spdk_max(tqpair->recv_buf_size, MIN_SOCK_PIPE_SIZE);
|
||||
/* Now that we know whether digests are enabled, properly size the receive buffer */
|
||||
if (spdk_sock_set_recvbuf(tqpair->sock, tqpair->recv_buf_size) < 0) {
|
||||
SPDK_WARNLOG("Unable to allocate enough memory for receive buffer on tqpair=%p with size=%d\n",
|
||||
@ -1867,6 +1936,31 @@ nvmf_tcp_sock_process(struct spdk_nvmf_tcp_qpair *tqpair)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static inline void *
|
||||
nvmf_tcp_control_msg_get(struct spdk_nvmf_tcp_control_msg_list *list)
|
||||
{
|
||||
struct spdk_nvmf_tcp_control_msg *msg;
|
||||
|
||||
assert(list);
|
||||
|
||||
msg = STAILQ_FIRST(&list->free_msgs);
|
||||
if (!msg) {
|
||||
SPDK_DEBUGLOG(nvmf_tcp, "Out of control messages\n");
|
||||
return NULL;
|
||||
}
|
||||
STAILQ_REMOVE_HEAD(&list->free_msgs, link);
|
||||
return msg;
|
||||
}
|
||||
|
||||
static inline void
|
||||
nvmf_tcp_control_msg_put(struct spdk_nvmf_tcp_control_msg_list *list, void *_msg)
|
||||
{
|
||||
struct spdk_nvmf_tcp_control_msg *msg = _msg;
|
||||
|
||||
assert(list);
|
||||
STAILQ_INSERT_HEAD(&list->free_msgs, msg, link);
|
||||
}
|
||||
|
||||
static int
|
||||
nvmf_tcp_req_parse_sgl(struct spdk_nvmf_tcp_req *tcp_req,
|
||||
struct spdk_nvmf_transport *transport,
|
||||
@ -1876,6 +1970,7 @@ nvmf_tcp_req_parse_sgl(struct spdk_nvmf_tcp_req *tcp_req,
|
||||
struct spdk_nvme_cmd *cmd;
|
||||
struct spdk_nvme_cpl *rsp;
|
||||
struct spdk_nvme_sgl_descriptor *sgl;
|
||||
struct spdk_nvmf_tcp_poll_group *tgroup;
|
||||
uint32_t length;
|
||||
|
||||
cmd = &req->cmd->nvme_cmd;
|
||||
@ -1922,6 +2017,7 @@ nvmf_tcp_req_parse_sgl(struct spdk_nvmf_tcp_req *tcp_req,
|
||||
sgl->unkeyed.subtype == SPDK_NVME_SGL_SUBTYPE_OFFSET) {
|
||||
uint64_t offset = sgl->address;
|
||||
uint32_t max_len = transport->opts.in_capsule_data_size;
|
||||
assert(tcp_req->has_incapsule_data);
|
||||
|
||||
SPDK_DEBUGLOG(nvmf_tcp, "In-capsule data: offset 0x%" PRIx64 ", length 0x%x\n",
|
||||
offset, length);
|
||||
@ -1934,16 +2030,33 @@ nvmf_tcp_req_parse_sgl(struct spdk_nvmf_tcp_req *tcp_req,
|
||||
}
|
||||
max_len -= (uint32_t)offset;
|
||||
|
||||
if (length > max_len) {
|
||||
SPDK_ERRLOG("In-capsule data length 0x%x exceeds capsule length 0x%x\n",
|
||||
length, max_len);
|
||||
rsp->status.sc = SPDK_NVME_SC_DATA_SGL_LENGTH_INVALID;
|
||||
return -1;
|
||||
if (spdk_unlikely(length > max_len)) {
|
||||
/* According to the SPEC we should support ICD up to 8192 bytes for admin and fabric commands */
|
||||
if (length <= SPDK_NVME_TCP_IN_CAPSULE_DATA_MAX_SIZE &&
|
||||
(cmd->opc == SPDK_NVME_OPC_FABRIC || req->qpair->qid == 0)) {
|
||||
|
||||
/* Get a buffer from dedicated list */
|
||||
SPDK_DEBUGLOG(nvmf_tcp, "Getting a buffer from control msg list\n");
|
||||
tgroup = SPDK_CONTAINEROF(group, struct spdk_nvmf_tcp_poll_group, group);
|
||||
assert(tgroup->control_msg_list);
|
||||
req->data = nvmf_tcp_control_msg_get(tgroup->control_msg_list);
|
||||
if (!req->data) {
|
||||
/* No available buffers. Queue this request up. */
|
||||
SPDK_DEBUGLOG(nvmf_tcp, "No available ICD buffers. Queueing request %p\n", tcp_req);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
SPDK_ERRLOG("In-capsule data length 0x%x exceeds capsule length 0x%x\n",
|
||||
length, max_len);
|
||||
rsp->status.sc = SPDK_NVME_SC_DATA_SGL_LENGTH_INVALID;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
req->data = tcp_req->buf;
|
||||
}
|
||||
|
||||
req->data = tcp_req->buf + offset;
|
||||
req->data_from_pool = false;
|
||||
req->length = length;
|
||||
req->data_from_pool = false;
|
||||
|
||||
if (spdk_unlikely(req->dif.dif_insert_or_strip)) {
|
||||
length = spdk_dif_get_length_with_md(length, &req->dif.dif_ctx);
|
||||
@ -2130,6 +2243,7 @@ nvmf_tcp_req_process(struct spdk_nvmf_tcp_transport *ttransport,
|
||||
bool progress = false;
|
||||
struct spdk_nvmf_transport *transport = &ttransport->transport;
|
||||
struct spdk_nvmf_transport_poll_group *group;
|
||||
struct spdk_nvmf_tcp_poll_group *tgroup;
|
||||
|
||||
tqpair = SPDK_CONTAINEROF(tcp_req->req.qpair, struct spdk_nvmf_tcp_qpair, qpair);
|
||||
group = &tqpair->group->group;
|
||||
@ -2301,6 +2415,12 @@ nvmf_tcp_req_process(struct spdk_nvmf_tcp_transport *ttransport,
|
||||
spdk_trace_record(TRACE_TCP_REQUEST_STATE_COMPLETED, 0, 0, (uintptr_t)tcp_req, 0);
|
||||
if (tcp_req->req.data_from_pool) {
|
||||
spdk_nvmf_request_free_buffers(&tcp_req->req, group, transport);
|
||||
} else if (spdk_unlikely(tcp_req->has_incapsule_data && (tcp_req->cmd.opc == SPDK_NVME_OPC_FABRIC ||
|
||||
tqpair->qpair.qid == 0) && tcp_req->req.length > transport->opts.in_capsule_data_size)) {
|
||||
tgroup = SPDK_CONTAINEROF(group, struct spdk_nvmf_tcp_poll_group, group);
|
||||
assert(tgroup->control_msg_list);
|
||||
SPDK_DEBUGLOG(nvmf_tcp, "Put buf to control msg list\n");
|
||||
nvmf_tcp_control_msg_put(tgroup->control_msg_list, tcp_req->req.data);
|
||||
}
|
||||
tcp_req->req.length = 0;
|
||||
tcp_req->req.iovcnt = 0;
|
||||
|
@ -663,8 +663,8 @@ fs_load_cb(__attribute__((unused)) void *ctx,
|
||||
}
|
||||
|
||||
static void
|
||||
base_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev,
|
||||
void *event_ctx)
|
||||
base_bdev_event_cb(enum spdk_bdev_event_type type, __attribute__((unused)) struct spdk_bdev *bdev,
|
||||
__attribute__((unused)) void *event_ctx)
|
||||
{
|
||||
printf("Unsupported bdev event: type %d\n", type);
|
||||
}
|
||||
|
@ -56,7 +56,6 @@ endif
|
||||
SPDK_LIB_LIST = $(ALL_MODULES_LIST)
|
||||
SPDK_LIB_LIST += $(EVENT_BDEV_SUBSYSTEM)
|
||||
SPDK_LIB_LIST += bdev accel event util conf trace log jsonrpc json rpc sock thread notify
|
||||
SPDK_LIB_LIST += blobfs_bdev
|
||||
|
||||
AM_LINK += $(SPDK_LIB_LINKER_ARGS) $(ENV_LINKER_ARGS)
|
||||
AM_LINK += $(SYS_LIBS)
|
||||
|
@ -500,6 +500,7 @@ msg_queue_run_batch(struct spdk_thread *thread, uint32_t max_msgs)
|
||||
unsigned count, i;
|
||||
void *messages[SPDK_MSG_BATCH_SIZE];
|
||||
uint64_t notify = 1;
|
||||
int rc;
|
||||
|
||||
#ifdef DEBUG
|
||||
/*
|
||||
@ -520,12 +521,18 @@ msg_queue_run_batch(struct spdk_thread *thread, uint32_t max_msgs)
|
||||
* so msg_acknowledge should be applied ahead. And then check for self's msg_notify.
|
||||
* This can avoid msg notification missing.
|
||||
*/
|
||||
read(thread->msg_fd, ¬ify, sizeof(notify));
|
||||
rc = read(thread->msg_fd, ¬ify, sizeof(notify));
|
||||
if (rc < 0) {
|
||||
SPDK_ERRLOG("failed to acknowledge msg_queue: %s.\n", spdk_strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
count = spdk_ring_dequeue(thread->messages, messages, max_msgs);
|
||||
if (thread->interrupt_mode && spdk_ring_count(thread->messages) != 0) {
|
||||
write(thread->msg_fd, ¬ify, sizeof(notify));
|
||||
rc = write(thread->msg_fd, ¬ify, sizeof(notify));
|
||||
if (rc < 0) {
|
||||
SPDK_ERRLOG("failed to notify msg_queue: %s.\n", spdk_strerror(errno));
|
||||
}
|
||||
}
|
||||
if (count == 0) {
|
||||
return 0;
|
||||
@ -917,7 +924,11 @@ spdk_thread_send_msg(const struct spdk_thread *thread, spdk_msg_fn fn, void *ctx
|
||||
if (thread->interrupt_mode) {
|
||||
uint64_t notify = 1;
|
||||
|
||||
write(thread->msg_fd, ¬ify, sizeof(notify));
|
||||
rc = write(thread->msg_fd, ¬ify, sizeof(notify));
|
||||
if (rc < 0) {
|
||||
SPDK_ERRLOG("failed to notify msg_queue: %s.\n", spdk_strerror(errno));
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -932,8 +943,13 @@ spdk_thread_send_critical_msg(struct spdk_thread *thread, spdk_msg_fn fn)
|
||||
__ATOMIC_SEQ_CST)) {
|
||||
if (thread->interrupt_mode) {
|
||||
uint64_t notify = 1;
|
||||
int rc;
|
||||
|
||||
write(thread->msg_fd, ¬ify, sizeof(notify));
|
||||
rc = write(thread->msg_fd, ¬ify, sizeof(notify));
|
||||
if (rc < 0) {
|
||||
SPDK_ERRLOG("failed to notify msg_queue: %s.\n", spdk_strerror(errno));
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -382,7 +382,8 @@ bdev_aio_group_interrupt(void *arg)
|
||||
|
||||
if (num_events > SPDK_AIO_QUEUE_DEPTH) {
|
||||
num_events -= SPDK_AIO_QUEUE_DEPTH;
|
||||
if (write(group_ch->efd, &num_events, sizeof(num_events))) {
|
||||
rc = write(group_ch->efd, &num_events, sizeof(num_events));
|
||||
if (rc < 0) {
|
||||
SPDK_ERRLOG("failed to notify aio group: %s.\n", spdk_strerror(errno));
|
||||
}
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ static struct spdk_sock_impl_opts g_spdk_posix_sock_impl_opts = {
|
||||
.recv_buf_size = MIN_SO_RCVBUF_SIZE,
|
||||
.send_buf_size = MIN_SO_SNDBUF_SIZE,
|
||||
.enable_recv_pipe = true,
|
||||
.enable_zerocopy_send = true,
|
||||
.enable_zerocopy_send = false,
|
||||
.enable_quickack = false,
|
||||
.enable_placement_id = false,
|
||||
};
|
||||
|
@ -2,12 +2,12 @@
|
||||
%bcond_with doc
|
||||
|
||||
Name: spdk
|
||||
Version: master
|
||||
Version: 20.10.x
|
||||
Release: 0%{?dist}
|
||||
Epoch: 0
|
||||
URL: http://spdk.io
|
||||
|
||||
Source: https://github.com/spdk/spdk/archive/master.tar.gz
|
||||
Source: https://github.com/spdk/spdk/archive/v20.10.x.tar.gz
|
||||
Summary: Set of libraries and utilities for high performance user-mode storage
|
||||
|
||||
%define package_version %{epoch}:%{version}-%{release}
|
||||
|
@ -152,7 +152,7 @@ parser.add_argument('-d', '--max-disks', default=0, type=int,
|
||||
each virtual machine gets it's own bdev to work on.")
|
||||
parser.add_argument('-v', '--vm-count', default=1, type=int,
|
||||
help="How many VMs to run in test. Default: 1")
|
||||
parser.add_argument('-i', '--vm-image', default="$HOME/vhost_vm_image.qcow2",
|
||||
parser.add_argument('-i', '--vm-image', default="$HOME/spdk_test_image.qcow2",
|
||||
type=str, help="VM image to use for running VMs.")
|
||||
|
||||
subparsers = parser.add_subparsers()
|
||||
|
@ -146,7 +146,7 @@ def nvmf_create_transport(client,
|
||||
params['max_qpairs_per_ctrlr'] = max_qpairs_per_ctrlr
|
||||
if max_io_qpairs_per_ctrlr:
|
||||
params['max_io_qpairs_per_ctrlr'] = max_io_qpairs_per_ctrlr
|
||||
if in_capsule_data_size:
|
||||
if in_capsule_data_size is not None:
|
||||
params['in_capsule_data_size'] = in_capsule_data_size
|
||||
if max_io_size:
|
||||
params['max_io_size'] = max_io_size
|
||||
@ -156,7 +156,7 @@ def nvmf_create_transport(client,
|
||||
params['max_aq_depth'] = max_aq_depth
|
||||
if num_shared_buffers:
|
||||
params['num_shared_buffers'] = num_shared_buffers
|
||||
if buf_cache_size:
|
||||
if buf_cache_size is not None:
|
||||
params['buf_cache_size'] = buf_cache_size
|
||||
if max_srq_depth:
|
||||
params['max_srq_depth'] = max_srq_depth
|
||||
@ -166,7 +166,7 @@ def nvmf_create_transport(client,
|
||||
params['c2h_success'] = c2h_success
|
||||
if dif_insert_or_strip:
|
||||
params['dif_insert_or_strip'] = dif_insert_or_strip
|
||||
if sock_priority:
|
||||
if sock_priority is not None:
|
||||
params['sock_priority'] = sock_priority
|
||||
if acceptor_backlog is not None:
|
||||
params['acceptor_backlog'] = acceptor_backlog
|
||||
@ -254,7 +254,7 @@ def nvmf_create_subsystem(client,
|
||||
if allow_any_host:
|
||||
params['allow_any_host'] = True
|
||||
|
||||
if max_namespaces:
|
||||
if max_namespaces is not None:
|
||||
params['max_namespaces'] = max_namespaces
|
||||
|
||||
if tgt_name:
|
||||
|
@ -31,43 +31,40 @@
|
||||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
DPDK_LIB = -lrte_eal -lrte_mempool -lrte_ring -lrte_mbuf -lrte_mempool_ring -lrte_pci
|
||||
DPDK_LIB += -lrte_bus_pci -lrte_kvargs -lrte_vhost -lrte_net -lrte_hash -lrte_telemetry
|
||||
DPDK_LIB += -lrte_cryptodev -lrte_power -lrte_rcu
|
||||
|
||||
# Shows how to compile both an external bdev and an external application against the SPDK combined shared object and dpdk shared objects.
|
||||
bdev_shared_combo:
|
||||
$(CC) $(COMMON_CFLAGS) -L../passthru -Wl,-rpath=$(SPDK_LIB_DIR),--no-as-needed -o hello_bdev ./hello_bdev.c -lpassthru_external \
|
||||
-lspdk -lspdk_env_dpdk -lrte_eal -lrte_mempool -lrte_ring -lrte_mbuf -lrte_mempool_ring -lrte_pci -lrte_bus_pci -lrte_kvargs \
|
||||
-lrte_vhost -lrte_net -lrte_hash -lrte_cryptodev -lrte_power -Wl,--no-whole-archive
|
||||
-lspdk -lspdk_env_dpdk $(DPDK_LIB) -Wl,--no-whole-archive
|
||||
|
||||
# Shows how to compile both an external bdev and an external application against the SPDK individual shared objects and dpdk shared objects.
|
||||
bdev_shared_iso:
|
||||
$(CC) $(COMMON_CFLAGS) -L../passthru -Wl,-rpath=$(SPDK_LIB_DIR),--no-as-needed -o hello_bdev ./hello_bdev.c \
|
||||
-lpassthru_external -lspdk_event_bdev -lspdk_event_accel -lspdk_event_vmd -lspdk_bdev -lspdk_bdev_malloc -lspdk_log -lspdk_thread -lspdk_util -lspdk_event \
|
||||
-lspdk_env_dpdk -lrte_eal -lrte_mempool -lrte_ring -lrte_mbuf -lrte_mempool_ring -lrte_pci -lrte_bus_pci -lrte_kvargs \
|
||||
-lrte_vhost -lrte_net -lrte_hash -lrte_cryptodev -lrte_power -Wl,--no-whole-archive -lnuma
|
||||
-lspdk_env_dpdk $(DPDK_LIB) -Wl,--no-whole-archive -lnuma
|
||||
|
||||
# Shows how to compile an external application against the SPDK combined shared object and dpdk shared objects.
|
||||
alone_shared_combo:
|
||||
$(CC) $(COMMON_CFLAGS) -Wl,-rpath=$(SPDK_LIB_DIR),--no-as-needed -o hello_bdev ./hello_bdev.c -lspdk -lspdk_env_dpdk -lrte_eal \
|
||||
-lrte_mempool -lrte_ring -lrte_mbuf -lrte_mempool_ring -lrte_pci -lrte_bus_pci -lrte_kvargs -lrte_vhost -lrte_net -lrte_hash -lrte_cryptodev -lrte_power
|
||||
$(CC) $(COMMON_CFLAGS) -Wl,-rpath=$(SPDK_LIB_DIR),--no-as-needed -o hello_bdev ./hello_bdev.c -lspdk -lspdk_env_dpdk $(DPDK_LIB)
|
||||
|
||||
# Shows how to compile an external application against the SPDK individual shared objects and dpdk shared objects.
|
||||
alone_shared_iso:
|
||||
$(CC) $(COMMON_CFLAGS) -Wl,-rpath=$(SPDK_LIB_DIR),--no-as-needed -o hello_bdev ./hello_bdev.c -lspdk_event_bdev \
|
||||
-lspdk_event_accel -lspdk_event_vmd -lspdk_bdev -lspdk_bdev_malloc -lspdk_log -lspdk_thread -lspdk_util -lspdk_event \
|
||||
-lspdk_env_dpdk -lrte_eal -lrte_mempool -lrte_ring -lrte_mbuf -lrte_mempool_ring -lrte_pci -lrte_bus_pci -lrte_kvargs \
|
||||
-lrte_vhost -lrte_net -lrte_hash -lrte_cryptodev -lrte_power
|
||||
-lspdk_event_accel -lspdk_event_vmd -lspdk_bdev -lspdk_bdev_malloc -lspdk_log -lspdk_thread -lspdk_util -lspdk_event -lspdk_env_dpdk $(DPDK_LIB)
|
||||
|
||||
# Shows how to compile an external application against the SPDK archives.
|
||||
alone_static:
|
||||
$(CC) $(COMMON_CFLAGS) -o hello_bdev ./hello_bdev.c -Wl,--whole-archive,-Bstatic -lspdk_bdev_malloc -lspdk_event_bdev -lspdk_event_accel -lspdk_event_vmd \
|
||||
-lspdk_event_sock -lspdk_bdev -lspdk_accel -lspdk_event -lspdk_thread -lspdk_util -lspdk_conf -lspdk_trace -lspdk_log -lspdk_json \
|
||||
-lspdk_jsonrpc -lspdk_rpc -lspdk_sock -lspdk_notify -lspdk_vmd -lspdk_env_dpdk -lrte_eal -lrte_mempool -lrte_ring \
|
||||
-lrte_mbuf -lrte_mempool_ring -lrte_pci -lrte_bus_pci -lrte_kvargs -lrte_vhost -lrte_net -lrte_hash -lrte_telemetry \
|
||||
-lrte_cryptodev -lrte_power -Wl,--no-whole-archive,-Bdynamic -lnuma -luuid -lpthread -ldl -lrt
|
||||
-lspdk_jsonrpc -lspdk_rpc -lspdk_sock -lspdk_notify -lspdk_vmd -lspdk_env_dpdk \
|
||||
$(DPDK_LIB) -Wl,--no-whole-archive,-Bdynamic -lnuma -luuid -lpthread -ldl -lrt
|
||||
|
||||
# Shows how to compile and external bdev and application sgainst the SPDK archives.
|
||||
bdev_static:
|
||||
$(CC) $(COMMON_CFLAGS) -L../passthru -o hello_bdev ./hello_bdev.c -Wl,--whole-archive,-Bstatic -lpassthru_external -lspdk_bdev_malloc -lspdk_event_bdev \
|
||||
-lspdk_event_accel -lspdk_event_vmd -lspdk_event_sock -lspdk_bdev -lspdk_accel -lspdk_event -lspdk_thread -lspdk_util -lspdk_conf -lspdk_trace \
|
||||
-lspdk_log -lspdk_json -lspdk_jsonrpc -lspdk_rpc -lspdk_sock -lspdk_notify -lspdk_vmd -lspdk_env_dpdk -lrte_eal -lrte_mempool \
|
||||
-lrte_ring -lrte_mbuf -lrte_mempool_ring -lrte_pci -lrte_bus_pci -lrte_kvargs -lrte_vhost -lrte_net -lrte_hash -lrte_telemetry -lrte_cryptodev \
|
||||
-lrte_power -Wl,--no-whole-archive,-Bdynamic -lnuma -luuid -lpthread -ldl -lrt
|
||||
-lspdk_log -lspdk_json -lspdk_jsonrpc -lspdk_rpc -lspdk_sock -lspdk_notify -lspdk_vmd -lspdk_env_dpdk $(DPDK_LIB) \
|
||||
-Wl,--no-whole-archive,-Bdynamic -lnuma -luuid -lpthread -ldl -lrt
|
||||
|
@ -54,9 +54,8 @@ function devices_delete() {
|
||||
}
|
||||
|
||||
password=$1
|
||||
base_img=${DEPENDENCY_DIR}/fedora-hotplug.qcow2
|
||||
test_img=${DEPENDENCY_DIR}/fedora-hotplug-test.qcow2
|
||||
qemu_pidfile=${DEPENDENCY_DIR}/qemupid
|
||||
base_img=$HOME/spdk_test_image.qcow2
|
||||
qemu_pidfile=$HOME/qemupid
|
||||
|
||||
if [ ! -e "$base_img" ]; then
|
||||
echo "Hotplug VM image not found; skipping test"
|
||||
@ -65,8 +64,6 @@ fi
|
||||
|
||||
timing_enter start_qemu
|
||||
|
||||
qemu-img create -b "$base_img" -f qcow2 "$test_img"
|
||||
|
||||
for i in {0..3}; do
|
||||
dd if=/dev/zero of="$SPDK_TEST_STORAGE/nvme$i.img" bs=1M count=1024
|
||||
done
|
||||
@ -74,7 +71,7 @@ done
|
||||
qemu-system-x86_64 \
|
||||
-daemonize -display none -m 8192 \
|
||||
-pidfile "$qemu_pidfile" \
|
||||
-hda "$test_img" \
|
||||
-hda "$base_img" \
|
||||
-net user,hostfwd=tcp::10022-:22 \
|
||||
-net nic \
|
||||
-cpu host \
|
||||
@ -85,7 +82,8 @@ qemu-system-x86_64 \
|
||||
-drive format=raw,file="$SPDK_TEST_STORAGE/nvme0.img",if=none,id=drive0 \
|
||||
-drive format=raw,file="$SPDK_TEST_STORAGE/nvme1.img",if=none,id=drive1 \
|
||||
-drive format=raw,file="$SPDK_TEST_STORAGE/nvme2.img",if=none,id=drive2 \
|
||||
-drive format=raw,file="$SPDK_TEST_STORAGE/nvme3.img",if=none,id=drive3
|
||||
-drive format=raw,file="$SPDK_TEST_STORAGE/nvme3.img",if=none,id=drive3 \
|
||||
-snapshot
|
||||
|
||||
timing_exit start_qemu
|
||||
|
||||
@ -98,7 +96,15 @@ files_to_copy="scripts "
|
||||
files_to_copy+="include/spdk/pci_ids.h "
|
||||
files_to_copy+="build/examples/hotplug "
|
||||
files_to_copy+="build/lib "
|
||||
files_to_copy+="dpdk/build/lib "
|
||||
|
||||
# Select which dpdk libs to copy in case we're not building with
|
||||
# spdk/dpdk submodule
|
||||
if [[ -n "$SPDK_RUN_EXTERNAL_DPDK" ]]; then
|
||||
files_to_copy+="-C $SPDK_RUN_EXTERNAL_DPDK/../.. dpdk/build/lib"
|
||||
else
|
||||
files_to_copy+="dpdk/build/lib "
|
||||
fi
|
||||
|
||||
(
|
||||
cd "$rootdir"
|
||||
tar -cf - $files_to_copy
|
||||
@ -129,6 +135,5 @@ trap - SIGINT SIGTERM EXIT
|
||||
qemupid=$(awk '{printf $0}' "$qemu_pidfile")
|
||||
kill -9 $qemupid
|
||||
rm "$qemu_pidfile"
|
||||
rm "$test_img"
|
||||
|
||||
timing_exit hotplug_test
|
||||
|
@ -91,6 +91,13 @@ nvme_ctrlr_destruct_poll_async(struct spdk_nvme_ctrlr *ctrlr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
union spdk_nvme_csts_register
|
||||
spdk_nvme_ctrlr_get_regs_csts(struct spdk_nvme_ctrlr *ctrlr)
|
||||
{
|
||||
union spdk_nvme_csts_register csts = {};
|
||||
return csts;
|
||||
}
|
||||
|
||||
void
|
||||
spdk_nvme_ctrlr_get_default_ctrlr_opts(struct spdk_nvme_ctrlr_opts *opts, size_t opts_size)
|
||||
{
|
||||
@ -382,7 +389,7 @@ test_nvme_init_controllers(void)
|
||||
probe_ctx->attach_cb = attach_cb;
|
||||
probe_ctx->trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
|
||||
rc = nvme_init_controllers(probe_ctx);
|
||||
CU_ASSERT(rc != 0);
|
||||
CU_ASSERT(rc == 0);
|
||||
CU_ASSERT(g_spdk_nvme_driver->initialized == true);
|
||||
CU_ASSERT(ut_destruct_called == true);
|
||||
|
||||
@ -1270,9 +1277,13 @@ static void
|
||||
test_nvme_wait_for_completion(void)
|
||||
{
|
||||
struct spdk_nvme_qpair qpair;
|
||||
struct spdk_nvme_ctrlr ctrlr;
|
||||
int rc = 0;
|
||||
|
||||
memset(&ctrlr, 0, sizeof(ctrlr));
|
||||
ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
|
||||
memset(&qpair, 0, sizeof(qpair));
|
||||
qpair.ctrlr = &ctrlr;
|
||||
|
||||
/* completion timeout */
|
||||
memset(&g_status, 0, sizeof(g_status));
|
||||
|
@ -44,6 +44,8 @@ bool trace_flag = false;
|
||||
|
||||
#include "nvme/nvme_qpair.c"
|
||||
|
||||
SPDK_LOG_REGISTER_COMPONENT(nvme)
|
||||
|
||||
struct nvme_driver _g_nvme_driver = {
|
||||
.lock = PTHREAD_MUTEX_INITIALIZER,
|
||||
};
|
||||
|
@ -459,6 +459,7 @@ test_nvmf_tcp_poll_group_create(void)
|
||||
{
|
||||
struct spdk_nvmf_transport *transport;
|
||||
struct spdk_nvmf_transport_poll_group *group;
|
||||
struct spdk_nvmf_tcp_poll_group *tgroup;
|
||||
struct spdk_thread *thread;
|
||||
struct spdk_nvmf_transport_opts opts;
|
||||
struct spdk_sock_group grp = {};
|
||||
@ -482,6 +483,10 @@ test_nvmf_tcp_poll_group_create(void)
|
||||
group = nvmf_tcp_poll_group_create(transport);
|
||||
MOCK_CLEAR_P(spdk_sock_group_create);
|
||||
SPDK_CU_ASSERT_FATAL(group);
|
||||
if (opts.in_capsule_data_size < SPDK_NVME_TCP_IN_CAPSULE_DATA_MAX_SIZE) {
|
||||
tgroup = SPDK_CONTAINEROF(group, struct spdk_nvmf_tcp_poll_group, group);
|
||||
SPDK_CU_ASSERT_FATAL(tgroup->control_msg_list);
|
||||
}
|
||||
group->transport = transport;
|
||||
nvmf_tcp_poll_group_destroy(group);
|
||||
nvmf_tcp_destroy(transport);
|
||||
|
@ -8,8 +8,7 @@ VM_DIR=$VHOST_DIR/vms
|
||||
TARGET_DIR=$VHOST_DIR/vhost
|
||||
VM_PASSWORD="root"
|
||||
|
||||
#TODO: Move vhost_vm_image.qcow2 into VHOST_DIR on test systems.
|
||||
VM_IMAGE=$HOME/vhost_vm_image.qcow2
|
||||
VM_IMAGE=$HOME/spdk_test_image.qcow2
|
||||
|
||||
if ! hash $QEMU_IMG_BIN $QEMU_BIN; then
|
||||
error 'QEMU is not installed on this system. Unable to run vhost tests.'
|
||||
|
@ -21,7 +21,7 @@ case $1 in
|
||||
echo " -h |--help prints this message"
|
||||
echo ""
|
||||
echo "Environment:"
|
||||
echo " VM_IMAGE path to QCOW2 VM image used during test (default: $HOME/vhost_vm_image.qcow2)"
|
||||
echo " VM_IMAGE path to QCOW2 VM image used during test (default: $HOME/spdk_test_image.qcow2)"
|
||||
echo ""
|
||||
echo "Tests are performed only on Linux machine. For other OS no action is performed."
|
||||
echo ""
|
||||
|
@ -53,7 +53,7 @@ function usage() {
|
||||
echo " --vm-memory=INT Amount of RAM memory (in MB) to pass to a single VM."
|
||||
echo " Default: 2048 MB"
|
||||
echo " --vm-image=PATH OS image to use for running the VMs."
|
||||
echo " Default: \$HOME/vhost_vm_image.qcow2"
|
||||
echo " Default: \$HOME/spdk_test_image.qcow2"
|
||||
echo " --vm-sar-enable Measure CPU utilization in guest VMs using sar."
|
||||
echo " --host-sar-enable Measure CPU utilization on host using sar."
|
||||
echo " --sar-delay=INT Wait for X seconds before starting SAR measurement. Default: 0."
|
||||
|
Loading…
Reference in New Issue
Block a user