Re: [PATCH] nbd: fix circular lock dependency in nbd_disconnect_and_put

"Zhou, Yun" <[email protected]>
Newsgroups org.kernel.vger.linux-block,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Friendly ping.

On 6/30/2026 11:10 AM, Yun Zhou wrote:
> Move flush_workqueue() out of the config_lock critical section in
> nbd_disconnect_and_put() to break a circular lock dependency.
> 
> The lockdep splat shows:
> 
>    config_lock -> (wq_completion)nbd0-recv
>      from nbd_disconnect_and_put() holding config_lock then calling
>      flush_workqueue() which waits for recv_work to complete.
> 
>    (work_completion)(&args->work) -> config_lock
>      from recv_work() -> nbd_config_put() -> refcount_dec_and_mutex_lock()
>      which may acquire config_lock when the last reference is dropped.
> 
> Fix by splitting the config_lock region: first hold config_lock to
> perform nbd_disconnect(), sock_shutdown(), and clear NBD_RT_BOUND (to
> prevent nbd_genl_reconfigure from queueing new recv_work during the
> window), then release config_lock before flush_workqueue(), and
> re-acquire it for nbd_clear_que(). This is safe because:
> 
> - sock_shutdown() ensures recv_work will observe errors and exit
> - NBD_RT_BOUND cleared prevents concurrent reconfigure from reconnecting
> - flush_workqueue() guarantees all recv_work has completed before
>    the second config_lock section clears the queue
> 
> Fixes: e2daec488c57 ("nbd: Fix hungtask when nbd_config_put")
> Reported-by: [email protected]
> Closes: https://syzkaller.appspot.com/bug?extid=3add0454d5a2619b8e80
> Signed-off-by: Yun Zhou <[email protected]>
> ---
>   drivers/block/nbd.c | 13 +++++++++++--
>   1 file changed, 11 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
> index c5d3ae8f5fc5..87b97bd9d0d3 100644
> --- a/drivers/block/nbd.c
> +++ b/drivers/block/nbd.c
> @@ -2329,14 +2329,23 @@ static void nbd_disconnect_and_put(struct nbd_device *nbd)
>   	nbd_disconnect(nbd);
>   	sock_shutdown(nbd);
>   	wake_up(&nbd->config->conn_wait);
> +	/*
> +	 * Clear NBD_RT_BOUND before releasing config_lock so that
> +	 * nbd_genl_reconfigure() won't queue new recv_work between
> +	 * here and flush_workqueue().
> +	 */
> +	nbd->task_setup = NULL;
> +	clear_bit(NBD_RT_BOUND, &nbd->config->runtime_flags);
> +	mutex_unlock(&nbd->config_lock);
> +
>   	/*
>   	 * Make sure recv thread has finished, we can safely call nbd_clear_que()
>   	 * to cancel the inflight I/Os.
>   	 */
>   	flush_workqueue(nbd->recv_workq);
> +
> +	mutex_lock(&nbd->config_lock);
>   	nbd_clear_que(nbd);
> -	nbd->task_setup = NULL;
> -	clear_bit(NBD_RT_BOUND, &nbd->config->runtime_flags);
>   	mutex_unlock(&nbd->config_lock);
>   
>   	if (test_and_clear_bit(NBD_RT_HAS_CONFIG_REF,
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.