diff options
author | Stuart Hayes <Stuart_Hayes@dell.com> | 2005-05-26 09:38:45 -0400 |
---|---|---|
committer | Bartlomiej Zolnierkiewicz <bzolnier@elka.pw.edu.pl> | 2005-05-26 09:38:45 -0400 |
commit | 41bb4c43b34bcde7eb62cf19acdcf9f2eb13801d (patch) | |
tree | cfaeeca6836443ee680e38273cb4f7ae94c023b2 /drivers/scsi/ide-scsi.c | |
parent | 8604affde9d4f52f04342d6a37c77d95fa167e7a (diff) |
[PATCH] ide-scsi: kmap scatter/gather before doing PIO
From: Stuart Hayes <Stuart_Hayes@dell.com>
The system can panic with a null pointer dereference using ide-scsi if
PIO is being done on scatter gather pages that are in high memory,
because page_address() returns 0. We are actually seeing this using a
tape drive. This patch will kmap_atomic() the pages before performing
PIO.
Signed-off-by: Bartlomiej Zolnierkiewicz <bzolnier@elka.pw.edu.pl>
Diffstat (limited to 'drivers/scsi/ide-scsi.c')
-rw-r--r-- | drivers/scsi/ide-scsi.c | 28 |
1 files changed, 24 insertions, 4 deletions
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index d80c4c9d5a63..83f062ed9082 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c | |||
@@ -179,8 +179,18 @@ static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigne | |||
179 | return; | 179 | return; |
180 | } | 180 | } |
181 | count = min(pc->sg->length - pc->b_count, bcount); | 181 | count = min(pc->sg->length - pc->b_count, bcount); |
182 | buf = page_address(pc->sg->page) + pc->sg->offset; | 182 | if (PageHighMem(pc->sg->page)) { |
183 | drive->hwif->atapi_input_bytes(drive, buf + pc->b_count, count); | 183 | unsigned long flags; |
184 | |||
185 | local_irq_save(flags); | ||
186 | buf = kmap_atomic(pc->sg->page, KM_IRQ0) + pc->sg->offset; | ||
187 | drive->hwif->atapi_input_bytes(drive, buf + pc->b_count, count); | ||
188 | kunmap_atomic(buf - pc->sg->offset, KM_IRQ0); | ||
189 | local_irq_restore(flags); | ||
190 | } else { | ||
191 | buf = page_address(pc->sg->page) + pc->sg->offset; | ||
192 | drive->hwif->atapi_input_bytes(drive, buf + pc->b_count, count); | ||
193 | } | ||
184 | bcount -= count; pc->b_count += count; | 194 | bcount -= count; pc->b_count += count; |
185 | if (pc->b_count == pc->sg->length) { | 195 | if (pc->b_count == pc->sg->length) { |
186 | pc->sg++; | 196 | pc->sg++; |
@@ -201,8 +211,18 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign | |||
201 | return; | 211 | return; |
202 | } | 212 | } |
203 | count = min(pc->sg->length - pc->b_count, bcount); | 213 | count = min(pc->sg->length - pc->b_count, bcount); |
204 | buf = page_address(pc->sg->page) + pc->sg->offset; | 214 | if (PageHighMem(pc->sg->page)) { |
205 | drive->hwif->atapi_output_bytes(drive, buf + pc->b_count, count); | 215 | unsigned long flags; |
216 | |||
217 | local_irq_save(flags); | ||
218 | buf = kmap_atomic(pc->sg->page, KM_IRQ0) + pc->sg->offset; | ||
219 | drive->hwif->atapi_output_bytes(drive, buf + pc->b_count, count); | ||
220 | kunmap_atomic(buf - pc->sg->offset, KM_IRQ0); | ||
221 | local_irq_restore(flags); | ||
222 | } else { | ||
223 | buf = page_address(pc->sg->page) + pc->sg->offset; | ||
224 | drive->hwif->atapi_output_bytes(drive, buf + pc->b_count, count); | ||
225 | } | ||
206 | bcount -= count; pc->b_count += count; | 226 | bcount -= count; pc->b_count += count; |
207 | if (pc->b_count == pc->sg->length) { | 227 | if (pc->b_count == pc->sg->length) { |
208 | pc->sg++; | 228 | pc->sg++; |