vhost_scsi: implemented vhost device hotremove

Vhost devices can now be removed via RPC at any time.

Change-Id: Ib91dd6eb11ae8c777e8b9498d140e89a3fe382db
Signed-off-by: Dariusz Stojaczyk <dariuszx.stojaczyk@intel.com>
Reviewed-on: https://review.gerrithub.io/366726
Tested-by: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Daniel Verkamp <daniel.verkamp@intel.com>
This commit is contained in:
Dariusz Stojaczyk 2017-06-22 19:29:21 +02:00 committed by Daniel Verkamp
parent 57f9221fab
commit 76e5900d50

View File

@ -78,6 +78,7 @@ struct spdk_vhost_scsi_dev {
struct spdk_vhost_dev vdev;
struct spdk_scsi_dev *scsi_dev[SPDK_VHOST_SCSI_CTRLR_MAX_DEVS];
bool removed_dev[SPDK_VHOST_SCSI_CTRLR_MAX_DEVS];
struct spdk_poller *requestq_poller;
struct spdk_poller *mgmt_poller;
@ -183,6 +184,24 @@ process_eventq(struct spdk_vhost_scsi_dev *svdev)
}
}
static void
process_removed_devs(struct spdk_vhost_scsi_dev *svdev)
{
struct spdk_scsi_dev *dev;
int i;
for (i = 0; i < SPDK_VHOST_SCSI_CTRLR_MAX_DEVS; ++i) {
dev = svdev->scsi_dev[i];
if (dev && svdev->removed_dev[i] && !spdk_scsi_dev_has_pending_tasks(dev)) {
spdk_scsi_dev_free_io_channels(dev);
spdk_scsi_dev_destruct(dev);
svdev->scsi_dev[i] = NULL;
SPDK_NOTICELOG("%s: hotremoved device 'Dev %u'.\n", svdev->vdev.name, i);
}
}
}
static void
eventq_enqueue(struct spdk_vhost_scsi_dev *svdev, const struct spdk_scsi_dev *dev,
const struct spdk_scsi_lun *lun, uint32_t event, uint32_t reason)
@ -311,11 +330,14 @@ spdk_vhost_task_init_target(struct spdk_vhost_task *task, const __u8 *lun)
return -1;
dev = task->svdev->scsi_dev[lun[1]];
task->scsi_dev = dev;
if (dev == NULL) {
return -1;
/* If dev has been hotremoved, return 0 to allow sending additional
* hotremove event via sense codes.
*/
return task->svdev->removed_dev[lun[1]] ? 0 : -1;
}
task->scsi_dev = dev;
task->scsi.target_port = spdk_scsi_dev_find_port_by_id(task->scsi_dev, 0);
task->scsi.lun = spdk_scsi_dev_get_lun(dev, lun_id);
return 0;
@ -596,6 +618,7 @@ vdev_mgmt_worker(void *arg)
{
struct spdk_vhost_scsi_dev *svdev = arg;
process_removed_devs(svdev);
process_eventq(svdev);
process_controlq(svdev, &svdev->vdev.virtqueue[VIRTIO_SCSI_CONTROLQ]);
}
@ -810,6 +833,7 @@ spdk_vhost_scsi_dev_add_dev(const char *ctrlr_name, unsigned scsi_dev_num, const
lun_id_list[0] = 0;
lun_names_list[0] = (char *)lun_name;
svdev->removed_dev[scsi_dev_num] = false;
svdev->scsi_dev[scsi_dev_num] = spdk_scsi_dev_construct(dev_name, lun_names_list, lun_id_list, 1,
SPDK_SPC_PROTOCOL_IDENTIFIER_SAS, spdk_vhost_scsi_lun_hotremove, svdev);
@ -828,11 +852,11 @@ int
spdk_vhost_scsi_dev_remove_dev(struct spdk_vhost_dev *vdev, unsigned scsi_dev_num)
{
struct spdk_vhost_scsi_dev *svdev;
struct spdk_scsi_dev *scsi_dev;
assert(vdev != NULL);
if (vdev->lcore != -1) {
SPDK_ERRLOG("Controller %s is in use and hotremove is not supported\n", vdev->name);
return -EBUSY;
if (scsi_dev_num >= SPDK_VHOST_SCSI_CTRLR_MAX_DEVS) {
SPDK_ERRLOG("%s: invalid device number %d\n", vdev->name, scsi_dev_num);
return -EINVAL;
}
svdev = to_scsi_dev(vdev);
@ -840,16 +864,29 @@ spdk_vhost_scsi_dev_remove_dev(struct spdk_vhost_dev *vdev, unsigned scsi_dev_nu
return -ENODEV;
}
if (svdev->scsi_dev[scsi_dev_num] == NULL) {
scsi_dev = svdev->scsi_dev[scsi_dev_num];
if (scsi_dev == NULL) {
SPDK_ERRLOG("Controller %s dev %u is not occupied\n", vdev->name, scsi_dev_num);
return -ENODEV;
}
spdk_scsi_dev_destruct(svdev->scsi_dev[scsi_dev_num]);
if (svdev->vdev.lcore == -1) {
/* controller is not in use, remove dev and exit */
spdk_scsi_dev_destruct(scsi_dev);
svdev->scsi_dev[scsi_dev_num] = NULL;
SPDK_NOTICELOG("%s: removed device 'Dev %u'\n", vdev->name, scsi_dev_num);
return 0;
}
SPDK_NOTICELOG("Controller %s: removed device 'Dev %u'\n",
vdev->name, scsi_dev_num);
if ((svdev->vdev.negotiated_features & (1ULL << VIRTIO_SCSI_F_HOTPLUG)) == 0) {
SPDK_WARNLOG("Controller %s: hotremove is not supported\n", svdev->vdev.name);
return -ENOTSUP;
}
svdev->removed_dev[scsi_dev_num] = true;
eventq_enqueue(svdev, scsi_dev, NULL, VIRTIO_SCSI_T_TRANSPORT_RESET, VIRTIO_SCSI_EVT_RESET_REMOVED);
SPDK_NOTICELOG("%s: 'Dev %u' marked for hotremove.\n", vdev->name, scsi_dev_num);
return 0;
}