unsigned int headroom);
 struct sk_buff *skb_copy_expand(const struct sk_buff *skb, int newheadroom,
                                int newtailroom, gfp_t priority);
-int skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg,
-                       int offset, int len);
-int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset,
-                int len);
+int __must_check skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg,
+                                    int offset, int len);
+int __must_check skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg,
+                             int offset, int len);
 int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer);
 int skb_pad(struct sk_buff *skb, int pad);
 #define dev_kfree_skb(a)       consume_skb(a)
 
                                                NULL);
 }
 
-/**
- *     skb_to_sgvec - Fill a scatter-gather list from a socket buffer
- *     @skb: Socket buffer containing the buffers to be mapped
- *     @sg: The scatter-gather list to map into
- *     @offset: The offset into the buffer's contents to start mapping
- *     @len: Length of buffer space to be mapped
- *
- *     Fill the specified scatter-gather list with mappings/pointers into a
- *     region of the buffer space attached to a socket buffer.
- */
 static int
-__skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
+__skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len,
+              unsigned int recursion_level)
 {
        int start = skb_headlen(skb);
        int i, copy = start - offset;
        struct sk_buff *frag_iter;
        int elt = 0;
 
+       if (unlikely(recursion_level >= 24))
+               return -EMSGSIZE;
+
        if (copy > 0) {
                if (copy > len)
                        copy = len;
                end = start + skb_frag_size(&skb_shinfo(skb)->frags[i]);
                if ((copy = end - offset) > 0) {
                        skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+                       if (unlikely(elt && sg_is_last(&sg[elt - 1])))
+                               return -EMSGSIZE;
 
                        if (copy > len)
                                copy = len;
        }
 
        skb_walk_frags(skb, frag_iter) {
-               int end;
+               int end, ret;
 
                WARN_ON(start > offset + len);
 
                end = start + frag_iter->len;
                if ((copy = end - offset) > 0) {
+                       if (unlikely(elt && sg_is_last(&sg[elt - 1])))
+                               return -EMSGSIZE;
+
                        if (copy > len)
                                copy = len;
-                       elt += __skb_to_sgvec(frag_iter, sg+elt, offset - start,
-                                             copy);
+                       ret = __skb_to_sgvec(frag_iter, sg+elt, offset - start,
+                                             copy, recursion_level + 1);
+                       if (unlikely(ret < 0))
+                               return ret;
+                       elt += ret;
                        if ((len -= copy) == 0)
                                return elt;
                        offset += copy;
        return elt;
 }
 
+/**
+ *     skb_to_sgvec - Fill a scatter-gather list from a socket buffer
+ *     @skb: Socket buffer containing the buffers to be mapped
+ *     @sg: The scatter-gather list to map into
+ *     @offset: The offset into the buffer's contents to start mapping
+ *     @len: Length of buffer space to be mapped
+ *
+ *     Fill the specified scatter-gather list with mappings/pointers into a
+ *     region of the buffer space attached to a socket buffer. Returns either
+ *     the number of scatterlist items used, or -EMSGSIZE if the contents
+ *     could not fit.
+ */
+int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
+{
+       int nsg = __skb_to_sgvec(skb, sg, offset, len, 0);
+
+       if (nsg <= 0)
+               return nsg;
+
+       sg_mark_end(&sg[nsg - 1]);
+
+       return nsg;
+}
+EXPORT_SYMBOL_GPL(skb_to_sgvec);
+
 /* As compared with skb_to_sgvec, skb_to_sgvec_nomark only map skb to given
  * sglist without mark the sg which contain last skb data as the end.
  * So the caller can mannipulate sg list as will when padding new data after
 int skb_to_sgvec_nomark(struct sk_buff *skb, struct scatterlist *sg,
                        int offset, int len)
 {
-       return __skb_to_sgvec(skb, sg, offset, len);
+       return __skb_to_sgvec(skb, sg, offset, len, 0);
 }
 EXPORT_SYMBOL_GPL(skb_to_sgvec_nomark);
 
-int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int len)
-{
-       int nsg = __skb_to_sgvec(skb, sg, offset, len);
 
-       sg_mark_end(&sg[nsg - 1]);
-
-       return nsg;
-}
-EXPORT_SYMBOL_GPL(skb_to_sgvec);
 
 /**
  *     skb_cow_data - Check that a socket buffer's data buffers are writable