inet: lockless getsockopt(IP_OPTIONS)
authorEric Dumazet <edumazet@google.com>
Fri, 22 Sep 2023 03:42:17 +0000 (03:42 +0000)
committerDavid S. Miller <davem@davemloft.net>
Sun, 1 Oct 2023 18:39:18 +0000 (19:39 +0100)
inet->inet_opt being RCU protected, we can use RCU instead
of locking the socket.

Signed-off-by: Eric Dumazet <edumazet@google.com>
Reviewed-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/ipv4/ip_sockglue.c

index 50c008efbb6de7303621dd30b178c90cb3f5a2fc..45d89487914a12061f05c192004ad79f0abbf756 100644 (file)
@@ -1591,27 +1591,20 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
        case IP_TOS:
                val = READ_ONCE(inet->tos);
                goto copyval;
-       }
-
-       if (needs_rtnl)
-               rtnl_lock();
-       sockopt_lock_sock(sk);
-
-       switch (optname) {
        case IP_OPTIONS:
        {
                unsigned char optbuf[sizeof(struct ip_options)+40];
                struct ip_options *opt = (struct ip_options *)optbuf;
                struct ip_options_rcu *inet_opt;
 
-               inet_opt = rcu_dereference_protected(inet->inet_opt,
-                                                    lockdep_sock_is_held(sk));
+               rcu_read_lock();
+               inet_opt = rcu_dereference(inet->inet_opt);
                opt->optlen = 0;
                if (inet_opt)
                        memcpy(optbuf, &inet_opt->opt,
                               sizeof(struct ip_options) +
                               inet_opt->opt.optlen);
-               sockopt_release_sock(sk);
+               rcu_read_unlock();
 
                if (opt->optlen == 0) {
                        len = 0;
@@ -1627,6 +1620,13 @@ int do_ip_getsockopt(struct sock *sk, int level, int optname,
                        return -EFAULT;
                return 0;
        }
+       }
+
+       if (needs_rtnl)
+               rtnl_lock();
+       sockopt_lock_sock(sk);
+
+       switch (optname) {
        case IP_MTU:
        {
                struct dst_entry *dst;