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:
parent
1c3bc9d64d
commit
59237d22b8
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
137
lib/env_dpdk/sigbus_handler.c
Normal file
137
lib/env_dpdk/sigbus_handler.c
Normal 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);
|
||||
}
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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_ */
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
|
1
test/unit/lib/nvme/nvme_uevent.c/.gitignore
vendored
1
test/unit/lib/nvme/nvme_uevent.c/.gitignore
vendored
@ -1 +0,0 @@
|
||||
nvme_uevent_ut
|
@ -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
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user