Commit ab8edab1 authored by Nicholas Bellinger's avatar Nicholas Bellinger

vhost-scsi: Take configfs group dependency during VHOST_SCSI_SET_ENDPOINT

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>
Cc: <stable@vger.kernel.org> # 3.6+
Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
parent 885e7b0e
...@@ -1312,6 +1312,7 @@ static int ...@@ -1312,6 +1312,7 @@ static int
vhost_scsi_set_endpoint(struct vhost_scsi *vs, vhost_scsi_set_endpoint(struct vhost_scsi *vs,
struct vhost_scsi_target *t) struct vhost_scsi_target *t)
{ {
struct se_portal_group *se_tpg;
struct tcm_vhost_tport *tv_tport; struct tcm_vhost_tport *tv_tport;
struct tcm_vhost_tpg *tpg; struct tcm_vhost_tpg *tpg;
struct tcm_vhost_tpg **vs_tpg; struct tcm_vhost_tpg **vs_tpg;
...@@ -1359,6 +1360,21 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs, ...@@ -1359,6 +1360,21 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs,
ret = -EEXIST; ret = -EEXIST;
goto out; 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->tv_tpg_vhost_count++;
tpg->vhost_scsi = vs; tpg->vhost_scsi = vs;
vs_tpg[tpg->tport_tpgt] = tpg; vs_tpg[tpg->tport_tpgt] = tpg;
...@@ -1401,6 +1417,7 @@ static int ...@@ -1401,6 +1417,7 @@ static int
vhost_scsi_clear_endpoint(struct vhost_scsi *vs, vhost_scsi_clear_endpoint(struct vhost_scsi *vs,
struct vhost_scsi_target *t) struct vhost_scsi_target *t)
{ {
struct se_portal_group *se_tpg;
struct tcm_vhost_tport *tv_tport; struct tcm_vhost_tport *tv_tport;
struct tcm_vhost_tpg *tpg; struct tcm_vhost_tpg *tpg;
struct vhost_virtqueue *vq; struct vhost_virtqueue *vq;
...@@ -1449,6 +1466,13 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs, ...@@ -1449,6 +1466,13 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs,
vs->vs_tpg[target] = NULL; vs->vs_tpg[target] = NULL;
match = true; match = true;
mutex_unlock(&tpg->tv_tpg_mutex); 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) { if (match) {
for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) { for (i = 0; i < VHOST_SCSI_MAX_VQ; i++) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment