diff options
author | Pavel Begunkov <asml.silence@gmail.com> | 2022-01-27 03:36:30 +0300 |
---|---|---|
committer | Jakub Kicinski <kuba@kernel.org> | 2022-01-28 06:46:11 +0300 |
commit | 40ac240c2e06e4b5477705da1b37fb1d160572de (patch) | |
tree | 5afd911fc5b755701078c2b2dd7fcdde58b70fd4 | |
parent | 5298953e742dc9211d3b724fb5394da8a1f3ed04 (diff) | |
download | linux-40ac240c2e06e4b5477705da1b37fb1d160572de.tar.xz |
ipv6: optimise dst refcounting on cork init
udpv6_sendmsg() doesn't need dst after calling ip6_make_skb(), so
instead of taking an additional reference inside ip6_setup_cork()
and releasing the initial one afterwards, we can hand over a reference
into ip6_make_skb() saving two atomics. The only other user of
ip6_setup_cork() is ip6_append_data() and it requires an extra
dst_hold().
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Reviewed-by: Willem de Bruijn <willemb@google.com>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
-rw-r--r-- | net/ipv6/ip6_output.c | 13 | ||||
-rw-r--r-- | net/ipv6/udp.c | 3 |
2 files changed, 11 insertions, 5 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 0cc490f2cfbf..0c6c971ce0a5 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -1356,6 +1356,11 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork, unsigned int mtu; struct ipv6_txoptions *nopt, *opt = ipc6->opt; + /* callers pass dst together with a reference, set it first so + * ip6_cork_release() can put it down even in case of an error. + */ + cork->base.dst = &rt->dst; + /* * setup for corking */ @@ -1389,8 +1394,6 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork, /* need source address above miyazawa*/ } - dst_hold(&rt->dst); - cork->base.dst = &rt->dst; v6_cork->hop_limit = ipc6->hlimit; v6_cork->tclass = ipc6->tclass; if (rt->dst.flags & DST_XFRM_TUNNEL) @@ -1784,6 +1787,7 @@ int ip6_append_data(struct sock *sk, /* * setup for corking */ + dst_hold(&rt->dst); err = ip6_setup_cork(sk, &inet->cork, &np->cork, ipc6, rt); if (err) @@ -1974,15 +1978,16 @@ struct sk_buff *ip6_make_skb(struct sock *sk, int exthdrlen = (ipc6->opt ? ipc6->opt->opt_flen : 0); int err; - if (flags & MSG_PROBE) + if (flags & MSG_PROBE) { + dst_release(&rt->dst); return NULL; + } __skb_queue_head_init(&queue); cork->base.flags = 0; cork->base.addr = 0; cork->base.opt = NULL; - cork->base.dst = NULL; v6_cork.opt = NULL; err = ip6_setup_cork(sk, cork, &v6_cork, ipc6, rt); if (err) { diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index cfcf08c3df4d..c6872596b408 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1541,7 +1541,8 @@ back_from_confirm: err = PTR_ERR(skb); if (!IS_ERR_OR_NULL(skb)) err = udp_v6_send_skb(skb, fl6, &cork.base); - goto out; + /* ip6_make_skb steals dst reference */ + goto out_no_dst; } lock_sock(sk); |