Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: use indirect call wrappers for skb_copy_datagram_iter()

TCP recvmsg() calls skb_copy_datagram_iter(), which
calls an indirect function (cb pointing to simple_copy_to_iter())
for every MSS (fragment) present in the skb.

CONFIG_RETPOLINE=y forces a very expensive operation
that we can avoid thanks to indirect call wrappers.

This patch gives a 13% increase of performance on
a single flow, if the bottleneck is the thread reading
the TCP socket.

Fixes: 950fcaecd5cc ("datagram: consolidate datagram copy to iter helpers")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Acked-by: Paolo Abeni <pabeni@redhat.com>
Acked-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Eric Dumazet and committed by
David S. Miller
29f3490b fab90c82

+11 -3
+11 -3
net/core/datagram.c
··· 51 51 #include <linux/slab.h> 52 52 #include <linux/pagemap.h> 53 53 #include <linux/uio.h> 54 + #include <linux/indirect_call_wrapper.h> 54 55 55 56 #include <net/protocol.h> 56 57 #include <linux/skbuff.h> ··· 404 403 } 405 404 EXPORT_SYMBOL(skb_kill_datagram); 406 405 406 + INDIRECT_CALLABLE_DECLARE(static size_t simple_copy_to_iter(const void *addr, 407 + size_t bytes, 408 + void *data __always_unused, 409 + struct iov_iter *i)); 410 + 407 411 static int __skb_datagram_iter(const struct sk_buff *skb, int offset, 408 412 struct iov_iter *to, int len, bool fault_short, 409 413 size_t (*cb)(const void *, size_t, void *, ··· 422 416 if (copy > 0) { 423 417 if (copy > len) 424 418 copy = len; 425 - n = cb(skb->data + offset, copy, data, to); 419 + n = INDIRECT_CALL_1(cb, simple_copy_to_iter, 420 + skb->data + offset, copy, data, to); 426 421 offset += n; 427 422 if (n != copy) 428 423 goto short_copy; ··· 445 438 446 439 if (copy > len) 447 440 copy = len; 448 - n = cb(vaddr + skb_frag_off(frag) + offset - start, 449 - copy, data, to); 441 + n = INDIRECT_CALL_1(cb, simple_copy_to_iter, 442 + vaddr + skb_frag_off(frag) + offset - start, 443 + copy, data, to); 450 444 kunmap(page); 451 445 offset += n; 452 446 if (n != copy)