If a sock is marked as sending zc data, have the iterator retrieve the correct zc pages from the netgpu module.
Signed-off-by: Jonathan Lemon <jonathan.le...@gmail.com> --- include/linux/uio.h | 4 ++++ lib/iov_iter.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ net/core/datagram.c | 6 +++++- 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/include/linux/uio.h b/include/linux/uio.h index 9576fd8158d7..d4c15205a248 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -227,6 +227,10 @@ ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages, ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages, size_t maxsize, size_t *start); int iov_iter_npages(const struct iov_iter *i, int maxpages); +struct sock; +ssize_t iov_iter_sk_get_pages(struct iov_iter *i, struct sock *sk, + size_t maxsize, struct page **pages, unsigned maxpages, + size_t *pgoff); const void *dup_iter(struct iov_iter *new, struct iov_iter *old, gfp_t flags); diff --git a/lib/iov_iter.c b/lib/iov_iter.c index bf538c2bec77..a50fa3999de3 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -10,6 +10,9 @@ #include <linux/scatterlist.h> #include <linux/instrumented.h> +#include <net/netgpu.h> +#include <net/sock.h> + #define PIPE_PARANOIA /* for now */ #define iterate_iovec(i, n, __v, __p, skip, STEP) { \ @@ -1349,6 +1352,48 @@ ssize_t iov_iter_get_pages(struct iov_iter *i, } EXPORT_SYMBOL(iov_iter_get_pages); +ssize_t iov_iter_sk_get_pages(struct iov_iter *i, struct sock *sk, + size_t maxsize, struct page **pages, unsigned maxpages, + size_t *pgoff) +{ + const struct iovec *iov; + unsigned long addr; + struct iovec v; + size_t len; + unsigned n; + int ret; + + if (!sk->sk_user_data) + return iov_iter_get_pages(i, pages, maxsize, maxpages, pgoff); + + if (maxsize > i->count) + maxsize = i->count; + + if (!iter_is_iovec(i)) + return -EFAULT; + + if (iov_iter_rw(i) != WRITE) + return -EFAULT; + + iterate_iovec(i, maxsize, v, iov, i->iov_offset, ({ + addr = (unsigned long)v.iov_base; + *pgoff = addr & (PAGE_SIZE - 1); + len = v.iov_len + *pgoff; + + if (len > maxpages * PAGE_SIZE) + len = maxpages * PAGE_SIZE; + + n = DIV_ROUND_UP(len, PAGE_SIZE); + + ret = __netgpu_get_pages(sk, pages, addr, n); + if (ret > 0) + ret = (ret == n ? len : ret * PAGE_SIZE) - *pgoff; + return ret; + 0;})); + return 0; +} +EXPORT_SYMBOL(iov_iter_sk_get_pages); + static struct page **get_pages_array(size_t n) { return kvmalloc_array(n, sizeof(struct page *), GFP_KERNEL); diff --git a/net/core/datagram.c b/net/core/datagram.c index 639745d4f3b9..7dd8814c222a 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -530,6 +530,10 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset, struct iov_iter *to, int len) { trace_skb_copy_datagram_iovec(skb, len); + if (skb->zc_netgpu) { + pr_err("skb netgpu datagram on !netgpu sk\n"); + return -EFAULT; + } return __skb_datagram_iter(skb, offset, to, len, false, simple_copy_to_iter, NULL); } @@ -631,7 +635,7 @@ int __zerocopy_sg_from_iter(struct sock *sk, struct sk_buff *skb, if (frag == MAX_SKB_FRAGS) return -EMSGSIZE; - copied = iov_iter_get_pages(from, pages, length, + copied = iov_iter_sk_get_pages(from, sk, length, pages, MAX_SKB_FRAGS - frag, &start); if (copied < 0) return -EFAULT; -- 2.24.1