lib: add a hotplug lib for device

The hotplug lib can be used for pcie devices
such as nvme, virtio_blk and virtio scsi.

For the sigbus handler, there is only one in a
process and it should handle all the devices.

And align nvme to the hotplug lib

Add the ADD uevent support for allowing the
device hotplug.

Change-Id: I82cd3b4af38ca24cee8b041a215a85c4a69e60f7
Signed-off-by: Jin Yu <jin.yu@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/5653
Community-CI: Broadcom CI
Community-CI: Mellanox Build Bot
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: <dongx.yi@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
This commit is contained in:
Jin Yu 2020-12-17 23:18:53 +08:00 committed by Tomasz Zawadzki
parent 1c3bc9d64d
commit 59237d22b8
18 changed files with 346 additions and 536 deletions

View File

@ -1333,6 +1333,56 @@ int spdk_mem_reserve(void *vaddr, size_t len);
*/
int spdk_mem_get_fd_and_offset(void *vaddr, uint64_t *offset);
enum spdk_pci_event_type {
SPDK_UEVENT_ADD = 0,
SPDK_UEVENT_REMOVE = 1,
};
struct spdk_pci_event {
enum spdk_pci_event_type action;
struct spdk_pci_addr traddr;
};
typedef void (*spdk_pci_error_handler)(siginfo_t *info, void *ctx);
/**
* Begin listening for PCI bus events. This is used to detect hot-insert and
* hot-remove events. Once the system is listening, events may be retrieved
* by calling spdk_pci_get_event() periodically.
*
* \return negative errno on failure, otherwise, return a file descriptor
* that may be later passed to spdk_pci_get_event().
*/
int spdk_pci_event_listen(void);
/**
* Get the next PCI bus event.
*
* \param fd A file descriptor returned by spdk_pci_event_listen()
* \param event An event on the PCI bus
*
* \return Negative errno on failure. 0 for no event. A positive number
* when an event has been returned
*/
int spdk_pci_get_event(int fd, struct spdk_pci_event *event);
/**
* Register a signal handler to handle bus errors on the PCI bus
*
* \param sighandler Signal bus handler of the PCI bus
* \param ctx The arg pass to the registered signal bus handler.
*
* \return negative errno on failure, otherwise it means successful
*/
int spdk_pci_register_error_handler(spdk_pci_error_handler sighandler, void *ctx);
/**
* Register a signal handler to handle bus errors on the PCI bus
*
* \param sighandler Signal bus handler of the PCI bus
*/
void spdk_pci_unregister_error_handler(spdk_pci_error_handler sighandler);
#ifdef __cplusplus
}
#endif

View File

@ -40,6 +40,7 @@ SO_MINOR := 0
CFLAGS += $(ENV_CFLAGS)
C_SRCS = env.c memory.c pci.c init.c threads.c
C_SRCS += pci_ioat.c pci_virtio.c pci_vmd.c pci_idxd.c
C_SRCS += pci_event.c sigbus_handler.c
LIBNAME = env_dpdk
SPDK_MAP_FILE = $(abspath $(CURDIR)/spdk_env_dpdk.map)

View File

