return NULL;
 
        /* len contains both payload and hdr */
-       skb = virtio_vsock_alloc_linear_skb(len, GFP_KERNEL);
+       skb = virtio_vsock_alloc_skb(len, GFP_KERNEL);
        if (!skb)
                return NULL;
 
 
        virtio_vsock_skb_rx_put(skb, payload_len);
 
-       nbytes = copy_from_iter(skb->data, payload_len, &iov_iter);
-       if (nbytes != payload_len) {
-               vq_err(vq, "Expected %zu byte payload, got %zu bytes\n",
-                      payload_len, nbytes);
+       if (skb_copy_datagram_from_iter(skb, 0, &iov_iter, payload_len)) {
+               vq_err(vq, "Failed to copy %zu byte payload\n", payload_len);
                kfree_skb(skb);
                return NULL;
        }
 
 
 static inline void virtio_vsock_skb_rx_put(struct sk_buff *skb, u32 len)
 {
-       skb_put(skb, len);
+       DEBUG_NET_WARN_ON_ONCE(skb->len);
+
+       if (skb_is_nonlinear(skb))
+               skb->len = len;
+       else
+               skb_put(skb, len);
 }
 
 static inline struct sk_buff *
-virtio_vsock_alloc_linear_skb(unsigned int size, gfp_t mask)
+__virtio_vsock_alloc_skb_with_frags(unsigned int header_len,
+                                   unsigned int data_len,
+                                   gfp_t mask)
 {
        struct sk_buff *skb;
+       int err;
 
-       skb = alloc_skb(size, mask);
+       skb = alloc_skb_with_frags(header_len, data_len,
+                                  PAGE_ALLOC_COSTLY_ORDER, &err, mask);
        if (!skb)
                return NULL;
 
        skb_reserve(skb, VIRTIO_VSOCK_SKB_HEADROOM);
+       skb->data_len = data_len;
        return skb;
 }
 
+static inline struct sk_buff *
+virtio_vsock_alloc_linear_skb(unsigned int size, gfp_t mask)
+{
+       return __virtio_vsock_alloc_skb_with_frags(size, 0, mask);
+}
+
+static inline struct sk_buff *virtio_vsock_alloc_skb(unsigned int size, gfp_t mask)
+{
+       if (size <= SKB_WITH_OVERHEAD(PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER))
+               return virtio_vsock_alloc_linear_skb(size, mask);
+
+       size -= VIRTIO_VSOCK_SKB_HEADROOM;
+       return __virtio_vsock_alloc_skb_with_frags(VIRTIO_VSOCK_SKB_HEADROOM,
+                                                  size, mask);
+}
+
 static inline void
 virtio_vsock_skb_queue_head(struct sk_buff_head *list, struct sk_buff *skb)
 {