aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2008-04-18 11:43:15 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-04-22 16:16:32 -0400
commit93c20a59af4624aedf53f8320606b355aa951bc1 (patch)
tree9d17e23f66e4db98171f7342f3ddf27af9664b49
parent97f46ae45c70857e459b7f8df1fc2807e7bd90a9 (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.c22
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
195static 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
195static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy) 205static 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}