http://bugzilla.kernel.org/show_bug.cgi?id=7018

Looking at this, it seems that when NFS hands UDP a fragmented (non-linear skb),
it traps because it tries to trim bytes off a non-linear skb. Not sure if 
skb_trim
needs fixing, or IP is broken..

---

ssize_t ip_append_page(struct sock *sk, struct page *page,
                       int offset, size_t size, int flags)
{
        struct inet_sock *inet = inet_sk(sk);
        struct sk_buff *skb;
        struct rtable *rt;
        struct ip_options *opt = NULL;
        int hh_len;
        int mtu;
        int len;
        int err;
        unsigned int maxfraglen, fragheaderlen, fraggap;

        if (inet->hdrincl)
                return -EPERM;

        if (flags&MSG_PROBE)
                return 0;

        if (skb_queue_empty(&sk->sk_write_queue))
                return -EINVAL;

        rt = inet->cork.rt;
        if (inet->cork.flags & IPCORK_OPT)
                opt = inet->cork.opt;

        if (!(rt->u.dst.dev->features&NETIF_F_SG))
                return -EOPNOTSUPP;

        hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
        mtu = inet->cork.fragsize;

        fragheaderlen = sizeof(struct iphdr) + (opt ? opt->optlen : 0);
        maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen;

        if (inet->cork.length + size > 0xFFFF - fragheaderlen) {
                ip_local_error(sk, EMSGSIZE, rt->rt_dst, inet->dport, mtu);
                return -EMSGSIZE;
        }

        if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL)
                return -EINVAL;

        inet->cork.length += size;
        if ((sk->sk_protocol == IPPROTO_UDP) &&
            (rt->u.dst.dev->features & NETIF_F_UFO)) {
                skb_shinfo(skb)->gso_size = mtu - fragheaderlen;
                skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
        }


        while (size > 0) {
                int i;

                if (skb_is_gso(skb))
                        len = size;
                else {

                        /* Check if the remaining data fits into current 
packet. */
                        len = mtu - skb->len;
                        if (len < size)
                                len = maxfraglen - skb->len;
                }
                if (len <= 0) {
                        struct sk_buff *skb_prev;
                        char *data;
                        struct iphdr *iph;
                        int alloclen;

                        skb_prev = skb;
                        fraggap = skb_prev->len - maxfraglen;

                        alloclen = fragheaderlen + hh_len + fraggap + 15;
                        skb = sock_wmalloc(sk, alloclen, 1, sk->sk_allocation);
                        if (unlikely(!skb)) {
                                err = -ENOBUFS;
                                goto error;
                        }

                        /*
                         *      Fill in the control structures
                         */
                        skb->ip_summed = CHECKSUM_NONE;
                        skb->csum = 0;
                        skb_reserve(skb, hh_len);

                        /*
                         *      Find where to start putting bytes.
                         */
                        data = skb_put(skb, fragheaderlen + fraggap);
                        skb->nh.iph = iph = (struct iphdr *)data;
                        data += fragheaderlen;
                        skb->h.raw = data;

                        if (fraggap) {
                                skb->csum = skb_copy_and_csum_bits(
                                        skb_prev, maxfraglen,
                                        data, fraggap, 0);
                                skb_prev->csum = csum_sub(skb_prev->csum,
                                                          skb->csum);
----->                          pskb_trim_unique(skb_prev, maxfraglen);

                                

-- 
Stephen Hemminger <[EMAIL PROTECTED]>
-
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

Reply via email to