Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 93c20a59 authored by FUJITA Tomonori's avatar FUJITA Tomonori Committed by James Bottomley
Browse files

[SCSI] scsi_transport_sas: fix the lifetime of sas bsg objects



scsi_transport_sas calls blk_cleanup_queue too early for bsg
queues. If a user holds a sas_host, end_device, or expander device
open, remove the device, then send a request to it, we get a kernel
crash. We need to call blk_cleanup_queue in the release callback as we
do with scsi devices.

This patch moves blk_cleanup_queue to sas_expander_release and
sas_end_device_release from sas_bsg_remove. sas_host can't use the
release callback in struct device so use bsg's release callback.

Signed-off-by: default avatarFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 97f46ae4
Loading
Loading
Loading
Loading
+20 −2
Original line number Diff line number Diff line
@@ -192,6 +192,16 @@ static void sas_non_host_smp_request(struct request_queue *q)
	sas_smp_request(q, rphy_to_shost(rphy), rphy);
}

static void sas_host_release(struct device *dev)
{
	struct Scsi_Host *shost = dev_to_shost(dev);
	struct sas_host_attrs *sas_host = to_sas_host_attrs(shost);
	struct request_queue *q = sas_host->q;

	if (q)
		blk_cleanup_queue(q);
}

static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
{
	struct request_queue *q;
@@ -199,6 +209,7 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
	struct device *dev;
	char namebuf[BUS_ID_SIZE];
	const char *name;
	void (*release)(struct device *);

	if (!to_sas_internal(shost->transportt)->f->smp_handler) {
		printk("%s can't handle SMP requests\n", shost->hostt->name);
@@ -209,17 +220,19 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
		q = blk_init_queue(sas_non_host_smp_request, NULL);
		dev = &rphy->dev;
		name = dev->bus_id;
		release = NULL;
	} else {
		q = blk_init_queue(sas_host_smp_request, NULL);
		dev = &shost->shost_gendev;
		snprintf(namebuf, sizeof(namebuf),
			 "sas_host%d", shost->host_no);
		name = namebuf;
		release = sas_host_release;
	}
	if (!q)
		return -ENOMEM;

	error = bsg_register_queue(q, dev, name, NULL);
	error = bsg_register_queue(q, dev, name, release);
	if (error) {
		blk_cleanup_queue(q);
		return -ENOMEM;
@@ -253,7 +266,6 @@ static void sas_bsg_remove(struct Scsi_Host *shost, struct sas_rphy *rphy)
		return;

	bsg_unregister_queue(q);
	blk_cleanup_queue(q);
}

/*
@@ -1301,6 +1313,9 @@ static void sas_expander_release(struct device *dev)
	struct sas_rphy *rphy = dev_to_rphy(dev);
	struct sas_expander_device *edev = rphy_to_expander_device(rphy);

	if (rphy->q)
		blk_cleanup_queue(rphy->q);

	put_device(dev->parent);
	kfree(edev);
}
@@ -1310,6 +1325,9 @@ static void sas_end_device_release(struct device *dev)
	struct sas_rphy *rphy = dev_to_rphy(dev);
	struct sas_end_device *edev = rphy_to_end_device(rphy);

	if (rphy->q)
		blk_cleanup_queue(rphy->q);

	put_device(dev->parent);
	kfree(edev);
}