All of lore.kernel.org
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Anfernee Cao" <anferneemelokc5@gmail.com>
Cc: linux-rdma@vger.kernel.org, linux-s390@vger.kernel.org,
	"Heiko Carstens" <hca@linux.ibm.com>,
	"Vasily Gorbik" <gor@linux.ibm.com>,
	"Alexander Gordeev" <agordeev@linux.ibm.com>,
	"Christian Borntraeger" <borntraeger@linux.ibm.com>
Subject: Re: [PATCH] net/smc: fix possible recursive locking in __smc_lgr_terminate()
Date: Mon, 26 Oct 2026 04:03:26 +0000	[thread overview]
Message-ID: <sashiko-outbox-184612@kernel.org> (raw)
In-Reply-To: <179290097759.51540.15412712294727302463@gmail.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] net/smc: self-deadlock in __smc_lgr_terminate() masked by lock_sock_nested()
- [Medium] net/smc: lockdep subclass inversion and unannotated relock in smc_conn_kill()
--

commit 7303e5e7071cf52d837c7140d6a0e1615372a594
Author: Anfernee Cao <anferneemelokc5@gmail.com>

net/smc: fix possible recursive locking in __smc_lgr_terminate()

This commit replaces lock_sock() with lock_sock_nested() in
__smc_lgr_terminate() to suppress a lockdep recursive locking warning when
smc_listen_work() aborts a connection and cleans up the link group early.

> diff --git a/net/smc/smc_core.c b/net/smc/smc_core.c
> index 6021322253e93..64c5ee592e641 100644
> --- a/net/smc/smc_core.c
> +++ b/net/smc/smc_core.c
> @@ -1579,7 +1579,7 @@ static void __smc_lgr_terminate(struct smc_link_group *lgr, bool soft)
>  		smc = container_of(conn, struct smc_sock, conn);
>  		sock_hold(&smc->sk); /* sock_put below */
>  		read_unlock_bh(&lgr->conns_lock);
> -		lock_sock(&smc->sk);
> +		lock_sock_nested(&smc->sk, SINGLE_DEPTH_NESTING);

[Severity: High]
Can this mask a real self-deadlock on new_smc->sk rather than a false
positive?

The commit description assumes smc_conn_free() always unregisters new_smc
from lgr->conns_all before smc_conn_abort() calls smc_lgr_cleanup_early().
However, in net/smc/smc_core.c, smc_conn_free() only unregisters the
connection if lgr->list is non-empty:

net/smc/smc_core.c:smc_conn_free() {
	...
	if (!list_empty(&lgr->list)) {
		smc_buf_unuse(conn, lgr); /* allow buffer reuse */
		smc_lgr_unregister_conn(conn);
	}
	...
}

When smc_listen_work() in net/smc/af_smc.c holds lock_sock(&new_smc->sk) and
waits for a confirm message via smc_clc_wait_msg(), a peer decline message
with the first-contact flag set causes smc_clc_wait_msg() in
net/smc/smc_clc.c to schedule link group termination before returning:

net/smc/smc_clc.c:smc_clc_wait_msg() {
	...
		if ((dclc->hdr.typev2 & SMC_FIRST_CONTACT_MASK) &&
		    smc->conn.lgr) {
			smc->conn.lgr->sync_err = 1;
			smc_lgr_terminate_sched(smc->conn.lgr);
		}
	...
}

smc_lgr_terminate_sched() runs list_del_init(&lgr->list) and queues
lgr->terminate_work asynchronously while lgr->terminating is still 0.

When smc_listen_work() then calls
smc_listen_decline() -> smc_conn_abort() -> smc_conn_free(),
list_empty(&lgr->list) is already true, so smc_lgr_unregister_conn(conn) is
skipped and new_smc->conn remains in lgr->conns_all:

net/smc/af_smc.c:smc_conn_abort() {
	...
	smc_conn_free(conn);
	if (local_first && lgr_valid)
		smc_lgr_cleanup_early(lgr);
}

If smc_lgr_cleanup_early() -> __smc_lgr_terminate() runs before
lgr->terminate_work sets lgr->terminating, rb_first(&lgr->conns_all) returns
new_smc->conn itself. Using lock_sock_nested() here hides the recursive lock
acquisition from lockdep by assigning subclass 1 while the current task
already holds &new_smc->sk at subclass 0, causing the worker to hang in
__lock_sock(). The same sequence also applies to client first-contact setup
in smc_connect_rdma() and smc_connect_ism().

>  		smc_conn_kill(conn, soft);

[Severity: Medium]
Even when __smc_lgr_terminate() locks a different socket on the link group,
does using subclass 1 here invert the existing lockdep subclass hierarchy and
leave unannotated relocks inside smc_conn_kill()?

In net/smc/af_smc.c, smc_release() locks listening sockets with subclass 1
before smc_close_active() -> smc_close_cleanup_listen() ->
smc_close_non_accepted() locks child sockets at subclass 0:

net/smc/af_smc.c:smc_release() {
	...
	if (sk->sk_state == SMC_LISTEN)
		/* smc_close_non_accepted() is called and acquires
		 * sock lock for child sockets again
		 */
		lock_sock_nested(sk, SINGLE_DEPTH_NESTING);
	else
		lock_sock(sk);
	...
}

Locking a connection socket with subclass 1 in __smc_lgr_terminate() while
smc_listen_work() holds new_smc->sk at subclass 0 establishes the reverse
0 -> 1 ordering.

In addition, smc_conn_kill() calls smc_close_active_abort() in
net/smc/smc_close.c, which drops the socket lock and re-acquires it at
subclass 0 via smc_close_cancel_work() and when releasing clcsock:

net/smc/smc_close.c:smc_close_cancel_work() {
	struct sock *sk = &smc->sk;

	release_sock(sk);
	if (cancel_work_sync(&smc->conn.close_work))
		sock_put(sk);
	if (cancel_delayed_work_sync(&smc->conn.tx_work))
		sock_put(sk);
	lock_sock(sk);
}

net/smc/smc_close.c:smc_close_active_abort() {
	...
	if (release_clcsock) {
		release_sock(sk);
		smc_clcsock_release(smc);
		lock_sock(sk);
	}
	...
}

Wouldn't those plain lock_sock(sk) calls still trigger the recursive locking
warning against new_smc->sk when killing another active connection in the
link group?

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/179290097759.51540.15412712294727302463@gmail.com?part=1

  reply	other threads:[~2026-10-26  4:03 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-25  3:53 [PATCH] net/smc: fix possible recursive locking in __smc_lgr_terminate() Anfernee Cao
2026-10-26  4:03 ` sashiko-bot [this message]
2026-10-26  4:33 ` netdev-bot+sashiko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=sashiko-outbox-184612@kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=agordeev@linux.ibm.com \
    --cc=anferneemelokc5@gmail.com \
    --cc=borntraeger@linux.ibm.com \
    --cc=gor@linux.ibm.com \
    --cc=hca@linux.ibm.com \
    --cc=linux-rdma@vger.kernel.org \
    --cc=linux-s390@vger.kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.