ip, udp: Support MSG_SPLICE_PAGES
authorDavid Howells <dhowells@redhat.com>
Mon, 22 May 2023 12:11:20 +0000 (13:11 +0100)
committerJakub Kicinski <kuba@kernel.org>
Wed, 24 May 2023 03:48:27 +0000 (20:48 -0700)
Make IP/UDP sendmsg() support MSG_SPLICE_PAGES.  This causes pages to be
spliced from the source iterator.

This allows ->sendpage() to be replaced by something that can handle
multiple multipage folios in a single transaction.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
cc: David Ahern <dsahern@kernel.org>
cc: Jens Axboe <axboe@kernel.dk>
cc: Matthew Wilcox <willy@infradead.org>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/ipv4/ip_output.c

index 52fc840..c7db973 100644 (file)
@@ -1048,6 +1048,14 @@ static int __ip_append_data(struct sock *sk,
                                skb_zcopy_set(skb, uarg, &extra_uref);
                        }
                }
                                skb_zcopy_set(skb, uarg, &extra_uref);
                        }
                }
+       } else if ((flags & MSG_SPLICE_PAGES) && length) {
+               if (inet->hdrincl)
+                       return -EPERM;
+               if (rt->dst.dev->features & NETIF_F_SG)
+                       /* We need an empty buffer to attach stuff to */
+                       paged = true;
+               else
+                       flags &= ~MSG_SPLICE_PAGES;
        }
 
        cork->length += length;
        }
 
        cork->length += length;
@@ -1207,6 +1215,15 @@ alloc_new_skb:
                                err = -EFAULT;
                                goto error;
                        }
                                err = -EFAULT;
                                goto error;
                        }
+               } else if (flags & MSG_SPLICE_PAGES) {
+                       struct msghdr *msg = from;
+
+                       err = skb_splice_from_iter(skb, &msg->msg_iter, copy,
+                                                  sk->sk_allocation);
+                       if (err < 0)
+                               goto error;
+                       copy = err;
+                       wmem_alloc_delta += copy;
                } else if (!zc) {
                        int i = skb_shinfo(skb)->nr_frags;
 
                } else if (!zc) {
                        int i = skb_shinfo(skb)->nr_frags;