aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Spencer <aspencer@spacex.com>2018-02-22 14:05:33 -0500
committerDavid S. Miller <davem@davemloft.net>2018-02-23 12:26:36 -0500
commitd903ec77118c09f93a610b384d83a6df33a64fe6 (patch)
tree37814077fb7396a5542f2c9b5efbac2297f72723
parentca79bec237f5809a7c3c59bd41cd0880aa889966 (diff)
gianfar: simplify FCS handling and fix memory leak
Previously, buffer descriptors containing only the frame check sequence (FCS) were skipped and not added to the skb. However, the page reference count was still incremented, leading to a memory leak. Fixing this inside gfar_add_rx_frag() is difficult due to reserved memory handling and page reuse. Instead, move the FCS handling to gfar_process_frame() and trim off the FCS before passing the skb up the networking stack. Signed-off-by: Andy Spencer <aspencer@spacex.com> Signed-off-by: Jim Gruen <jgruen@spacex.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c23
1 files changed, 7 insertions, 16 deletions
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 3bdeb295514b..f5c87bd35fa1 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -2934,29 +2934,17 @@ static bool gfar_add_rx_frag(struct gfar_rx_buff *rxb, u32 lstatus,
2934{ 2934{
2935 int size = lstatus & BD_LENGTH_MASK; 2935 int size = lstatus & BD_LENGTH_MASK;
2936 struct page *page = rxb->page; 2936 struct page *page = rxb->page;
2937 bool last = !!(lstatus & BD_LFLAG(RXBD_LAST));
2938
2939 /* Remove the FCS from the packet length */
2940 if (last)
2941 size -= ETH_FCS_LEN;
2942 2937
2943 if (likely(first)) { 2938 if (likely(first)) {
2944 skb_put(skb, size); 2939 skb_put(skb, size);
2945 } else { 2940 } else {
2946 /* the last fragments' length contains the full frame length */ 2941 /* the last fragments' length contains the full frame length */
2947 if (last) 2942 if (lstatus & BD_LFLAG(RXBD_LAST))
2948 size -= skb->len; 2943 size -= skb->len;
2949 2944
2950 /* Add the last fragment if it contains something other than 2945 skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
2951 * the FCS, otherwise drop it and trim off any part of the FCS 2946 rxb->page_offset + RXBUF_ALIGNMENT,
2952 * that was already received. 2947 size, GFAR_RXB_TRUESIZE);
2953 */
2954 if (size > 0)
2955 skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
2956 rxb->page_offset + RXBUF_ALIGNMENT,
2957 size, GFAR_RXB_TRUESIZE);
2958 else if (size < 0)
2959 pskb_trim(skb, skb->len + size);
2960 } 2948 }
2961 2949
2962 /* try reuse page */ 2950 /* try reuse page */
@@ -3069,6 +3057,9 @@ static void gfar_process_frame(struct net_device *ndev, struct sk_buff *skb)
3069 if (priv->padding) 3057 if (priv->padding)
3070 skb_pull(skb, priv->padding); 3058 skb_pull(skb, priv->padding);
3071 3059
3060 /* Trim off the FCS */
3061 pskb_trim(skb, skb->len - ETH_FCS_LEN);
3062
3072 if (ndev->features & NETIF_F_RXCSUM) 3063 if (ndev->features & NETIF_F_RXCSUM)
3073 gfar_rx_checksum(skb, fcb); 3064 gfar_rx_checksum(skb, fcb);
3074 3065