Module Name: src
Committed By: riastradh
Date: Mon Aug 18 03:43:10 UTC 2014
Modified Files:
src/sys/dev/ic: oosiop.c
Log Message:
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.
To generate a diff of this commit:
cvs rdiff -u -r1.13 -r1.14 src/sys/dev/ic/oosiop.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/sys/dev/ic/oosiop.c
diff -u src/sys/dev/ic/oosiop.c:1.13 src/sys/dev/ic/oosiop.c:1.14
--- src/sys/dev/ic/oosiop.c:1.13 Sat Nov 13 13:52:02 2010
+++ src/sys/dev/ic/oosiop.c Mon Aug 18 03:43:10 2014
@@ -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 @@ static int
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 @@ oosiop_alloc_cb(struct oosiop_softc *sc,
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 @@ oosiop_alloc_cb(struct oosiop_softc *sc,
&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;
+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;
+ }
+
+ for (i = 0; i < ncb; i++) {
s = splbio();
- TAILQ_INSERT_TAIL(&sc->sc_free_cb, cb, chain);
+ TAILQ_INSERT_TAIL(&sc->sc_free_cb, &cb[i], chain);
splx(s);
-
- cb++;
- xfer++;
}
- return (0);
+ /* 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