]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Hannes Reinecke <hare@suse.de> |
2 | Subject: Kernel bug triggered in multipath | |
3 | References: bnc#486001 | |
4 | ||
5 | Starting multipath on a cciss device will cause a kernel | |
6 | warning to be triggered. Problem is that we're using the | |
7 | ->queuedata field of the request_queue to derefence the | |
8 | scsi device; however, for other (non-SCSI) devices this | |
9 | points to a totally different structure. | |
10 | So we should rather be using accessors here which make | |
11 | sure we're only returning valid SCSI device structures. | |
12 | ||
13 | Signed-off-by: Hannes Reinecke <hare@suse.de> | |
14 | ||
15 | --- | |
16 | drivers/scsi/device_handler/scsi_dh.c | 10 +++++----- | |
17 | drivers/scsi/scsi_lib.c | 11 +++++++++++ | |
18 | include/scsi/scsi_device.h | 1 + | |
19 | 3 files changed, 17 insertions(+), 5 deletions(-) | |
20 | ||
21 | --- a/drivers/scsi/device_handler/scsi_dh.c | |
22 | +++ b/drivers/scsi/device_handler/scsi_dh.c | |
23 | @@ -427,7 +427,7 @@ int scsi_dh_activate(struct request_queu | |
24 | struct scsi_device_handler *scsi_dh = NULL; | |
25 | ||
26 | spin_lock_irqsave(q->queue_lock, flags); | |
27 | - sdev = q->queuedata; | |
28 | + sdev = scsi_device_from_queue(q); | |
29 | if (sdev && sdev->scsi_dh_data) | |
30 | scsi_dh = sdev->scsi_dh_data->scsi_dh; | |
31 | if (!scsi_dh || !get_device(&sdev->sdev_gendev)) | |
32 | @@ -456,7 +456,7 @@ int scsi_dh_handler_exist(const char *na | |
33 | EXPORT_SYMBOL_GPL(scsi_dh_handler_exist); | |
34 | ||
35 | /* | |
36 | - * scsi_dh_handler_attach - Attach device handler | |
37 | + * scsi_dh_attach - Attach device handler | |
38 | * @sdev - sdev the handler should be attached to | |
39 | * @name - name of the handler to attach | |
40 | */ | |
41 | @@ -472,7 +472,7 @@ int scsi_dh_attach(struct request_queue | |
42 | return -EINVAL; | |
43 | ||
44 | spin_lock_irqsave(q->queue_lock, flags); | |
45 | - sdev = q->queuedata; | |
46 | + sdev = scsi_device_from_queue(q); | |
47 | if (!sdev || !get_device(&sdev->sdev_gendev)) | |
48 | err = -ENODEV; | |
49 | spin_unlock_irqrestore(q->queue_lock, flags); | |
50 | @@ -487,7 +487,7 @@ int scsi_dh_attach(struct request_queue | |
51 | EXPORT_SYMBOL_GPL(scsi_dh_attach); | |
52 | ||
53 | /* | |
54 | - * scsi_dh_handler_detach - Detach device handler | |
55 | + * scsi_dh_detach - Detach device handler | |
56 | * @sdev - sdev the handler should be detached from | |
57 | * | |
58 | * This function will detach the device handler only | |
59 | @@ -501,7 +501,7 @@ void scsi_dh_detach(struct request_queue | |
60 | struct scsi_device_handler *scsi_dh = NULL; | |
61 | ||
62 | spin_lock_irqsave(q->queue_lock, flags); | |
63 | - sdev = q->queuedata; | |
64 | + sdev = scsi_device_from_queue(q); | |
65 | if (!sdev || !get_device(&sdev->sdev_gendev)) | |
66 | sdev = NULL; | |
67 | spin_unlock_irqrestore(q->queue_lock, flags); | |
68 | --- a/drivers/scsi/scsi_lib.c | |
69 | +++ b/drivers/scsi/scsi_lib.c | |
70 | @@ -1696,6 +1696,17 @@ static void scsi_request_fn(struct reque | |
71 | spin_lock_irq(q->queue_lock); | |
72 | } | |
73 | ||
74 | +struct scsi_device *scsi_device_from_queue(struct request_queue *q) | |
75 | +{ | |
76 | + struct scsi_device *sdev = NULL; | |
77 | + | |
78 | + if (q->request_fn == scsi_request_fn) | |
79 | + sdev = q->queuedata; | |
80 | + | |
81 | + return sdev; | |
82 | +} | |
83 | +EXPORT_SYMBOL_GPL(scsi_device_from_queue); | |
84 | + | |
85 | u64 scsi_calculate_bounce_limit(struct Scsi_Host *shost) | |
86 | { | |
87 | struct device *host_dev; | |
88 | --- a/include/scsi/scsi_device.h | |
89 | +++ b/include/scsi/scsi_device.h | |
90 | @@ -291,6 +291,7 @@ extern void starget_for_each_device(stru | |
91 | extern void __starget_for_each_device(struct scsi_target *, void *, | |
92 | void (*fn)(struct scsi_device *, | |
93 | void *)); | |
94 | +extern struct scsi_device *scsi_device_from_queue(struct request_queue *); | |
95 | ||
96 | /* only exposed to implement shost_for_each_device */ | |
97 | extern struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *, |