diff options
author | Eric Dumazet <edumazet@google.com> | 2023-09-12 16:02:02 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2023-09-15 10:33:46 +0100 |
commit | 15f926c4457aa65b1ac83bda1bbdcaad3f48e4e7 (patch) | |
tree | d9b050478d9d4e2b9d81ae88c5a6494875a77196 /net/ipv6/ip6_output.c | |
parent | 2da23eb07c91241d962f3ff05565065484cd8929 (diff) | |
download | linux-15f926c4457aa65b1ac83bda1bbdcaad3f48e4e7.tar.gz linux-15f926c4457aa65b1ac83bda1bbdcaad3f48e4e7.tar.bz2 linux-15f926c4457aa65b1ac83bda1bbdcaad3f48e4e7.zip |
ipv6: lockless IPV6_MTU implementation
np->frag_size can be read/written without holding socket lock.
Add missing annotations and make IPV6_MTU setsockopt() lockless.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/ip6_output.c')
-rw-r--r-- | net/ipv6/ip6_output.c | 19 |
1 files changed, 11 insertions, 8 deletions
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 1e16d56d8c38..ab7ede4a731a 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -881,9 +881,11 @@ int ip6_fragment(struct net *net, struct sock *sk, struct sk_buff *skb, mtu = IPV6_MIN_MTU; } - if (np && np->frag_size < mtu) { - if (np->frag_size) - mtu = np->frag_size; + if (np) { + u32 frag_size = READ_ONCE(np->frag_size); + + if (frag_size && frag_size < mtu) + mtu = frag_size; } if (mtu < hlen + sizeof(struct frag_hdr) + 8) goto fail_toobig; @@ -1392,7 +1394,7 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork, struct rt6_info *rt) { struct ipv6_pinfo *np = inet6_sk(sk); - unsigned int mtu; + unsigned int mtu, frag_size; struct ipv6_txoptions *nopt, *opt = ipc6->opt; /* callers pass dst together with a reference, set it first so @@ -1441,10 +1443,11 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork, else mtu = np->pmtudisc >= IPV6_PMTUDISC_PROBE ? READ_ONCE(rt->dst.dev->mtu) : dst_mtu(xfrm_dst_path(&rt->dst)); - if (np->frag_size < mtu) { - if (np->frag_size) - mtu = np->frag_size; - } + + frag_size = READ_ONCE(np->frag_size); + if (frag_size && frag_size < mtu) + mtu = frag_size; + cork->base.fragsize = mtu; cork->base.gso_size = ipc6->gso_size; cork->base.tx_flags = 0; |