summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Buesch <mb@bu3sch.de>2008-01-25 12:20:20 +0100
committerGreg Kroah-Hartman <gregkh@suse.de>2008-02-08 11:46:28 -0800
commita30954e2544519c8920c04b46f8300ec6179618f (patch)
tree681be0c872f809c1f74afc5bf0716cfa08fe621a
parent2e892f92fe8b48824cf647e812d7fac1c289a854 (diff)
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>
-rw-r--r--drivers/net/wireless/b43/dma.c19
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;
}