diff options
author | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2008-04-18 11:43:15 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@HansenPartnership.com> | 2008-04-22 16:16:32 -0400 |
commit | 93c20a59af4624aedf53f8320606b355aa951bc1 (patch) | |
tree | 9d17e23f66e4db98171f7342f3ddf27af9664b49 | |
parent | 97f46ae45c70857e459b7f8df1fc2807e7bd90a9 (diff) |
[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>
-rw-r--r-- | drivers/scsi/scsi_transport_sas.c | 22 |
1 files changed, 20 insertions, 2 deletions
diff --git a/drivers/scsi/scsi_transport_sas.c b/drivers/scsi/scsi_transport_sas.c index 94ff29f7c34b..7899e3dda9bf 100644 --- a/drivers/scsi/scsi_transport_sas.c +++ b/drivers/scsi/scsi_transport_sas.c | |||
@@ -192,6 +192,16 @@ static void sas_non_host_smp_request(struct request_queue *q) | |||
192 | sas_smp_request(q, rphy_to_shost(rphy), rphy); | 192 | sas_smp_request(q, rphy_to_shost(rphy), rphy); |
193 | } | 193 | } |
194 | 194 | ||
195 | static void sas_host_release(struct device *dev) | ||
196 | { | ||
197 | struct Scsi_Host *shost = dev_to_shost(dev); | ||
198 | struct sas_host_attrs *sas_host = to_sas_host_attrs(shost); | ||
199 | struct request_queue *q = sas_host->q; | ||
200 | |||
201 | if (q) | ||
202 | blk_cleanup_queue(q); | ||
203 | } | ||
204 | |||
195 | static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy) | 205 | static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy) |
196 | { | 206 | { |
197 | struct request_queue *q; | 207 | struct request_queue *q; |
@@ -199,6 +209,7 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy) | |||
199 | struct device *dev; | 209 | struct device *dev; |
200 | char namebuf[BUS_ID_SIZE]; | 210 | char namebuf[BUS_ID_SIZE]; |
201 | const char *name; | 211 | const char *name; |
212 | void (*release)(struct device *); | ||
202 | 213 | ||
203 | if (!to_sas_internal(shost->transportt)->f->smp_handler) { | 214 | if (!to_sas_internal(shost->transportt)->f->smp_handler) { |
204 | printk("%s can't handle SMP requests\n", shost->hostt->name); | 215 | 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) | |||
209 | q = blk_init_queue(sas_non_host_smp_request, NULL); | 220 | q = blk_init_queue(sas_non_host_smp_request, NULL); |
210 | dev = &rphy->dev; | 221 | dev = &rphy->dev; |
211 | name = dev->bus_id; | 222 | name = dev->bus_id; |
223 | release = NULL; | ||
212 | } else { | 224 | } else { |
213 | q = blk_init_queue(sas_host_smp_request, NULL); | 225 | q = blk_init_queue(sas_host_smp_request, NULL); |
214 | dev = &shost->shost_gendev; | 226 | dev = &shost->shost_gendev; |
215 | snprintf(namebuf, sizeof(namebuf), | 227 | snprintf(namebuf, sizeof(namebuf), |
216 | "sas_host%d", shost->host_no); | 228 | "sas_host%d", shost->host_no); |
217 | name = namebuf; | 229 | name = namebuf; |
230 | release = sas_host_release; | ||
218 | } | 231 | } |
219 | if (!q) | 232 | if (!q) |
220 | return -ENOMEM; | 233 | return -ENOMEM; |
221 | 234 | ||
222 | error = bsg_register_queue(q, dev, name, NULL); | 235 | error = bsg_register_queue(q, dev, name, release); |
223 | if (error) { | 236 | if (error) { |
224 | blk_cleanup_queue(q); | 237 | blk_cleanup_queue(q); |
225 | return -ENOMEM; | 238 | return -ENOMEM; |
@@ -253,7 +266,6 @@ static void sas_bsg_remove(struct Scsi_Host *shost, struct sas_rphy *rphy) | |||
253 | return; | 266 | return; |
254 | 267 | ||
255 | bsg_unregister_queue(q); | 268 | bsg_unregister_queue(q); |
256 | blk_cleanup_queue(q); | ||
257 | } | 269 | } |
258 | 270 | ||
259 | /* | 271 | /* |
@@ -1301,6 +1313,9 @@ static void sas_expander_release(struct device *dev) | |||
1301 | struct sas_rphy *rphy = dev_to_rphy(dev); | 1313 | struct sas_rphy *rphy = dev_to_rphy(dev); |
1302 | struct sas_expander_device *edev = rphy_to_expander_device(rphy); | 1314 | struct sas_expander_device *edev = rphy_to_expander_device(rphy); |
1303 | 1315 | ||
1316 | if (rphy->q) | ||
1317 | blk_cleanup_queue(rphy->q); | ||
1318 | |||
1304 | put_device(dev->parent); | 1319 | put_device(dev->parent); |
1305 | kfree(edev); | 1320 | kfree(edev); |
1306 | } | 1321 | } |
@@ -1310,6 +1325,9 @@ static void sas_end_device_release(struct device *dev) | |||
1310 | struct sas_rphy *rphy = dev_to_rphy(dev); | 1325 | struct sas_rphy *rphy = dev_to_rphy(dev); |
1311 | struct sas_end_device *edev = rphy_to_end_device(rphy); | 1326 | struct sas_end_device *edev = rphy_to_end_device(rphy); |
1312 | 1327 | ||
1328 | if (rphy->q) | ||
1329 | blk_cleanup_queue(rphy->q); | ||
1330 | |||
1313 | put_device(dev->parent); | 1331 | put_device(dev->parent); |
1314 | kfree(edev); | 1332 | kfree(edev); |
1315 | } | 1333 | } |