nvmf/vfio-user: re-check doorbells upon resuming
If we're in interrupt mode and live migrating a guest, there is a window where the I/O queues haven't been set up but the device is in running state, during which the guest might write to a doorbell. This doorbell write will go unnoticed. This patch ensures that we re-check the doorbells after an I/O queue has been set up. Fixes #2410 Signed-off-by: Thanos Makatos <thanos.makatos@nutanix.com> Signed-off-by: John Levon <john.levon@nutanix.com> Change-Id: I161d2a0e7ab3065022b2bccbe17f019640cceeba Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/11809 Community-CI: Broadcom CI <spdk-ci.pdl@broadcom.com> Community-CI: Mellanox Build Bot Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Changpeng Liu <changpeng.liu@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
parent
f3950cf457
commit
eb0305e0e6
@ -349,6 +349,8 @@ struct nvmf_vfio_user_ctrlr {
|
||||
TAILQ_ENTRY(nvmf_vfio_user_ctrlr) link;
|
||||
|
||||
volatile uint32_t *doorbells;
|
||||
|
||||
bool self_kick_requested;
|
||||
};
|
||||
|
||||
struct nvmf_vfio_user_endpoint {
|
||||
@ -497,6 +499,38 @@ vfio_user_migr_data_len(void)
|
||||
return SPDK_ALIGN_CEIL(sizeof(struct vfio_user_nvme_migr_state), PAGE_SIZE);
|
||||
}
|
||||
|
||||
static int
|
||||
vfio_user_handle_intr(void *ctx);
|
||||
|
||||
/*
|
||||
* Wrap vfio_user_handle_intr() such that it can be used with
|
||||
* spdk_thread_send_msg().
|
||||
* Pollers have type int (*)(void *) while message functions should have type
|
||||
* void (*)(void *), so simply discard the returned value.
|
||||
*/
|
||||
static void
|
||||
vfio_user_handle_intr_wrapper(void *ctx)
|
||||
{
|
||||
vfio_user_handle_intr(ctx);
|
||||
}
|
||||
|
||||
static inline int
|
||||
self_kick(struct nvmf_vfio_user_ctrlr *ctrlr)
|
||||
{
|
||||
assert(ctrlr != NULL);
|
||||
assert(ctrlr->thread != NULL);
|
||||
|
||||
if (ctrlr->self_kick_requested) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctrlr->self_kick_requested = true;
|
||||
|
||||
return spdk_thread_send_msg(ctrlr->thread,
|
||||
vfio_user_handle_intr_wrapper,
|
||||
ctrlr);
|
||||
}
|
||||
|
||||
static int
|
||||
nvme_cmd_map_prps(void *prv, struct spdk_nvme_cmd *cmd, struct iovec *iovs,
|
||||
uint32_t max_iovcnt, uint32_t len, size_t mps,
|
||||
@ -3550,6 +3584,13 @@ nvmf_vfio_user_poll_group_create(struct spdk_nvmf_transport *transport,
|
||||
return &vu_group->group;
|
||||
}
|
||||
|
||||
static bool
|
||||
in_interrupt_mode(struct nvmf_vfio_user_transport *vu_transport)
|
||||
{
|
||||
return spdk_interrupt_mode_is_enabled() &&
|
||||
vu_transport->intr_mode_supported;
|
||||
}
|
||||
|
||||
static struct spdk_nvmf_transport_poll_group *
|
||||
nvmf_vfio_user_get_optimal_poll_group(struct spdk_nvmf_qpair *qpair)
|
||||
{
|
||||
@ -3586,8 +3627,7 @@ nvmf_vfio_user_get_optimal_poll_group(struct spdk_nvmf_qpair *qpair)
|
||||
* on the same poll group, to avoid complications in
|
||||
* vfio_user_handle_intr().
|
||||
*/
|
||||
if (spdk_interrupt_mode_is_enabled() &&
|
||||
vu_transport->intr_mode_supported) {
|
||||
if (in_interrupt_mode(vu_transport)) {
|
||||
result = sq->ctrlr->sqs[0]->group;
|
||||
goto out;
|
||||
}
|
||||
@ -3746,6 +3786,8 @@ vfio_user_handle_intr(void *ctx)
|
||||
assert(ctrlr->sqs[0] != NULL);
|
||||
assert(ctrlr->sqs[0]->group != NULL);
|
||||
|
||||
ctrlr->self_kick_requested = false;
|
||||
|
||||
vfio_user_poll_vfu_ctx(ctrlr);
|
||||
|
||||
/*
|
||||
@ -3797,8 +3839,7 @@ handle_queue_connect_rsp(struct nvmf_vfio_user_req *req, void *cb_arg)
|
||||
|
||||
cq->thread = spdk_get_thread();
|
||||
|
||||
if (spdk_interrupt_mode_is_enabled() &&
|
||||
endpoint->transport->intr_mode_supported) {
|
||||
if (in_interrupt_mode(endpoint->transport)) {
|
||||
vu_ctrlr->intr_fd = vfu_get_poll_fd(vu_ctrlr->endpoint->vfu_ctx);
|
||||
assert(vu_ctrlr->intr_fd != -1);
|
||||
|
||||
@ -3840,6 +3881,14 @@ handle_queue_connect_rsp(struct nvmf_vfio_user_req *req, void *cb_arg)
|
||||
sq->create_io_sq_cmd.cid, SPDK_NVME_SC_SUCCESS, SPDK_NVME_SCT_GENERIC);
|
||||
}
|
||||
sq->post_create_io_sq_completion = false;
|
||||
} else if (in_interrupt_mode(endpoint->transport)) {
|
||||
/*
|
||||
* FIXME self_kick() ends up polling all queues on the
|
||||
* controller thread, and this will be wrong if we ever
|
||||
* support interrupt mode with I/O queues in a
|
||||
* different poll group than the controller's.
|
||||
*/
|
||||
self_kick(vu_ctrlr);
|
||||
}
|
||||
sq->sq_state = VFIO_USER_SQ_ACTIVE;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user