]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
tcp: Save lock_sock() for memcg in inet_csk_accept().
authorKuniyuki Iwashima <kuniyu@google.com>
Tue, 14 Oct 2025 23:54:54 +0000 (23:54 +0000)
committerMartin KaFai Lau <martin.lau@kernel.org>
Thu, 16 Oct 2025 19:04:47 +0000 (12:04 -0700)
If memcg is enabled, accept() acquires lock_sock() twice for each new
TCP/MPTCP socket in inet_csk_accept() and __inet_accept().

Let's move memcg operations from inet_csk_accept() to __inet_accept().

Note that SCTP somehow allocates a new socket by sk_alloc() in
sk->sk_prot->accept() and clones fields manually, instead of using
sk_clone_lock().

mem_cgroup_sk_alloc() is called for SCTP before __inet_accept(),
so I added the protocol check in __inet_accept(), but this can be
removed once SCTP uses sk_clone_lock().

Signed-off-by: Kuniyuki Iwashima <kuniyu@google.com>
Signed-off-by: Martin KaFai Lau <martin.lau@kernel.org>
Reviewed-by: Shakeel Butt <shakeel.butt@linux.dev>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Acked-by: Roman Gushchin <roman.gushchin@linux.dev>
Link: https://patch.msgid.link/20251014235604.3057003-2-kuniyu@google.com
net/ipv4/af_inet.c
net/ipv4/inet_connection_sock.c

index 3109c5ec38f39de7295f6f50068c42d5fd23b43d..e8771faa5bbfdea8b24ee562804edd176f7b267b 100644 (file)
@@ -755,6 +755,28 @@ EXPORT_SYMBOL(inet_stream_connect);
 
 void __inet_accept(struct socket *sock, struct socket *newsock, struct sock *newsk)
 {
+       /* TODO: use sk_clone_lock() in SCTP and remove protocol checks */
+       if (mem_cgroup_sockets_enabled &&
+           (!IS_ENABLED(CONFIG_IP_SCTP) || sk_is_tcp(newsk))) {
+               gfp_t gfp = GFP_KERNEL | __GFP_NOFAIL;
+
+               mem_cgroup_sk_alloc(newsk);
+
+               if (mem_cgroup_from_sk(newsk)) {
+                       int amt;
+
+                       /* The socket has not been accepted yet, no need
+                        * to look at newsk->sk_wmem_queued.
+                        */
+                       amt = sk_mem_pages(newsk->sk_forward_alloc +
+                                          atomic_read(&newsk->sk_rmem_alloc));
+                       if (amt)
+                               mem_cgroup_sk_charge(newsk, amt, gfp);
+               }
+
+               kmem_cache_charge(newsk, gfp);
+       }
+
        sock_rps_record_flow(newsk);
        WARN_ON(!((1 << newsk->sk_state) &
                  (TCPF_ESTABLISHED | TCPF_SYN_RECV |
index cdd1e12aac8c0332d4ce6cd96ae93342d45f6b15..3b83b66b2284cac671d326244965625c249db426 100644 (file)
@@ -712,31 +712,6 @@ struct sock *inet_csk_accept(struct sock *sk, struct proto_accept_arg *arg)
 
        release_sock(sk);
 
-       if (mem_cgroup_sockets_enabled) {
-               gfp_t gfp = GFP_KERNEL | __GFP_NOFAIL;
-               int amt = 0;
-
-               /* atomically get the memory usage, set and charge the
-                * newsk->sk_memcg.
-                */
-               lock_sock(newsk);
-
-               mem_cgroup_sk_alloc(newsk);
-               if (mem_cgroup_from_sk(newsk)) {
-                       /* The socket has not been accepted yet, no need
-                        * to look at newsk->sk_wmem_queued.
-                        */
-                       amt = sk_mem_pages(newsk->sk_forward_alloc +
-                                          atomic_read(&newsk->sk_rmem_alloc));
-               }
-
-               if (amt)
-                       mem_cgroup_sk_charge(newsk, amt, gfp);
-               kmem_cache_charge(newsk, gfp);
-
-               release_sock(newsk);
-       }
-
        if (req)
                reqsk_put(req);