summaryrefslogtreecommitdiffstats
path: root/net/ipv6/ip6_output.c
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2023-09-12 16:02:02 +0000
committerDavid S. Miller <davem@davemloft.net>2023-09-15 10:33:46 +0100
commit15f926c4457aa65b1ac83bda1bbdcaad3f48e4e7 (patch)
treed9b050478d9d4e2b9d81ae88c5a6494875a77196 /net/ipv6/ip6_output.c
parent2da23eb07c91241d962f3ff05565065484cd8929 (diff)
downloadlinux-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.c19
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;