diff options
author | Michael Buesch <mb@bu3sch.de> | 2008-01-25 12:20:20 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-02-08 11:46:28 -0800 |
commit | a30954e2544519c8920c04b46f8300ec6179618f (patch) | |
tree | 681be0c872f809c1f74afc5bf0716cfa08fe621a /drivers/net | |
parent | 2e892f92fe8b48824cf647e812d7fac1c289a854 (diff) | |
download | lwn-a30954e2544519c8920c04b46f8300ec6179618f.tar.gz lwn-a30954e2544519c8920c04b46f8300ec6179618f.zip |
b43: Fix dma-slot resource leakage
patch 8dd0100ce9511e52614ecd0a6587c13ce5769c8b in mainline.
This fixes four resource leakages.
In any error path we must deallocate the DMA frame slots we
previously allocated by request_slot().
This is done by storing the ring pointers before doing any ring
allocation and restoring the old pointers in case of an error.
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: Stefano Brivio <stefano.brivio@polimi.it>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/b43/dma.c | 19 |
1 files changed, 16 insertions, 3 deletions
diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index fe0c56079049..559a9a961f04 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1106,7 +1106,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring, { const struct b43_dma_ops *ops = ring->ops; u8 *header; - int slot; + int slot, old_top_slot, old_used_slots; int err; struct b43_dmadesc_generic *desc; struct b43_dmadesc_meta *meta; @@ -1116,6 +1116,9 @@ static int dma_tx_fragment(struct b43_dmaring *ring, #define SLOTS_PER_PACKET 2 B43_WARN_ON(skb_shinfo(skb)->nr_frags); + old_top_slot = ring->current_slot; + old_used_slots = ring->used_slots; + /* Get a slot for the header. */ slot = request_slot(ring); desc = ops->idx2desc(ring, slot, &meta_hdr); @@ -1125,13 +1128,19 @@ static int dma_tx_fragment(struct b43_dmaring *ring, err = b43_generate_txhdr(ring->dev, header, skb->data, skb->len, ctl, generate_cookie(ring, slot)); - if (unlikely(err)) + if (unlikely(err)) { + ring->current_slot = old_top_slot; + ring->used_slots = old_used_slots; return err; + } meta_hdr->dmaaddr = map_descbuffer(ring, (unsigned char *)header, sizeof(struct b43_txhdr_fw4), 1); - if (dma_mapping_error(meta_hdr->dmaaddr)) + if (dma_mapping_error(meta_hdr->dmaaddr)) { + ring->current_slot = old_top_slot; + ring->used_slots = old_used_slots; return -EIO; + } ops->fill_descriptor(ring, desc, meta_hdr->dmaaddr, sizeof(struct b43_txhdr_fw4), 1, 0, 0); @@ -1149,6 +1158,8 @@ static int dma_tx_fragment(struct b43_dmaring *ring, if (dma_mapping_error(meta->dmaaddr)) { bounce_skb = __dev_alloc_skb(skb->len, GFP_ATOMIC | GFP_DMA); if (!bounce_skb) { + ring->current_slot = old_top_slot; + ring->used_slots = old_used_slots; err = -ENOMEM; goto out_unmap_hdr; } @@ -1159,6 +1170,8 @@ static int dma_tx_fragment(struct b43_dmaring *ring, meta->skb = skb; meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1); if (dma_mapping_error(meta->dmaaddr)) { + ring->current_slot = old_top_slot; + ring->used_slots = old_used_slots; err = -EIO; goto out_free_bounce; } |