Re: PCI DMA to small buffers on cache-incoherent arch

From: Anton Blanchard (anton@samba.org)
Date: Sat Jun 08 2002 - 08:58:45 EST


 
> The problem that caused crashes on cache-incoherent architectures (my
> specific system uses a PPC 440GP but this should apply in general) was
> the following. The USB stack was doing PCI DMA into buffers that were
> allocated on the stack, which causes stack corruption: on the PPC
> 440GP, pci_map_single() with PCI_DMA_FROMDEVICE just invalidates the
> cache for the region being mapped. However, if a buffer is smaller
> than a cache line, then two bad things can happen.

Yes, DMAing to the stack is definitely a bug, thats mentioned in
Documentation/DMA-mapping.txt. We used to vmalloc our kernel stacks
on ppc64 and that picked up all sorts of DMA violations.

I just checked 2.5 and noticed the scsi code is _still_ DMAing to the
stack! Maybe it would be worth having a debug option for x86 where
it uses vmalloc for kernel stack allocation :)

Anyway attached is a patch from Todd Inglett that I updated for 2.5.

Anton

===== drivers/scsi/scsi_scan.c 1.13 vs edited =====
--- 1.13/drivers/scsi/scsi_scan.c Fri May 31 11:17:30 2002
+++ edited/drivers/scsi/scsi_scan.c Sun Jun 9 07:28:25 2002
@@ -368,7 +368,6 @@
         unsigned int dev;
         unsigned int lun;
         unsigned char *scsi_result;
- unsigned char scsi_result0[256];
         Scsi_Device *SDpnt;
         Scsi_Device *SDtail;
 
@@ -390,9 +389,7 @@
                  */
                 scsi_initialize_queue(SDpnt, shpnt);
                 SDpnt->request_queue.queuedata = (void *) SDpnt;
- /* Make sure we have something that is valid for DMA purposes */
- scsi_result = ((!shpnt->unchecked_isa_dma)
- ? &scsi_result0[0] : kmalloc(512, GFP_DMA));
+ scsi_result = kmalloc(512, GFP_DMA);
         }
 
         if (scsi_result == NULL) {
@@ -532,10 +529,9 @@
                 kfree((char *) SDpnt);
         }
 
- /* If we allocated a buffer so we could do DMA, free it now */
- if (scsi_result != &scsi_result0[0] && scsi_result != NULL) {
- kfree(scsi_result);
- } {
+ kfree(scsi_result);
+
+ {
                 Scsi_Device *sdev;
                 Scsi_Cmnd *scmd;
 
===== drivers/scsi/sr_ioctl.c 1.13 vs edited =====
--- 1.13/drivers/scsi/sr_ioctl.c Thu May 23 23:18:39 2002
+++ edited/drivers/scsi/sr_ioctl.c Sun Jun 9 07:30:15 2002
@@ -344,7 +344,12 @@
         Scsi_CD *SCp = cdi->handle;
         u_char sr_cmd[10];
         int result, target = minor(cdi->dev);
- unsigned char buffer[32];
+ unsigned char *buffer = kmalloc(512, GFP_DMA);
+
+ if (buffer == NULL) {
+ printk("SCSI DMA pool exhausted.");
+ return -ENOMEM;
+ }
 
         memset(sr_cmd, 0, sizeof(sr_cmd));
 
@@ -417,6 +422,7 @@
                 return -EINVAL;
         }
 
+ kfree(buffer);
 #if 0
         if (result)
                 printk("DEBUG: sr_audio: result for ioctl %x: %x\n", cmd, result);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sat Jun 15 2002 - 22:00:13 EST