[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>

authored by Stuart Hayes and committed by Bartlomiej Zolnierkiewicz 41bb4c43 8604affd

+24 -4
+24 -4
drivers/scsi/ide-scsi.c
··· 179 179 return; 180 180 } 181 181 count = min(pc->sg->length - pc->b_count, bcount); 182 - buf = page_address(pc->sg->page) + pc->sg->offset; 183 - drive->hwif->atapi_input_bytes(drive, buf + pc->b_count, count); 182 + if (PageHighMem(pc->sg->page)) { 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 194 bcount -= count; pc->b_count += count; 185 195 if (pc->b_count == pc->sg->length) { 186 196 pc->sg++; ··· 211 201 return; 212 202 } 213 203 count = min(pc->sg->length - pc->b_count, bcount); 214 - buf = page_address(pc->sg->page) + pc->sg->offset; 215 - drive->hwif->atapi_output_bytes(drive, buf + pc->b_count, count); 204 + if (PageHighMem(pc->sg->page)) { 205 + unsigned long flags; 206 + 207 + local_irq_save(flags); 208 + buf = kmap_atomic(pc->sg->page, KM_IRQ0) + pc->sg->offset; 209 + drive->hwif->atapi_output_bytes(drive, buf + pc->b_count, count); 210 + kunmap_atomic(buf - pc->sg->offset, KM_IRQ0); 211 + local_irq_restore(flags); 212 + } else { 213 + buf = page_address(pc->sg->page) + pc->sg->offset; 214 + drive->hwif->atapi_output_bytes(drive, buf + pc->b_count, count); 215 + } 216 216 bcount -= count; pc->b_count += count; 217 217 if (pc->b_count == pc->sg->length) { 218 218 pc->sg++;