diff options
author | Eric Dumazet <edumazet@google.com> | 2023-09-22 03:42:16 +0000 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2023-10-01 19:39:18 +0100 |
commit | e08d0b3d172311e2bb500865c0d0038533d0ff11 (patch) | |
tree | 0c5343300213611a52bf2904f1aa129567929171 /net/ipv4/ip_sockglue.c | |
parent | ceaa714138a372ac63cc2c5c19ee0882d22827f9 (diff) | |
download | linux-e08d0b3d172311e2bb500865c0d0038533d0ff11.tar.gz linux-e08d0b3d172311e2bb500865c0d0038533d0ff11.tar.bz2 linux-e08d0b3d172311e2bb500865c0d0038533d0ff11.zip |
inet: implement lockless IP_TOS
Some reads of inet->tos are racy.
Add needed READ_ONCE() annotations and convert IP_TOS option lockless.
v2: missing changes in include/net/route.h (David Ahern)
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/ipv4/ip_sockglue.c')
-rw-r--r-- | net/ipv4/ip_sockglue.c | 29 |
1 files changed, 12 insertions, 17 deletions
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 6d874cc03c8b..50c008efbb6d 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -585,25 +585,20 @@ out: return err; } -void __ip_sock_set_tos(struct sock *sk, int val) +void ip_sock_set_tos(struct sock *sk, int val) { + u8 old_tos = READ_ONCE(inet_sk(sk)->tos); + if (sk->sk_type == SOCK_STREAM) { val &= ~INET_ECN_MASK; - val |= inet_sk(sk)->tos & INET_ECN_MASK; + val |= old_tos & INET_ECN_MASK; } - if (inet_sk(sk)->tos != val) { - inet_sk(sk)->tos = val; + if (old_tos != val) { + WRITE_ONCE(inet_sk(sk)->tos, val); WRITE_ONCE(sk->sk_priority, rt_tos2priority(val)); sk_dst_reset(sk); } } - -void ip_sock_set_tos(struct sock *sk, int val) -{ - lock_sock(sk); - __ip_sock_set_tos(sk, val); - release_sock(sk); -} EXPORT_SYMBOL(ip_sock_set_tos); void ip_sock_set_freebind(struct sock *sk) @@ -1050,6 +1045,9 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname, return 0; case IP_MTU_DISCOVER: return ip_sock_set_mtu_discover(sk, val); + case IP_TOS: /* This sets both TOS and Precedence */ + ip_sock_set_tos(sk, val); + return 0; } err = 0; @@ -1104,9 +1102,6 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname, } } break; - case IP_TOS: /* This sets both TOS and Precedence */ - __ip_sock_set_tos(sk, val); - break; case IP_UNICAST_IF: { struct net_device *dev = NULL; @@ -1593,6 +1588,9 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname, case IP_MTU_DISCOVER: val = READ_ONCE(inet->pmtudisc); goto copyval; + case IP_TOS: + val = READ_ONCE(inet->tos); + goto copyval; } if (needs_rtnl) @@ -1629,9 +1627,6 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname, return -EFAULT; return 0; } - case IP_TOS: - val = inet->tos; - break; case IP_MTU: { struct dst_entry *dst; |