From 0a6ad9b02ee388987216c1f6e593ef18bba54d8a Mon Sep 17 00:00:00 2001 From: Darek Stojaczyk Date: Sat, 23 Feb 2019 12:59:34 +0100 Subject: [PATCH] vhost: install external msg handling hooks to rte_vhost DPDK 19.05+ gives us an ability to pre or post-process any single vhost-user message. The user can either perform additional actions upon some generic events, or can implement handling for brand new message types that rte_vhost doesn't even know about. In order to smoothly switch to the upstream rte_vhost and drop our internal copy, we introduce an SPDK wrapper function to register SPDK-specific message handlers. For DPDK 19.05+ this will use the new rte_vhost API to register those message handlers, and for older DPDKs this function simply won't do anything - as w assume the internal rte_copy already contains all the necessary changes and does not need any "external" hooks. For now we use the message handlers to stop the vhost device and wait for any pending DMA ops before letting rte_vhost to process the SET_MEM_TABLE message and unmap the current shared memory. Change-Id: Ic0fefa9174254627cb3fc0ed30ab1e54be4dd654 Signed-off-by: Darek Stojaczyk Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/446085 Tested-by: SPDK CI Jenkins Reviewed-by: Ben Walker Reviewed-by: Changpeng Liu --- lib/vhost/Makefile | 2 +- lib/vhost/rte_vhost_compat.c | 132 +++++++++++++++++++++++++ lib/vhost/vhost.c | 9 +- lib/vhost/vhost_internal.h | 5 + test/unit/lib/vhost/vhost.c/vhost_ut.c | 2 + 5 files changed, 146 insertions(+), 4 deletions(-) create mode 100644 lib/vhost/rte_vhost_compat.c 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);