On Mon, Jan 09, 2006 at 04:43:08AM +0000, Paul Janzen wrote:
> Paul Janzen <[EMAIL PROTECTED]> writes:
> > In mv643xx_eth_start_xmit:
> > [...]
> > spin_lock_irqsave(&mp->lock, flags);
> > [...]
> > /* Since hardware can't handle unaligned fragments smaller
> > * than 9 bytes, if we find any, we linearize the skb
> > * and start again. */
> > [...]
> > skb_linearize(skb, GFP_ATOMIC);
> > [...]
> >
> > which ends up calling kunmap_skb_frag(vaddr), which, when
> > CONFIG_HIGHMEM=y, calls local_bh_enable with interrupts off.
>
> A patch for this problem is enclosed. I believe it also solves a
> potential deadlock if skb_linearize() returns -ENOMEM.
>
> Signed-off-by: Paul Janzen <[EMAIL PROTECTED]>
Thank you Paul. Good find and fix. I have one question below.
> --- a/drivers/net/mv643xx_eth.c 2005-12-24 15:47:48.000000000 -0800
> +++ b/drivers/net/mv643xx_eth.c 2006-01-08 20:30:25.000000000 -0800
> @@ -1093,6 +1093,27 @@ static int mv643xx_poll(struct net_devic
> }
> #endif
>
> +/* Hardware can't handle unaligned fragments smaller than 9 bytes.
> + * This helper function detects that case. When I've seen it, it's
> + * always been the first frag (probably near the end of the page), but
> + * we check all frags to be safe.
> + */
By the way, the above comment is mine, but since then, I have seen small,
unaligned fragments beyond the first frag, so I'll remove the last
sentence.
> +static inline unsigned int has_tiny_unaligned_frags(struct sk_buff *skb)
> +{
> + unsigned int frag;
> + skb_frag_t *fragp;
> +
> + for (frag = 0; frag < skb_shinfo(skb)->nr_frags; frag++) {
> + fragp = &skb_shinfo(skb)->frags[frag];
> + if (fragp->size <= 8 && fragp->page_offset & 0x7)
> + return 1;
> +
> + }
> + return 0;
> +}
> +
> +
> /*
> * mv643xx_eth_start_xmit
> *
> @@ -1136,12 +1157,22 @@ static int mv643xx_eth_start_xmit(struct
> return 1;
> }
>
> + if (has_tiny_unaligned_frags(skb)) {
> + if ((skb_linearize(skb, GFP_ATOMIC) != 0)
> + || has_tiny_unaligned_frags(skb)) {
There is no way that skb_linearize can return without removing all frags
from the skb. So the extra call to has_tiny_unaligned_frags() is
unnecessary, right?
-Dale
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html