|
@@ -573,27 +573,12 @@ fault:
|
|
}
|
|
}
|
|
EXPORT_SYMBOL(skb_copy_datagram_from_iter);
|
|
EXPORT_SYMBOL(skb_copy_datagram_from_iter);
|
|
|
|
|
|
-/**
|
|
|
|
- * zerocopy_sg_from_iter - Build a zerocopy datagram from an iov_iter
|
|
|
|
- * @skb: buffer to copy
|
|
|
|
- * @from: the source to copy from
|
|
|
|
- *
|
|
|
|
- * The function will first copy up to headlen, and then pin the userspace
|
|
|
|
- * pages and build frags through them.
|
|
|
|
- *
|
|
|
|
- * Returns 0, -EFAULT or -EMSGSIZE.
|
|
|
|
- */
|
|
|
|
-int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *from)
|
|
|
|
|
|
+int __zerocopy_sg_from_iter(struct sock *sk, struct sk_buff *skb,
|
|
|
|
+ struct iov_iter *from, size_t length)
|
|
{
|
|
{
|
|
- int len = iov_iter_count(from);
|
|
|
|
- int copy = min_t(int, skb_headlen(skb), len);
|
|
|
|
- int frag = 0;
|
|
|
|
|
|
+ int frag = skb_shinfo(skb)->nr_frags;
|
|
|
|
|
|
- /* copy up to skb headlen */
|
|
|
|
- if (skb_copy_datagram_from_iter(skb, 0, from, copy))
|
|
|
|
- return -EFAULT;
|
|
|
|
-
|
|
|
|
- while (iov_iter_count(from)) {
|
|
|
|
|
|
+ while (length && iov_iter_count(from)) {
|
|
struct page *pages[MAX_SKB_FRAGS];
|
|
struct page *pages[MAX_SKB_FRAGS];
|
|
size_t start;
|
|
size_t start;
|
|
ssize_t copied;
|
|
ssize_t copied;
|
|
@@ -603,18 +588,24 @@ int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *from)
|
|
if (frag == MAX_SKB_FRAGS)
|
|
if (frag == MAX_SKB_FRAGS)
|
|
return -EMSGSIZE;
|
|
return -EMSGSIZE;
|
|
|
|
|
|
- copied = iov_iter_get_pages(from, pages, ~0U,
|
|
|
|
|
|
+ copied = iov_iter_get_pages(from, pages, length,
|
|
MAX_SKB_FRAGS - frag, &start);
|
|
MAX_SKB_FRAGS - frag, &start);
|
|
if (copied < 0)
|
|
if (copied < 0)
|
|
return -EFAULT;
|
|
return -EFAULT;
|
|
|
|
|
|
iov_iter_advance(from, copied);
|
|
iov_iter_advance(from, copied);
|
|
|
|
+ length -= copied;
|
|
|
|
|
|
truesize = PAGE_ALIGN(copied + start);
|
|
truesize = PAGE_ALIGN(copied + start);
|
|
skb->data_len += copied;
|
|
skb->data_len += copied;
|
|
skb->len += copied;
|
|
skb->len += copied;
|
|
skb->truesize += truesize;
|
|
skb->truesize += truesize;
|
|
- refcount_add(truesize, &skb->sk->sk_wmem_alloc);
|
|
|
|
|
|
+ if (sk && sk->sk_type == SOCK_STREAM) {
|
|
|
|
+ sk->sk_wmem_queued += truesize;
|
|
|
|
+ sk_mem_charge(sk, truesize);
|
|
|
|
+ } else {
|
|
|
|
+ refcount_add(truesize, &skb->sk->sk_wmem_alloc);
|
|
|
|
+ }
|
|
while (copied) {
|
|
while (copied) {
|
|
int size = min_t(int, copied, PAGE_SIZE - start);
|
|
int size = min_t(int, copied, PAGE_SIZE - start);
|
|
skb_fill_page_desc(skb, frag++, pages[n], start, size);
|
|
skb_fill_page_desc(skb, frag++, pages[n], start, size);
|
|
@@ -625,6 +616,28 @@ int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *from)
|
|
}
|
|
}
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
+EXPORT_SYMBOL(__zerocopy_sg_from_iter);
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * zerocopy_sg_from_iter - Build a zerocopy datagram from an iov_iter
|
|
|
|
+ * @skb: buffer to copy
|
|
|
|
+ * @from: the source to copy from
|
|
|
|
+ *
|
|
|
|
+ * The function will first copy up to headlen, and then pin the userspace
|
|
|
|
+ * pages and build frags through them.
|
|
|
|
+ *
|
|
|
|
+ * Returns 0, -EFAULT or -EMSGSIZE.
|
|
|
|
+ */
|
|
|
|
+int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *from)
|
|
|
|
+{
|
|
|
|
+ int copy = min_t(int, skb_headlen(skb), iov_iter_count(from));
|
|
|
|
+
|
|
|
|
+ /* copy up to skb headlen */
|
|
|
|
+ if (skb_copy_datagram_from_iter(skb, 0, from, copy))
|
|
|
|
+ return -EFAULT;
|
|
|
|
+
|
|
|
|
+ return __zerocopy_sg_from_iter(NULL, skb, from, ~0U);
|
|
|
|
+}
|
|
EXPORT_SYMBOL(zerocopy_sg_from_iter);
|
|
EXPORT_SYMBOL(zerocopy_sg_from_iter);
|
|
|
|
|
|
static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
|
|
static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset,
|