summaryrefslogtreecommitdiffstats
path: root/drivers/ata/libata-scsi.c
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@HansenPartnership.com>2008-01-22 20:43:48 +0100
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-01-23 18:27:54 +0100
commitd0ad3bc97c06fba5d37b4ca03c03b7eeeda39c47 (patch)
tree5aaecdc97e807dc9be911243604c9b9e0f22bde6 /drivers/ata/libata-scsi.c
parent[SCSI] relax scsi dma alignment (diff)
downloadlinux-d0ad3bc97c06fba5d37b4ca03c03b7eeeda39c47.tar.xz
linux-d0ad3bc97c06fba5d37b4ca03c03b7eeeda39c47.zip
[SCSI] libata: fix corruption induced by relaxed DMA alignment in SCSI
Hugh Dickens noticed that SMART commands issued from user space can end up corupting memory. The problem occurs if the buffer used to read data spans two pages. The reason is that the PIO sector routines in libata are expecting physically contiguous pages when they do sector operations, so the left overs on the second page go into the next physically adjacent page rather than the next page in the sg mapping. Fix this by enforcing strict 512 byte alignment on all buffers from userspace. Acked-by: Hugh Dickins <hugh@veritas.com> Acked-by: Jeff Garzik <jeff@garzik.org> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers/ata/libata-scsi.c')
-rw-r--r--drivers/ata/libata-scsi.c12
1 files changed, 8 insertions, 4 deletions
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 4bb268b9aaeb..bc5cf6b8a4b8 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -824,9 +824,6 @@ static void ata_scsi_sdev_config(struct scsi_device *sdev)
* requests.
*/
sdev->max_device_blocked = 1;
-
- /* set the min alignment */
- blk_queue_update_dma_alignment(sdev->request_queue, ATA_DMA_PAD_SZ - 1);
}
static void ata_scsi_dev_config(struct scsi_device *sdev,
@@ -842,7 +839,14 @@ static void ata_scsi_dev_config(struct scsi_device *sdev,
if (dev->class == ATA_DEV_ATAPI) {
struct request_queue *q = sdev->request_queue;
blk_queue_max_hw_segments(q, q->max_hw_segments - 1);
- }
+
+ /* set the min alignment */
+ blk_queue_update_dma_alignment(sdev->request_queue,
+ ATA_DMA_PAD_SZ - 1);
+ } else
+ /* ATA devices must be sector aligned */
+ blk_queue_update_dma_alignment(sdev->request_queue,
+ ATA_SECT_SIZE - 1);
if (dev->flags & ATA_DFLAG_AN)
set_bit(SDEV_EVT_MEDIA_CHANGE, sdev->supported_events);