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..00e19705cd39adec934d516a8a97d061909d4e8a 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,12 +1375,17 @@ 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(level, "skb frag[%d] netmem %px offset %u len %u\n", i,
+                      frag->netmem, skb_frag_off(frag), skb_frag_size(frag));
+               if (!len)
+                       continue;
+
                if (skb_frag_is_net_iov(frag)) {
                        printk("%sskb frag %d: not readable\n", level, i);
                        len -= skb_frag_size(frag);
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);