Compare commits
27 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
64f1ea8ea4 | ||
|
1f0dd58a43 | ||
|
049e9290cf | ||
|
82c0c8ca03 | ||
|
1cf1b00b1b | ||
|
1d839c1ac3 | ||
|
9bdc45693a | ||
|
c7a0275edf | ||
|
a5a51c7b56 | ||
|
f2a113d144 | ||
|
b4ed65d26f | ||
|
26e589c3a4 | ||
|
14eeeea669 | ||
|
3f732d80d3 | ||
|
e02a868dd3 | ||
|
d02ff4c422 | ||
|
4b87c7259a | ||
|
02f9f45524 | ||
|
84c4530e9b | ||
|
0811dda8bf | ||
|
9b37f63fe9 | ||
|
edb5cd988a | ||
|
68eb748759 | ||
|
bbe2ed83dc | ||
|
d53d7a5723 | ||
|
2a1fe02d98 | ||
|
081cd04ea2 |
39
CHANGELOG.md
39
CHANGELOG.md
@ -1,6 +1,39 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## v21.01: (Upcoming Release)
|
## v21.01.2: (Upcoming Release)
|
||||||
|
|
||||||
|
## v21.01.1:
|
||||||
|
|
||||||
|
### dpdk
|
||||||
|
|
||||||
|
Added `rte_ethdev` and `rte_net` dependencies for all builds with DPDK.
|
||||||
|
|
||||||
|
Fixed compatibility issues with DPDK 19.11.
|
||||||
|
|
||||||
|
### iscsi
|
||||||
|
|
||||||
|
A security vulnerability has been identified and fixed in the SPDK iSCSI target.
|
||||||
|
A TEXT PDU with no data, but CONTINUE flag set, would result in a NULL pointer dereference
|
||||||
|
and crash the SPDK iSCSI target process. All users of the SPDK iSCSI target
|
||||||
|
are recommended to update. All SPDK versions <= v21.01 are affected.
|
||||||
|
|
||||||
|
### nbd
|
||||||
|
|
||||||
|
Fixed kernel hang when bdev is removed by always setting NBD_SET_TIMEOUT.
|
||||||
|
|
||||||
|
### nvme
|
||||||
|
|
||||||
|
Fixed segfault when removing qpair when transport connection fails (issue #1777).
|
||||||
|
|
||||||
|
### ocssd
|
||||||
|
|
||||||
|
Fixed the bug that no media event is pushed to the target bdev.
|
||||||
|
|
||||||
|
### sock
|
||||||
|
|
||||||
|
Added `enable_quickack` and `enable_placement_id` when saving JSON configuration.
|
||||||
|
|
||||||
|
## v21.01: Dynamic scheduler, vfio-user, ZNS Zone Append
|
||||||
|
|
||||||
### bdev
|
### bdev
|
||||||
|
|
||||||
@ -75,6 +108,10 @@ The `--pci-blacklist` command line option has been deprecated, replaced with
|
|||||||
The `--pci-whitelist/-W` command line options have been deprecated, replaced with
|
The `--pci-whitelist/-W` command line options have been deprecated, replaced with
|
||||||
`--pci-allowed/-A`.
|
`--pci-allowed/-A`.
|
||||||
|
|
||||||
|
Added new experimental `dynamic` scheduler that rebalances idle threads, adjusts CPU frequency
|
||||||
|
using dpdk_governor and turns idle reactor cores to interrupt mode. Please see
|
||||||
|
[scheduler documentation](https://www.spdk.io/doc/scheduler.html) for details.
|
||||||
|
|
||||||
## ioat
|
## ioat
|
||||||
|
|
||||||
The PCI BDF whitelist option has been removed from the `ioat_scan_accel_engine` RPC.
|
The PCI BDF whitelist option has been removed from the `ioat_scan_accel_engine` RPC.
|
||||||
|
2
CONFIG
2
CONFIG
@ -121,7 +121,7 @@ CONFIG_VHOST=y
|
|||||||
CONFIG_VIRTIO=y
|
CONFIG_VIRTIO=y
|
||||||
|
|
||||||
# Build custom vfio-user transport for NVMf target and NVMe initiator.
|
# Build custom vfio-user transport for NVMf target and NVMe initiator.
|
||||||
CONFIG_VFIO_USER=y
|
CONFIG_VFIO_USER=n
|
||||||
|
|
||||||
# Build with PMDK backends
|
# Build with PMDK backends
|
||||||
CONFIG_PMDK=n
|
CONFIG_PMDK=n
|
||||||
|
@ -2027,6 +2027,7 @@ show_thread(uint8_t current_page)
|
|||||||
|
|
||||||
get_data();
|
get_data();
|
||||||
|
|
||||||
|
assert(thread_number < g_threads_stats.threads.threads_count);
|
||||||
for (i = 0; i < g_threads_stats.threads.threads_count; i++) {
|
for (i = 0; i < g_threads_stats.threads.threads_count; i++) {
|
||||||
thread_info[i] = &g_threads_stats.threads.thread_info[i];
|
thread_info[i] = &g_threads_stats.threads.thread_info[i];
|
||||||
}
|
}
|
||||||
@ -2067,6 +2068,7 @@ show_core(uint8_t current_page)
|
|||||||
|
|
||||||
get_data();
|
get_data();
|
||||||
|
|
||||||
|
assert(core_number < g_cores_stats.cores.cores_count);
|
||||||
for (i = 0; i < g_cores_stats.cores.cores_count; i++) {
|
for (i = 0; i < g_cores_stats.cores.cores_count; i++) {
|
||||||
core_info[i] = &g_cores_stats.cores.core[i];
|
core_info[i] = &g_cores_stats.cores.core[i];
|
||||||
}
|
}
|
||||||
@ -2178,6 +2180,7 @@ show_poller(uint8_t current_page)
|
|||||||
get_data();
|
get_data();
|
||||||
|
|
||||||
prepare_poller_data(current_page, pollers, &count, current_page);
|
prepare_poller_data(current_page, pollers, &count, current_page);
|
||||||
|
assert(poller_number < count);
|
||||||
|
|
||||||
poller_win = newwin(POLLER_WIN_HEIGHT, POLLER_WIN_WIDTH,
|
poller_win = newwin(POLLER_WIN_HEIGHT, POLLER_WIN_WIDTH,
|
||||||
(g_max_row - poller_counter) / 2, (g_max_col - POLLER_WIN_HOR_POS) / 2);
|
(g_max_row - poller_counter) / 2, (g_max_col - POLLER_WIN_HOR_POS) / 2);
|
||||||
@ -2300,6 +2303,7 @@ show_stats(void)
|
|||||||
} else {
|
} else {
|
||||||
active_tab = THREADS_TAB;
|
active_tab = THREADS_TAB;
|
||||||
}
|
}
|
||||||
|
g_selected_row = 0;
|
||||||
current_page = 0;
|
current_page = 0;
|
||||||
switch_tab(active_tab);
|
switch_tab(active_tab);
|
||||||
break;
|
break;
|
||||||
|
@ -4,7 +4,8 @@ set -e
|
|||||||
|
|
||||||
rootdir=$(readlink -f $(dirname $0))
|
rootdir=$(readlink -f $(dirname $0))
|
||||||
|
|
||||||
conf=~/autorun-spdk.conf
|
default_conf=~/autorun-spdk.conf
|
||||||
|
conf=${1:-${default_conf}}
|
||||||
|
|
||||||
# If the configuration of tests is not provided, no tests will be carried out.
|
# If the configuration of tests is not provided, no tests will be carried out.
|
||||||
if [[ ! -f $conf ]]; then
|
if [[ ! -f $conf ]]; then
|
||||||
|
42
configure
vendored
42
configure
vendored
@ -454,36 +454,22 @@ else
|
|||||||
fi
|
fi
|
||||||
BUILD_CMD+=(-I/usr/local/include -L/usr/local/lib)
|
BUILD_CMD+=(-I/usr/local/include -L/usr/local/lib)
|
||||||
|
|
||||||
function set_os_id_version() {
|
|
||||||
if [[ -f /etc/os-release ]]; then
|
|
||||||
source /etc/os-release
|
|
||||||
fi
|
|
||||||
|
|
||||||
OSID=$ID
|
|
||||||
OSVERSION=$VERSION_ID
|
|
||||||
|
|
||||||
echo "OS-ID: $OSID | OS-Version: $OSVERSION"
|
|
||||||
}
|
|
||||||
|
|
||||||
if [[ "${CONFIG[VFIO_USER]}" = "y" ]]; then
|
if [[ "${CONFIG[VFIO_USER]}" = "y" ]]; then
|
||||||
set_os_id_version
|
|
||||||
|
|
||||||
if [[ $arch != x86_64* ]] || [[ $sys_name == "FreeBSD" ]]; then
|
if ! hash cmake; then
|
||||||
echo "Non x86_64 and Linux platform, disable CONFIG_VFIO_USER"
|
echo "ERROR: --with-vfio-user requires cmake"
|
||||||
CONFIG[VFIO_USER]="n"
|
echo "Please install then re-run this script"
|
||||||
# disable tests on ubuntu16 due to lack of macro definition in pci_regs.h
|
exit 1
|
||||||
elif [[ $OSID == "ubuntu" ]] && [[ $OSVERSION == "16.04" ]]; then
|
fi
|
||||||
echo "ubuntu16 OS, disable CONFIG_VFIO_USER"
|
if [[ ! -d /usr/include/json-c ]] && [[ ! -d /usr/local/include/json-c ]]; then
|
||||||
CONFIG[VFIO_USER]="n"
|
echo "ERROR: --with-vfio-user requires json-c-devel"
|
||||||
elif ! hash cmake; then
|
echo "Please install then re-run this script"
|
||||||
echo "cmake not installed, disable CONFIG_VFIO_USER"
|
exit 1
|
||||||
CONFIG[VFIO_USER]="n"
|
fi
|
||||||
elif [[ ! -d /usr/include/json-c ]] && [[ ! -d /usr/local/include/json-c ]]; then
|
if [[ ! -e /usr/include/cmocka.h ]] && [[ ! -e /usr/local/include/cmocka.h ]]; then
|
||||||
echo "json-c-devel not installed, disable CONFIG_VFIO_USER"
|
echo "ERROR: --with-vfio-user requires libcmocka-devel"
|
||||||
CONFIG[VFIO_USER]="n"
|
echo "Please install then re-run this script"
|
||||||
elif [[ ! -e /usr/include/cmocka.h ]] && [[ ! -e /usr/local/include/cmocka.h ]]; then
|
exit 1
|
||||||
echo "libcmocka-devel not installed, disable CONFIG_VFIO_USER"
|
|
||||||
CONFIG[VFIO_USER]="n"
|
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -835,6 +835,7 @@ INPUT += \
|
|||||||
peer_2_peer.md \
|
peer_2_peer.md \
|
||||||
pkgconfig.md \
|
pkgconfig.md \
|
||||||
porting.md \
|
porting.md \
|
||||||
|
scheduler.md \
|
||||||
shfmt.md \
|
shfmt.md \
|
||||||
spdkcli.md \
|
spdkcli.md \
|
||||||
spdk_top.md \
|
spdk_top.md \
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
# General Information {#general}
|
# General Information {#general}
|
||||||
|
|
||||||
- @subpage event
|
- @subpage event
|
||||||
|
- @subpage scheduler
|
||||||
- @subpage logical_volumes
|
- @subpage logical_volumes
|
||||||
- @subpage accel_fw
|
- @subpage accel_fw
|
||||||
|
@ -78,7 +78,7 @@ A detailed description of each RPC method and its parameters is also available.
|
|||||||
scripts/rpc.py bdev_nvme_attach_controller --help
|
scripts/rpc.py bdev_nvme_attach_controller --help
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
### Generate JSON-RPC methods for current configuration
|
### Generate JSON-RPC methods for current configuration {#jsonrpc_generate}
|
||||||
|
|
||||||
An initial configuration can be specified for an SPDK application via the '-c' command line parameter.
|
An initial configuration can be specified for an SPDK application via the '-c' command line parameter.
|
||||||
The configuration file is a JSON file containing all of the JSON-RPC method invocations necessary
|
The configuration file is a JSON file containing all of the JSON-RPC method invocations necessary
|
||||||
@ -206,6 +206,18 @@ Finally, call the rpc.py script with '--plugin' parameter to provide above pytho
|
|||||||
./scripts/rpc.py --plugin rpc_plugin bdev_example_create 10 4096
|
./scripts/rpc.py --plugin rpc_plugin bdev_example_create 10 4096
|
||||||
~~~
|
~~~
|
||||||
|
|
||||||
|
### Converting from legacy configuration {#jsonrpc_convert}
|
||||||
|
|
||||||
|
Starting with SPDK 20.10, legacy configuration file support has been removed.
|
||||||
|
Users with extensive configuration files already running in SPDK application,
|
||||||
|
can [generate JSON-RPC for current configuration](@ref jsonrpc_generate).
|
||||||
|
|
||||||
|
If binary for deploying the application is unavailable, the legacy configuration
|
||||||
|
file can be converted to JSON-RPC using python tool:
|
||||||
|
~~~
|
||||||
|
./scripts/config_converter.py < config.ini > config.json
|
||||||
|
~~~
|
||||||
|
|
||||||
# App Framework {#jsonrpc_components_app}
|
# App Framework {#jsonrpc_components_app}
|
||||||
|
|
||||||
## spdk_kill_instance {#rpc_spdk_kill_instance}
|
## spdk_kill_instance {#rpc_spdk_kill_instance}
|
||||||
|
@ -116,10 +116,6 @@ An NVMe over Fabrics target can be configured using JSON RPCs.
|
|||||||
The basic RPCs needed to configure the NVMe-oF subsystem are detailed below. More information about
|
The basic RPCs needed to configure the NVMe-oF subsystem are detailed below. More information about
|
||||||
working with NVMe over Fabrics specific RPCs can be found on the @ref jsonrpc_components_nvmf_tgt RPC page.
|
working with NVMe over Fabrics specific RPCs can be found on the @ref jsonrpc_components_nvmf_tgt RPC page.
|
||||||
|
|
||||||
Using .ini style configuration files for configuration of the NVMe-oF target is deprecated and should
|
|
||||||
be replaced with JSON based RPCs. .ini style configuration files can be converted to json format by way
|
|
||||||
of the new script `scripts/config_converter.py`.
|
|
||||||
|
|
||||||
## FC transport support {#nvmf_fc_transport}
|
## FC transport support {#nvmf_fc_transport}
|
||||||
|
|
||||||
To build nvmf_tgt with the FC transport, there is an additional FC LLD (Low Level Driver) code dependency.
|
To build nvmf_tgt with the FC transport, there is an additional FC LLD (Low Level Driver) code dependency.
|
||||||
|
82
doc/scheduler.md
Normal file
82
doc/scheduler.md
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
# Scheduler {#scheduler}
|
||||||
|
|
||||||
|
SPDK's event/application framework (`lib/event`) now supports scheduling of
|
||||||
|
lightweight threads. Schedulers are provided as plugins, called
|
||||||
|
implementations. A default implementation is provided, but users may wish to
|
||||||
|
write their own scheduler to integrate into broader code frameworks or meet
|
||||||
|
their performance needs.
|
||||||
|
|
||||||
|
This feature should be considered experimental and is disabled by default. When
|
||||||
|
enabled, the scheduler framework gathers data for each spdk thread and reactor
|
||||||
|
and passes it to a scheduler implementation to perform one of the following
|
||||||
|
actions.
|
||||||
|
|
||||||
|
## Actions
|
||||||
|
|
||||||
|
### Move a thread
|
||||||
|
|
||||||
|
`spdk_thread`s can be moved to another reactor. Schedulers can examine the
|
||||||
|
suggested cpu_mask value for each lightweight thread to see if the user has
|
||||||
|
requested specific reactors, or choose a reactor using whatever algorithm they
|
||||||
|
deem fit.
|
||||||
|
|
||||||
|
### Switch reactor mode
|
||||||
|
|
||||||
|
Reactors by default run in a mode that constantly polls for new actions for the
|
||||||
|
most efficient processing. Schedulers can switch a reactor into a mode that
|
||||||
|
instead waits for an event on a file descriptor. On Linux, this is implemented
|
||||||
|
using epoll. This results in reduced CPU usage but may be less responsive when
|
||||||
|
events occur. A reactor cannot enter this mode if any `spdk_threads` are
|
||||||
|
currently scheduled to it. This limitation is expected to be lifted in the
|
||||||
|
future, allowing `spdk_threads` to enter interrupt mode.
|
||||||
|
|
||||||
|
### Set frequency of CPU core
|
||||||
|
|
||||||
|
The frequency of CPU cores can be modified by the scheduler in response to
|
||||||
|
load. Only CPU cores that match the application cpu_mask may be modified. The
|
||||||
|
mechanism for controlling CPU frequency is pluggable and the default provided
|
||||||
|
implementation is called `dpdk_governor`, based on the `rte_power` library from
|
||||||
|
DPDK.
|
||||||
|
|
||||||
|
#### Known limitation
|
||||||
|
|
||||||
|
When SMT (Hyperthreading) is enabled the two logical CPU cores sharing a single
|
||||||
|
physical CPU core must run at the same frequency. If one of two of such logical
|
||||||
|
CPU cores is outside the application cpu_mask, the policy and frequency on that
|
||||||
|
core has to be managed by the administrator.
|
||||||
|
|
||||||
|
## Scheduler implementations
|
||||||
|
|
||||||
|
The scheduler in use may be controlled by JSON-RPC. Please use the
|
||||||
|
[framework_set_scheduler](jsonrpc.md/#rpc_framework_set_scheduler) RPC to
|
||||||
|
switch between schedulers or change their options.
|
||||||
|
|
||||||
|
[spdk_top](spdk_top.md#spdk_top) is a useful tool to observe the behavior of
|
||||||
|
schedulers in different scenarios and workloads.
|
||||||
|
|
||||||
|
### static [default]
|
||||||
|
|
||||||
|
The `static` scheduler is the default scheduler and does no dynamic scheduling.
|
||||||
|
Lightweight threads are distributed round-robin among reactors, respecting
|
||||||
|
their requested cpu_mask, and then they are never moved. This is equivalent to
|
||||||
|
the previous behavior of the SPDK event/application framework.
|
||||||
|
|
||||||
|
### dynamic
|
||||||
|
|
||||||
|
The `dynamic` scheduler is designed for power saving and reduction of CPU
|
||||||
|
utilization, especially in cases where workloads show large variations over
|
||||||
|
time.
|
||||||
|
|
||||||
|
Active threads are distributed equally among reactors, taking cpu_mask into
|
||||||
|
account. All idle threads are moved to the main core. Once an idle thread becomes
|
||||||
|
active, it is redistributed again.
|
||||||
|
|
||||||
|
When a reactor has no scheduled `spdk_thread`s it is switched into interrupt
|
||||||
|
mode and stops actively polling. After enough threads become active, the
|
||||||
|
reactor is switched back into poll mode and threads are assigned to it again.
|
||||||
|
|
||||||
|
The main core can contain active threads only when their execution time does
|
||||||
|
not exceed the sum of all idle threads. When no active threads are present on
|
||||||
|
the main core, the frequency of that CPU core will decrease as the load
|
||||||
|
decreases. All CPU cores corresponding to the other reactors remain at maximum
|
||||||
|
frequency.
|
@ -54,7 +54,7 @@
|
|||||||
* Patch level is incremented on maintenance branch releases and reset to 0 for each
|
* Patch level is incremented on maintenance branch releases and reset to 0 for each
|
||||||
* new major.minor release.
|
* new major.minor release.
|
||||||
*/
|
*/
|
||||||
#define SPDK_VERSION_PATCH 0
|
#define SPDK_VERSION_PATCH 2
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Version string suffix.
|
* Version string suffix.
|
||||||
|
@ -51,7 +51,7 @@ DPDK_INC := -I$(DPDK_INC_DIR)
|
|||||||
DPDK_LIB_LIST = rte_eal rte_mempool rte_ring rte_mbuf rte_pci rte_bus_pci rte_mempool_ring
|
DPDK_LIB_LIST = rte_eal rte_mempool rte_ring rte_mbuf rte_pci rte_bus_pci rte_mempool_ring
|
||||||
|
|
||||||
ifeq ($(OS),Linux)
|
ifeq ($(OS),Linux)
|
||||||
DPDK_LIB_LIST += rte_power
|
DPDK_LIB_LIST += rte_power rte_ethdev rte_net
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# DPDK 20.05 eal dependency
|
# DPDK 20.05 eal dependency
|
||||||
@ -101,7 +101,7 @@ endif
|
|||||||
LINK_HASH=n
|
LINK_HASH=n
|
||||||
|
|
||||||
ifeq ($(CONFIG_VHOST),y)
|
ifeq ($(CONFIG_VHOST),y)
|
||||||
DPDK_LIB_LIST += rte_vhost rte_net
|
DPDK_LIB_LIST += rte_vhost
|
||||||
LINK_HASH=y
|
LINK_HASH=y
|
||||||
ifneq ($(DPDK_FRAMEWORK),y)
|
ifneq ($(DPDK_FRAMEWORK),y)
|
||||||
DPDK_LIB_LIST += rte_cryptodev
|
DPDK_LIB_LIST += rte_cryptodev
|
||||||
|
@ -1238,7 +1238,11 @@ vtophys_iommu_device_event(const char *device_name,
|
|||||||
RTE_DEV_FOREACH(dev, "bus=pci", &dev_iter) {
|
RTE_DEV_FOREACH(dev, "bus=pci", &dev_iter) {
|
||||||
if (strcmp(dev->name, device_name) == 0) {
|
if (strcmp(dev->name, device_name) == 0) {
|
||||||
struct rte_pci_device *pci_dev = RTE_DEV_TO_PCI(dev);
|
struct rte_pci_device *pci_dev = RTE_DEV_TO_PCI(dev);
|
||||||
|
#if RTE_VERSION < RTE_VERSION_NUM(20, 11, 0, 0)
|
||||||
|
if (pci_dev->kdrv == RTE_KDRV_VFIO) {
|
||||||
|
#else
|
||||||
if (pci_dev->kdrv == RTE_PCI_KDRV_VFIO) {
|
if (pci_dev->kdrv == RTE_PCI_KDRV_VFIO) {
|
||||||
|
#endif
|
||||||
/* This is a new PCI device using vfio */
|
/* This is a new PCI device using vfio */
|
||||||
g_vfio.device_ref++;
|
g_vfio.device_ref++;
|
||||||
}
|
}
|
||||||
@ -1267,7 +1271,11 @@ vtophys_iommu_device_event(const char *device_name,
|
|||||||
RTE_DEV_FOREACH(dev, "bus=pci", &dev_iter) {
|
RTE_DEV_FOREACH(dev, "bus=pci", &dev_iter) {
|
||||||
if (strcmp(dev->name, device_name) == 0) {
|
if (strcmp(dev->name, device_name) == 0) {
|
||||||
struct rte_pci_device *pci_dev = RTE_DEV_TO_PCI(dev);
|
struct rte_pci_device *pci_dev = RTE_DEV_TO_PCI(dev);
|
||||||
|
#if RTE_VERSION < RTE_VERSION_NUM(20, 11, 0, 0)
|
||||||
|
if (pci_dev->kdrv == RTE_KDRV_VFIO) {
|
||||||
|
#else
|
||||||
if (pci_dev->kdrv == RTE_PCI_KDRV_VFIO) {
|
if (pci_dev->kdrv == RTE_PCI_KDRV_VFIO) {
|
||||||
|
#endif
|
||||||
/* This is a PCI device using vfio */
|
/* This is a PCI device using vfio */
|
||||||
g_vfio.device_ref--;
|
g_vfio.device_ref--;
|
||||||
}
|
}
|
||||||
@ -1362,7 +1370,11 @@ vtophys_iommu_init(void)
|
|||||||
RTE_DEV_FOREACH(dev, "bus=pci", &dev_iter) {
|
RTE_DEV_FOREACH(dev, "bus=pci", &dev_iter) {
|
||||||
struct rte_pci_device *pci_dev = RTE_DEV_TO_PCI(dev);
|
struct rte_pci_device *pci_dev = RTE_DEV_TO_PCI(dev);
|
||||||
|
|
||||||
|
#if RTE_VERSION < RTE_VERSION_NUM(20, 11, 0, 0)
|
||||||
|
if (pci_dev->kdrv == RTE_KDRV_VFIO) {
|
||||||
|
#else
|
||||||
if (pci_dev->kdrv == RTE_PCI_KDRV_VFIO) {
|
if (pci_dev->kdrv == RTE_PCI_KDRV_VFIO) {
|
||||||
|
#endif
|
||||||
/* This is a PCI device using vfio */
|
/* This is a PCI device using vfio */
|
||||||
g_vfio.device_ref++;
|
g_vfio.device_ref++;
|
||||||
}
|
}
|
||||||
|
@ -1010,8 +1010,10 @@ void
|
|||||||
spdk_reactors_start(void)
|
spdk_reactors_start(void)
|
||||||
{
|
{
|
||||||
struct spdk_reactor *reactor;
|
struct spdk_reactor *reactor;
|
||||||
|
struct spdk_cpuset tmp_cpumask = {};
|
||||||
uint32_t i, current_core;
|
uint32_t i, current_core;
|
||||||
int rc;
|
int rc;
|
||||||
|
char thread_name[32];
|
||||||
|
|
||||||
g_rusage_period = (CONTEXT_SWITCH_MONITOR_PERIOD * spdk_get_ticks_hz()) / SPDK_SEC_TO_USEC;
|
g_rusage_period = (CONTEXT_SWITCH_MONITOR_PERIOD * spdk_get_ticks_hz()) / SPDK_SEC_TO_USEC;
|
||||||
g_reactor_state = SPDK_REACTOR_STATE_RUNNING;
|
g_reactor_state = SPDK_REACTOR_STATE_RUNNING;
|
||||||
@ -1030,6 +1032,14 @@ spdk_reactors_start(void)
|
|||||||
assert(false);
|
assert(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For now, for each reactor spawn one thread. */
|
||||||
|
snprintf(thread_name, sizeof(thread_name), "reactor_%u", reactor->lcore);
|
||||||
|
|
||||||
|
spdk_cpuset_zero(&tmp_cpumask);
|
||||||
|
spdk_cpuset_set_cpu(&tmp_cpumask, i, true);
|
||||||
|
|
||||||
|
spdk_thread_create(thread_name, &tmp_cpumask);
|
||||||
}
|
}
|
||||||
spdk_cpuset_set_cpu(&g_reactor_core_mask, i, true);
|
spdk_cpuset_set_cpu(&g_reactor_core_mask, i, true);
|
||||||
}
|
}
|
||||||
|
@ -315,6 +315,16 @@ iscsi_parse_params(struct iscsi_param **params, const uint8_t *data,
|
|||||||
char *p;
|
char *p;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
/* Spec does not disallow TEXT PDUs with zero length, just return
|
||||||
|
* immediately in that case, since there is no param data to parse
|
||||||
|
* and any existing partial parameter would remain as-is.
|
||||||
|
*/
|
||||||
|
if (len == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(data != NULL);
|
||||||
|
|
||||||
/* strip the partial text parameters if previous PDU have C enabled */
|
/* strip the partial text parameters if previous PDU have C enabled */
|
||||||
if (partial_parameter && *partial_parameter) {
|
if (partial_parameter && *partial_parameter) {
|
||||||
for (i = 0; i < len && data[i] != '\0'; i++) {
|
for (i = 0; i < len && data[i] != '\0'; i++) {
|
||||||
|
@ -50,6 +50,7 @@
|
|||||||
#define GET_IO_LOOP_COUNT 16
|
#define GET_IO_LOOP_COUNT 16
|
||||||
#define NBD_BUSY_WAITING_MS 1000
|
#define NBD_BUSY_WAITING_MS 1000
|
||||||
#define NBD_BUSY_POLLING_INTERVAL_US 20000
|
#define NBD_BUSY_POLLING_INTERVAL_US 20000
|
||||||
|
#define NBD_IO_TIMEOUT_S 60
|
||||||
|
|
||||||
enum nbd_io_state_t {
|
enum nbd_io_state_t {
|
||||||
/* Receiving or ready to receive nbd request header */
|
/* Receiving or ready to receive nbd request header */
|
||||||
@ -922,6 +923,17 @@ nbd_start_complete(struct spdk_nbd_start_ctx *ctx)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef NBD_SET_TIMEOUT
|
||||||
|
rc = ioctl(ctx->nbd->dev_fd, NBD_SET_TIMEOUT, NBD_IO_TIMEOUT_S);
|
||||||
|
if (rc == -1) {
|
||||||
|
SPDK_ERRLOG("ioctl(NBD_SET_TIMEOUT) failed: %s\n", spdk_strerror(errno));
|
||||||
|
rc = -errno;
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
SPDK_NOTICELOG("ioctl(NBD_SET_TIMEOUT) is not supported.\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef NBD_FLAG_SEND_TRIM
|
#ifdef NBD_FLAG_SEND_TRIM
|
||||||
rc = ioctl(ctx->nbd->dev_fd, NBD_SET_FLAGS, NBD_FLAG_SEND_TRIM);
|
rc = ioctl(ctx->nbd->dev_fd, NBD_SET_FLAGS, NBD_FLAG_SEND_TRIM);
|
||||||
if (rc == -1) {
|
if (rc == -1) {
|
||||||
|
@ -418,8 +418,12 @@ spdk_nvme_ctrlr_alloc_io_qpair(struct spdk_nvme_ctrlr *ctrlr,
|
|||||||
rc = spdk_nvme_ctrlr_connect_io_qpair(ctrlr, qpair);
|
rc = spdk_nvme_ctrlr_connect_io_qpair(ctrlr, qpair);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
SPDK_ERRLOG("nvme_transport_ctrlr_connect_io_qpair() failed\n");
|
SPDK_ERRLOG("nvme_transport_ctrlr_connect_io_qpair() failed\n");
|
||||||
|
nvme_robust_mutex_lock(&ctrlr->ctrlr_lock);
|
||||||
|
nvme_ctrlr_proc_remove_io_qpair(qpair);
|
||||||
TAILQ_REMOVE(&ctrlr->active_io_qpairs, qpair, tailq);
|
TAILQ_REMOVE(&ctrlr->active_io_qpairs, qpair, tailq);
|
||||||
|
spdk_bit_array_set(ctrlr->free_io_qids, qpair->id);
|
||||||
nvme_transport_ctrlr_delete_io_qpair(ctrlr, qpair);
|
nvme_transport_ctrlr_delete_io_qpair(ctrlr, qpair);
|
||||||
|
nvme_robust_mutex_unlock(&ctrlr->ctrlr_lock);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
* BSD LICENSE
|
* BSD LICENSE
|
||||||
*
|
*
|
||||||
* Copyright (c) Intel Corporation. All rights reserved.
|
* Copyright (c) Intel Corporation. All rights reserved.
|
||||||
* Copyright (c) 2019, 2020 Mellanox Technologies LTD. All rights reserved.
|
* Copyright (c) 2019-2021 Mellanox Technologies LTD. All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@ -944,6 +944,11 @@ nvmf_rdma_resize_cq(struct spdk_nvmf_rdma_qpair *rqpair, struct spdk_nvmf_rdma_d
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rpoller->num_cqe != num_cqe) {
|
if (rpoller->num_cqe != num_cqe) {
|
||||||
|
if (device->context->device->transport_type == IBV_TRANSPORT_IWARP) {
|
||||||
|
SPDK_ERRLOG("iWARP doesn't support CQ resize. Current capacity %u, required %u\n"
|
||||||
|
"Using CQ of insufficient size may lead to CQ overrun\n", rpoller->num_cqe, num_cqe);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
if (required_num_wr > device->attr.max_cqe) {
|
if (required_num_wr > device->attr.max_cqe) {
|
||||||
SPDK_ERRLOG("RDMA CQE requirement (%d) exceeds device max_cqe limitation (%d)\n",
|
SPDK_ERRLOG("RDMA CQE requirement (%d) exceeds device max_cqe limitation (%d)\n",
|
||||||
required_num_wr, device->attr.max_cqe);
|
required_num_wr, device->attr.max_cqe);
|
||||||
@ -4106,19 +4111,24 @@ nvmf_rdma_qpair_abort_request(struct spdk_nvmf_qpair *qpair,
|
|||||||
struct spdk_nvmf_rdma_transport *rtransport;
|
struct spdk_nvmf_rdma_transport *rtransport;
|
||||||
struct spdk_nvmf_transport *transport;
|
struct spdk_nvmf_transport *transport;
|
||||||
uint16_t cid;
|
uint16_t cid;
|
||||||
uint32_t i;
|
uint32_t i, max_req_count;
|
||||||
struct spdk_nvmf_rdma_request *rdma_req_to_abort = NULL;
|
struct spdk_nvmf_rdma_request *rdma_req_to_abort = NULL, *rdma_req;
|
||||||
|
|
||||||
rqpair = SPDK_CONTAINEROF(qpair, struct spdk_nvmf_rdma_qpair, qpair);
|
rqpair = SPDK_CONTAINEROF(qpair, struct spdk_nvmf_rdma_qpair, qpair);
|
||||||
rtransport = SPDK_CONTAINEROF(qpair->transport, struct spdk_nvmf_rdma_transport, transport);
|
rtransport = SPDK_CONTAINEROF(qpair->transport, struct spdk_nvmf_rdma_transport, transport);
|
||||||
transport = &rtransport->transport;
|
transport = &rtransport->transport;
|
||||||
|
|
||||||
cid = req->cmd->nvme_cmd.cdw10_bits.abort.cid;
|
cid = req->cmd->nvme_cmd.cdw10_bits.abort.cid;
|
||||||
|
max_req_count = rqpair->srq == NULL ? rqpair->max_queue_depth : rqpair->poller->max_srq_depth;
|
||||||
|
|
||||||
for (i = 0; i < rqpair->max_queue_depth; i++) {
|
for (i = 0; i < max_req_count; i++) {
|
||||||
if (rqpair->resources->reqs[i].state != RDMA_REQUEST_STATE_FREE &&
|
rdma_req = &rqpair->resources->reqs[i];
|
||||||
rqpair->resources->reqs[i].req.cmd->nvme_cmd.cid == cid) {
|
/* When SRQ == NULL, rqpair has its own requests and req.qpair pointer always points to the qpair
|
||||||
rdma_req_to_abort = &rqpair->resources->reqs[i];
|
* When SRQ != NULL all rqpairs share common requests and qpair pointer is assigned when we start to
|
||||||
|
* process a request. So in both cases all requests which are not in FREE state have valid qpair ptr */
|
||||||
|
if (rdma_req->state != RDMA_REQUEST_STATE_FREE && rdma_req->req.cmd->nvme_cmd.cid == cid &&
|
||||||
|
rdma_req->req.qpair == qpair) {
|
||||||
|
rdma_req_to_abort = rdma_req;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -832,6 +832,8 @@ spdk_sock_write_config_json(struct spdk_json_write_ctx *w)
|
|||||||
spdk_json_write_named_uint32(w, "send_buf_size", opts.send_buf_size);
|
spdk_json_write_named_uint32(w, "send_buf_size", opts.send_buf_size);
|
||||||
spdk_json_write_named_bool(w, "enable_recv_pipe", opts.enable_recv_pipe);
|
spdk_json_write_named_bool(w, "enable_recv_pipe", opts.enable_recv_pipe);
|
||||||
spdk_json_write_named_bool(w, "enable_zerocopy_send", opts.enable_zerocopy_send);
|
spdk_json_write_named_bool(w, "enable_zerocopy_send", opts.enable_zerocopy_send);
|
||||||
|
spdk_json_write_named_bool(w, "enable_quickack", opts.enable_quickack);
|
||||||
|
spdk_json_write_named_bool(w, "enable_placement_id", opts.enable_placement_id);
|
||||||
spdk_json_write_object_end(w);
|
spdk_json_write_object_end(w);
|
||||||
spdk_json_write_object_end(w);
|
spdk_json_write_object_end(w);
|
||||||
} else {
|
} else {
|
||||||
|
@ -85,8 +85,8 @@ int
|
|||||||
spdk_fd_group_add(struct spdk_fd_group *fgrp,
|
spdk_fd_group_add(struct spdk_fd_group *fgrp,
|
||||||
int efd, spdk_fd_fn fn, void *arg)
|
int efd, spdk_fd_fn fn, void *arg)
|
||||||
{
|
{
|
||||||
struct event_handler *ehdlr;
|
struct event_handler *ehdlr = NULL;
|
||||||
struct epoll_event epevent;
|
struct epoll_event epevent = {0};
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
/* parameter checking */
|
/* parameter checking */
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#include "spdk/barrier.h"
|
#include "spdk/barrier.h"
|
||||||
#include "spdk/vhost.h"
|
#include "spdk/vhost.h"
|
||||||
#include "vhost_internal.h"
|
#include "vhost_internal.h"
|
||||||
|
#include <rte_version.h>
|
||||||
|
|
||||||
#include "spdk_internal/vhost_user.h"
|
#include "spdk_internal/vhost_user.h"
|
||||||
|
|
||||||
@ -331,7 +332,11 @@ vhost_register_unix_socket(const char *path, const char *ctrl_name,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if RTE_VERSION < RTE_VERSION_NUM(20, 8, 0, 0)
|
||||||
if (rte_vhost_driver_register(path, 0) != 0) {
|
if (rte_vhost_driver_register(path, 0) != 0) {
|
||||||
|
#else
|
||||||
|
if (rte_vhost_driver_register(path, RTE_VHOST_USER_ASYNC_COPY) != 0) {
|
||||||
|
#endif
|
||||||
SPDK_ERRLOG("Could not register controller %s with vhost library\n", ctrl_name);
|
SPDK_ERRLOG("Could not register controller %s with vhost library\n", ctrl_name);
|
||||||
SPDK_ERRLOG("Check if domain socket %s already exists\n", path);
|
SPDK_ERRLOG("Check if domain socket %s already exists\n", path);
|
||||||
return -EIO;
|
return -EIO;
|
||||||
|
@ -888,6 +888,7 @@ static int
|
|||||||
vhost_parse_core_mask(const char *mask, struct spdk_cpuset *cpumask)
|
vhost_parse_core_mask(const char *mask, struct spdk_cpuset *cpumask)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
struct spdk_cpuset negative_vhost_mask;
|
||||||
|
|
||||||
if (cpumask == NULL) {
|
if (cpumask == NULL) {
|
||||||
return -1;
|
return -1;
|
||||||
@ -904,6 +905,16 @@ vhost_parse_core_mask(const char *mask, struct spdk_cpuset *cpumask)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spdk_cpuset_copy(&negative_vhost_mask, &g_vhost_core_mask);
|
||||||
|
spdk_cpuset_negate(&negative_vhost_mask);
|
||||||
|
spdk_cpuset_and(&negative_vhost_mask, cpumask);
|
||||||
|
|
||||||
|
if (spdk_cpuset_count(&negative_vhost_mask) != 0) {
|
||||||
|
SPDK_ERRLOG("one of selected cpu is outside of core mask(=%s)\n",
|
||||||
|
spdk_cpuset_fmt(&g_vhost_core_mask));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
spdk_cpuset_and(cpumask, &g_vhost_core_mask);
|
spdk_cpuset_and(cpumask, &g_vhost_core_mask);
|
||||||
|
|
||||||
if (spdk_cpuset_count(cpumask) == 0) {
|
if (spdk_cpuset_count(cpumask) == 0) {
|
||||||
|
@ -967,7 +967,7 @@ bdev_ocssd_push_media_events(struct nvme_bdev_ns *nvme_ns,
|
|||||||
TAILQ_FOREACH(nvme_bdev, &nvme_ns->bdevs, tailq) {
|
TAILQ_FOREACH(nvme_bdev, &nvme_ns->bdevs, tailq) {
|
||||||
ocssd_bdev = SPDK_CONTAINEROF(nvme_bdev, struct ocssd_bdev, nvme_bdev);
|
ocssd_bdev = SPDK_CONTAINEROF(nvme_bdev, struct ocssd_bdev, nvme_bdev);
|
||||||
if (bdev_ocssd_lba_in_range(ocssd_bdev, ocssd_ns, chunk_entry->lba)) {
|
if (bdev_ocssd_lba_in_range(ocssd_bdev, ocssd_ns, chunk_entry->lba)) {
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,12 +2,12 @@
|
|||||||
%bcond_with doc
|
%bcond_with doc
|
||||||
|
|
||||||
Name: spdk
|
Name: spdk
|
||||||
Version: master
|
Version: 21.01.x
|
||||||
Release: 0%{?dist}
|
Release: 0%{?dist}
|
||||||
Epoch: 0
|
Epoch: 0
|
||||||
URL: http://spdk.io
|
URL: http://spdk.io
|
||||||
|
|
||||||
Source: https://github.com/spdk/spdk/archive/master.tar.gz
|
Source: https://github.com/spdk/spdk/archive/v21.01.x.tar.gz
|
||||||
Summary: Set of libraries and utilities for high performance user-mode storage
|
Summary: Set of libraries and utilities for high performance user-mode storage
|
||||||
|
|
||||||
%define package_version %{epoch}:%{version}-%{release}
|
%define package_version %{epoch}:%{version}-%{release}
|
||||||
@ -22,7 +22,7 @@ License: BSD
|
|||||||
ExclusiveArch: x86_64
|
ExclusiveArch: x86_64
|
||||||
|
|
||||||
BuildRequires: gcc gcc-c++ make
|
BuildRequires: gcc gcc-c++ make
|
||||||
BuildRequires: dpdk-devel, numactl-devel
|
BuildRequires: dpdk-devel, numactl-devel, ncurses-devel
|
||||||
BuildRequires: libiscsi-devel, libaio-devel, openssl-devel, libuuid-devel
|
BuildRequires: libiscsi-devel, libaio-devel, openssl-devel, libuuid-devel
|
||||||
BuildRequires: libibverbs-devel, librdmacm-devel
|
BuildRequires: libibverbs-devel, librdmacm-devel
|
||||||
%if %{with doc}
|
%if %{with doc}
|
||||||
@ -32,6 +32,7 @@ BuildRequires: doxygen mscgen graphviz
|
|||||||
# Install dependencies
|
# Install dependencies
|
||||||
Requires: dpdk >= 19.11, numactl-libs, openssl-libs
|
Requires: dpdk >= 19.11, numactl-libs, openssl-libs
|
||||||
Requires: libiscsi, libaio, libuuid
|
Requires: libiscsi, libaio, libuuid
|
||||||
|
Requires: python3-configshell, python3-pexpect
|
||||||
# NVMe over Fabrics
|
# NVMe over Fabrics
|
||||||
Requires: librdmacm, librdmacm
|
Requires: librdmacm, librdmacm
|
||||||
Requires(post): /sbin/ldconfig
|
Requires(post): /sbin/ldconfig
|
||||||
|
@ -9,6 +9,7 @@ SPDK_TEST_ISCSI_INITIATOR=0
|
|||||||
SPDK_TEST_NVME=0
|
SPDK_TEST_NVME=0
|
||||||
SPDK_TEST_NVME_CLI=0
|
SPDK_TEST_NVME_CLI=0
|
||||||
SPDK_TEST_NVMF=1
|
SPDK_TEST_NVMF=1
|
||||||
|
SPDK_TEST_VFIOUSER=1
|
||||||
SPDK_TEST_RBD=0
|
SPDK_TEST_RBD=0
|
||||||
SPDK_TEST_CRYPTO=0
|
SPDK_TEST_CRYPTO=0
|
||||||
SPDK_TEST_OCF=0
|
SPDK_TEST_OCF=0
|
||||||
|
@ -81,6 +81,8 @@ export SPDK_TEST_NVME_CLI
|
|||||||
export SPDK_TEST_NVME_CUSE
|
export SPDK_TEST_NVME_CUSE
|
||||||
: ${SPDK_TEST_NVMF=0}
|
: ${SPDK_TEST_NVMF=0}
|
||||||
export SPDK_TEST_NVMF
|
export SPDK_TEST_NVMF
|
||||||
|
: ${SPDK_TEST_VFIOUSER=0}
|
||||||
|
export SPDK_TEST_VFIOUSER
|
||||||
: ${SPDK_TEST_NVMF_TRANSPORT="rdma"}
|
: ${SPDK_TEST_NVMF_TRANSPORT="rdma"}
|
||||||
export SPDK_TEST_NVMF_TRANSPORT
|
export SPDK_TEST_NVMF_TRANSPORT
|
||||||
: ${SPDK_TEST_RBD=0}
|
: ${SPDK_TEST_RBD=0}
|
||||||
@ -422,6 +424,10 @@ function get_config_params() {
|
|||||||
config_params+=' --with-raid5'
|
config_params+=' --with-raid5'
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ $SPDK_TEST_VFIOUSER -eq 1 ]; then
|
||||||
|
config_params+=' --with-vfio-user'
|
||||||
|
fi
|
||||||
|
|
||||||
# Check whether liburing library header exists
|
# Check whether liburing library header exists
|
||||||
if [ -f /usr/include/liburing/io_uring.h ] && [ $SPDK_TEST_URING -eq 1 ]; then
|
if [ -f /usr/include/liburing/io_uring.h ] && [ $SPDK_TEST_URING -eq 1 ]; then
|
||||||
config_params+=' --with-uring'
|
config_params+=' --with-uring'
|
||||||
|
@ -185,6 +185,7 @@ SPDK_TEST_ISCSI_INITIATOR=1
|
|||||||
SPDK_TEST_NVME=1
|
SPDK_TEST_NVME=1
|
||||||
SPDK_TEST_NVME_CLI=1
|
SPDK_TEST_NVME_CLI=1
|
||||||
SPDK_TEST_NVMF=1
|
SPDK_TEST_NVMF=1
|
||||||
|
SPDK_TEST_VFIOUSER=1
|
||||||
SPDK_TEST_RBD=1
|
SPDK_TEST_RBD=1
|
||||||
SPDK_TEST_BLOCKDEV=1
|
SPDK_TEST_BLOCKDEV=1
|
||||||
SPDK_TEST_BLOBFS=1
|
SPDK_TEST_BLOBFS=1
|
||||||
|
@ -49,17 +49,6 @@ function confirm_abi_deps() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
cat << EOF > ${suppression_file}
|
cat << EOF > ${suppression_file}
|
||||||
[suppress_type]
|
|
||||||
name = spdk_nvme_ctrlr_data
|
|
||||||
[suppress_type]
|
|
||||||
type_kind = enum
|
|
||||||
changed_enumerators = SPDK_BDEV_NUM_IO_TYPES
|
|
||||||
[suppress_type]
|
|
||||||
name = spdk_env_opts
|
|
||||||
[suppress_type]
|
|
||||||
name = spdk_app_opts
|
|
||||||
[suppress_type]
|
|
||||||
name = spdk_thread
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
for object in "$libdir"/libspdk_*.so; do
|
for object in "$libdir"/libspdk_*.so; do
|
||||||
|
@ -41,7 +41,7 @@ run_test "nvmf_invalid" test/nvmf/target/invalid.sh "${TEST_ARGS[@]}"
|
|||||||
run_test "nvmf_abort" test/nvmf/target/abort.sh "${TEST_ARGS[@]}"
|
run_test "nvmf_abort" test/nvmf/target/abort.sh "${TEST_ARGS[@]}"
|
||||||
run_test "nvmf_ns_hotplug_stress" test/nvmf/target/ns_hotplug_stress.sh "${TEST_ARGS[@]}"
|
run_test "nvmf_ns_hotplug_stress" test/nvmf/target/ns_hotplug_stress.sh "${TEST_ARGS[@]}"
|
||||||
|
|
||||||
if grep -q '#define SPDK_CONFIG_VFIO_USER 1' $rootdir/include/spdk/config.h; then
|
if [ $SPDK_TEST_VFIOUSER -eq 1 ]; then
|
||||||
run_test "nvmf_vfio_user" test/nvmf/target/nvmf_vfio_user.sh "${TEST_ARGS[@]}"
|
run_test "nvmf_vfio_user" test/nvmf/target/nvmf_vfio_user.sh "${TEST_ARGS[@]}"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"cpumask": "$(S)",
|
"cpumask": "0x3",
|
||||||
"ctrlr": "vhost_scsi1",
|
"ctrlr": "vhost_scsi1",
|
||||||
"delay_base_us": 20,
|
"delay_base_us": 20,
|
||||||
"iops_threshold": 1000000,
|
"iops_threshold": 1000000,
|
||||||
|
@ -1993,6 +1993,43 @@ pdu_hdr_op_data_test(void)
|
|||||||
g_task_pool_is_empty = false;
|
g_task_pool_is_empty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Test an ISCSI_OP_TEXT PDU with CONTINUE bit set but
|
||||||
|
* no data.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
empty_text_with_cbit_test(void)
|
||||||
|
{
|
||||||
|
struct spdk_iscsi_sess sess = {};
|
||||||
|
struct spdk_iscsi_conn conn = {};
|
||||||
|
struct spdk_scsi_dev dev = {};
|
||||||
|
struct spdk_iscsi_pdu *req_pdu;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
req_pdu = iscsi_get_pdu(&conn);
|
||||||
|
|
||||||
|
sess.ExpCmdSN = 0;
|
||||||
|
sess.MaxCmdSN = 64;
|
||||||
|
sess.session_type = SESSION_TYPE_NORMAL;
|
||||||
|
sess.MaxBurstLength = 1024;
|
||||||
|
|
||||||
|
conn.full_feature = 1;
|
||||||
|
conn.sess = &sess;
|
||||||
|
conn.dev = &dev;
|
||||||
|
conn.state = ISCSI_CONN_STATE_RUNNING;
|
||||||
|
|
||||||
|
memset(&req_pdu->bhs, 0, sizeof(req_pdu->bhs));
|
||||||
|
req_pdu->bhs.opcode = ISCSI_OP_TEXT;
|
||||||
|
req_pdu->bhs.flags = ISCSI_TEXT_CONTINUE;
|
||||||
|
|
||||||
|
rc = iscsi_pdu_hdr_handle(&conn, req_pdu);
|
||||||
|
CU_ASSERT(rc == 0);
|
||||||
|
CU_ASSERT(!req_pdu->is_rejected);
|
||||||
|
rc = iscsi_pdu_payload_handle(&conn, req_pdu);
|
||||||
|
CU_ASSERT(rc == 0);
|
||||||
|
|
||||||
|
iscsi_put_pdu(req_pdu);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -2024,6 +2061,7 @@ main(int argc, char **argv)
|
|||||||
CU_ADD_TEST(suite, pdu_hdr_op_task_mgmt_test);
|
CU_ADD_TEST(suite, pdu_hdr_op_task_mgmt_test);
|
||||||
CU_ADD_TEST(suite, pdu_hdr_op_nopout_test);
|
CU_ADD_TEST(suite, pdu_hdr_op_nopout_test);
|
||||||
CU_ADD_TEST(suite, pdu_hdr_op_data_test);
|
CU_ADD_TEST(suite, pdu_hdr_op_data_test);
|
||||||
|
CU_ADD_TEST(suite, empty_text_with_cbit_test);
|
||||||
|
|
||||||
CU_basic_set_mode(CU_BRM_VERBOSE);
|
CU_basic_set_mode(CU_BRM_VERBOSE);
|
||||||
CU_basic_run_tests();
|
CU_basic_run_tests();
|
||||||
|
@ -264,6 +264,14 @@ parse_valid_test(void)
|
|||||||
EXPECT_VAL("F", "IIII");
|
EXPECT_VAL("F", "IIII");
|
||||||
CU_ASSERT_PTR_NULL(partial_parameter);
|
CU_ASSERT_PTR_NULL(partial_parameter);
|
||||||
|
|
||||||
|
/* partial parameter: NULL data */
|
||||||
|
/* It is technically allowed to have a TEXT PDU with no data, yet
|
||||||
|
* CONTINUE bit is enabled - make sure we handle that case correctly.
|
||||||
|
*/
|
||||||
|
rc = iscsi_parse_params(¶ms, NULL, 0, true, &partial_parameter);
|
||||||
|
CU_ASSERT(rc == 0);
|
||||||
|
CU_ASSERT_PTR_NULL(partial_parameter);
|
||||||
|
|
||||||
/* Second partial parameter is the only parameter */
|
/* Second partial parameter is the only parameter */
|
||||||
PARSE("OOOO", true, &partial_parameter);
|
PARSE("OOOO", true, &partial_parameter);
|
||||||
CU_ASSERT_STRING_EQUAL(partial_parameter, "OOOO");
|
CU_ASSERT_STRING_EQUAL(partial_parameter, "OOOO");
|
||||||
|
@ -2162,6 +2162,27 @@ test_nvme_ctrlr_init_set_keep_alive_timeout(void)
|
|||||||
nvme_ctrlr_destruct(&ctrlr);
|
nvme_ctrlr_destruct(&ctrlr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_alloc_io_qpair_fail(void)
|
||||||
|
{
|
||||||
|
struct spdk_nvme_ctrlr ctrlr = {};
|
||||||
|
struct spdk_nvme_qpair *q0;
|
||||||
|
|
||||||
|
setup_qpairs(&ctrlr, 1);
|
||||||
|
|
||||||
|
/* Modify the connect_qpair return code to inject a failure */
|
||||||
|
g_connect_qpair_return_code = 1;
|
||||||
|
|
||||||
|
/* Attempt to allocate a qpair, this should fail */
|
||||||
|
q0 = spdk_nvme_ctrlr_alloc_io_qpair(&ctrlr, NULL, 0);
|
||||||
|
SPDK_CU_ASSERT_FATAL(q0 == NULL);
|
||||||
|
|
||||||
|
/* Verify that the qpair is removed from the lists */
|
||||||
|
SPDK_CU_ASSERT_FATAL(TAILQ_EMPTY(&ctrlr.active_io_qpairs));
|
||||||
|
|
||||||
|
cleanup_qpairs(&ctrlr);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
CU_pSuite suite = NULL;
|
CU_pSuite suite = NULL;
|
||||||
@ -2200,6 +2221,7 @@ int main(int argc, char **argv)
|
|||||||
CU_ADD_TEST(suite, test_nvme_ctrlr_init_set_nvmf_ioccsz);
|
CU_ADD_TEST(suite, test_nvme_ctrlr_init_set_nvmf_ioccsz);
|
||||||
CU_ADD_TEST(suite, test_nvme_ctrlr_init_set_num_queues);
|
CU_ADD_TEST(suite, test_nvme_ctrlr_init_set_num_queues);
|
||||||
CU_ADD_TEST(suite, test_nvme_ctrlr_init_set_keep_alive_timeout);
|
CU_ADD_TEST(suite, test_nvme_ctrlr_init_set_keep_alive_timeout);
|
||||||
|
CU_ADD_TEST(suite, test_alloc_io_qpair_fail);
|
||||||
|
|
||||||
CU_basic_set_mode(CU_BRM_VERBOSE);
|
CU_basic_set_mode(CU_BRM_VERBOSE);
|
||||||
CU_basic_run_tests();
|
CU_basic_run_tests();
|
||||||
|
@ -267,28 +267,56 @@ create_controller_test(void)
|
|||||||
int ret;
|
int ret;
|
||||||
char long_name[PATH_MAX];
|
char long_name[PATH_MAX];
|
||||||
|
|
||||||
spdk_cpuset_set_cpu(&g_vhost_core_mask, 0, true);
|
spdk_cpuset_parse(&g_vhost_core_mask, "0xf");
|
||||||
|
|
||||||
|
/* Create device with cpumask implcitly matching whole application */
|
||||||
|
ret = alloc_vdev(&vdev, "vdev_name_0", NULL);
|
||||||
|
SPDK_CU_ASSERT_FATAL(ret == 0 && vdev);
|
||||||
|
SPDK_CU_ASSERT_FATAL(!strcmp(spdk_cpuset_fmt(spdk_thread_get_cpumask(vdev->thread)), "f"));
|
||||||
|
cleanup_vdev(vdev);
|
||||||
|
|
||||||
|
/* Create device with cpumask matching whole application */
|
||||||
|
ret = alloc_vdev(&vdev, "vdev_name_0", "0xf");
|
||||||
|
SPDK_CU_ASSERT_FATAL(ret == 0 && vdev);
|
||||||
|
SPDK_CU_ASSERT_FATAL(!strcmp(spdk_cpuset_fmt(spdk_thread_get_cpumask(vdev->thread)), "f"));
|
||||||
|
cleanup_vdev(vdev);
|
||||||
|
|
||||||
|
/* Create device with single core in cpumask */
|
||||||
|
ret = alloc_vdev(&vdev, "vdev_name_0", "0x2");
|
||||||
|
SPDK_CU_ASSERT_FATAL(ret == 0 && vdev);
|
||||||
|
SPDK_CU_ASSERT_FATAL(!strcmp(spdk_cpuset_fmt(spdk_thread_get_cpumask(vdev->thread)), "2"));
|
||||||
|
cleanup_vdev(vdev);
|
||||||
|
|
||||||
|
/* Create device with cpumask spanning two cores */
|
||||||
|
ret = alloc_vdev(&vdev, "vdev_name_0", "0x3");
|
||||||
|
SPDK_CU_ASSERT_FATAL(ret == 0 && vdev);
|
||||||
|
SPDK_CU_ASSERT_FATAL(!strcmp(spdk_cpuset_fmt(spdk_thread_get_cpumask(vdev->thread)), "3"));
|
||||||
|
cleanup_vdev(vdev);
|
||||||
|
|
||||||
|
/* Create device with incorrect cpumask outside of application cpumask */
|
||||||
|
ret = alloc_vdev(&vdev, "vdev_name_0", "0xf0");
|
||||||
|
SPDK_CU_ASSERT_FATAL(ret != 0);
|
||||||
|
|
||||||
|
/* Create device with incorrect cpumask partially outside of application cpumask */
|
||||||
|
ret = alloc_vdev(&vdev, "vdev_name_0", "0xff");
|
||||||
|
SPDK_CU_ASSERT_FATAL(ret != 0);
|
||||||
|
|
||||||
/* Create device with no name */
|
/* Create device with no name */
|
||||||
ret = alloc_vdev(&vdev, NULL, "0x1");
|
ret = alloc_vdev(&vdev, NULL, NULL);
|
||||||
CU_ASSERT(ret != 0);
|
|
||||||
|
|
||||||
/* Create device with incorrect cpumask */
|
|
||||||
ret = alloc_vdev(&vdev, "vdev_name_0", "0x2");
|
|
||||||
CU_ASSERT(ret != 0);
|
CU_ASSERT(ret != 0);
|
||||||
|
|
||||||
/* Create device with too long name and path */
|
/* Create device with too long name and path */
|
||||||
memset(long_name, 'x', sizeof(long_name));
|
memset(long_name, 'x', sizeof(long_name));
|
||||||
long_name[PATH_MAX - 1] = 0;
|
long_name[PATH_MAX - 1] = 0;
|
||||||
snprintf(dev_dirname, sizeof(dev_dirname), "some_path/");
|
snprintf(dev_dirname, sizeof(dev_dirname), "some_path/");
|
||||||
ret = alloc_vdev(&vdev, long_name, "0x1");
|
ret = alloc_vdev(&vdev, long_name, NULL);
|
||||||
CU_ASSERT(ret != 0);
|
CU_ASSERT(ret != 0);
|
||||||
dev_dirname[0] = 0;
|
dev_dirname[0] = 0;
|
||||||
|
|
||||||
/* Create device when device name is already taken */
|
/* Create device when device name is already taken */
|
||||||
ret = alloc_vdev(&vdev, "vdev_name_0", "0x1");
|
ret = alloc_vdev(&vdev, "vdev_name_0", NULL);
|
||||||
SPDK_CU_ASSERT_FATAL(ret == 0 && vdev);
|
SPDK_CU_ASSERT_FATAL(ret == 0 && vdev);
|
||||||
ret = alloc_vdev(&vdev2, "vdev_name_0", "0x1");
|
ret = alloc_vdev(&vdev2, "vdev_name_0", NULL);
|
||||||
CU_ASSERT(ret != 0);
|
CU_ASSERT(ret != 0);
|
||||||
cleanup_vdev(vdev);
|
cleanup_vdev(vdev);
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ function err_cleanup() {
|
|||||||
|
|
||||||
# start vhost and configure it
|
# start vhost and configure it
|
||||||
trap 'err_cleanup; exit 1' SIGINT SIGTERM EXIT
|
trap 'err_cleanup; exit 1' SIGINT SIGTERM EXIT
|
||||||
$SPDK_BIN_DIR/vhost &
|
$SPDK_BIN_DIR/vhost -m 0xf &
|
||||||
vhost_pid=$!
|
vhost_pid=$!
|
||||||
waitforlisten $vhost_pid
|
waitforlisten $vhost_pid
|
||||||
|
|
||||||
@ -35,17 +35,22 @@ rpc_cmd vhost_scsi_controller_add_target naa.Nvme0n1_scsi0.0 0 Nvme0n1p0
|
|||||||
rpc_cmd vhost_scsi_controller_add_target naa.Nvme0n1_scsi0.0 1 Nvme0n1p1
|
rpc_cmd vhost_scsi_controller_add_target naa.Nvme0n1_scsi0.0 1 Nvme0n1p1
|
||||||
rpc_cmd vhost_scsi_controller_add_target naa.Nvme0n1_scsi0.0 2 Nvme0n1p2
|
rpc_cmd vhost_scsi_controller_add_target naa.Nvme0n1_scsi0.0 2 Nvme0n1p2
|
||||||
rpc_cmd vhost_scsi_controller_add_target naa.Nvme0n1_scsi0.0 3 Nvme0n1p3
|
rpc_cmd vhost_scsi_controller_add_target naa.Nvme0n1_scsi0.0 3 Nvme0n1p3
|
||||||
|
[[ "$(rpc_cmd vhost_get_controllers -n naa.Nvme0n1_scsi0.0 | jq -r '.[].cpumask')" == "0xf" ]]
|
||||||
|
|
||||||
rpc_cmd vhost_create_blk_controller naa.Nvme0n1_blk0.0 Nvme0n1p4
|
rpc_cmd vhost_create_blk_controller naa.Nvme0n1_blk0.0 Nvme0n1p4 --cpumask 0xf
|
||||||
rpc_cmd vhost_create_blk_controller naa.Nvme0n1_blk1.0 Nvme0n1p5
|
[[ "$(rpc_cmd vhost_get_controllers -n naa.Nvme0n1_blk0.0 | jq -r '.[].cpumask')" == "0xf" ]]
|
||||||
|
rpc_cmd vhost_create_blk_controller naa.Nvme0n1_blk1.0 Nvme0n1p5 --cpumask 0x1
|
||||||
|
[[ "$(rpc_cmd vhost_get_controllers -n naa.Nvme0n1_blk1.0 | jq -r '.[].cpumask')" == "0x1" ]]
|
||||||
|
|
||||||
rpc_cmd bdev_malloc_create 128 512 --name Malloc0
|
rpc_cmd bdev_malloc_create 128 512 --name Malloc0
|
||||||
rpc_cmd vhost_create_scsi_controller naa.Malloc0.0
|
rpc_cmd vhost_create_scsi_controller naa.Malloc0.0 --cpumask 0x2
|
||||||
rpc_cmd vhost_scsi_controller_add_target naa.Malloc0.0 0 Malloc0
|
rpc_cmd vhost_scsi_controller_add_target naa.Malloc0.0 0 Malloc0
|
||||||
|
[[ "$(rpc_cmd vhost_get_controllers -n naa.Malloc0.0 | jq -r '.[].cpumask')" == "0x2" ]]
|
||||||
|
|
||||||
rpc_cmd bdev_malloc_create 128 4096 --name Malloc1
|
rpc_cmd bdev_malloc_create 128 4096 --name Malloc1
|
||||||
rpc_cmd vhost_create_scsi_controller naa.Malloc1.0
|
rpc_cmd vhost_create_scsi_controller naa.Malloc1.0 --cpumask 0xc
|
||||||
rpc_cmd vhost_scsi_controller_add_target naa.Malloc1.0 0 Malloc1
|
rpc_cmd vhost_scsi_controller_add_target naa.Malloc1.0 0 Malloc1
|
||||||
|
[[ "$(rpc_cmd vhost_get_controllers -n naa.Malloc1.0 | jq -r '.[].cpumask')" == "0xc" ]]
|
||||||
|
|
||||||
# start a dummy app, create vhost bdevs in it, then dump the config for FIO
|
# start a dummy app, create vhost bdevs in it, then dump the config for FIO
|
||||||
$SPDK_BIN_DIR/spdk_tgt -r /tmp/spdk2.sock -g &
|
$SPDK_BIN_DIR/spdk_tgt -r /tmp/spdk2.sock -g &
|
||||||
|
@ -63,7 +63,7 @@ notice "==============="
|
|||||||
notice ""
|
notice ""
|
||||||
notice "running SPDK"
|
notice "running SPDK"
|
||||||
notice ""
|
notice ""
|
||||||
vhost_run 0
|
vhost_run 0 "-m 0xf"
|
||||||
notice ""
|
notice ""
|
||||||
rpc_py="$rootdir/scripts/rpc.py -s $(get_vhost_dir 0)/rpc.sock"
|
rpc_py="$rootdir/scripts/rpc.py -s $(get_vhost_dir 0)/rpc.sock"
|
||||||
$rpc_py bdev_malloc_create -b Malloc0 128 4096
|
$rpc_py bdev_malloc_create -b Malloc0 128 4096
|
||||||
@ -88,8 +88,13 @@ if $rpc_py vhost_delete_controller unk0 > /dev/null; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# SCSI
|
# SCSI
|
||||||
notice "Trying to create scsi controller with incorrect cpumask"
|
notice "Trying to create scsi controller with incorrect cpumask outside of application cpumask"
|
||||||
if $rpc_py vhost_create_scsi_controller vhost.invalid.cpumask --cpumask 0x2; then
|
if $rpc_py vhost_create_scsi_controller vhost.invalid.cpumask --cpumask 0xf0; then
|
||||||
|
error "Creating scsi controller with incorrect cpumask succeeded, but it shouldn't"
|
||||||
|
fi
|
||||||
|
|
||||||
|
notice "Trying to create scsi controller with incorrect cpumask partially outside of application cpumask"
|
||||||
|
if $rpc_py vhost_create_scsi_controller vhost.invalid.cpumask --cpumask 0xff; then
|
||||||
error "Creating scsi controller with incorrect cpumask succeeded, but it shouldn't"
|
error "Creating scsi controller with incorrect cpumask succeeded, but it shouldn't"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -167,8 +172,13 @@ notice "Re-adding device 0 to naa.0"
|
|||||||
$rpc_py vhost_scsi_controller_add_target naa.0 0 Malloc0
|
$rpc_py vhost_scsi_controller_add_target naa.0 0 Malloc0
|
||||||
|
|
||||||
# BLK
|
# BLK
|
||||||
notice "Trying to create block controller with incorrect cpumask"
|
notice "Trying to create block controller with incorrect cpumask outside of application cpumask"
|
||||||
if $rpc_py vhost_create_blk_controller vhost.invalid.cpumask Malloc0 --cpumask 0x2; then
|
if $rpc_py vhost_create_blk_controller vhost.invalid.cpumask Malloc0 --cpumask 0xf0; then
|
||||||
|
error "Creating block controller with incorrect cpumask succeeded, but it shouldn't"
|
||||||
|
fi
|
||||||
|
|
||||||
|
notice "Trying to create block controller with incorrect cpumask partially outside of application cpumask"
|
||||||
|
if $rpc_py vhost_create_blk_controller vhost.invalid.cpumask Malloc0 --cpumask 0xff; then
|
||||||
error "Creating block controller with incorrect cpumask succeeded, but it shouldn't"
|
error "Creating block controller with incorrect cpumask succeeded, but it shouldn't"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user