aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorBart Van Assche <bvanassche@acm.org>2012-06-29 11:33:22 -0400
committerJames Bottomley <JBottomley@Parallels.com>2012-07-20 03:58:40 -0400
commit67bd94130015c507011af37858989b199c52e1de (patch)
tree9b4bc8ef5c7180d920eae0f95158dc377c38df8c /drivers/scsi
parente81ca6fe85b77109a32489a5db82f575d51dfc98 (diff)
[SCSI] Fix device removal NULL pointer dereference
Use blk_queue_dead() to test whether the queue is dead instead of !sdev. Since scsi_prep_fn() may be invoked concurrently with __scsi_remove_device(), keep the queuedata (sdev) pointer in __scsi_remove_device(). This patch fixes a kernel oops that can be triggered by USB device removal. See also http://www.spinics.net/lists/linux-scsi/msg56254.html. Other changes included in this patch: - Swap the blk_cleanup_queue() and kfree() calls in scsi_host_dev_release() to make that code easier to grasp. - Remove the queue dead check from scsi_run_queue() since the queue state can change anyway at any point in that function where the queue lock is not held. - Remove the queue dead check from the start of scsi_request_fn() since it is redundant with the scsi_device_online() check. Reported-by: Jun'ichi Nomura <j-nomura@ce.jp.nec.com> Signed-off-by: Bart Van Assche <bvanassche@acm.org> Reviewed-by: Mike Christie <michaelc@cs.wisc.edu> Reviewed-by: Tejun Heo <tj@kernel.org> Cc: <stable@kernel.org> Signed-off-by: James Bottomley <JBottomley@Parallels.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/hosts.c7
-rw-r--r--drivers/scsi/scsi_lib.c32
-rw-r--r--drivers/scsi/scsi_priv.h1
-rw-r--r--drivers/scsi/scsi_sysfs.c5
4 files changed, 9 insertions, 36 deletions
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 2b6a03de5787..593085a52275 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -290,6 +290,7 @@ static void scsi_host_dev_release(struct device *dev)
290 struct Scsi_Host *shost = dev_to_shost(dev); 290 struct Scsi_Host *shost = dev_to_shost(dev);
291 struct device *parent = dev->parent; 291 struct device *parent = dev->parent;
292 struct request_queue *q; 292 struct request_queue *q;
293 void *queuedata;
293 294
294 scsi_proc_hostdir_rm(shost->hostt); 295 scsi_proc_hostdir_rm(shost->hostt);
295 296
@@ -299,9 +300,9 @@ static void scsi_host_dev_release(struct device *dev)
299 destroy_workqueue(shost->work_q); 300 destroy_workqueue(shost->work_q);
300 q = shost->uspace_req_q; 301 q = shost->uspace_req_q;
301 if (q) { 302 if (q) {
302 kfree(q->queuedata); 303 queuedata = q->queuedata;
303 q->queuedata = NULL; 304 blk_cleanup_queue(q);
304 scsi_free_queue(q); 305 kfree(queuedata);
305 } 306 }
306 307
307 scsi_destroy_command_freelist(shost); 308 scsi_destroy_command_freelist(shost);
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 9f00c128e4d1..4acf5c284c2e 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -406,10 +406,6 @@ static void scsi_run_queue(struct request_queue *q)
406 LIST_HEAD(starved_list); 406 LIST_HEAD(starved_list);
407 unsigned long flags; 407 unsigned long flags;
408 408
409 /* if the device is dead, sdev will be NULL, so no queue to run */
410 if (!sdev)
411 return;
412
413 shost = sdev->host; 409 shost = sdev->host;
414 if (scsi_target(sdev)->single_lun) 410 if (scsi_target(sdev)->single_lun)
415 scsi_single_lun_run(sdev); 411 scsi_single_lun_run(sdev);
@@ -1371,16 +1367,16 @@ static inline int scsi_host_queue_ready(struct request_queue *q,
1371 * may be changed after request stacking drivers call the function, 1367 * may be changed after request stacking drivers call the function,
1372 * regardless of taking lock or not. 1368 * regardless of taking lock or not.
1373 * 1369 *
1374 * When scsi can't dispatch I/Os anymore and needs to kill I/Os 1370 * When scsi can't dispatch I/Os anymore and needs to kill I/Os scsi
1375 * (e.g. !sdev), scsi needs to return 'not busy'. 1371 * needs to return 'not busy'. Otherwise, request stacking drivers
1376 * Otherwise, request stacking drivers may hold requests forever. 1372 * may hold requests forever.
1377 */ 1373 */
1378static int scsi_lld_busy(struct request_queue *q) 1374static int scsi_lld_busy(struct request_queue *q)
1379{ 1375{
1380 struct scsi_device *sdev = q->queuedata; 1376 struct scsi_device *sdev = q->queuedata;
1381 struct Scsi_Host *shost; 1377 struct Scsi_Host *shost;
1382 1378
1383 if (!sdev) 1379 if (blk_queue_dead(q))
1384 return 0; 1380 return 0;
1385 1381
1386 shost = sdev->host; 1382 shost = sdev->host;
@@ -1491,12 +1487,6 @@ static void scsi_request_fn(struct request_queue *q)
1491 struct scsi_cmnd *cmd; 1487 struct scsi_cmnd *cmd;
1492 struct request *req; 1488 struct request *req;
1493 1489
1494 if (!sdev) {
1495 while ((req = blk_peek_request(q)) != NULL)
1496 scsi_kill_request(req, q);
1497 return;
1498 }
1499
1500 if(!get_device(&sdev->sdev_gendev)) 1490 if(!get_device(&sdev->sdev_gendev))
1501 /* We must be tearing the block queue down already */ 1491 /* We must be tearing the block queue down already */
1502 return; 1492 return;
@@ -1698,20 +1688,6 @@ struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
1698 return q; 1688 return q;
1699} 1689}
1700 1690
1701void scsi_free_queue(struct request_queue *q)
1702{
1703 unsigned long flags;
1704
1705 WARN_ON(q->queuedata);
1706
1707 /* cause scsi_request_fn() to kill all non-finished requests */
1708 spin_lock_irqsave(q->queue_lock, flags);
1709 q->request_fn(q);
1710 spin_unlock_irqrestore(q->queue_lock, flags);
1711
1712 blk_cleanup_queue(q);
1713}
1714
1715/* 1691/*
1716 * Function: scsi_block_requests() 1692 * Function: scsi_block_requests()
1717 * 1693 *
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index cbfe5df24a3b..291db6effffb 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -85,7 +85,6 @@ extern void scsi_next_command(struct scsi_cmnd *cmd);
85extern void scsi_io_completion(struct scsi_cmnd *, unsigned int); 85extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
86extern void scsi_run_host_queues(struct Scsi_Host *shost); 86extern void scsi_run_host_queues(struct Scsi_Host *shost);
87extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev); 87extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev);
88extern void scsi_free_queue(struct request_queue *q);
89extern int scsi_init_queue(void); 88extern int scsi_init_queue(void);
90extern void scsi_exit_queue(void); 89extern void scsi_exit_queue(void);
91struct request_queue; 90struct request_queue;
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index 5747478a2bf8..9aa578a5da11 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -972,11 +972,8 @@ void __scsi_remove_device(struct scsi_device *sdev)
972 sdev->host->hostt->slave_destroy(sdev); 972 sdev->host->hostt->slave_destroy(sdev);
973 transport_destroy_device(dev); 973 transport_destroy_device(dev);
974 974
975 /* cause the request function to reject all I/O requests */
976 sdev->request_queue->queuedata = NULL;
977
978 /* Freeing the queue signals to block that we're done */ 975 /* Freeing the queue signals to block that we're done */
979 scsi_free_queue(sdev->request_queue); 976 blk_cleanup_queue(sdev->request_queue);
980 put_device(dev); 977 put_device(dev);
981} 978}
982 979