lib/vhost: register VQ interrupt handler when enable VQ
In commit 23baa67
, we will start virtio device only once,
and update the VQ's information in SET_VRING_KICK message
context, so when multi-queues are enabled, SPDK doesn't
register VQ's interrupt handler, here we add it when enable
VQ.
Fix issue #2940.
Change-Id: I29dbd7bf0b81b23c2e47e37c467952cc5887b5bf
Signed-off-by: Changpeng Liu <changpeng.liu@intel.com>
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/17354
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Community-CI: Mellanox Build Bot
Reviewed-by: Jim Harris <james.r.harris@intel.com>
This commit is contained in:
parent
7062988c66
commit
f3d3338b29
@ -1098,17 +1098,27 @@ enable_device_vq(struct spdk_vhost_session *vsession, uint16_t qid)
|
||||
q->packed.used_phase = q->last_used_idx >> 15;
|
||||
q->last_used_idx = q->last_used_idx & 0x7FFF;
|
||||
|
||||
if (!vsession->interrupt_mode) {
|
||||
if (!spdk_interrupt_mode_is_enabled()) {
|
||||
/* Disable I/O submission notifications, we'll be polling. */
|
||||
q->vring.device_event->flags = VRING_PACKED_EVENT_FLAG_DISABLE;
|
||||
} else {
|
||||
/* Enable I/O submission notifications, we'll be interrupting. */
|
||||
q->vring.device_event->flags = VRING_PACKED_EVENT_FLAG_ENABLE;
|
||||
}
|
||||
} else {
|
||||
if (!vsession->interrupt_mode) {
|
||||
if (!spdk_interrupt_mode_is_enabled()) {
|
||||
/* Disable I/O submission notifications, we'll be polling. */
|
||||
q->vring.used->flags = VRING_USED_F_NO_NOTIFY;
|
||||
} else {
|
||||
/* Enable I/O submission notifications, we'll be interrupting. */
|
||||
q->vring.used->flags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (spdk_interrupt_mode_is_enabled() && backend->register_vq_interrupt) {
|
||||
backend->register_vq_interrupt(vsession, q);
|
||||
}
|
||||
|
||||
q->packed.packed_ring = packed_ring;
|
||||
vsession->max_queues = spdk_max(vsession->max_queues, qid + 1);
|
||||
|
||||
@ -1405,11 +1415,8 @@ void
|
||||
vhost_user_session_set_interrupt_mode(struct spdk_vhost_session *vsession, bool interrupt_mode)
|
||||
{
|
||||
uint16_t i;
|
||||
bool packed_ring;
|
||||
int rc = 0;
|
||||
|
||||
packed_ring = ((vsession->negotiated_features & (1ULL << VIRTIO_F_RING_PACKED)) != 0);
|
||||
|
||||
for (i = 0; i < vsession->max_queues; i++) {
|
||||
struct spdk_vhost_virtqueue *q = &vsession->virtqueue[i];
|
||||
uint64_t num_events = 1;
|
||||
@ -1422,12 +1429,6 @@ vhost_user_session_set_interrupt_mode(struct spdk_vhost_session *vsession, bool
|
||||
}
|
||||
|
||||
if (interrupt_mode) {
|
||||
/* Enable I/O submission notifications, we'll be interrupting. */
|
||||
if (packed_ring) {
|
||||
* (volatile uint16_t *) &q->vring.device_event->flags = VRING_PACKED_EVENT_FLAG_ENABLE;
|
||||
} else {
|
||||
* (volatile uint16_t *) &q->vring.used->flags = 0;
|
||||
}
|
||||
|
||||
/* In case of race condition, always kick vring when switch to intr */
|
||||
rc = write(q->vring.kickfd, &num_events, sizeof(num_events));
|
||||
@ -1437,19 +1438,12 @@ vhost_user_session_set_interrupt_mode(struct spdk_vhost_session *vsession, bool
|
||||
|
||||
vsession->interrupt_mode = true;
|
||||
} else {
|
||||
/* Disable I/O submission notifications, we'll be polling. */
|
||||
if (packed_ring) {
|
||||
* (volatile uint16_t *) &q->vring.device_event->flags = VRING_PACKED_EVENT_FLAG_DISABLE;
|
||||
} else {
|
||||
* (volatile uint16_t *) &q->vring.used->flags = VRING_USED_F_NO_NOTIFY;
|
||||
}
|
||||
|
||||
vsession->interrupt_mode = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
extern_vhost_pre_msg_handler(int vid, void *_msg)
|
||||
{
|
||||
|
@ -1070,9 +1070,35 @@ vhost_blk_session_unregister_interrupts(struct spdk_vhost_blk_session *bvsession
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_vhost_blk_vq_register_interrupt(void *arg)
|
||||
{
|
||||
struct spdk_vhost_virtqueue *vq = arg;
|
||||
struct spdk_vhost_session *vsession = vq->vsession;
|
||||
struct spdk_vhost_blk_dev *bvdev = to_blk_dev(vsession->vdev);
|
||||
|
||||
if (bvdev->bdev) {
|
||||
vq->intr = spdk_interrupt_register(vq->vring.kickfd, vdev_vq_worker, vq, "vdev_vq_worker");
|
||||
} else {
|
||||
vq->intr = spdk_interrupt_register(vq->vring.kickfd, no_bdev_vdev_vq_worker, vq,
|
||||
"no_bdev_vdev_vq_worker");
|
||||
}
|
||||
|
||||
if (vq->intr == NULL) {
|
||||
SPDK_ERRLOG("Fail to register req notifier handler.\n");
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
vhost_blk_vq_register_interrupt(struct spdk_vhost_session *vsession,
|
||||
struct spdk_vhost_virtqueue *vq)
|
||||
{
|
||||
spdk_thread_send_msg(vsession->vdev->thread, _vhost_blk_vq_register_interrupt, vq);
|
||||
}
|
||||
|
||||
static int
|
||||
vhost_blk_session_register_interrupts(struct spdk_vhost_blk_session *bvsession,
|
||||
spdk_interrupt_fn fn, const char *name)
|
||||
vhost_blk_session_register_no_bdev_interrupts(struct spdk_vhost_blk_session *bvsession)
|
||||
{
|
||||
struct spdk_vhost_session *vsession = &bvsession->vsession;
|
||||
struct spdk_vhost_virtqueue *vq = NULL;
|
||||
@ -1083,19 +1109,18 @@ vhost_blk_session_register_interrupts(struct spdk_vhost_blk_session *bvsession,
|
||||
vq = &vsession->virtqueue[i];
|
||||
SPDK_DEBUGLOG(vhost_blk, "Register vq[%d]'s kickfd is %d\n",
|
||||
i, vq->vring.kickfd);
|
||||
|
||||
vq->intr = spdk_interrupt_register(vq->vring.kickfd, fn, vq, name);
|
||||
vq->intr = spdk_interrupt_register(vq->vring.kickfd, no_bdev_vdev_vq_worker, vq,
|
||||
"no_bdev_vdev_vq_worker");
|
||||
if (vq->intr == NULL) {
|
||||
SPDK_ERRLOG("Fail to register req notifier handler.\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
vhost_blk_session_unregister_interrupts(bvsession);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -1157,10 +1182,9 @@ vhost_user_session_bdev_remove_cb(struct spdk_vhost_dev *vdev,
|
||||
bvsession = to_blk_session(vsession);
|
||||
if (bvsession->requestq_poller) {
|
||||
spdk_poller_unregister(&bvsession->requestq_poller);
|
||||
if (vsession->virtqueue[0].intr) {
|
||||
if (vsession->interrupt_mode) {
|
||||
vhost_blk_session_unregister_interrupts(bvsession);
|
||||
rc = vhost_blk_session_register_interrupts(bvsession, no_bdev_vdev_vq_worker,
|
||||
"no_bdev_vdev_vq_worker");
|
||||
rc = vhost_blk_session_register_no_bdev_interrupts(bvsession);
|
||||
if (rc) {
|
||||
SPDK_ERRLOG("%s: Interrupt register failed\n", vsession->name);
|
||||
return rc;
|
||||
@ -1292,7 +1316,7 @@ vhost_blk_start(struct spdk_vhost_dev *vdev,
|
||||
{
|
||||
struct spdk_vhost_blk_session *bvsession = to_blk_session(vsession);
|
||||
struct spdk_vhost_blk_dev *bvdev;
|
||||
int i, rc = 0;
|
||||
int i;
|
||||
|
||||
/* return if start is already in progress */
|
||||
if (bvsession->requestq_poller) {
|
||||
@ -1324,23 +1348,6 @@ vhost_blk_start(struct spdk_vhost_dev *vdev,
|
||||
}
|
||||
}
|
||||
|
||||
if (spdk_interrupt_mode_is_enabled()) {
|
||||
if (bvdev->bdev) {
|
||||
rc = vhost_blk_session_register_interrupts(bvsession,
|
||||
vdev_vq_worker,
|
||||
"vdev_vq_worker");
|
||||
} else {
|
||||
rc = vhost_blk_session_register_interrupts(bvsession,
|
||||
no_bdev_vdev_vq_worker,
|
||||
"no_bdev_vdev_vq_worker");
|
||||
}
|
||||
|
||||
if (rc) {
|
||||
SPDK_ERRLOG("%s: Interrupt register failed\n", vsession->name);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
if (bvdev->bdev) {
|
||||
bvsession->requestq_poller = SPDK_POLLER_REGISTER(vdev_worker, bvsession, 0);
|
||||
} else {
|
||||
@ -1409,10 +1416,7 @@ vhost_blk_stop(struct spdk_vhost_dev *vdev,
|
||||
}
|
||||
|
||||
spdk_poller_unregister(&bvsession->requestq_poller);
|
||||
|
||||
if (vsession->virtqueue[0].intr) {
|
||||
vhost_blk_session_unregister_interrupts(bvsession);
|
||||
}
|
||||
vhost_blk_session_unregister_interrupts(bvsession);
|
||||
|
||||
/* vhost_user_session_send_event timeout is 3 seconds, here set retry within 4 seconds */
|
||||
bvsession->vsession.stop_retry_count = 4000;
|
||||
@ -1558,6 +1562,7 @@ static const struct spdk_vhost_user_dev_backend vhost_blk_user_device_backend =
|
||||
.start_session = vhost_blk_start,
|
||||
.stop_session = vhost_blk_stop,
|
||||
.alloc_vq_tasks = alloc_vq_task_pool,
|
||||
.register_vq_interrupt = vhost_blk_vq_register_interrupt,
|
||||
};
|
||||
|
||||
static const struct spdk_vhost_dev_backend vhost_blk_device_backend = {
|
||||
|
@ -224,6 +224,7 @@ struct spdk_vhost_user_dev_backend {
|
||||
spdk_vhost_session_fn start_session;
|
||||
spdk_vhost_session_fn stop_session;
|
||||
int (*alloc_vq_tasks)(struct spdk_vhost_session *vsession, uint16_t qid);
|
||||
void (*register_vq_interrupt)(struct spdk_vhost_session *vsession, struct spdk_vhost_virtqueue *vq);
|
||||
};
|
||||
|
||||
enum vhost_backend_type {
|
||||
|
Loading…
Reference in New Issue
Block a user