Linux RDMA and InfiniBand development
 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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox