[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <2a27d3730903262126v1a0282a5u6c8ee234dff8708d@mail.gmail.com>
Date: Fri, 27 Mar 2009 12:26:33 +0800
From: Li Yang <leoli@...escale.com>
To: Stephen Hemminger <shemminger@...tta.com>
Cc: David Miller <davem@...emloft.net>, netdev@...r.kernel.org
Subject: Re: [PATCH] gianfar: fix headroom expansion code
On Fri, Mar 27, 2009 at 1:08 AM, Stephen Hemminger
<shemminger@...tta.com> wrote:
> The code that was added to increase headroom was wrong.
> It doesn't handle the case where gfar_add_fcb() changes the skb.
Oops. I messed up the pointer to pointer manipulating.
> Better to do check at start of transmit (outside of lock), where
> error handling is better anyway.
>
> Signed-off-by: Stephen Hemminger <shemminger@...tta.com>
>
>
> --- a/drivers/net/gianfar.c 2009-03-26 09:14:39.273669929 -0700
> +++ b/drivers/net/gianfar.c 2009-03-26 09:22:46.477545004 -0700
> @@ -1239,19 +1239,9 @@ static int gfar_enet_open(struct net_dev
> return err;
> }
>
> -static inline struct txfcb *gfar_add_fcb(struct sk_buff **skbp)
> +static inline struct txfcb *gfar_add_fcb(struct sk_buff *skb)
> {
> - struct txfcb *fcb;
> - struct sk_buff *skb = *skbp;
> -
> - if (unlikely(skb_headroom(skb) < GMAC_FCB_LEN)) {
> - struct sk_buff *old_skb = skb;
> - skb = skb_realloc_headroom(old_skb, GMAC_FCB_LEN);
> - if (!skb)
> - return NULL;
> - dev_kfree_skb_any(old_skb);
> - }
> - fcb = (struct txfcb *)skb_push(skb, GMAC_FCB_LEN);
> + struct txfcb *fcb = (struct txfcb *)skb_push(skb, GMAC_FCB_LEN);
> cacheable_memzero(fcb, GMAC_FCB_LEN);
>
> return fcb;
> @@ -1320,6 +1310,20 @@ static int gfar_start_xmit(struct sk_buf
>
> base = priv->tx_bd_base;
>
> + /* make space for additional header */
> + if (skb_headroom(skb) < GMAC_FCB_LEN) {
> + struct sk_buff *skb_new;
> +
> + skb_new = skb_realloc_headroom(skb, GMAC_FCB_LEN);
> + if (!skb_new) {
> + dev->stats.tx_errors++;
> + kfree(skb);
> + return NETDEV_TX_OK;
> + }
> + kfree_skb(skb);
> + skb = skb_new;
> + }
> +
We have legacy devices without the offloading feature. And we can
even turn off the IP checksum offloading at runtime. Your code will
cause unnecessary realloc for these cases.
I can propose a new patch to fix the pointer problem and add more
error handling.
> /* total number of fragments in the SKB */
> nr_frags = skb_shinfo(skb)->nr_frags;
>
> @@ -1372,20 +1376,18 @@ static int gfar_start_xmit(struct sk_buf
>
> /* Set up checksumming */
> if (CHECKSUM_PARTIAL == skb->ip_summed) {
> - fcb = gfar_add_fcb(&skb);
> - if (likely(fcb != NULL)) {
> - lstatus |= BD_LFLAG(TXBD_TOE);
> - gfar_tx_checksum(skb, fcb);
> - }
> + fcb = gfar_add_fcb(skb);
> + lstatus |= BD_LFLAG(TXBD_TOE);
> + gfar_tx_checksum(skb, fcb);
> }
>
> if (priv->vlgrp && vlan_tx_tag_present(skb)) {
> - if (unlikely(NULL == fcb))
> - fcb = gfar_add_fcb(&skb);
> - if (likely(fcb != NULL)) {
> + if (unlikely(NULL == fcb)) {
> + fcb = gfar_add_fcb(skb);
> lstatus |= BD_LFLAG(TXBD_TOE);
> - gfar_tx_vlan(skb, fcb);
> }
> +
> + gfar_tx_vlan(skb, fcb);
> }
>
> /* setup the TxBD length and buffer pointer for the first BD */
> @@ -1433,7 +1435,7 @@ static int gfar_start_xmit(struct sk_buf
> /* Unlock priv */
> spin_unlock_irqrestore(&priv->txlock, flags);
>
> - return 0;
> + return NETDEV_TX_OK;
> }
>
> /* Stops the kernel queue, and halts the controller */
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists