diff options
author | Eric Dumazet <edumazet@google.com> | 2023-08-16 10:15:34 +0200 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2023-08-16 12:09:17 +0200 |
commit | b4d84bce4c437c4ac1b6f7ef4d612d7d52f62cfe (patch) | |
tree | b29d6153bd51752d08e5a669832e37286cff8fbd /net/ipv4/ip_sockglue.c | |
parent | inet: introduce inet->inet_flags (diff) | |
download | linux-b4d84bce4c437c4ac1b6f7ef4d612d7d52f62cfe.tar.xz linux-b4d84bce4c437c4ac1b6f7ef4d612d7d52f62cfe.zip |
inet: set/get simple options locklessly
Now we have inet->inet_flags, we can set following options
without having to hold the socket lock:
IP_PKTINFO, IP_RECVTTL, IP_RECVTOS, IP_RECVOPTS, IP_RETOPTS,
IP_PASSSEC, IP_RECVORIGDSTADDR, IP_RECVFRAGSIZE.
ip_sock_set_pktinfo() no longer hold the socket lock.
Similarly we can get the following options whithout holding
the socket lock:
IP_PKTINFO, IP_RECVTTL, IP_RECVTOS, IP_RECVOPTS, IP_RETOPTS,
IP_PASSSEC, IP_RECVORIGDSTADDR, IP_CHECKSUM, IP_RECVFRAGSIZE.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Acked-by: Soheil Hassas Yeganeh <soheil@google.com>
Reviewed-by: Simon Horman <horms@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 | 118 |
1 files changed, 62 insertions, 56 deletions
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 66f55f3db5ec..69b87518348a 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -636,9 +636,7 @@ EXPORT_SYMBOL(ip_sock_set_mtu_discover); void ip_sock_set_pktinfo(struct sock *sk) { - lock_sock(sk); inet_set_bit(PKTINFO, sk); - release_sock(sk); } EXPORT_SYMBOL(ip_sock_set_pktinfo); @@ -952,6 +950,36 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname, if (ip_mroute_opt(optname)) return ip_mroute_setsockopt(sk, optname, optval, optlen); + /* Handle options that can be set without locking the socket. */ + switch (optname) { + case IP_PKTINFO: + inet_assign_bit(PKTINFO, sk, val); + return 0; + case IP_RECVTTL: + inet_assign_bit(TTL, sk, val); + return 0; + case IP_RECVTOS: + inet_assign_bit(TOS, sk, val); + return 0; + case IP_RECVOPTS: + inet_assign_bit(RECVOPTS, sk, val); + return 0; + case IP_RETOPTS: + inet_assign_bit(RETOPTS, sk, val); + return 0; + case IP_PASSSEC: + inet_assign_bit(PASSSEC, sk, val); + return 0; + case IP_RECVORIGDSTADDR: + inet_assign_bit(ORIGDSTADDR, sk, val); + return 0; + case IP_RECVFRAGSIZE: + if (sk->sk_type != SOCK_RAW && sk->sk_type != SOCK_DGRAM) + return -EINVAL; + inet_assign_bit(RECVFRAGSIZE, sk, val); + return 0; + } + err = 0; if (needs_rtnl) rtnl_lock(); @@ -991,27 +1019,6 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname, kfree_rcu(old, rcu); break; } - case IP_PKTINFO: - inet_assign_bit(PKTINFO, sk, val); - break; - case IP_RECVTTL: - inet_assign_bit(TTL, sk, val); - break; - case IP_RECVTOS: - inet_assign_bit(TOS, sk, val); - break; - case IP_RECVOPTS: - inet_assign_bit(RECVOPTS, sk, val); - break; - case IP_RETOPTS: - inet_assign_bit(RETOPTS, sk, val); - break; - case IP_PASSSEC: - inet_assign_bit(PASSSEC, sk, val); - break; - case IP_RECVORIGDSTADDR: - inet_assign_bit(ORIGDSTADDR, sk, val); - break; case IP_CHECKSUM: if (val) { if (!(inet_test_bit(CHECKSUM, sk))) { @@ -1025,11 +1032,6 @@ int do_ip_setsockopt(struct sock *sk, int level, int optname, } } break; - case IP_RECVFRAGSIZE: - if (sk->sk_type != SOCK_RAW && sk->sk_type != SOCK_DGRAM) - goto e_inval; - inet_assign_bit(RECVFRAGSIZE, sk, val); - break; case IP_TOS: /* This sets both TOS and Precedence */ __ip_sock_set_tos(sk, val); break; @@ -1544,6 +1546,37 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname, if (len < 0) return -EINVAL; + /* Handle options that can be read without locking the socket. */ + switch (optname) { + case IP_PKTINFO: + val = inet_test_bit(PKTINFO, sk); + goto copyval; + case IP_RECVTTL: + val = inet_test_bit(TTL, sk); + goto copyval; + case IP_RECVTOS: + val = inet_test_bit(TOS, sk); + goto copyval; + case IP_RECVOPTS: + val = inet_test_bit(RECVOPTS, sk); + goto copyval; + case IP_RETOPTS: + val = inet_test_bit(RETOPTS, sk); + goto copyval; + case IP_PASSSEC: + val = inet_test_bit(PASSSEC, sk); + goto copyval; + case IP_RECVORIGDSTADDR: + val = inet_test_bit(ORIGDSTADDR, sk); + goto copyval; + case IP_CHECKSUM: + val = inet_test_bit(CHECKSUM, sk); + goto copyval; + case IP_RECVFRAGSIZE: + val = inet_test_bit(RECVFRAGSIZE, sk); + goto copyval; + } + if (needs_rtnl) rtnl_lock(); sockopt_lock_sock(sk); @@ -1578,33 +1611,6 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname, return -EFAULT; return 0; } - case IP_PKTINFO: - val = inet_test_bit(PKTINFO, sk); - break; - case IP_RECVTTL: - val = inet_test_bit(TTL, sk); - break; - case IP_RECVTOS: - val = inet_test_bit(TOS, sk); - break; - case IP_RECVOPTS: - val = inet_test_bit(RECVOPTS, sk); - break; - case IP_RETOPTS: - val = inet_test_bit(RETOPTS, sk); - break; - case IP_PASSSEC: - val = inet_test_bit(PASSSEC, sk); - break; - case IP_RECVORIGDSTADDR: - val = inet_test_bit(ORIGDSTADDR, sk); - break; - case IP_CHECKSUM: - val = inet_test_bit(CHECKSUM, sk); - break; - case IP_RECVFRAGSIZE: - val = inet_test_bit(RECVFRAGSIZE, sk); - break; case IP_TOS: val = inet->tos; break; @@ -1754,7 +1760,7 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname, return -ENOPROTOOPT; } sockopt_release_sock(sk); - +copyval: if (len < sizeof(int) && len > 0 && val >= 0 && val <= 255) { unsigned char ucval = (unsigned char)val; len = 1; |