]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: Add sk_clone().
authorKuniyuki Iwashima <kuniyu@google.com>
Thu, 23 Oct 2025 23:16:53 +0000 (23:16 +0000)
committerJakub Kicinski <kuba@kernel.org>
Tue, 28 Oct 2025 01:04:57 +0000 (18:04 -0700)
sctp_accept() will use sk_clone_lock(), but it will be called
with the parent socket locked, and sctp_migrate() acquires the
child lock later.

Let's add no lock version of sk_clone_lock().

Note that lockdep complains if we simply use bh_lock_sock_nested().

Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Reviewed-by: Xin Long <lucien.xin@gmail.com>
Link: https://patch.msgid.link/20251023231751.4168390-5-kuniyu@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
include/net/sock.h
net/core/sock.c

index 01ce231603db0cc4e82ae27271df7734112c038d..c7e58b8e8a90744dce81ce8251178c8362e5c260 100644 (file)
@@ -1822,7 +1822,12 @@ struct sock *sk_alloc(struct net *net, int family, gfp_t priority,
 void sk_free(struct sock *sk);
 void sk_net_refcnt_upgrade(struct sock *sk);
 void sk_destruct(struct sock *sk);
-struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority);
+struct sock *sk_clone(const struct sock *sk, const gfp_t priority, bool lock);
+
+static inline struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
+{
+       return sk_clone(sk, priority, true);
+}
 
 struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force,
                             gfp_t priority);
index a99132cc0965604a8d4e30e626837606afe316f4..7a9bbc2afcf0867e8f13fc1b3630ac789bd213ae 100644 (file)
@@ -2462,13 +2462,16 @@ static void sk_init_common(struct sock *sk)
 }
 
 /**
- *     sk_clone_lock - clone a socket, and lock its clone
- *     @sk: the socket to clone
- *     @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc)
+ * sk_clone - clone a socket
+ * @sk: the socket to clone
+ * @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc)
+ * @lock: if true, lock the cloned sk
  *
- *     Caller must unlock socket even in error path (bh_unlock_sock(newsk))
+ * If @lock is true, the clone is locked by bh_lock_sock(), and
+ * caller must unlock socket even in error path by bh_unlock_sock().
  */
-struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
+struct sock *sk_clone(const struct sock *sk, const gfp_t priority,
+                     bool lock)
 {
        struct proto *prot = READ_ONCE(sk->sk_prot);
        struct sk_filter *filter;
@@ -2497,9 +2500,13 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)
                __netns_tracker_alloc(sock_net(newsk), &newsk->ns_tracker,
                                      false, priority);
        }
+
        sk_node_init(&newsk->sk_node);
        sock_lock_init(newsk);
-       bh_lock_sock(newsk);
+
+       if (lock)
+               bh_lock_sock(newsk);
+
        newsk->sk_backlog.head  = newsk->sk_backlog.tail = NULL;
        newsk->sk_backlog.len = 0;
 
@@ -2590,12 +2597,13 @@ free:
         * destructor and make plain sk_free()
         */
        newsk->sk_destruct = NULL;
-       bh_unlock_sock(newsk);
+       if (lock)
+               bh_unlock_sock(newsk);
        sk_free(newsk);
        newsk = NULL;
        goto out;
 }
-EXPORT_SYMBOL_GPL(sk_clone_lock);
+EXPORT_SYMBOL_GPL(sk_clone);
 
 static u32 sk_dst_gso_max_size(struct sock *sk, const struct net_device *dev)
 {