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 <dariusz.stojaczyk@intel.com>
Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/446085
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Changpeng Liu <changpeng.liu@intel.com>
This commit is contained in:
Darek Stojaczyk 2019-02-23 12:59:34 +01:00 committed by Jim Harris
parent 2725b5191e
commit 0a6ad9b02e
5 changed files with 146 additions and 4 deletions

View File

@ -37,7 +37,7 @@ include $(SPDK_ROOT_DIR)/mk/spdk.common.mk
CFLAGS += -I. CFLAGS += -I.
CFLAGS += $(ENV_CFLAGS) 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) ifeq ($(CONFIG_VHOST_INTERNAL_LIB),y)
C_SRCS += vhost_nvme.c C_SRCS += vhost_nvme.c

View File

@ -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

View File

@ -527,7 +527,7 @@ spdk_vhost_session_find_by_id(struct spdk_vhost_dev *vdev, unsigned id)
return NULL; return NULL;
} }
static struct spdk_vhost_session * struct spdk_vhost_session *
spdk_vhost_session_find_by_vid(int vid) spdk_vhost_session_find_by_vid(int vid)
{ {
struct spdk_vhost_dev *vdev; struct spdk_vhost_dev *vdev;
@ -1018,7 +1018,7 @@ stop_device(int vid)
vdev = vsession->vdev; vdev = vsession->vdev;
if (vsession->lcore == -1) { 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); pthread_mutex_unlock(&g_spdk_vhost_mutex);
return; return;
} }
@ -1064,7 +1064,8 @@ start_device(int vid)
vdev = vsession->vdev; vdev = vsession->vdev;
if (vsession->lcore != -1) { if (vsession->lcore != -1) {
SPDK_ERRLOG("Controller %s already loaded.\n", vdev->name); /* already started, nothing to do */
rc = 0;
goto out; goto out;
} }
@ -1302,6 +1303,8 @@ new_connection(int vid)
vsession->stats_check_interval = SPDK_VHOST_STATS_CHECK_INTERVAL_MS * vsession->stats_check_interval = SPDK_VHOST_STATS_CHECK_INTERVAL_MS *
spdk_get_ticks_hz() / 1000UL; spdk_get_ticks_hz() / 1000UL;
TAILQ_INSERT_TAIL(&vdev->vsessions, vsession, tailq); TAILQ_INSERT_TAIL(&vdev->vsessions, vsession, tailq);
spdk_vhost_session_install_rte_compat_hooks(vsession);
pthread_mutex_unlock(&g_spdk_vhost_mutex); pthread_mutex_unlock(&g_spdk_vhost_mutex);
return 0; return 0;
} }

View File

@ -126,6 +126,8 @@ struct spdk_vhost_session {
int32_t lcore; int32_t lcore;
bool needs_restart;
struct rte_vhost_memory *mem; struct rte_vhost_memory *mem;
int task_cnt; 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); 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); void spdk_vhost_free_reactor(uint32_t lcore);
uint32_t spdk_vhost_allocate_reactor(struct spdk_cpuset *cpumask); uint32_t spdk_vhost_allocate_reactor(struct spdk_cpuset *cpumask);

View File

@ -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); 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, 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); 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(rte_vhost_driver_unregister, int, (const char *path), 0);
DEFINE_STUB(spdk_event_allocate, struct spdk_event *, DEFINE_STUB(spdk_event_allocate, struct spdk_event *,
(uint32_t lcore, spdk_event_fn fn, void *arg1, void *arg2), NULL); (uint32_t lcore, spdk_event_fn fn, void *arg1, void *arg2), NULL);