@ -35,8 +35,7 @@
#include "spdk/string.h"
#include "spdk/log.h"
#include "nvme_uevent.h"
#include "spdk/env.h"
#ifdef __linux__
@ -46,12 +45,12 @@
#define SPDK_UEVENT_RECVBUF_SIZE 1024 * 1024
int
nvme_uevent_connect(void)
spdk_pci_event_listen(void)
{
struct sockaddr_nl addr;
int netlink_fd;
int size = SPDK_UEVENT_RECVBUF_SIZE;
int flag;
int flag, rc;
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
@ -60,58 +59,79 @@ nvme_uevent_connect(void)
netlink_fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
if (netlink_fd < 0) {
return -1;
SPDK_ERRLOG("Failed to create netlink socket\n");
return netlink_fd;
}
setsockopt(netlink_fd, SOL_SOCKET, SO_RCVBUFFORCE, &size, sizeof(size));
if (setsockopt(netlink_fd, SOL_SOCKET, SO_RCVBUFFORCE, &size, sizeof(size)) < 0) {
rc = errno;
SPDK_ERRLOG("Failed to set socket option\n");
return -rc;
}
flag = fcntl(netlink_fd, F_GETFL);
if (fcntl(netlink_fd, F_SETFL, flag | O_NONBLOCK) < 0) {
SPDK_ERRLOG("fcntl can't set nonblocking mode for socket, fd: %d (%s)\n", netlink_fd,
spdk_strerror(errno));
if (flag < 0) {
rc = errno;
SPDK_ERRLOG("Failed to get socket flag, fd: %d\n", netlink_fd);
close(netlink_fd);
return -1;
return -rc;
}
if (fcntl(netlink_fd, F_SETFL, flag | O_NONBLOCK) < 0) {
rc = errno;
SPDK_ERRLOG("Fcntl can't set nonblocking mode for socket, fd: %d\n", netlink_fd);
close(netlink_fd);
return -rc;
}
if (bind(netlink_fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
rc = errno;
SPDK_ERRLOG("Failed to bind the netlink\n");
close(netlink_fd);
return -1;
return -rc;
}
return netlink_fd;
}
/* Note: We only parse the event from uio subsystem and will ignore
/* Note: We parse the event from uio and vfio subsystem and will ignore
* all the event from other subsystem. the event from uio subsystem
* as below:
* action: "add" or "remove"
* subsystem: "uio"
* dev_path: "/devices/pci0000:80/0000:80:01.0/0000:81:00.0/uio/uio0"
* VFIO subsystem add event:
* ACTION=bind
* DRIVER=vfio-pci
* PCI_SLOT_NAME=0000:d8:00.0
*/
static int
parse_event(const char *buf, struct spdk_uevent *event)
parse_subsystem_event(const char *buf, struct spdk_pci_event *event)
{
char action[SPDK_UEVENT_MSG_LEN];
char subsystem[SPDK_UEVENT_MSG_LEN];
char action[SPDK_UEVENT_MSG_LEN];
char dev_path[SPDK_UEVENT_MSG_LEN];
char driver[SPDK_UEVENT_MSG_LEN];
char vfio_pci_addr[SPDK_UEVENT_MSG_LEN];
char *pci_address, *tmp;
int rc;
memset(action, 0, SPDK_UEVENT_MSG_LEN);
memset(subsystem, 0, SPDK_UEVENT_MSG_LEN);
memset(action, 0, SPDK_UEVENT_MSG_LEN);
memset(dev_path, 0, SPDK_UEVENT_MSG_LEN);
memset(driver, 0, SPDK_UEVENT_MSG_LEN);
memset(vfio_pci_addr, 0, SPDK_UEVENT_MSG_LEN);
while (*buf) {
if (!strncmp(buf, "ACTION=", 7)) {
if (!strncmp(buf, "SUBSYSTEM=", 10)) {
buf += 10;
snprintf(subsystem, sizeof(subsystem), "%s", buf);
} else if (!strncmp(buf, "ACTION=", 7)) {
buf += 7;
snprintf(action, sizeof(action), "%s", buf);
} else if (!strncmp(buf, "DEVPATH=", 8)) {
buf += 8;
snprintf(dev_path, sizeof(dev_path), "%s", buf);
} else if (!strncmp(buf, "SUBSYSTEM=", 10)) {
buf += 10;
snprintf(subsystem, sizeof(subsystem), "%s", buf);
} else if (!strncmp(buf, "DRIVER=", 7)) {
buf += 7;
snprintf(driver, sizeof(driver), "%s", buf);
@ -119,102 +139,111 @@ parse_event(const char *buf, struct spdk_uevent *event)
buf += 14;
snprintf(vfio_pci_addr, sizeof(vfio_pci_addr), "%s", buf);
}
while (*buf++)
;
}
if (!strncmp(subsystem, "uio", 3)) {
char *pci_address, *tmp;
struct spdk_pci_addr pci_addr;
event->subsystem = SPDK_NVME_UEVENT_SUBSYSTEM_UIO;
if (!strncmp(action, "add", 3)) {
event->action = SPDK_NVME_UEVENT_ADD;
}
if (!strncmp(action, "remove", 6)) {
event->action = SPDK_NVME_UEVENT_REMOVE;
event->action = SPDK_UEVENT_REMOVE;
} else if (!strncmp(action, "add", 3)) {
/* Support the ADD UEVENT for the device allow */
event->action = SPDK_UEVENT_ADD;
} else {
return 0;
}
tmp = strstr(dev_path, "/uio/");
if (!tmp) {
SPDK_ERRLOG("Invalid format of uevent: %s\n", dev_path);
return -1;
return -EBADMSG;
}
memset(tmp, 0, SPDK_UEVENT_MSG_LEN - (tmp - dev_path));
pci_address = strrchr(dev_path, '/');
if (!pci_address) {
SPDK_ERRLOG("Not found NVMe BDF in uevent: %s\n", dev_path);
return -1;
SPDK_ERRLOG("Not found PCI device BDF in uevent: %s\n", dev_path);
return -EBADMSG;
}
pci_address++;
if (spdk_pci_addr_parse(&pci_addr, pci_address) != 0) {
SPDK_ERRLOG("Invalid format for NVMe BDF: %s\n", pci_address);
return -1;
}
spdk_pci_addr_fmt(event->traddr, sizeof(event->traddr), &pci_addr);
} else if (!strncmp(driver, "vfio-pci", 8)) {
struct spdk_pci_addr pci_addr;
event->subsystem = SPDK_NVME_UEVENT_SUBSYSTEM_VFIO;
if (!strncmp(action, "bind", 4)) {
event->action = SPDK_NVME_UEVENT_ADD;
rc = spdk_pci_addr_parse(&event->traddr, pci_address);
if (rc != 0) {
SPDK_ERRLOG("Invalid format for PCI device BDF: %s\n", pci_address);
return rc;
}
if (!strncmp(action, "remove", 6)) {
event->action = SPDK_NVME_UEVENT_REMOVE;
}
if (spdk_pci_addr_parse(&pci_addr, vfio_pci_addr) != 0) {
SPDK_ERRLOG("Invalid format for NVMe BDF: %s\n", vfio_pci_addr);
return -1;
}
spdk_pci_addr_fmt(event->traddr, sizeof(event->traddr), &pci_addr);
} else {
event->subsystem = SPDK_NVME_UEVENT_SUBSYSTEM_UNRECOGNIZED;
return 1;
}
return 1;
if (!strncmp(driver, "vfio-pci", 8)) {
if (!strncmp(action, "bind", 4)) {
/* Support the ADD UEVENT for the device allow */
event->action = SPDK_UEVENT_ADD;
} else {
/* Only need to support add event.
* VFIO hotplug interface is "pci.c:pci_device_rte_dev_event".
* VFIO informs the userspace hotplug through vfio req notifier interrupt.
* The app needs to free the device userspace driver resource first then
* the OS remove the device VFIO driver and boardcast the VFIO uevent.
*/
return 0;
}
rc = spdk_pci_addr_parse(&event->traddr, vfio_pci_addr);
if (rc != 0) {
SPDK_ERRLOG("Invalid format for PCI device BDF: %s\n", vfio_pci_addr);
return rc;
}
return 1;
}
return 0;
}
int
nvme_get_uevent(int fd, struct spdk_uevent *uevent)
spdk_pci_get_event(int fd, struct spdk_pci_event *event)
{
int ret;
char buf[SPDK_UEVENT_MSG_LEN];
memset(uevent, 0, sizeof(struct spdk_uevent));
memset(buf, 0, SPDK_UEVENT_MSG_LEN);
memset(event, 0, sizeof(*event));
ret = recv(fd, buf, SPDK_UEVENT_MSG_LEN - 1, MSG_DONTWAIT);
if (ret > 0) {
return parse_event(buf, uevent);
}
if (ret < 0) {
return parse_subsystem_event(buf, event);
} else if (ret < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
return 0;
} else {
SPDK_ERRLOG("Socket read error(%d): %s\n", errno, spdk_strerror(errno));
return -1;
ret = errno;
SPDK_ERRLOG("Socket read error %d\n", errno);
return -ret;
}
} else {
/* connection closed */
return -ENOTCONN;
}
/* connection closed */
if (ret == 0) {
return -1;
}
return 0;
}
#else /* Not Linux */
int
nvme_uevent_connect(void)
spdk_pci_event_listen(void)
{
return -1;
SPDK_ERRLOG("Non-Linux does not support this operation\n");
return -ENOTSUP;
}
int
nvme_get_uevent(int fd, struct spdk_uevent *uevent)
spdk_pci_get_event(int fd, struct spdk_pci_event *event)
{
return -1;
SPDK_ERRLOG("Non-Linux does not support this operation\n");
return -ENOTSUP;
}
#endif

View File

@ -0,0 +1,137 @@
/*-
* BSD LICENSE
*
* Copyright (c) Intel Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "spdk/stdinc.h"
#include "spdk/env.h"
#include "spdk/log.h"
struct sigbus_handler {
spdk_pci_error_handler func;
void *ctx;
TAILQ_ENTRY(sigbus_handler) tailq;
};
static pthread_mutex_t g_sighandler_mutex = PTHREAD_MUTEX_INITIALIZER;
static TAILQ_HEAD(, sigbus_handler) g_sigbus_handler =
TAILQ_HEAD_INITIALIZER(g_sigbus_handler);
static void
sigbus_fault_sighandler(int signum, siginfo_t *info, void *ctx)
{
struct sigbus_handler *sigbus_handler;
pthread_mutex_lock(&g_sighandler_mutex);
TAILQ_FOREACH(sigbus_handler, &g_sigbus_handler, tailq) {
sigbus_handler->func(info, sigbus_handler->ctx);
}
pthread_mutex_unlock(&g_sighandler_mutex);
}
__attribute__((constructor)) static void
device_set_signal(void)
{
struct sigaction sa;
sa.sa_sigaction = sigbus_fault_sighandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sigaction(SIGBUS, &sa, NULL);
}
__attribute__((destructor)) static void
device_destroy_signal(void)
{
struct sigbus_handler *sigbus_handler, *tmp;
TAILQ_FOREACH_SAFE(sigbus_handler, &g_sigbus_handler, tailq, tmp) {
free(sigbus_handler);
}
}
int
spdk_pci_register_error_handler(spdk_pci_error_handler sighandler, void *ctx)
{
struct sigbus_handler *sigbus_handler;
if (!sighandler) {
SPDK_ERRLOG("Error handler is NULL\n");
return -EINVAL;
}
pthread_mutex_lock(&g_sighandler_mutex);
TAILQ_FOREACH(sigbus_handler, &g_sigbus_handler, tailq) {
if (sigbus_handler->func == sighandler) {
pthread_mutex_unlock(&g_sighandler_mutex);
SPDK_ERRLOG("Error handler has been registered\n");
return -EINVAL;
}
}
pthread_mutex_unlock(&g_sighandler_mutex);
sigbus_handler = calloc(1, sizeof(*sigbus_handler));
if (!sigbus_handler) {
SPDK_ERRLOG("Failed to allocate sigbus handler\n");
return -ENOMEM;
}
sigbus_handler->func = sighandler;
sigbus_handler->ctx = ctx;
pthread_mutex_lock(&g_sighandler_mutex);
TAILQ_INSERT_TAIL(&g_sigbus_handler, sigbus_handler, tailq);
pthread_mutex_unlock(&g_sighandler_mutex);
return 0;
}
void
spdk_pci_unregister_error_handler(spdk_pci_error_handler sighandler)
{
struct sigbus_handler *sigbus_handler;
if (!sighandler) {
return;
}
pthread_mutex_lock(&g_sighandler_mutex);
TAILQ_FOREACH(sigbus_handler, &g_sigbus_handler, tailq) {
if (sigbus_handler->func == sighandler) {
TAILQ_REMOVE(&g_sigbus_handler, sigbus_handler, tailq);
free(sigbus_handler);
pthread_mutex_unlock(&g_sighandler_mutex);
return;
}
}
pthread_mutex_unlock(&g_sighandler_mutex);
}

View File

@ -105,6 +105,10 @@
spdk_mem_register;
spdk_mem_unregister;
spdk_mem_get_fd_and_offset;
spdk_pci_event_listen;
spdk_pci_get_event;
spdk_pci_register_error_handler;
spdk_pci_unregister_error_handler;
# Public functions in env_dpdk.h
spdk_env_dpdk_post_init;

View File

@ -37,7 +37,7 @@ include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
SO_VER := 5
SO_MINOR := 0
C_SRCS = nvme_ctrlr_cmd.c nvme_ctrlr.c nvme_fabric.c nvme_ns_cmd.c nvme_ns.c nvme_pcie_common.c nvme_pcie.c nvme_qpair.c nvme.c nvme_quirks.c nvme_transport.c nvme_uevent.c \
C_SRCS = nvme_ctrlr_cmd.c nvme_ctrlr.c nvme_fabric.c nvme_ns_cmd.c nvme_ns.c nvme_pcie_common.c nvme_pcie.c nvme_qpair.c nvme.c nvme_quirks.c nvme_transport.c \
nvme_ctrlr_ocssd_cmd.c nvme_ns_ocssd_cmd.c nvme_tcp.c nvme_opal.c nvme_io_msg.c nvme_poll_group.c nvme_zns.c
C_SRCS-$(CONFIG_VFIO_USER) += nvme_vfio_user.c
C_SRCS-$(CONFIG_RDMA) += nvme_rdma.c

View File

@ -33,9 +33,9 @@
#include "spdk/nvmf_spec.h"
#include "spdk/string.h"
#include "spdk/env.h"
#include "nvme_internal.h"
#include "nvme_io_msg.h"
#include "nvme_uevent.h"
#define SPDK_NVME_DRIVER_NAME "spdk_nvme_driver"
@ -620,7 +620,7 @@ nvme_driver_init(void)
nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
g_spdk_nvme_driver->initialized = false;
g_spdk_nvme_driver->hotplug_fd = nvme_uevent_connect();
g_spdk_nvme_driver->hotplug_fd = spdk_pci_event_listen();
if (g_spdk_nvme_driver->hotplug_fd < 0) {
SPDK_DEBUGLOG(nvme, "Failed to open uevent netlink socket\n");
}

View File

@ -42,7 +42,6 @@
#include "spdk/string.h"
#include "nvme_internal.h"
#include "nvme_pcie_internal.h"
#include "nvme_uevent.h"
struct nvme_pcie_enum_ctx {
struct spdk_nvme_probe_ctx *probe_ctx;
@ -50,15 +49,12 @@ struct nvme_pcie_enum_ctx {
bool has_pci_addr;
};
static int nvme_pcie_ctrlr_attach(struct spdk_nvme_probe_ctx *probe_ctx,
struct spdk_pci_addr *pci_addr);
static uint16_t g_signal_lock;
static bool g_sigset = false;
static spdk_nvme_pcie_hotplug_filter_cb g_hotplug_filter_cb;
static void
nvme_sigbus_fault_sighandler(int signum, siginfo_t *info, void *ctx)
nvme_sigbus_fault_sighandler(siginfo_t *info, void *ctx)
{
void *map_address;
uint16_t flag = 0;
@ -69,7 +65,9 @@ nvme_sigbus_fault_sighandler(int signum, siginfo_t *info, void *ctx)
return;
}
assert(g_thread_mmio_ctrlr != NULL);
if (g_thread_mmio_ctrlr == NULL) {
return;
}
if (!g_thread_mmio_ctrlr->is_remapped) {
map_address = mmap((void *)g_thread_mmio_ctrlr->regs, g_thread_mmio_ctrlr->regs_size,
@ -88,67 +86,58 @@ nvme_sigbus_fault_sighandler(int signum, siginfo_t *info, void *ctx)
}
static void
nvme_pcie_ctrlr_setup_signal(void)
_nvme_pcie_event_process(struct spdk_pci_event *event, void *cb_ctx)
{
struct sigaction sa;
struct spdk_nvme_transport_id trid;
struct spdk_nvme_ctrlr *ctrlr;
sa.sa_sigaction = nvme_sigbus_fault_sighandler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sigaction(SIGBUS, &sa, NULL);
if (event->action == SPDK_UEVENT_ADD) {
if (spdk_process_is_primary()) {
if (g_hotplug_filter_cb == NULL || g_hotplug_filter_cb(&event->traddr)) {
/* The enumerate interface implement the add operation */
spdk_pci_device_allow(&event->traddr);
}
}
} else if (event->action == SPDK_UEVENT_REMOVE) {
memset(&trid, 0, sizeof(trid));
spdk_nvme_trid_populate_transport(&trid, SPDK_NVME_TRANSPORT_PCIE);
if (spdk_pci_addr_fmt(trid.traddr, sizeof(trid.traddr), &event->traddr) < 0) {
SPDK_ERRLOG("Failed to format pci address\n");
return;
}
ctrlr = nvme_get_ctrlr_by_trid_unsafe(&trid);
if (ctrlr == NULL) {
return;
}
SPDK_DEBUGLOG(nvme, "remove nvme address: %s\n", trid.traddr);
nvme_robust_mutex_lock(&ctrlr->ctrlr_lock);
nvme_ctrlr_fail(ctrlr, true);
nvme_robust_mutex_unlock(&ctrlr->ctrlr_lock);
/* get the user app to clean up and stop I/O */
if (ctrlr->remove_cb) {
nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
ctrlr->remove_cb(cb_ctx, ctrlr);
nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
}
}
}
static int
_nvme_pcie_hotplug_monitor(struct spdk_nvme_probe_ctx *probe_ctx)
{
struct spdk_nvme_ctrlr *ctrlr, *tmp;
struct spdk_uevent event;
struct spdk_pci_addr pci_addr;
struct spdk_pci_event event;
if (g_spdk_nvme_driver->hotplug_fd < 0) {
return 0;
}
while (nvme_get_uevent(g_spdk_nvme_driver->hotplug_fd, &event) > 0) {
if (event.subsystem == SPDK_NVME_UEVENT_SUBSYSTEM_UIO ||
event.subsystem == SPDK_NVME_UEVENT_SUBSYSTEM_VFIO) {
if (event.action == SPDK_NVME_UEVENT_ADD) {
SPDK_DEBUGLOG(nvme, "add nvme address: %s\n",
event.traddr);
if (spdk_process_is_primary()) {
if (spdk_pci_addr_parse(&pci_addr, event.traddr) != 0) {
continue;
}
if (g_hotplug_filter_cb == NULL || g_hotplug_filter_cb(&pci_addr)) {
nvme_pcie_ctrlr_attach(probe_ctx, &pci_addr);
}
}
} else if (event.action == SPDK_NVME_UEVENT_REMOVE) {
struct spdk_nvme_transport_id trid;
memset(&trid, 0, sizeof(trid));
spdk_nvme_trid_populate_transport(&trid, SPDK_NVME_TRANSPORT_PCIE);
snprintf(trid.traddr, sizeof(trid.traddr), "%s", event.traddr);
ctrlr = nvme_get_ctrlr_by_trid_unsafe(&trid);
if (ctrlr == NULL) {
return 0;
}
SPDK_DEBUGLOG(nvme, "remove nvme address: %s\n",
event.traddr);
nvme_robust_mutex_lock(&ctrlr->ctrlr_lock);
nvme_ctrlr_fail(ctrlr, true);
nvme_robust_mutex_unlock(&ctrlr->ctrlr_lock);
/* get the user app to clean up and stop I/O */
if (ctrlr->remove_cb) {
nvme_robust_mutex_unlock(&g_spdk_nvme_driver->lock);
ctrlr->remove_cb(ctrlr->cb_ctx, ctrlr);
nvme_robust_mutex_lock(&g_spdk_nvme_driver->lock);
}
}
}
while (spdk_pci_get_event(g_spdk_nvme_driver->hotplug_fd, &event) > 0) {
_nvme_pcie_event_process(&event, probe_ctx->cb_ctx);
}
/* Initiate removal of physically hotremoved PCI controllers. Even after
@ -593,19 +582,6 @@ nvme_pcie_ctrlr_scan(struct spdk_nvme_probe_ctx *probe_ctx,
}
}
static int
nvme_pcie_ctrlr_attach(struct spdk_nvme_probe_ctx *probe_ctx, struct spdk_pci_addr *pci_addr)
{
struct nvme_pcie_enum_ctx enum_ctx;
enum_ctx.probe_ctx = probe_ctx;
enum_ctx.has_pci_addr = true;
enum_ctx.pci_addr = *pci_addr;
spdk_pci_device_allow(pci_addr);
return spdk_pci_enumerate(spdk_pci_nvme_get_driver(), pcie_nvme_enum_cb, &enum_ctx);
}
static struct spdk_nvme_ctrlr *nvme_pcie_ctrlr_construct(const struct spdk_nvme_transport_id *trid,
const struct spdk_nvme_ctrlr_opts *opts,
void *devhandle)
@ -695,7 +671,8 @@ static struct spdk_nvme_ctrlr *nvme_pcie_ctrlr_construct(const struct spdk_nvme_
}
if (g_sigset != true) {
nvme_pcie_ctrlr_setup_signal();
spdk_pci_register_error_handler(nvme_sigbus_fault_sighandler,
NULL);
g_sigset = true;
}

View File

@ -1,62 +0,0 @@
/*-
* BSD LICENSE
*
* Copyright (c) Intel Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/** \file
* SPDK uevent
*/
#include "spdk/env.h"
#include "spdk/nvmf_spec.h"
#ifndef SPDK_UEVENT_H_
#define SPDK_UEVENT_H_
#define SPDK_NVME_UEVENT_SUBSYSTEM_UNRECOGNIZED 0
#define SPDK_NVME_UEVENT_SUBSYSTEM_UIO 1
#define SPDK_NVME_UEVENT_SUBSYSTEM_VFIO 2
enum spdk_nvme_uevent_action {
SPDK_NVME_UEVENT_ADD = 0,
SPDK_NVME_UEVENT_REMOVE = 1,
};
struct spdk_uevent {
enum spdk_nvme_uevent_action action;
int subsystem;
char traddr[SPDK_NVMF_TRADDR_MAX_LEN + 1];
};
int nvme_uevent_connect(void);
int nvme_get_uevent(int fd, struct spdk_uevent *uevent);
#endif /* SPDK_UEVENT_H_ */

View File

@ -35,7 +35,7 @@ SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../..)
include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
DIRS-y = nvme.c nvme_ctrlr.c nvme_ctrlr_cmd.c nvme_ctrlr_ocssd_cmd.c nvme_ns.c nvme_ns_cmd.c nvme_ns_ocssd_cmd.c nvme_pcie.c nvme_poll_group.c nvme_qpair.c \
nvme_quirks.c nvme_tcp.c nvme_uevent.c nvme_transport.c nvme_io_msg.c nvme_pcie_common.c \
nvme_quirks.c nvme_tcp.c nvme_transport.c nvme_io_msg.c nvme_pcie_common.c \
DIRS-$(CONFIG_RDMA) += nvme_rdma.c
DIRS-$(CONFIG_NVME_CUSE) += nvme_cuse.c

View File

@ -63,7 +63,7 @@ DEFINE_STUB(nvme_transport_ctrlr_construct, struct spdk_nvme_ctrlr *,
DEFINE_STUB_V(nvme_io_msg_ctrlr_detach, (struct spdk_nvme_ctrlr *ctrlr));
DEFINE_STUB(spdk_nvme_transport_available, bool,
(enum spdk_nvme_transport_type trtype), true);
DEFINE_STUB(nvme_uevent_connect, int, (void), 1);
DEFINE_STUB(spdk_pci_event_listen, int, (void), 0);
DEFINE_STUB(spdk_nvme_poll_group_process_completions, int64_t, (struct spdk_nvme_poll_group *group,
uint32_t completions_per_qpair, spdk_nvme_disconnected_qpair_cb disconnected_qpair_cb), 0);

View File

@ -77,7 +77,7 @@ DEFINE_STUB(spdk_nvme_ctrlr_get_regs_csts,
(struct spdk_nvme_ctrlr *ctrlr),
{});
DEFINE_STUB(nvme_uevent_connect, int, (void), 1);
DEFINE_STUB(spdk_pci_event_listen, int, (void), 1);
DEFINE_STUB(nvme_transport_ctrlr_destruct,
int,

View File

@ -73,7 +73,7 @@ DEFINE_STUB(spdk_nvme_ctrlr_get_regs_csts,
(struct spdk_nvme_ctrlr *ctrlr),
{});
DEFINE_STUB(nvme_uevent_connect, int, (void), 1);
DEFINE_STUB(spdk_pci_event_listen, int, (void), 1);
DEFINE_STUB_V(nvme_ctrlr_fail,
(struct spdk_nvme_ctrlr *ctrlr, bool hotremove));

View File

@ -72,9 +72,12 @@ DEFINE_STUB(spdk_pci_device_cfg_write16, int, (struct spdk_pci_device *dev, uint
uint32_t offset), 0);
DEFINE_STUB(spdk_pci_device_cfg_read16, int, (struct spdk_pci_device *dev, uint16_t *value,
uint32_t offset), 0);
DEFINE_STUB(spdk_pci_device_get_id, struct spdk_pci_id, (struct spdk_pci_device *dev), {0})
DEFINE_STUB(nvme_uevent_connect, int, (void), 0);
DEFINE_STUB(spdk_pci_device_get_id, struct spdk_pci_id, (struct spdk_pci_device *dev), {0});
DEFINE_STUB(spdk_pci_event_listen, int, (void), 0);
DEFINE_STUB(spdk_pci_get_event, int, (int fd, struct spdk_pci_event *uevent), 0);
DEFINE_STUB(spdk_pci_register_error_handler, int, (spdk_pci_error_handler sighandler, void *ctx),
0);
DEFINE_STUB_V(spdk_pci_unregister_error_handler, (spdk_pci_error_handler sighandler));
SPDK_LOG_REGISTER_COMPONENT(nvme)
@ -93,30 +96,6 @@ nvme_ctrlr_fail(struct spdk_nvme_ctrlr *ctrlr, bool hot_remove)
ctrlr->is_failed = true;
}
struct spdk_uevent_entry {
struct spdk_uevent uevent;
STAILQ_ENTRY(spdk_uevent_entry) link;
};
static STAILQ_HEAD(, spdk_uevent_entry) g_uevents = STAILQ_HEAD_INITIALIZER(g_uevents);
int
nvme_get_uevent(int fd, struct spdk_uevent *uevent)
{
struct spdk_uevent_entry *entry;
if (STAILQ_EMPTY(&g_uevents)) {
return 0;
}
entry = STAILQ_FIRST(&g_uevents);
STAILQ_REMOVE_HEAD(&g_uevents, link);
*uevent = entry->uevent;
return 1;
}
int
spdk_pci_enumerate(struct spdk_pci_driver *driver, spdk_pci_enum_cb enum_cb, void *enum_ctx)
{
@ -293,107 +272,6 @@ test_prp_list_append(void)
(NVME_MAX_PRP_LIST_ENTRIES + 1) * 0x1000, 0x1000) == -EFAULT);
}
static void
test_nvme_pcie_hotplug_monitor(void)
{
struct nvme_pcie_ctrlr pctrlr = {};
struct spdk_uevent_entry entry = {};
struct nvme_driver driver;
pthread_mutexattr_t attr;
struct spdk_nvme_probe_ctx test_nvme_probe_ctx = {};
/* Initiate variables and ctrlr */
driver.initialized = true;
driver.hotplug_fd = 123;
CU_ASSERT(pthread_mutexattr_init(&attr) == 0);
CU_ASSERT(pthread_mutex_init(&pctrlr.ctrlr.ctrlr_lock, &attr) == 0);
CU_ASSERT(pthread_mutex_init(&driver.lock, &attr) == 0);
TAILQ_INIT(&driver.shared_attached_ctrlrs);
g_spdk_nvme_driver = &driver;
/* Case 1: SPDK_NVME_UEVENT_ADD/ NVME_VFIO */
entry.uevent.subsystem = SPDK_NVME_UEVENT_SUBSYSTEM_VFIO;
entry.uevent.action = SPDK_NVME_UEVENT_ADD;
snprintf(entry.uevent.traddr, sizeof(entry.uevent.traddr), "0000:05:00.0");
CU_ASSERT(STAILQ_EMPTY(&g_uevents));
STAILQ_INSERT_TAIL(&g_uevents, &entry, link);
_nvme_pcie_hotplug_monitor(&test_nvme_probe_ctx);
CU_ASSERT(STAILQ_EMPTY(&g_uevents));
CU_ASSERT(g_device_is_enumerated == true);
g_device_is_enumerated = false;
/* Case 2: SPDK_NVME_UEVENT_ADD/ NVME_UIO */
entry.uevent.subsystem = SPDK_NVME_UEVENT_SUBSYSTEM_UIO;
entry.uevent.action = SPDK_NVME_UEVENT_ADD;
snprintf(entry.uevent.traddr, sizeof(entry.uevent.traddr), "0000:05:00.0");
CU_ASSERT(STAILQ_EMPTY(&g_uevents));
STAILQ_INSERT_TAIL(&g_uevents, &entry, link);
_nvme_pcie_hotplug_monitor(&test_nvme_probe_ctx);
CU_ASSERT(STAILQ_EMPTY(&g_uevents));
CU_ASSERT(g_device_is_enumerated == true);
g_device_is_enumerated = false;
/* Case 3: SPDK_NVME_UEVENT_REMOVE/ NVME_UIO */
entry.uevent.subsystem = SPDK_NVME_UEVENT_SUBSYSTEM_UIO;
entry.uevent.action = SPDK_NVME_UEVENT_REMOVE;
snprintf(entry.uevent.traddr, sizeof(entry.uevent.traddr), "0000:05:00.0");
CU_ASSERT(STAILQ_EMPTY(&g_uevents));
STAILQ_INSERT_TAIL(&g_uevents, &entry, link);
MOCK_SET(nvme_get_ctrlr_by_trid_unsafe, &pctrlr.ctrlr);
_nvme_pcie_hotplug_monitor(&test_nvme_probe_ctx);
CU_ASSERT(STAILQ_EMPTY(&g_uevents));
CU_ASSERT(pctrlr.ctrlr.is_failed == true);
pctrlr.ctrlr.is_failed = false;
MOCK_CLEAR(nvme_get_ctrlr_by_trid_unsafe);
/* Case 4: SPDK_NVME_UEVENT_REMOVE/ NVME_VFIO */
entry.uevent.subsystem = SPDK_NVME_UEVENT_SUBSYSTEM_VFIO;
entry.uevent.action = SPDK_NVME_UEVENT_REMOVE;
snprintf(entry.uevent.traddr, sizeof(entry.uevent.traddr), "0000:05:00.0");
CU_ASSERT(STAILQ_EMPTY(&g_uevents));
STAILQ_INSERT_TAIL(&g_uevents, &entry, link);
MOCK_SET(nvme_get_ctrlr_by_trid_unsafe, &pctrlr.ctrlr);
_nvme_pcie_hotplug_monitor(&test_nvme_probe_ctx);
CU_ASSERT(STAILQ_EMPTY(&g_uevents));
CU_ASSERT(pctrlr.ctrlr.is_failed == true);
pctrlr.ctrlr.is_failed = false;
MOCK_CLEAR(nvme_get_ctrlr_by_trid_unsafe);
/* Case 5: Removed device detected in another process */
pctrlr.ctrlr.trid.trtype = SPDK_NVME_TRANSPORT_PCIE;
snprintf(pctrlr.ctrlr.trid.traddr, sizeof(pctrlr.ctrlr.trid.traddr), "0000:02:00.0");
pctrlr.ctrlr.remove_cb = NULL;
pctrlr.ctrlr.is_failed = false;
pctrlr.ctrlr.is_removed = false;
TAILQ_INSERT_TAIL(&g_spdk_nvme_driver->shared_attached_ctrlrs, &pctrlr.ctrlr, tailq);
MOCK_SET(spdk_pci_device_is_removed, false);
_nvme_pcie_hotplug_monitor(&test_nvme_probe_ctx);
CU_ASSERT(pctrlr.ctrlr.is_failed == false);
MOCK_SET(spdk_pci_device_is_removed, true);
_nvme_pcie_hotplug_monitor(&test_nvme_probe_ctx);
CU_ASSERT(pctrlr.ctrlr.is_failed == true);
pthread_mutex_destroy(&driver.lock);
pthread_mutex_destroy(&pctrlr.ctrlr.ctrlr_lock);
pthread_mutexattr_destroy(&attr);
g_spdk_nvme_driver = NULL;
}
static void test_shadow_doorbell_update(void)
{
bool ret;
@ -525,7 +403,6 @@ int main(int argc, char **argv)
suite = CU_add_suite("nvme_pcie", NULL, NULL);
CU_ADD_TEST(suite, test_prp_list_append);
CU_ADD_TEST(suite, test_nvme_pcie_hotplug_monitor);
CU_ADD_TEST(suite, test_shadow_doorbell_update);
CU_ADD_TEST(suite, test_build_contig_hw_sgl_request);
CU_ADD_TEST(suite, test_nvme_pcie_qpair_build_metadata);

View File

@ -1 +0,0 @@
nvme_uevent_ut

View File

@ -1,38 +0,0 @@
#
# BSD LICENSE
#
# Copyright (c) Intel Corporation.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# * Neither the name of Intel Corporation nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
SPDK_ROOT_DIR := $(abspath $(CURDIR)/../../../../..)
TEST_FILE = nvme_uevent_ut.c
include $(SPDK_ROOT_DIR)/mk/spdk.unittest.mk

View File

@ -1,163 +0,0 @@
/*-
* BSD LICENSE
*
* Copyright (c) Intel Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "spdk_cunit.h"
#include "spdk/env.h"
#include "common/lib/test_env.c"
#include "nvme/nvme_uevent.c"
#ifdef __linux__
enum uevent_parse_event_return_type {
uevent_abnormal_exit = -1,
uevent_normal_exit = 0,
uevent_expected_continue = 1
};
static void
test_nvme_uevent_parse_event(void)
{
char *commands;
struct spdk_uevent uevent = {};
int rc = uevent_normal_exit;
/* Simulate commands to check expected behaviors */
/* Linux kernel puts null characters after every uevent */
/* Case 1: Add wrong non-uio or vfio-pci /devices/pci0000:80/0000:80:01.0/0000:81:00.0/uio/uio0 */
commands =
"ACTION=add\0DEVPATH=/devices/pci0000:80/0000:80:01.0/0000:81:00.0/uio/uio0\0SUBSYSTEM= \0DRIVER= \0PCI_SLOT_NAME= \0";
uevent.subsystem = 0xFF;
uevent.action = 0;
rc = parse_event(commands, &uevent);
CU_ASSERT(rc == uevent_expected_continue);
CU_ASSERT(uevent.subsystem == SPDK_NVME_UEVENT_SUBSYSTEM_UNRECOGNIZED);
CU_ASSERT(uevent.action == SPDK_NVME_UEVENT_ADD);
/* Case 2: Add uio /devices/pci0000:80/0000:80:01.0/0000:81:00.0/uio/uio0 */
commands =
"ACTION=add \0DEVPATH=/devices/pci0000:80/0000:80:01.0/0000:81:00.0/uio/uio0\0SUBSYSTEM=uio\0DRIVER=\0PCI_SLOT_NAME= \0";
uevent.subsystem = SPDK_NVME_UEVENT_SUBSYSTEM_UNRECOGNIZED;
uevent.action = 0;
rc = parse_event(commands, &uevent);
CU_ASSERT(rc == uevent_expected_continue);
CU_ASSERT(uevent.subsystem == SPDK_NVME_UEVENT_SUBSYSTEM_UIO);
CU_ASSERT(uevent.action == SPDK_NVME_UEVENT_ADD);
/* Case 3: Remove uio /devices/pci0000:80/0000:80:01.0/0000:81:00.0/uio/uio0 */
commands =
"ACTION=remove\0DEVPATH=/devices/pci0000:80/0000:80:01.0/0000:81:00.0/uio/uio0\0SUBSYSTEM=uio\0DRIVER=\0PCI_SLOT_NAME= \0";
uevent.subsystem = SPDK_NVME_UEVENT_SUBSYSTEM_UNRECOGNIZED;
rc = parse_event(commands, &uevent);
CU_ASSERT(rc == uevent_expected_continue);
CU_ASSERT(uevent.subsystem == SPDK_NVME_UEVENT_SUBSYSTEM_UIO);
CU_ASSERT(uevent.action == SPDK_NVME_UEVENT_REMOVE);
/* Case 4: Add vfio-pci 0000:81:00.0 */
commands = "ACTION=bind\0DEVPATH=\0SUBSYSTEM= \0DRIVER=vfio-pci\0PCI_SLOT_NAME=0000:81:00.0\0";
uevent.subsystem = SPDK_NVME_UEVENT_SUBSYSTEM_UNRECOGNIZED;
rc = parse_event(commands, &uevent);
CU_ASSERT(rc == uevent_expected_continue);
CU_ASSERT(uevent.subsystem == SPDK_NVME_UEVENT_SUBSYSTEM_VFIO);
CU_ASSERT(uevent.action == SPDK_NVME_UEVENT_ADD);
/* Case 5: Remove vfio-pci 0000:81:00.0 */
commands = "ACTION=remove\0DEVPATH= \0SUBSYSTEM= \0DRIVER=vfio-pci \0PCI_SLOT_NAME=0000:81:00.0\0";
uevent.subsystem = SPDK_NVME_UEVENT_SUBSYSTEM_UNRECOGNIZED;
rc = parse_event(commands, &uevent);
CU_ASSERT(rc == uevent_expected_continue);
CU_ASSERT(uevent.subsystem == SPDK_NVME_UEVENT_SUBSYSTEM_VFIO);
CU_ASSERT(uevent.action == SPDK_NVME_UEVENT_REMOVE);
/* Case 6: Add wrong vfio-pci addr 000000 */
commands = "ACTION=bind\0DEVPATH= \0SUBSYSTEM= \0DRIVER=vfio-pci \0PCI_SLOT_NAME=000000\0";
uevent.subsystem = SPDK_NVME_UEVENT_SUBSYSTEM_UNRECOGNIZED;
rc = parse_event(commands, &uevent);
CU_ASSERT(rc == uevent_abnormal_exit);
CU_ASSERT(uevent.subsystem == SPDK_NVME_UEVENT_SUBSYSTEM_VFIO);
CU_ASSERT(uevent.action == SPDK_NVME_UEVENT_ADD);
/* Case 7: Add wrong type vfio 0000:81:00.0 */
commands = "ACTION=bind\0DEVPATH= \0SUBSYSTEM= \0DRIVER=vfio \0PCI_SLOT_NAME=0000:81:00.0\0";
uevent.subsystem = SPDK_NVME_UEVENT_SUBSYSTEM_UIO;
uevent.action = 0;
rc = parse_event(commands, &uevent);
CU_ASSERT(rc == uevent_expected_continue);
CU_ASSERT(uevent.subsystem == SPDK_NVME_UEVENT_SUBSYSTEM_UNRECOGNIZED);
CU_ASSERT(uevent.action == SPDK_NVME_UEVENT_ADD);
}
#else
static void
test_nvme_uevent_parse_event(void)
{
CU_ASSERT(1);
}
#endif
int main(int argc, char **argv)
{
CU_pSuite suite = NULL;
unsigned int num_failures;
CU_set_error_action(CUEA_ABORT);
CU_initialize_registry();
suite = CU_add_suite("nvme_uevent", NULL, NULL);
CU_ADD_TEST(suite, test_nvme_uevent_parse_event);
CU_basic_set_mode(CU_BRM_VERBOSE);
CU_basic_run_tests();
num_failures = CU_get_number_of_failures();
CU_cleanup_registry();
return num_failures;
}

View File

@ -83,7 +83,6 @@ function unittest_nvme() {
$valgrind $testdir/lib/nvme/nvme_poll_group.c/nvme_poll_group_ut
$valgrind $testdir/lib/nvme/nvme_quirks.c/nvme_quirks_ut
$valgrind $testdir/lib/nvme/nvme_tcp.c/nvme_tcp_ut
$valgrind $testdir/lib/nvme/nvme_uevent.c/nvme_uevent_ut
$valgrind $testdir/lib/nvme/nvme_transport.c/nvme_transport_ut
$valgrind $testdir/lib/nvme/nvme_io_msg.c/nvme_io_msg_ut
$valgrind $testdir/lib/nvme/nvme_pcie_common.c/nvme_pcie_common_ut