netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 net-next 0/2] af_unix: Clean up unnecessary spin_lock(&sk->sk_peer_lock).
@ 2024-01-28 10:37 Kuniyuki Iwashima
  2024-01-28 10:37 ` [PATCH v1 net-next 1/2] af_unix: Set sk_peer_pid/sk_peer_cred locklessly for new socket Kuniyuki Iwashima
  2024-01-28 10:37 ` [PATCH v1 net-next 2/2] af_unix: Don't hold client's sk_peer_lock in copy_peercred() Kuniyuki Iwashima
  0 siblings, 2 replies; 4+ messages in thread
From: Kuniyuki Iwashima @ 2024-01-28 10:37 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
  Cc: Kent Overstreet, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev

Except for updating sk_peer_pid/sk_peer_cred, we do not need to hold
sk_peer_lock during initialisation.

This series removes unnecessary spin_lock() and spin_unlock() in such
places.


Kuniyuki Iwashima (2):
  af_unix: Set sk_peer_pid/sk_peer_cred locklessly for new socket.
  af_unix: Don't hold client's sk_peer_lock in copy_peercred().

 net/unix/af_unix.c | 31 ++++++++++---------------------
 1 file changed, 10 insertions(+), 21 deletions(-)

-- 
2.30.2


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v1 net-next 1/2] af_unix: Set sk_peer_pid/sk_peer_cred locklessly for new socket.
  2024-01-28 10:37 [PATCH v1 net-next 0/2] af_unix: Clean up unnecessary spin_lock(&sk->sk_peer_lock) Kuniyuki Iwashima
@ 2024-01-28 10:37 ` Kuniyuki Iwashima
  2024-01-28 10:37 ` [PATCH v1 net-next 2/2] af_unix: Don't hold client's sk_peer_lock in copy_peercred() Kuniyuki Iwashima
  1 sibling, 0 replies; 4+ messages in thread
From: Kuniyuki Iwashima @ 2024-01-28 10:37 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
  Cc: Kent Overstreet, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev

init_peercred() is called in 3 places:

  1. socketpair() : both sockets
  2. connect()    : child socket
  3. listen()     : listening socket

The first two need not hold sk_peer_lock because no one can
touch the socket.

Let's set cred/pid without holding lock for the two cases and
rename the old init_peercred() to update_peercred() to properly
reflect the use case.

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
---
 net/unix/af_unix.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 1720419d93d6..f07374d31f7c 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -684,6 +684,12 @@ static void unix_release_sock(struct sock *sk, int embrion)
 }
 
 static void init_peercred(struct sock *sk)
+{
+	sk->sk_peer_pid = get_pid(task_tgid(current));
+	sk->sk_peer_cred = get_current_cred();
+}
+
+static void update_peercred(struct sock *sk)
 {
 	const struct cred *old_cred;
 	struct pid *old_pid;
@@ -691,8 +697,7 @@ static void init_peercred(struct sock *sk)
 	spin_lock(&sk->sk_peer_lock);
 	old_pid = sk->sk_peer_pid;
 	old_cred = sk->sk_peer_cred;
-	sk->sk_peer_pid  = get_pid(task_tgid(current));
-	sk->sk_peer_cred = get_current_cred();
+	init_peercred(sk);
 	spin_unlock(&sk->sk_peer_lock);
 
 	put_pid(old_pid);
@@ -743,7 +748,7 @@ static int unix_listen(struct socket *sock, int backlog)
 	sk->sk_max_ack_backlog	= backlog;
 	sk->sk_state		= TCP_LISTEN;
 	/* set credentials so connect can copy them */
-	init_peercred(sk);
+	update_peercred(sk);
 	err = 0;
 
 out_unlock:
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v1 net-next 2/2] af_unix: Don't hold client's sk_peer_lock in copy_peercred().
  2024-01-28 10:37 [PATCH v1 net-next 0/2] af_unix: Clean up unnecessary spin_lock(&sk->sk_peer_lock) Kuniyuki Iwashima
  2024-01-28 10:37 ` [PATCH v1 net-next 1/2] af_unix: Set sk_peer_pid/sk_peer_cred locklessly for new socket Kuniyuki Iwashima
@ 2024-01-28 10:37 ` Kuniyuki Iwashima
  2024-01-28 21:04   ` Kuniyuki Iwashima
  1 sibling, 1 reply; 4+ messages in thread
From: Kuniyuki Iwashima @ 2024-01-28 10:37 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni
  Cc: Kent Overstreet, Kuniyuki Iwashima, Kuniyuki Iwashima, netdev

When (AF_UNIX, SOCK_STREAM) socket connect()s to a listening socket,
the listener's sk_peer_pid/sk_peer_cred are copied to the client in
copy_peercred().

Then, two sk_peer_locks are held there; one is client's and another
is listener's.  However, we need not hold the client's lock.

The only place where the client's sk_peer_pid/sk_peer_cred are set
is copy_peercred(), and once they are set, they never change.

Let's not hold client's sk_peer_lock in copy_peercred().

Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
---
 net/unix/af_unix.c | 20 ++------------------
 1 file changed, 2 insertions(+), 18 deletions(-)

diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index f07374d31f7c..c5c292393be8 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -706,26 +706,10 @@ static void update_peercred(struct sock *sk)
 
 static void copy_peercred(struct sock *sk, struct sock *peersk)
 {
-	const struct cred *old_cred;
-	struct pid *old_pid;
-
-	if (sk < peersk) {
-		spin_lock(&sk->sk_peer_lock);
-		spin_lock_nested(&peersk->sk_peer_lock, SINGLE_DEPTH_NESTING);
-	} else {
-		spin_lock(&peersk->sk_peer_lock);
-		spin_lock_nested(&sk->sk_peer_lock, SINGLE_DEPTH_NESTING);
-	}
-	old_pid = sk->sk_peer_pid;
-	old_cred = sk->sk_peer_cred;
-	sk->sk_peer_pid  = get_pid(peersk->sk_peer_pid);
+	spin_lock(&peersk->sk_peer_lock);
+	sk->sk_peer_pid = get_pid(peersk->sk_peer_pid);
 	sk->sk_peer_cred = get_cred(peersk->sk_peer_cred);
-
-	spin_unlock(&sk->sk_peer_lock);
 	spin_unlock(&peersk->sk_peer_lock);
-
-	put_pid(old_pid);
-	put_cred(old_cred);
 }
 
 static int unix_listen(struct socket *sock, int backlog)
-- 
2.30.2


^ permalink raw reply related	[flat|nested] 4+ messages in thread

* [PATCH v1 net-next 2/2] af_unix: Don't hold client's sk_peer_lock in copy_peercred().
  2024-01-28 10:37 ` [PATCH v1 net-next 2/2] af_unix: Don't hold client's sk_peer_lock in copy_peercred() Kuniyuki Iwashima
