Hi,

Bus_dmamem_map has a bug in its error path, where it frees the wrong
memory in the wrong way. Take this code in sparc64 for example:

        va = uvm_km_valloc(kernel_map, size);
        ...

        TAILQ_FOREACH(m, mlist, pageq) {
#ifdef DIAGNOSTIC
                if (size == 0)
                        panic("_bus_dmamem_map: size botch");
#endif
                addr = VM_PAGE_TO_PHYS(m);
                error = pmap_enter(pmap_kernel(), va, addr | cbit,
                    VM_PROT_READ | VM_PROT_WRITE, VM_PROT_READ |
                    VM_PROT_WRITE | PMAP_WIRED | PMAP_CANFAIL);
                if (error) {
                        /*
                         * Clean up after ourselves.
                         * XXX uvm_wait on WAITOK
                         */
                        pmap_update(pmap_kernel());
                        uvm_km_free(kernel_map, va, ssize);
                                                ^^
                        return (error);
                }
                va += PAGE_SIZE;
                size -= PAGE_SIZE;
        }

va is incremented in the loop, therefor the uvm_km_free was the wrong
address to free.
Furthermore, the pages that have been mapped in (suppose the error
occured halfway the loop) will be freed by uvm_km_free.

The diff below fixes this, for:
alpha, amd64, arm, aviion, i386, loongson, macppc, mvme{68k,88k,ppc},
octeon, sgi, socppc, sparc64 and vax.

Please test on all these architectures.
Ok?
-- 
Ariane


Index: arch/alpha/dev/bus_dma.c
===================================================================
RCS file: /cvs/src/sys/arch/alpha/dev/bus_dma.c,v
retrieving revision 1.30
diff -u -d -p -r1.30 bus_dma.c
--- arch/alpha/dev/bus_dma.c    26 Dec 2010 15:40:58 -0000      1.30
+++ arch/alpha/dev/bus_dma.c    21 Jun 2011 18:35:39 -0000
@@ -618,8 +618,9 @@ _bus_dmamem_map(t, segs, nsegs, size, kv
                                 * Clean up after ourselves.
                                 * XXX uvm_wait on WAITOK
                                 */
+                               pmap_remove(pmap_kernel(), sva, va);
                                pmap_update(pmap_kernel());
-                               uvm_km_free(kernel_map, va, ssize);
+                               uvm_km_free(kernel_map, sva, ssize);
                                return (error);
                        }
                }
Index: arch/amd64/amd64/bus_dma.c
===================================================================
RCS file: /cvs/src/sys/arch/amd64/amd64/bus_dma.c,v
retrieving revision 1.36
diff -u -d -p -r1.36 bus_dma.c
--- arch/amd64/amd64/bus_dma.c  2 Apr 2011 16:37:39 -0000       1.36
+++ arch/amd64/amd64/bus_dma.c  21 Jun 2011 18:35:39 -0000
@@ -496,8 +496,9 @@ _bus_dmamem_map(bus_dma_tag_t t, bus_dma
                                 * Clean up after ourselves.
                                 * XXX uvm_wait on WAITOK
                                 */
+                               pmap_remove(pmap_kernel(), sva, va);
                                pmap_update(pmap_kernel());
-                               uvm_km_free(kernel_map, va, ssize);
+                               uvm_km_free(kernel_map, sva, ssize);
                                return (error);
                        }
                }
