diff --git a/include/spdk/env.h b/include/spdk/env.h index adf082acc..c8fbad1c2 100644 --- a/include/spdk/env.h +++ b/include/spdk/env.h @@ -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 diff --git a/lib/env_dpdk/Makefile b/lib/env_dpdk/Makefile index 73c4aa48f..f869a0b48 100644 --- a/lib/env_dpdk/Makefile +++ b/lib/env_dpdk/Makefile @@ -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) diff --git a/lib/nvme/nvme_uevent.c b/lib/env_dpdk/pci_event.c similarity index 61% rename from lib/nvme/nvme_uevent.c rename to lib/env_dpdk/pci_event.c index b413ceb10..7ce9fc3ad 100644 --- a/lib/nvme/nvme_uevent.c +++ b/lib/env_dpdk/pci_event.c @@ -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 diff --git a/lib/env_dpdk/sigbus_handler.c b/lib/env_dpdk/sigbus_handler.c new file mode 100644 index 000000000..098e7647c --- /dev/null +++ b/lib/env_dpdk/sigbus_handler.c @@ -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); +} diff --git a/lib/env_dpdk/spdk_env_dpdk.map b/lib/env_dpdk/spdk_env_dpdk.map index 392c410fd..712228de1 100644 --- a/lib/env_dpdk/spdk_env_dpdk.map +++ b/lib/env_dpdk/spdk_env_dpdk.map @@ -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; diff --git a/lib/nvme/Makefile b/lib/nvme/Makefile index 5b7ff614f..65a494b34 100644 --- a/lib/nvme/Makefile +++ b/lib/nvme/Makefile @@ -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 diff --git a/lib/nvme/nvme.c b/lib/nvme/nvme.c index a23abf15f..1c92ea9e5 100644 --- a/lib/nvme/nvme.c +++ b/lib/nvme/nvme.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"); } diff --git a/lib/nvme/nvme_pcie.c b/lib/nvme/nvme_pcie.c index 4eb9c7c4f..04d33ea8a 100644 --- a/lib/nvme/nvme_pcie.c +++ b/lib/nvme/nvme_pcie.c @@ -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; } diff --git a/lib/nvme/nvme_uevent.h b/lib/nvme/nvme_uevent.h deleted file mode 100644 index 94f67101e..000000000 --- a/lib/nvme/nvme_uevent.h +++ /dev/null @@ -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_ */ diff --git a/test/unit/lib/nvme/Makefile b/test/unit/lib/nvme/Makefile index 7fc74c739..f594bc14c 100644 --- a/test/unit/lib/nvme/Makefile +++ b/test/unit/lib/nvme/Makefile @@ -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 diff --git a/test/unit/lib/nvme/nvme.c/nvme_ut.c b/test/unit/lib/nvme/nvme.c/nvme_ut.c index 006f17997..2c9696fcf 100644 --- a/test/unit/lib/nvme/nvme.c/nvme_ut.c +++ b/test/unit/lib/nvme/nvme.c/nvme_ut.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); diff --git a/test/unit/lib/nvme/nvme_ns_cmd.c/nvme_ns_cmd_ut.c b/test/unit/lib/nvme/nvme_ns_cmd.c/nvme_ns_cmd_ut.c index 1b5f33ca8..a102deecf 100644 --- a/test/unit/lib/nvme/nvme_ns_cmd.c/nvme_ns_cmd_ut.c +++ b/test/unit/lib/nvme/nvme_ns_cmd.c/nvme_ns_cmd_ut.c @@ -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, diff --git a/test/unit/lib/nvme/nvme_ns_ocssd_cmd.c/nvme_ns_ocssd_cmd_ut.c b/test/unit/lib/nvme/nvme_ns_ocssd_cmd.c/nvme_ns_ocssd_cmd_ut.c index 48a1d06be..17c80304b 100644 --- a/test/unit/lib/nvme/nvme_ns_ocssd_cmd.c/nvme_ns_ocssd_cmd_ut.c +++ b/test/unit/lib/nvme/nvme_ns_ocssd_cmd.c/nvme_ns_ocssd_cmd_ut.c @@ -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)); diff --git a/test/unit/lib/nvme/nvme_pcie.c/nvme_pcie_ut.c b/test/unit/lib/nvme/nvme_pcie.c/nvme_pcie_ut.c index e8f0454c2..c0ad2737f 100644 --- a/test/unit/lib/nvme/nvme_pcie.c/nvme_pcie_ut.c +++ b/test/unit/lib/nvme/nvme_pcie.c/nvme_pcie_ut.c @@ -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); diff --git a/test/unit/lib/nvme/nvme_uevent.c/.gitignore b/test/unit/lib/nvme/nvme_uevent.c/.gitignore deleted file mode 100644 index 1cb0d98ad..000000000 --- a/test/unit/lib/nvme/nvme_uevent.c/.gitignore +++ /dev/null @@ -1 +0,0 @@ -nvme_uevent_ut diff --git a/test/unit/lib/nvme/nvme_uevent.c/Makefile b/test/unit/lib/nvme/nvme_uevent.c/Makefile deleted file mode 100644 index 98687efb8..000000000 --- a/test/unit/lib/nvme/nvme_uevent.c/Makefile +++ /dev/null @@ -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 diff --git a/test/unit/lib/nvme/nvme_uevent.c/nvme_uevent_ut.c b/test/unit/lib/nvme/nvme_uevent.c/nvme_uevent_ut.c deleted file mode 100644 index c5a94223d..000000000 --- a/test/unit/lib/nvme/nvme_uevent.c/nvme_uevent_ut.c +++ /dev/null @@ -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; -} diff --git a/test/unit/unittest.sh b/test/unit/unittest.sh index 5a5780581..945f8b7ee 100755 --- a/test/unit/unittest.sh +++ b/test/unit/unittest.sh @@ -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