diff --git a/drivers/net/tun.c b/drivers/net/tun.c index d7a865ef370b6968c095510ae16b5196e30e54b9..e816aaba8e5f2ed06f8832f79553b6c976e75bb8 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -1481,7 +1481,7 @@ static struct sk_buff *tun_napi_alloc_frags(struct tun_file *tfile, skb->truesize += skb->data_len; for (i = 1; i < it->nr_segs; i++) { - const struct iovec *iov = iter_iov(it); + const struct iovec *iov = iter_iov(it) + i; size_t fragsz = iov->iov_len; struct page *page; void *frag; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 6841e61a6bd0b66e7b1df0545697604479c6b7a1..69891a2f4fb17b4aeb8f5fcc2b786bbad794534a 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -1115,6 +1115,16 @@ static void skb_release_data(struct sk_buff *skb, enum skb_drop_reason reason) goto free_head; } + if (shinfo->nr_frags > MAX_SKB_FRAGS) { + pr_err("nr_frags=%u\n", shinfo->nr_frags); + skb_dump(KERN_ERR, skb, false); + DEBUG_NET_WARN_ON_ONCE(shinfo->nr_frags > MAX_SKB_FRAGS); + } + if (shinfo->nr_frags && !skb->data_len) { + pr_err("skb->data_len is zero but nr_frags=%u\n", shinfo->nr_frags); + skb_dump(KERN_ERR, skb, false); + DEBUG_NET_WARN_ON_ONCE(shinfo->nr_frags && !skb->data_len); + } for (i = 0; i < shinfo->nr_frags; i++) __skb_frag_unref(&shinfo->frags[i], skb->pp_recycle); @@ -1365,17 +1375,22 @@ void skb_dump(const char *level, const struct sk_buff *skb, bool full_pkt) print_hex_dump(level, "skb tailroom: ", DUMP_PREFIX_OFFSET, 16, 1, skb_tail_pointer(skb), tailroom, false); - for (i = 0; len && i < skb_shinfo(skb)->nr_frags; i++) { + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; u32 p_off, p_len, copied; struct page *p; u8 *vaddr; + printk("%sskb frag[%d] netmem %lx offset %u len %u\n", level, i, + (unsigned long)frag->netmem, skb_frag_off(frag), skb_frag_size(frag)); + if (len <= 0) + continue; + if (skb_frag_is_net_iov(frag)) { printk("%sskb frag %d: not readable\n", level, i); len -= skb_frag_size(frag); - if (!len) - break; + if (len < 0) + len = 0; continue; } diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index 0e5b9a654254b32907ee9739f3443791104bd611..eda4f4ee702e1c4c0916f25065f72f65c2ce7e7e 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -4014,6 +4014,7 @@ static int tcp_send_syn_data(struct sock *sk, struct sk_buff *syn) skb_fill_page_desc(syn_data, 0, pfrag->page, pfrag->offset, space); page_ref_inc(pfrag->page); + pr_err("tcp_send_syn_data() space=%d page %px\n", space, pfrag->page); pfrag->offset += space; skb_len_add(syn_data, space); skb_zcopy_set(syn_data, fo->uarg, NULL);