From 5d07cfad5433632e9801d03926c9bbb86d46ad59 Mon Sep 17 00:00:00 2001 From: Darek Stojaczyk Date: Fri, 15 Feb 2019 11:29:09 +0100 Subject: [PATCH] vhost/scsi: handle io_channel allocation failure We assumed io_channel allocation always succeeds, but that's not true. Doing I/O to any vhost session that failed to allocate an io_channel would most likely cause a crash. We'll now detect io_channel allocation failure and print a proper error message. The SCSI target for which the channel allocation failed simply won't be visible to the vhost master. All I/O to that target will be rejected. We should probably report the error to the upper layer and either prevent the device from starting or fail the SCSI target hotplug request. But for now let's just prevent the crash. Change-Id: I735dfb930d8905f70636a236b4fa94288d0aaf3a Signed-off-by: Darek Stojaczyk Reviewed-on: https://review.gerrithub.io/c/444874 Tested-by: SPDK CI Jenkins Reviewed-by: Ben Walker Reviewed-by: Jim Harris --- lib/vhost/vhost_scsi.c | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/lib/vhost/vhost_scsi.c b/lib/vhost/vhost_scsi.c index b641f713bf..a460161624 100644 --- a/lib/vhost/vhost_scsi.c +++ b/lib/vhost/vhost_scsi.c @@ -900,13 +900,14 @@ spdk_vhost_scsi_session_add_tgt(struct spdk_vhost_dev *vdev, { unsigned scsi_tgt_num = (unsigned)(uintptr_t)ctx; struct spdk_vhost_scsi_session *svsession; + int rc; if (vsession == NULL) { /* Nothing more to do */ return 0; } - svsession = (struct spdk_vhost_scsi_session *)vsession;; + svsession = (struct spdk_vhost_scsi_session *)vsession; /* copy the entire device state */ svsession->scsi_dev_state[scsi_tgt_num] = svsession->svdev->scsi_dev_state[scsi_tgt_num]; @@ -915,7 +916,25 @@ spdk_vhost_scsi_session_add_tgt(struct spdk_vhost_dev *vdev, return 0; } - spdk_scsi_dev_allocate_io_channels(svsession->scsi_dev_state[scsi_tgt_num].dev); + rc = spdk_scsi_dev_allocate_io_channels(svsession->scsi_dev_state[scsi_tgt_num].dev); + if (rc != 0) { + SPDK_ERRLOG("Couldn't allocate io channnel for SCSI target %u in device %s\n", + scsi_tgt_num, vdev->name); + + /* unset the SCSI target so that all I/O to it will be rejected */ + svsession->scsi_dev_state[scsi_tgt_num].dev = NULL; + /* unset the removed flag so that we won't reply with SCSI hotremove + * sense codes - the device hasn't ever been added. + */ + svsession->scsi_dev_state[scsi_tgt_num].removed = false; + + /* Return with no error. We'll continue allocating io_channels for + * other sessions on this device in hopes they succeed. The sessions + * that failed to allocate io_channels simply won't be able to + * detect the SCSI target, nor do any I/O to it. + */ + return 0; + } if (spdk_vhost_dev_has_feature(vsession, VIRTIO_SCSI_F_HOTPLUG)) { eventq_enqueue(svsession, scsi_tgt_num, @@ -1249,7 +1268,17 @@ spdk_vhost_scsi_start_cb(struct spdk_vhost_dev *vdev, continue; } svsession->scsi_dev_state[i] = *state; - spdk_scsi_dev_allocate_io_channels(state->dev); + rc = spdk_scsi_dev_allocate_io_channels(state->dev); + if (rc != 0) { + SPDK_ERRLOG("%s: failed to alloc io_channel for SCSI target %"PRIu32"\n", vdev->name, i); + /* unset the SCSI target so that all I/O to it will be rejected */ + svsession->scsi_dev_state[i].dev = NULL; + /* unset the removed flag so that we won't reply with SCSI hotremove + * sense codes - the device hasn't ever been added. + */ + svsession->scsi_dev_state[i].removed = false; + continue; + } } SPDK_INFOLOG(SPDK_LOG_VHOST, "Started poller for vhost controller %s on lcore %d\n", vdev->name, vsession->lcore);