Index: arch/arm/arm/bus_dma.c
===================================================================
RCS file: /cvs/src/sys/arch/arm/arm/bus_dma.c,v
retrieving revision 1.20
diff -u -d -p -r1.20 bus_dma.c
--- arch/arm/arm/bus_dma.c      4 Jan 2011 21:12:55 -0000       1.20
+++ arch/arm/arm/bus_dma.c      21 Jun 2011 18:35:40 -0000
@@ -722,8 +722,9 @@ _bus_dmamem_map(bus_dma_tag_t t, bus_dma
                                 * Clean up after ourselves.
                                 * XXX uvm_wait on WAITOK
                                 */
+                               pmap_remove(pmap_kernel(), sva, va);
                                pmap_update(pmap_kernel());
-                               uvm_km_free(kernel_map, va, ssize);
+                               uvm_km_free(kernel_map, sva, ssize);
                                return (error);
                        }
                        /*
Index: arch/aviion/aviion/bus_dma.c
===================================================================
RCS file: /cvs/src/sys/arch/aviion/aviion/bus_dma.c,v
retrieving revision 1.3
diff -u -d -p -r1.3 bus_dma.c
--- arch/aviion/aviion/bus_dma.c        26 Dec 2010 15:40:59 -0000      1.3
+++ arch/aviion/aviion/bus_dma.c        21 Jun 2011 18:35:40 -0000
@@ -548,8 +548,9 @@ bus_dmamem_map(t, segs, nsegs, size, kva
                                 * Clean up after ourselves.
                                 * XXX uvm_wait on WAITOK
                                 */
+                               pmap_remove(pmap_kernel(), sva, va);
                                pmap_update(pmap_kernel());
-                               uvm_km_free(kernel_map, va, ssize);
+                               uvm_km_free(kernel_map, sva, ssize);
                                return (error);
                         }
                 }
Index: arch/i386/i386/bus_dma.c
===================================================================
RCS file: /cvs/src/sys/arch/i386/i386/bus_dma.c,v
retrieving revision 1.24
diff -u -d -p -r1.24 bus_dma.c
--- arch/i386/i386/bus_dma.c    26 Dec 2010 15:40:59 -0000      1.24
+++ arch/i386/i386/bus_dma.c    21 Jun 2011 18:35:40 -0000
@@ -460,10 +460,9 @@ _bus_dmamem_map(bus_dma_tag_t t, bus_dma
                                 * Clean up after ourselves.
                                 * XXX uvm_wait on WAITOK
                                 */
-                               pmap_remove(pmap_kernel(), sva, va - PAGE_SIZE);
+                               pmap_remove(pmap_kernel(), sva, va);
                                pmap_update(pmap_kernel());
-
-                               uvm_km_free(kernel_map, va, ssize);
+                               uvm_km_free(kernel_map, sva, ssize);
                                return (ret);
                        }
 
Index: arch/loongson/loongson/bus_dma.c
===================================================================
RCS file: /cvs/src/sys/arch/loongson/loongson/bus_dma.c,v
retrieving revision 1.6
diff -u -d -p -r1.6 bus_dma.c
--- arch/loongson/loongson/bus_dma.c    26 Dec 2010 15:40:59 -0000      1.6
+++ arch/loongson/loongson/bus_dma.c    21 Jun 2011 18:35:41 -0000
@@ -470,8 +470,9 @@ _dmamem_map(bus_dma_tag_t t, bus_dma_seg
                                 * Clean up after ourselves.
                                 * XXX uvm_wait on WAITOK
                                 */
+                               pmap_remove(pmap_kernel(), sva, va);
                                pmap_update(pmap_kernel());
-                               uvm_km_free(kernel_map, va, ssize);
+                               uvm_km_free(kernel_map, sva, ssize);
                                return (error);
                        }
 
Index: arch/macppc/macppc/dma.c
===================================================================
RCS file: /cvs/src/sys/arch/macppc/macppc/dma.c,v
retrieving revision 1.34
diff -u -d -p -r1.34 dma.c
--- arch/macppc/macppc/dma.c    26 Dec 2010 15:40:59 -0000      1.34
+++ arch/macppc/macppc/dma.c    21 Jun 2011 18:35:41 -0000
@@ -487,8 +487,9 @@ _dmamem_map(bus_dma_tag_t t, bus_dma_seg
                                 * Clean up after ourselves.
                                 * XXX uvm_wait on WAITOK
                                 */
+                               pmap_remove(pmap_kernel(), sva, va);
                                pmap_update(pmap_kernel());
-                               uvm_km_free(kernel_map, va, ssize);
+                               uvm_km_free(kernel_map, sva, ssize);
                                return (error);
                        }
                }
Index: arch/mvme68k/mvme68k/bus_dma.c
===================================================================
RCS file: /cvs/src/sys/arch/mvme68k/mvme68k/bus_dma.c,v
retrieving revision 1.8
diff -u -d -p -r1.8 bus_dma.c
--- arch/mvme68k/mvme68k/bus_dma.c      26 Dec 2010 15:40:59 -0000      1.8
+++ arch/mvme68k/mvme68k/bus_dma.c      21 Jun 2011 18:35:41 -0000
@@ -545,8 +545,9 @@ bus_dmamem_map(t, segs, nsegs, size, kva
                                 * Clean up after ourselves.
                                 * XXX uvm_wait on WAITOK
                                 */
+                               pmap_remove(pmap_kernel(), sva, va);
                                pmap_update(pmap_kernel());
-                               uvm_km_free(kernel_map, va, ssize);
+                               uvm_km_free(kernel_map, sva, ssize);
                                return (error);
                        }
                 }
Index: arch/mvme88k/mvme88k/bus_dma.c
===================================================================
RCS file: /cvs/src/sys/arch/mvme88k/mvme88k/bus_dma.c,v
retrieving revision 1.16
diff -u -d -p -r1.16 bus_dma.c
--- arch/mvme88k/mvme88k/bus_dma.c      26 Dec 2010 15:40:59 -0000      1.16
+++ arch/mvme88k/mvme88k/bus_dma.c      21 Jun 2011 18:35:41 -0000
@@ -548,8 +548,9 @@ bus_dmamem_map(t, segs, nsegs, size, kva
                                 * Clean up after ourselves.
                                 * XXX uvm_wait on WAITOK
                                 */
+                               pmap_remove(pmap_kernel(), sva, va);
                                pmap_update(pmap_kernel());
-                               uvm_km_free(kernel_map, va, ssize);
+                               uvm_km_free(kernel_map, sva, ssize);
                                return (error);
                         }
                 }
Index: arch/mvmeppc/mvmeppc/bus_dma.c
===================================================================
RCS file: /cvs/src/sys/arch/mvmeppc/mvmeppc/bus_dma.c,v
retrieving revision 1.28
diff -u -d -p -r1.28 bus_dma.c
--- arch/mvmeppc/mvmeppc/bus_dma.c      26 Dec 2010 15:40:59 -0000      1.28
+++ arch/mvmeppc/mvmeppc/bus_dma.c      21 Jun 2011 18:35:41 -0000
@@ -516,8 +516,9 @@ _bus_dmamem_map(t, segs, nsegs, size, kv
                                  * Clean up after ourselves.
                                  * XXX uvm_wait on WAITOK
                                  */
+                               pmap_remove(pmap_kernel(), sva, va);
                                 pmap_update(pmap_kernel());
-                                uvm_km_free(kernel_map, va, ssize);
+                                uvm_km_free(kernel_map, sva, ssize);
                                 return (error);
                         }
                 }
Index: arch/octeon/octeon/bus_dma.c
===================================================================
RCS file: /cvs/src/sys/arch/octeon/octeon/bus_dma.c,v
retrieving revision 1.2
diff -u -d -p -r1.2 bus_dma.c
--- arch/octeon/octeon/bus_dma.c        26 Dec 2010 15:41:00 -0000      1.2
+++ arch/octeon/octeon/bus_dma.c        21 Jun 2011 18:35:41 -0000
@@ -475,8 +475,9 @@ _dmamem_map(bus_dma_tag_t t, bus_dma_seg
                                 * Clean up after ourselves.
                                 * XXX uvm_wait on WAITOK
                                 */
+                               pmap_remove(pmap_kernel(), sva, va);
                                pmap_update(pmap_kernel());
-                               uvm_km_free(kernel_map, va, ssize);
+                               uvm_km_free(kernel_map, sva, ssize);
                                return (error);
                        }
 
Index: arch/sgi/sgi/bus_dma.c
===================================================================
RCS file: /cvs/src/sys/arch/sgi/sgi/bus_dma.c,v
retrieving revision 1.21
diff -u -d -p -r1.21 bus_dma.c
--- arch/sgi/sgi/bus_dma.c      3 Apr 2011 22:33:55 -0000       1.21
+++ arch/sgi/sgi/bus_dma.c      21 Jun 2011 18:35:41 -0000
@@ -475,8 +475,9 @@ _dmamem_map(bus_dma_tag_t t, bus_dma_seg
                                 * Clean up after ourselves.
                                 * XXX uvm_wait on WAITOK
                                 */
+                               pmap_remove(pmap_kernel(), sva, va);
                                pmap_update(pmap_kernel());
-                               uvm_km_free(kernel_map, va, ssize);
+                               uvm_km_free(kernel_map, sva, ssize);
                                return (error);
                        }
 
Index: arch/socppc/socppc/dma.c
===================================================================
RCS file: /cvs/src/sys/arch/socppc/socppc/dma.c,v
retrieving revision 1.8
diff -u -d -p -r1.8 dma.c
--- arch/socppc/socppc/dma.c    26 Dec 2010 15:41:00 -0000      1.8
+++ arch/socppc/socppc/dma.c    21 Jun 2011 18:35:41 -0000
@@ -487,8 +487,9 @@ _dmamem_map(bus_dma_tag_t t, bus_dma_seg
                                 * Clean up after ourselves.
                                 * XXX uvm_wait on WAITOK
                                 */
+                               pmap_remove(pmap_kernel(), sva, va);
                                pmap_update(pmap_kernel());
-                               uvm_km_free(kernel_map, va, ssize);
+                               uvm_km_free(kernel_map, sva, ssize);
                                return (error);
                        }
                }
Index: arch/sparc64/sparc64/machdep.c
===================================================================
RCS file: /cvs/src/sys/arch/sparc64/sparc64/machdep.c,v
retrieving revision 1.132
diff -u -d -p -r1.132 machdep.c
--- arch/sparc64/sparc64/machdep.c      5 Jun 2011 19:41:08 -0000       1.132
+++ arch/sparc64/sparc64/machdep.c      21 Jun 2011 18:35:41 -0000
@@ -1498,8 +1498,9 @@ _bus_dmamem_map(t, t0, segs, nsegs, size
                         * Clean up after ourselves.
                         * XXX uvm_wait on WAITOK
                         */
+                       pmap_remove(pmap_kernel(), sva, va);
                        pmap_update(pmap_kernel());
-                       uvm_km_free(kernel_map, va, ssize);
+                       uvm_km_free(kernel_map, sva, ssize);
                        return (error);
                }
                va += PAGE_SIZE;
Index: arch/vax/vax/bus_dma.c
===================================================================
RCS file: /cvs/src/sys/arch/vax/vax/bus_dma.c,v
retrieving revision 1.26
diff -u -d -p -r1.26 bus_dma.c
--- arch/vax/vax/bus_dma.c      26 Dec 2010 15:41:00 -0000      1.26
+++ arch/vax/vax/bus_dma.c      21 Jun 2011 18:35:41 -0000
@@ -473,8 +473,9 @@ _bus_dmamem_map(t, segs, nsegs, size, kv
                                 * Clean up after ourselves.
                                 * XXX uvm_wait on WAITOK
                                 */
+                               pmap_remove(pmap_kernel(), sva, va);
                                pmap_update(pmap_kernel());
-                               uvm_km_free(kernel_map, va, ssize);
+                               uvm_km_free(kernel_map, sva, ssize);
                                return (error);
                        }
                }

Reply via email to