@ 2024-01-28 21:04   ` Kuniyuki Iwashima
  0 siblings, 0 replies; 4+ messages in thread
From: Kuniyuki Iwashima @ 2024-01-28 21:04 UTC (permalink / raw)
  To: kuniyu; +Cc: davem, edumazet, kent.overstreet, kuba, kuni1840, netdev, pabeni

From: Kuniyuki Iwashima <kuniyu@amazon.com>
Date: Sun, 28 Jan 2024 02:37:32 -0800
> When (AF_UNIX, SOCK_STREAM) socket connect()s to a listening socket,
> the listener's sk_peer_pid/sk_peer_cred are copied to the client in
> copy_peercred().
> 
> Then, two sk_peer_locks are held there; one is client's and another
> is listener's.  However, we need not hold the client's lock.
> 
> The only place where the client's sk_peer_pid/sk_peer_cred are set
> is copy_peercred(), and once they are set, they never change.
> 
> Let's not hold client's sk_peer_lock in copy_peercred().
> 
> Signed-off-by: Kuniyuki Iwashima <kuniyu@amazon.com>
> ---
>  net/unix/af_unix.c | 20 ++------------------
>  1 file changed, 2 insertions(+), 18 deletions(-)
> 
> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
> index f07374d31f7c..c5c292393be8 100644
> --- a/net/unix/af_unix.c
> +++ b/net/unix/af_unix.c
> @@ -706,26 +706,10 @@ static void update_peercred(struct sock *sk)
>  
>  static void copy_peercred(struct sock *sk, struct sock *peersk)
>  {
> -	const struct cred *old_cred;
> -	struct pid *old_pid;
> -
> -	if (sk < peersk) {
> -		spin_lock(&sk->sk_peer_lock);
> -		spin_lock_nested(&peersk->sk_peer_lock, SINGLE_DEPTH_NESTING);
> -	} else {
> -		spin_lock(&peersk->sk_peer_lock);
> -		spin_lock_nested(&sk->sk_peer_lock, SINGLE_DEPTH_NESTING);

Somehow I forgot about that the client's sk_peer_pid could be
fetched at the same time by SO_PEERCRED/SO_PEERPIDFD, so the
lock is needed.


> -	}
> -	old_pid = sk->sk_peer_pid;
> -	old_cred = sk->sk_peer_cred;

but old_pid/old_cred are always NULL, so this can be removed.

Also, the locking order can be fixed as

  peer (TCP_LISTEN) -> sk (TCP_ESTABLISHED)

and we can write a lock_cmp_fn for sk_peer_lock.

I'll do so in v2, so

pw-bot: cr


> -	sk->sk_peer_pid  = get_pid(peersk->sk_peer_pid);
> +	spin_lock(&peersk->sk_peer_lock);
> +	sk->sk_peer_pid = get_pid(peersk->sk_peer_pid);
>  	sk->sk_peer_cred = get_cred(peersk->sk_peer_cred);
> -
> -	spin_unlock(&sk->sk_peer_lock);
>  	spin_unlock(&peersk->sk_peer_lock);
> -
> -	put_pid(old_pid);
> -	put_cred(old_cred);
>  }
>  
>  static int unix_listen(struct socket *sock, int backlog)
> -- 
> 2.30.2
> 

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2024-01-28 21:04 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-01-28 10:37 [PATCH v1 net-next 0/2] af_unix: Clean up unnecessary spin_lock(&sk->sk_peer_lock) Kuniyuki Iwashima
2024-01-28 10:37 ` [PATCH v1 net-next 1/2] af_unix: Set sk_peer_pid/sk_peer_cred locklessly for new socket Kuniyuki Iwashima
2024-01-28 10:37 ` [PATCH v1 net-next 2/2] af_unix: Don't hold client's sk_peer_lock in copy_peercred() Kuniyuki Iwashima
2024-01-28 21:04   ` Kuniyuki Iwashima

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).