diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-01-08 10:38:15 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2012-02-09 10:37:53 -0500 |
commit | ba84525bd9015e7dd20f7c97a2a96b0a238b0223 (patch) | |
tree | 1d1ff025ff9793cee4ae7e8bebec0837cff274fc /drivers/net | |
parent | 885767ca4ce0800c5d02eb66cc10a0494b7bf312 (diff) |
NET: sa11x0-ir: fix leak of tx skb
Ensure that we unmap and free a pending transmit skb when the interface
is stopped. We rearrange the code a little bit to give all places a
similar layout when freeing the skb in both the completion and interface
stop paths - this gives some consistency to the code.
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/irda/sa1100_ir.c | 29 |
1 files changed, 19 insertions, 10 deletions
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index adb7fea78c2d..9dc564830c9d 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c | |||
@@ -602,9 +602,7 @@ static void sa1100_irda_txdma_irq(void *id) | |||
602 | { | 602 | { |
603 | struct net_device *dev = id; | 603 | struct net_device *dev = id; |
604 | struct sa1100_irda *si = netdev_priv(dev); | 604 | struct sa1100_irda *si = netdev_priv(dev); |
605 | struct sk_buff *skb = si->dma_tx.skb; | 605 | struct sk_buff *skb; |
606 | |||
607 | si->dma_tx.skb = NULL; | ||
608 | 606 | ||
609 | /* | 607 | /* |
610 | * Wait for the transmission to complete. Unfortunately, | 608 | * Wait for the transmission to complete. Unfortunately, |
@@ -636,14 +634,15 @@ static void sa1100_irda_txdma_irq(void *id) | |||
636 | */ | 634 | */ |
637 | sa1100_irda_rx_dma_start(si); | 635 | sa1100_irda_rx_dma_start(si); |
638 | 636 | ||
639 | /* | 637 | /* Account and free the packet. */ |
640 | * Account and free the packet. | 638 | skb = si->dma_tx.skb; |
641 | */ | ||
642 | if (skb) { | 639 | if (skb) { |
643 | dma_unmap_single(si->dev, si->dma_tx.dma, skb->len, DMA_TO_DEVICE); | 640 | dma_unmap_single(si->dev, si->dma_tx.dma, skb->len, |
641 | DMA_TO_DEVICE); | ||
644 | dev->stats.tx_packets ++; | 642 | dev->stats.tx_packets ++; |
645 | dev->stats.tx_bytes += skb->len; | 643 | dev->stats.tx_bytes += skb->len; |
646 | dev_kfree_skb_irq(skb); | 644 | dev_kfree_skb_irq(skb); |
645 | si->dma_tx.skb = NULL; | ||
647 | } | 646 | } |
648 | 647 | ||
649 | /* | 648 | /* |
@@ -841,21 +840,31 @@ err_irq: | |||
841 | static int sa1100_irda_stop(struct net_device *dev) | 840 | static int sa1100_irda_stop(struct net_device *dev) |
842 | { | 841 | { |
843 | struct sa1100_irda *si = netdev_priv(dev); | 842 | struct sa1100_irda *si = netdev_priv(dev); |
843 | struct sk_buff *skb; | ||
844 | 844 | ||
845 | disable_irq(dev->irq); | 845 | disable_irq(dev->irq); |
846 | sa1100_irda_shutdown(si); | 846 | sa1100_irda_shutdown(si); |
847 | 847 | ||
848 | /* | 848 | /* |
849 | * If we have been doing DMA receive, make sure we | 849 | * If we have been doing any DMA activity, make sure we |
850 | * tidy that up cleanly. | 850 | * tidy that up cleanly. |
851 | */ | 851 | */ |
852 | if (si->dma_rx.skb) { | 852 | skb = si->dma_rx.skb; |
853 | if (skb) { | ||
853 | dma_unmap_single(si->dev, si->dma_rx.dma, HPSIR_MAX_RXLEN, | 854 | dma_unmap_single(si->dev, si->dma_rx.dma, HPSIR_MAX_RXLEN, |
854 | DMA_FROM_DEVICE); | 855 | DMA_FROM_DEVICE); |
855 | dev_kfree_skb(si->dma_rx.skb); | 856 | dev_kfree_skb(skb); |
856 | si->dma_rx.skb = NULL; | 857 | si->dma_rx.skb = NULL; |
857 | } | 858 | } |
858 | 859 | ||
860 | skb = si->dma_tx.skb; | ||
861 | if (skb) { | ||
862 | dma_unmap_single(si->dev, si->dma_tx.dma, skb->len, | ||
863 | DMA_TO_DEVICE); | ||
864 | dev_kfree_skb(skb); | ||
865 | si->dma_tx.skb = NULL; | ||
866 | } | ||
867 | |||
859 | /* Stop IrLAP */ | 868 | /* Stop IrLAP */ |
860 | if (si->irlap) { | 869 | if (si->irlap) { |
861 | irlap_close(si->irlap); | 870 | irlap_close(si->irlap); |