summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Bellinger <nab@linux-iscsi.org>2014-10-08 06:19:20 +0000
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-12-06 15:57:30 -0800
commitaec8181a5a4acb9a8037c4bcb6357bd28f788134 (patch)
treee8509aa5d45513e23108a33a3dc3c8fe59a841bf
parent6184818cd6ed588714e56fc6ee7327eb5f570f91 (diff)
vhost-scsi: Take configfs group dependency during VHOST_SCSI_SET_ENDPOINT
commit ab8edab132829b26dd13db6caca3c242cce35dc1 upstream. This patch addresses a bug where individual vhost-scsi configfs endpoint groups can be removed from below while active exports to QEMU userspace still exist, resulting in an OOPs. It adds a configfs_depend_item() in vhost_scsi_set_endpoint() to obtain an explicit dependency on se_tpg->tpg_group in order to prevent individual vhost-scsi WWPN endpoints from being released via normal configfs methods while an QEMU ioctl reference still exists. Also, add matching configfs_undepend_item() in vhost_scsi_clear_endpoint() to release the dependency, once QEMU's reference to the individual group at /sys/kernel/config/target/vhost/$WWPN/$TPGT is released. (Fix up vhost_scsi_clear_endpoint() error path - DanC) Cc: Michael S. Tsirkin <mst@redhat.com> Cc: Paolo Bonzini <pbonzini@redhat.com> Cc: Stefan Hajnoczi <stefanha@redhat.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/vhost/scsi.c24
1 files changed, 24 insertions, 0 deletions
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
index 69906cacd04f..a17f11850669 100644
--- a/drivers/vhost/scsi.c
+++ b/drivers/vhost/scsi.c
@@ -1312,6 +1312,7 @@ static int
vhost_scsi_set_endpoint(struct vhost_scsi *vs,
struct vhost_scsi_target *t)
{
+ struct se_portal_group *se_tpg;
struct tcm_vhost_tport *tv_tport;
struct tcm_vhost_tpg *tpg;
struct tcm_vhost_tpg **vs_tpg;
@@ -1359,6 +1360,21 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs,
ret = -EEXIST;
goto out;
}
+ /*
+ * In order to ensure individual vhost-scsi configfs
+ * groups cannot be removed while in use by vhost ioctl,
+ * go ahead and take an explicit se_tpg->tpg_group.cg_item
+ * dependency now.
+ */
+ se_tpg = &tpg->se_tpg;
+ ret = configfs_depend_item(se_tpg->se_tpg_tfo->tf_subsys,
+ &se_tpg->tpg_group.cg_item);
+ if (ret) {
+ pr_warn("configfs_depend_item() failed: %d\n", ret);
+ kfree(vs_tpg);
+ mutex_unlock(&tpg->tv_tpg_mutex);
+ goto out;
+ }
tpg->tv_tpg_vhost_count++;
tpg->vhost_scsi = vs;
vs_tpg[tpg->tport_tpgt] = tpg;
@@ -1401,6 +1417,7 @@ static int
vhost_scsi_clear_endpoint(struct vhost_scsi *vs,
struct vhost_scsi_target *t)
{
+ struct se_portal_group *se_tpg;
struct tcm_vhost_tport *tv_tport;
struct tcm_vhost_tpg *tpg;
struct vhost_virtqueue *vq;
@@ -1449,6 +1466,13 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs,
vs->vs_tpg[target] = NULL;
match = true;
mutex_unlock(&tpg->tv_tpg_mutex);
+ /*
+ * Release se_tpg->tpg_group.cg_item configfs dependency now
+ * to allow vhost-scsi WWPN se_tpg->tpg_group shutdown to occur.
+ */
+ se_tpg = &tpg->se_tpg;
+ configfs_undepend_item(se_tpg->se_tpg_tfo->tf_subsys,
+ &se_tpg->tpg_group.cg_item);
}
if (match) {
for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {