Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/ic Fix leaks in oosiop_alloc_cb error branches, note...



details:   https://anonhg.NetBSD.org/src/rev/1cf10955e8e5
branches:  trunk
changeset: 331643:1cf10955e8e5
user:      riastradh <riastradh%NetBSD.org@localhost>
date:      Mon Aug 18 03:43:10 2014 +0000

description:
Fix leaks in oosiop_alloc_cb error branches, noted by maxv@.

While here, avoid a sketchy pointer cast that probably falls afoul of
strict aliasing rules.

Compile-tested only, with hppa.

diffstat:

 sys/dev/ic/oosiop.c |  70 +++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 47 insertions(+), 23 deletions(-)

diffs (136 lines):

diff -r 82eea4a13e26 -r 1cf10955e8e5 sys/dev/ic/oosiop.c
--- a/sys/dev/ic/oosiop.c       Mon Aug 18 03:14:12 2014 +0000
+++ b/sys/dev/ic/oosiop.c       Mon Aug 18 03:43:10 2014 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: oosiop.c,v 1.13 2010/11/13 13:52:02 uebayasi Exp $     */
+/*     $NetBSD: oosiop.c,v 1.14 2014/08/18 03:43:10 riastradh Exp $    */
 
 /*
  * Copyright (c) 2001 Shuichiro URATA.  All rights reserved.
@@ -35,7 +35,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: oosiop.c,v 1.13 2010/11/13 13:52:02 uebayasi Exp $");
+__KERNEL_RCSID(0, "$NetBSD: oosiop.c,v 1.14 2014/08/18 03:43:10 riastradh Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -247,6 +247,7 @@
 oosiop_alloc_cb(struct oosiop_softc *sc, int ncb)
 {
        struct oosiop_cb *cb;
+       void *xfer_kva;
        struct oosiop_xfer *xfer;
        bus_size_t xfersize;
        bus_dma_segment_t seg;
@@ -258,7 +259,8 @@
        cb = malloc(sizeof(struct oosiop_cb) * ncb, M_DEVBUF, M_NOWAIT|M_ZERO);
        if (cb == NULL) {
                printf(": failed to allocate cb memory\n");
-               return (ENOMEM);
+               err = ENOMEM;
+               goto fail0;
        }
 
        /*
@@ -269,57 +271,79 @@
            &nseg, BUS_DMA_NOWAIT);
        if (err) {
                printf(": failed to allocate xfer block memory, err=%d\n", err);
-               return (err);
+               goto fail1;
        }
-       err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, xfersize,
-           (void **)(void *)&xfer, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
+       KASSERT(nseg == 1);
+       err = bus_dmamem_map(sc->sc_dmat, &seg, nseg, xfersize, &xfer_kva,
+           BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
        if (err) {
                printf(": failed to map xfer block memory, err=%d\n", err);
-               return (err);
+               goto fail2;
        }
+       xfer = xfer_kva;
 
        /* Initialize each command block */
        for (i = 0; i < ncb; i++) {
                err = bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE,
-                   0, BUS_DMA_NOWAIT, &cb->cmddma);
+                   0, BUS_DMA_NOWAIT, &cb[i].cmddma);
                if (err) {
                        printf(": failed to create cmddma map, err=%d\n", err);
-                       return (err);
+                       goto loop_fail0;
                }
                err = bus_dmamap_create(sc->sc_dmat, OOSIOP_MAX_XFER,
                    OOSIOP_NSG, OOSIOP_DBC_MAX, 0, BUS_DMA_NOWAIT,
-                   &cb->datadma);
+                   &cb[i].datadma);
                if (err) {
                        printf(": failed to create datadma map, err=%d\n", err);
-                       return (err);
+                       goto loop_fail1;
                }
 
                err = bus_dmamap_create(sc->sc_dmat,
                    sizeof(struct oosiop_xfer), 1, sizeof(struct oosiop_xfer),
-                   0, BUS_DMA_NOWAIT, &cb->xferdma);
+                   0, BUS_DMA_NOWAIT, &cb[i].xferdma);
                if (err) {
                        printf(": failed to create xfer block map, err=%d\n",
                            err);
-                       return (err);
+                       goto loop_fail2;
                }
-               err = bus_dmamap_load(sc->sc_dmat, cb->xferdma, xfer,
+               err = bus_dmamap_load(sc->sc_dmat, cb[i].xferdma, xfer,
                    sizeof(struct oosiop_xfer), NULL, BUS_DMA_NOWAIT);
                if (err) {
                        printf(": failed to load xfer block, err=%d\n", err);
-                       return (err);
+                       goto loop_fail3;
                }
 
-               cb->xfer = xfer;
+               cb[i].xfer = &xfer[i];
+               continue;
 
-               s = splbio();
-               TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
-               splx(s);
-
-               cb++;
-               xfer++;
+loop_fail4: __unused
+               bus_dmamap_unload(sc->sc_dmat, cb[i].xferdma);
+loop_fail3:    bus_dmamap_destroy(sc->sc_dmat, cb[i].xferdma);
+loop_fail2:    bus_dmamap_destroy(sc->sc_dmat, cb[i].datadma);
+loop_fail1:    bus_dmamap_destroy(sc->sc_dmat, cb[i].cmddma);
+loop_fail0:    goto fail3;
        }
 
-       return (0);
+       for (i = 0; i < ncb; i++) {
+               s = splbio();
+               TAILQ_INSERT_TAIL(&sc->sc_free_cb, &cb[i], chain);
+               splx(s);
+       }
+
+       /* Success!  */
+       return 0;
+
+fail3: while (i--) {
+               bus_dmamap_unload(sc->sc_dmat, cb[i].xferdma);
+               bus_dmamap_destroy(sc->sc_dmat, cb[i].xferdma);
+               bus_dmamap_destroy(sc->sc_dmat, cb[i].datadma);
+               bus_dmamap_destroy(sc->sc_dmat, cb[i].cmddma);
+       }
+       bus_dmamem_unmap(sc->sc_dmat, xfer_kva, xfersize);
+fail2: bus_dmamem_free(sc->sc_dmat, &seg, 1);
+fail1: free(cb, M_DEVBUF);
+fail0: KASSERT(err);
+       return err;
 }
 
 static inline void



Home | Main Index | Thread Index | Old Index