mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 20:51:44 +00:00
[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: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
parent
97f46ae45c
commit
93c20a59af
@ -192,6 +192,16 @@ static void sas_non_host_smp_request(struct request_queue *q)
|
|||||||
sas_smp_request(q, rphy_to_shost(rphy), rphy);
|
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)
|
static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
|
||||||
{
|
{
|
||||||
struct request_queue *q;
|
struct request_queue *q;
|
||||||
@ -199,6 +209,7 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)
|
|||||||
struct device *dev;
|
struct device *dev;
|
||||||
char namebuf[BUS_ID_SIZE];
|
char namebuf[BUS_ID_SIZE];
|
||||||
const char *name;
|
const char *name;
|
||||||
|
void (*release)(struct device *);
|
||||||
|
|
||||||
if (!to_sas_internal(shost->transportt)->f->smp_handler) {
|
if (!to_sas_internal(shost->transportt)->f->smp_handler) {
|
||||||
printk("%s can't handle SMP requests\n", shost->hostt->name);
|
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);
|
q = blk_init_queue(sas_non_host_smp_request, NULL);
|
||||||
dev = &rphy->dev;
|
dev = &rphy->dev;
|
||||||
name = dev->bus_id;
|
name = dev->bus_id;
|
||||||
|
release = NULL;
|
||||||
} else {
|
} else {
|
||||||
q = blk_init_queue(sas_host_smp_request, NULL);
|
q = blk_init_queue(sas_host_smp_request, NULL);
|
||||||
dev = &shost->shost_gendev;
|
dev = &shost->shost_gendev;
|
||||||
snprintf(namebuf, sizeof(namebuf),
|
snprintf(namebuf, sizeof(namebuf),
|
||||||
"sas_host%d", shost->host_no);
|
"sas_host%d", shost->host_no);
|
||||||
name = namebuf;
|
name = namebuf;
|
||||||
|
release = sas_host_release;
|
||||||
}
|
}
|
||||||
if (!q)
|
if (!q)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
error = bsg_register_queue(q, dev, name, NULL);
|
error = bsg_register_queue(q, dev, name, release);
|
||||||
if (error) {
|
if (error) {
|
||||||
blk_cleanup_queue(q);
|
blk_cleanup_queue(q);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
@ -253,7 +266,6 @@ static void sas_bsg_remove(struct Scsi_Host *shost, struct sas_rphy *rphy)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
bsg_unregister_queue(q);
|
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_rphy *rphy = dev_to_rphy(dev);
|
||||||
struct sas_expander_device *edev = rphy_to_expander_device(rphy);
|
struct sas_expander_device *edev = rphy_to_expander_device(rphy);
|
||||||
|
|
||||||
|
if (rphy->q)
|
||||||
|
blk_cleanup_queue(rphy->q);
|
||||||
|
|
||||||
put_device(dev->parent);
|
put_device(dev->parent);
|
||||||
kfree(edev);
|
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_rphy *rphy = dev_to_rphy(dev);
|
||||||
struct sas_end_device *edev = rphy_to_end_device(rphy);
|
struct sas_end_device *edev = rphy_to_end_device(rphy);
|
||||||
|
|
||||||
|
if (rphy->q)
|
||||||
|
blk_cleanup_queue(rphy->q);
|
||||||
|
|
||||||
put_device(dev->parent);
|
put_device(dev->parent);
|
||||||
kfree(edev);
|
kfree(edev);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user