]>
Commit | Line | Data |
---|---|---|
2b8d756a GKH |
1 | From c14a57264399efd39514a2329c591a4b954246d8 Mon Sep 17 00:00:00 2001 |
2 | From: Bart Van Assche <bvanassche@acm.org> | |
3 | Date: Mon, 25 Mar 2019 10:01:46 -0700 | |
4 | Subject: scsi: sd: Fix a race between closing an sd device and sd I/O | |
5 | ||
6 | From: Bart Van Assche <bvanassche@acm.org> | |
7 | ||
8 | commit c14a57264399efd39514a2329c591a4b954246d8 upstream. | |
9 | ||
10 | The scsi_end_request() function calls scsi_cmd_to_driver() indirectly and | |
11 | hence needs the disk->private_data pointer. Avoid that that pointer is | |
12 | cleared before all affected I/O requests have finished. This patch avoids | |
13 | that the following crash occurs: | |
14 | ||
15 | Unable to handle kernel NULL pointer dereference at virtual address 0000000000000000 | |
16 | Call trace: | |
17 | scsi_mq_uninit_cmd+0x1c/0x30 | |
18 | scsi_end_request+0x7c/0x1b8 | |
19 | scsi_io_completion+0x464/0x668 | |
20 | scsi_finish_command+0xbc/0x160 | |
21 | scsi_eh_flush_done_q+0x10c/0x170 | |
22 | sas_scsi_recover_host+0x84c/0xa98 [libsas] | |
23 | scsi_error_handler+0x140/0x5b0 | |
24 | kthread+0x100/0x12c | |
25 | ret_from_fork+0x10/0x18 | |
26 | ||
27 | Cc: Christoph Hellwig <hch@lst.de> | |
28 | Cc: Ming Lei <ming.lei@redhat.com> | |
29 | Cc: Hannes Reinecke <hare@suse.com> | |
30 | Cc: Johannes Thumshirn <jthumshirn@suse.de> | |
31 | Cc: Jason Yan <yanaijie@huawei.com> | |
32 | Cc: <stable@vger.kernel.org> | |
33 | Signed-off-by: Bart Van Assche <bvanassche@acm.org> | |
34 | Reported-by: Jason Yan <yanaijie@huawei.com> | |
35 | Reviewed-by: Christoph Hellwig <hch@lst.de> | |
36 | Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> | |
37 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
38 | ||
39 | --- | |
40 | drivers/scsi/sd.c | 19 +++++++++++++------ | |
41 | 1 file changed, 13 insertions(+), 6 deletions(-) | |
42 | ||
43 | --- a/drivers/scsi/sd.c | |
44 | +++ b/drivers/scsi/sd.c | |
45 | @@ -1420,11 +1420,6 @@ static void sd_release(struct gendisk *d | |
46 | scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW); | |
47 | } | |
48 | ||
49 | - /* | |
50 | - * XXX and what if there are packets in flight and this close() | |
51 | - * XXX is followed by a "rmmod sd_mod"? | |
52 | - */ | |
53 | - | |
54 | scsi_disk_put(sdkp); | |
55 | } | |
56 | ||
57 | @@ -3521,11 +3516,23 @@ static void scsi_disk_release(struct dev | |
58 | { | |
59 | struct scsi_disk *sdkp = to_scsi_disk(dev); | |
60 | struct gendisk *disk = sdkp->disk; | |
61 | - | |
62 | + struct request_queue *q = disk->queue; | |
63 | + | |
64 | spin_lock(&sd_index_lock); | |
65 | ida_remove(&sd_index_ida, sdkp->index); | |
66 | spin_unlock(&sd_index_lock); | |
67 | ||
68 | + /* | |
69 | + * Wait until all requests that are in progress have completed. | |
70 | + * This is necessary to avoid that e.g. scsi_end_request() crashes | |
71 | + * due to clearing the disk->private_data pointer. Wait from inside | |
72 | + * scsi_disk_release() instead of from sd_release() to avoid that | |
73 | + * freezing and unfreezing the request queue affects user space I/O | |
74 | + * in case multiple processes open a /dev/sd... node concurrently. | |
75 | + */ | |
76 | + blk_mq_freeze_queue(q); | |
77 | + blk_mq_unfreeze_queue(q); | |
78 | + | |
79 | disk->private_data = NULL; | |
80 | put_disk(disk); | |
81 | put_device(&sdkp->device->sdev_gendev); |