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/include/linux/skbuff.h b/include/linux/skbuff.h
index 58009fa661026bd9a9a1448cc7fdaea29b4901ef..0030b52d60b50fa436646b938202944ec55e3c37 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -2578,6 +2578,7 @@ static inline void __skb_fill_page_desc(struct sk_buff *skb, int i,
 static inline void skb_fill_netmem_desc(struct sk_buff *skb, int i,
                                        netmem_ref netmem, int off, int size)
 {
+       DEBUG_NET_WARN_ON_ONCE(size <= 0);
        __skb_fill_netmem_desc(skb, i, netmem, off, size);
        skb_shinfo(skb)->nr_frags = i + 1;
 }
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);
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/include/linux/skbuff.h b/include/linux/skbuff.h
index 58009fa661026bd9a9a1448cc7fdaea29b4901ef..161d3198e9229e187ddbfc5644c21e863ed8eeb4 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -2510,6 +2510,7 @@ static inline void __skb_fill_netmem_desc_noacc(struct skb_shared_info *shinfo,
 {
        skb_frag_t *frag = &shinfo->frags[i];
 
+       DEBUG_NET_WARN_ON_ONCE(size <= 0);
        skb_frag_fill_netmem_desc(frag, netmem, off, size);
 }
 
@@ -2551,6 +2552,7 @@ static inline void __skb_fill_netmem_desc(struct sk_buff *skb, int i,
 {
        struct page *page;
 
+       DEBUG_NET_WARN_ON_ONCE(size <= 0);
        __skb_fill_netmem_desc_noacc(skb_shinfo(skb), i, netmem, off, size);
 
        if (netmem_is_net_iov(netmem)) {
@@ -2578,6 +2580,7 @@ static inline void __skb_fill_page_desc(struct sk_buff *skb, int i,
 static inline void skb_fill_netmem_desc(struct sk_buff *skb, int i,
                                        netmem_ref netmem, int off, int size)
 {
+       DEBUG_NET_WARN_ON_ONCE(size <= 0);
        __skb_fill_netmem_desc(skb, i, netmem, off, size);
        skb_shinfo(skb)->nr_frags = i + 1;
 }
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);
diff --git a/net/mptcp/protocol.c b/net/mptcp/protocol.c
index 08a72242428c0348471a5995465aec32c67af347..ea68ca923dc06713f92af614d179f7fe911e67df 100644
--- a/net/mptcp/protocol.c
+++ b/net/mptcp/protocol.c
@@ -1324,6 +1324,12 @@ static int mptcp_sendmsg_frag(struct sock *sk, struct sock *ssk,
        }
 
        copy = min_t(size_t, copy, info->limit - info->sent);
+       if (!copy) {
+               pr_err("Oops, %u - %u = 0\n", info->limit, info->sent);
+               tcp_remove_empty_skb(ssk);
+               DEBUG_NET_WARN_ON_ONCE(1);
+               return 0;
+       }
        if (!sk_wmem_schedule(ssk, copy)) {
                tcp_remove_empty_skb(ssk);
                return -ENOMEM;