Commit 4a997d49 authored by Kuniyuki Iwashima's avatar Kuniyuki Iwashima Committed by Martin KaFai Lau
Browse files

tcp: Save lock_sock() for memcg in inet_csk_accept().



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: default avatarKuniyuki Iwashima <kuniyu@google.com>
Signed-off-by: default avatarMartin KaFai Lau <martin.lau@kernel.org>
Reviewed-by: default avatarShakeel Butt <shakeel.butt@linux.dev>
Reviewed-by: default avatarEric Dumazet <edumazet@google.com>
Acked-by: default avatarRoman Gushchin <roman.gushchin@linux.dev>
Link: https://patch.msgid.link/20251014235604.3057003-2-kuniyu@google.com
parent 55db64dd
Loading
Loading
Loading
Loading
+22 −0
Original line number Diff line number Diff line
@@ -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 |
+0 −25
Original line number Diff line number Diff line
@@ -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);