diff --git a/lib/vhost/Makefile b/lib/vhost/Makefile index 83efcc01b..3d33cdb92 100644 --- a/lib/vhost/Makefile +++ b/lib/vhost/Makefile @@ -37,7 +37,7 @@ include $(SPDK_ROOT_DIR)/mk/spdk.common.mk CFLAGS += -I. CFLAGS += $(ENV_CFLAGS) -C_SRCS = vhost.c vhost_rpc.c vhost_scsi.c vhost_blk.c +C_SRCS = vhost.c vhost_rpc.c vhost_scsi.c vhost_blk.c rte_vhost_compat.c ifeq ($(CONFIG_VHOST_INTERNAL_LIB),y) C_SRCS += vhost_nvme.c diff --git a/lib/vhost/rte_vhost_compat.c b/lib/vhost/rte_vhost_compat.c new file mode 100644 index 000000000..7e0adf75c --- /dev/null +++ b/lib/vhost/rte_vhost_compat.c @@ -0,0 +1,132 @@ +/*- + * 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 + * Set of workarounds for rte_vhost to make it work with device types + * other than vhost-net. + */ + +#include "spdk/stdinc.h" + +#include "spdk/env.h" +#include "spdk/likely.h" +#include "spdk/string.h" +#include "spdk/util.h" +#include "spdk/barrier.h" +#include "spdk/vhost.h" +#include "vhost_internal.h" + +#include "spdk_internal/vhost_user.h" + +#ifndef SPDK_CONFIG_VHOST_INTERNAL_LIB +extern const struct vhost_device_ops g_spdk_vhost_ops; + +static enum rte_vhost_msg_result +spdk_extern_vhost_pre_msg_handler(int vid, void *_msg) +{ + struct vhost_user_msg *msg = _msg; + struct spdk_vhost_session *vsession; + + vsession = spdk_vhost_session_find_by_vid(vid); + if (vsession == NULL) { + SPDK_ERRLOG("Received a message to unitialized session (vid %d).\n", vid); + assert(false); + return RTE_VHOST_MSG_RESULT_ERR; + } + + switch (msg->request) { + case VHOST_USER_SET_MEM_TABLE: + /* rte_vhost will unmap previous memory that SPDK may still + * have pending DMA operations on. We can't let that happen, + * so stop the device before letting rte_vhost unmap anything. + * This will block until all pending I/Os are finished. + * We will start the device again from the post-processing + * message handler. + */ + if (vsession->lcore != -1) { + g_spdk_vhost_ops.destroy_device(vid); + vsession->needs_restart = true; + } + break; + default: + break; + } + + return RTE_VHOST_MSG_RESULT_NOT_HANDLED; +} + +static enum rte_vhost_msg_result +spdk_extern_vhost_post_msg_handler(int vid, void *_msg) +{ + struct spdk_vhost_session *vsession; + + vsession = spdk_vhost_session_find_by_vid(vid); + if (vsession == NULL) { + SPDK_ERRLOG("Received a message to unitialized session (vid %d).\n", vid); + assert(false); + return RTE_VHOST_MSG_RESULT_ERR; + } + + if (vsession->needs_restart) { + g_spdk_vhost_ops.new_device(vid); + vsession->needs_restart = false; + } + + return RTE_VHOST_MSG_RESULT_NOT_HANDLED; +} + +struct rte_vhost_user_extern_ops g_spdk_extern_vhost_ops = { + .pre_msg_handle = spdk_extern_vhost_pre_msg_handler, + .post_msg_handle = spdk_extern_vhost_post_msg_handler, +}; + +void +spdk_vhost_session_install_rte_compat_hooks(struct spdk_vhost_session *vsession) +{ + int rc; + + rc = rte_vhost_extern_callback_register(vsession->vid, &g_spdk_extern_vhost_ops, NULL); + if (rc != 0) { + SPDK_ERRLOG("rte_vhost_extern_callback_register() failed for vid = %d\n", + vsession->vid); + return; + } +} + +#else /* SPDK_CONFIG_VHOST_INTERNAL_LIB */ +void +spdk_vhost_session_install_rte_compat_hooks(struct spdk_vhost_session *vsession) +{ + /* nothing to do. all the changes are already incorporated into rte_vhost */ +} +#endif diff --git a/lib/vhost/vhost.c b/lib/vhost/vhost.c index 0f7b0a71c..20dab1feb 100644 --- a/lib/vhost/vhost.c +++ b/lib/vhost/vhost.c @@ -527,7 +527,7 @@ spdk_vhost_session_find_by_id(struct spdk_vhost_dev *vdev, unsigned id) return NULL; } -static struct spdk_vhost_session * +struct spdk_vhost_session * spdk_vhost_session_find_by_vid(int vid) { struct spdk_vhost_dev *vdev; @@ -1018,7 +1018,7 @@ stop_device(int vid) vdev = vsession->vdev; if (vsession->lcore == -1) { - SPDK_ERRLOG("Controller %s is not loaded.\n", vdev->name); + /* already stopped, nothing to do */ pthread_mutex_unlock(&g_spdk_vhost_mutex); return; } @@ -1064,7 +1064,8 @@ start_device(int vid) vdev = vsession->vdev; if (vsession->lcore != -1) { - SPDK_ERRLOG("Controller %s already loaded.\n", vdev->name); + /* already started, nothing to do */ + rc = 0; goto out; } @@ -1302,6 +1303,8 @@ new_connection(int vid) vsession->stats_check_interval = SPDK_VHOST_STATS_CHECK_INTERVAL_MS * spdk_get_ticks_hz() / 1000UL; TAILQ_INSERT_TAIL(&vdev->vsessions, vsession, tailq); + + spdk_vhost_session_install_rte_compat_hooks(vsession); pthread_mutex_unlock(&g_spdk_vhost_mutex); return 0; } diff --git a/lib/vhost/vhost_internal.h b/lib/vhost/vhost_internal.h index fb3566fbe..9080ef5b1 100644 --- a/lib/vhost/vhost_internal.h +++ b/lib/vhost/vhost_internal.h @@ -126,6 +126,8 @@ struct spdk_vhost_session { int32_t lcore; + bool needs_restart; + struct rte_vhost_memory *mem; int task_cnt; @@ -345,6 +347,9 @@ int spdk_vhost_session_send_event(struct spdk_vhost_session *vsession, */ void spdk_vhost_session_event_done(void *event_ctx, int response); +struct spdk_vhost_session *spdk_vhost_session_find_by_vid(int vid); +void spdk_vhost_session_install_rte_compat_hooks(struct spdk_vhost_session *vsession); + void spdk_vhost_free_reactor(uint32_t lcore); uint32_t spdk_vhost_allocate_reactor(struct spdk_cpuset *cpumask); diff --git a/test/unit/lib/vhost/vhost.c/vhost_ut.c b/test/unit/lib/vhost/vhost.c/vhost_ut.c index 62f6588d3..ae132133e 100644 --- a/test/unit/lib/vhost/vhost.c/vhost_ut.c +++ b/test/unit/lib/vhost/vhost.c/vhost_ut.c @@ -46,6 +46,8 @@ DEFINE_STUB(rte_vhost_set_vring_base, int, (int vid, uint16_t queue_id, uint16_t last_avail_idx, uint16_t last_used_idx), 0); DEFINE_STUB(rte_vhost_get_vring_base, int, (int vid, uint16_t queue_id, uint16_t *last_avail_idx, uint16_t *last_used_idx), 0); +DEFINE_STUB_V(spdk_vhost_session_install_rte_compat_hooks, + (struct spdk_vhost_session *vsession)); DEFINE_STUB(rte_vhost_driver_unregister, int, (const char *path), 0); DEFINE_STUB(spdk_event_allocate, struct spdk_event *, (uint32_t lcore, spdk_event_fn fn, void *arg1, void *arg2), NULL);