[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <230e7159f1e9d3ae0d5317c913a0797baac8dc3a.camel@redhat.com>
Date: Tue, 18 Jun 2024 12:54:53 +0200
From: Paolo Abeni <pabeni@...hat.com>
To: Kuniyuki Iwashima <kuniyu@...zon.com>, Kent Overstreet
<kent.overstreet@...ux.dev>
Cc: "David S. Miller" <davem@...emloft.net>, Eric Dumazet
<edumazet@...gle.com>, Jakub Kicinski <kuba@...nel.org>, Kuniyuki Iwashima
<kuni1840@...il.com>, netdev@...r.kernel.org
Subject: Re: [PATCH v3 net-next 04/11] af_unix: Define locking order for
U_LOCK_SECOND in unix_stream_connect().
On Fri, 2024-06-14 at 13:07 -0700, Kuniyuki Iwashima wrote:
> While a SOCK_(STREAM|SEQPACKET) socket connect()s to another, we hold
> two locks of them by unix_state_lock() and unix_state_lock_nested() in
> unix_stream_connect().
>
> Before unix_state_lock_nested(), the following is guaranteed by checking
> sk->sk_state:
>
> 1. The first socket is TCP_LISTEN
> 2. The second socket is not the first one
> 3. Simultaneous connect() must fail
>
> So, the client state can be TCP_CLOSE or TCP_LISTEN or TCP_ESTABLISHED.
>
> Let's define the expected states as unix_state_lock_cmp_fn() instead of
> using unix_state_lock_nested().
>
> Note that 2. is detected by debug_spin_lock_before() and 3. cannot be
> expressed as lock_cmp_fn.
>
> Signed-off-by: Kuniyuki Iwashima <kuniyu@...zon.com>
> ---
> include/net/af_unix.h | 1 -
> net/unix/af_unix.c | 26 +++++++++++++++++++++++++-
> 2 files changed, 25 insertions(+), 2 deletions(-)
>
> diff --git a/include/net/af_unix.h b/include/net/af_unix.h
> index b6eedf7650da..fd813ad73ab8 100644
> --- a/include/net/af_unix.h
> +++ b/include/net/af_unix.h
> @@ -98,7 +98,6 @@ struct unix_sock {
> #define unix_state_unlock(s) spin_unlock(&unix_sk(s)->lock)
> enum unix_socket_lock_class {
> U_LOCK_NORMAL,
> - U_LOCK_SECOND, /* for double locking, see unix_state_double_lock(). */
> U_LOCK_DIAG, /* used while dumping icons, see sk_diag_dump_icons(). */
> U_LOCK_GC_LISTENER, /* used for listening socket while determining gc
> * candidates to close a small race window.
> diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
> index 88f2c5d039c4..5d2728e33f3f 100644
> --- a/net/unix/af_unix.c
> +++ b/net/unix/af_unix.c
> @@ -143,6 +143,30 @@ static int unix_state_lock_cmp_fn(const struct lockdep_map *_a,
> a = container_of(_a, struct unix_sock, lock.dep_map);
> b = container_of(_b, struct unix_sock, lock.dep_map);
>
> + if (a->sk.sk_state == TCP_LISTEN) {
> + /* unix_stream_connect(): Before the 2nd unix_state_lock(),
> + *
> + * 1. a is TCP_LISTEN.
> + * 2. b is not a.
> + * 3. concurrent connect(b -> a) must fail.
> + *
> + * Except for 2. & 3., the b's state can be any possible
> + * value due to concurrent connect() or listen().
> + *
> + * 2. is detected in debug_spin_lock_before(), and 3. cannot
> + * be expressed as lock_cmp_fn.
> + */
> + switch (b->sk.sk_state) {
> + case TCP_CLOSE:
> + case TCP_ESTABLISHED:
> + case TCP_LISTEN:
> + return -1;
> + default:
> + /* Invalid case. */
> + return 0;
> + }
I'm sorry for missing this before, but I'm wondering if we need to
enforce even this case to be symmetric? that is, explicitly check for b
state == TCP_LISTEN, ...
Kent, WDYT?
Thanks!
Paolo
Powered by blists - more mailing lists