7.3-stable review patch. If anyone has any objections, please let me know. ------------------ From: Chuck Lever commit 2a25cc8e984610828a526086313b8a7aeefe507d upstream. Once blkmapd has read a whole upcall, rpc_pipe_read() unlinks the message from every pipe list, so the purges in rpc_pipe_release() and rpc_close_pipes() no longer reach it. bl_upcall_ops supplies no .release_pipe callback, and bl_pipe_destroy_msg() returns without completing the upcall because a downcall is expected to follow. A daemon that exits between the read and the write therefore strands its waiter: bl_resolve_deviceid() sleeps in wait_for_completion() and never returns, and it holds nn->bl_mutex across that wait, so every later device resolution in the net namespace blocks behind it. Add a .release_pipe that completes an upcall blkmapd has consumed and left unanswered. Completing an upcall retires it, so a message the framework has already purged is no longer in flight and is not completed a second time here. Fixes: fe0a9b740881 ("pnfsblock: add device operations") Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260901-alemi-v2-8-e163f94a3a6e@kernel.org Signed-off-by: Chuck Lever Signed-off-by: Greg Kroah-Hartman --- fs/nfs/blocklayout/rpc_pipefs.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) --- a/fs/nfs/blocklayout/rpc_pipefs.c +++ b/fs/nfs/blocklayout/rpc_pipefs.c @@ -151,10 +151,31 @@ static void bl_pipe_destroy_msg(struct r complete(&nn->bl_done); } +/* + * An upcall blkmapd has consumed is off every pipe list, so the + * purges in rpc_pipe_release() and rpc_close_pipes() cannot reach it. + * No downcall can arrive once the pipe is closed; release its waiter + * here. + */ +static void bl_release_pipe(struct inode *inode) +{ + struct nfs_net *nn = net_generic(inode->i_sb->s_fs_info, nfs_net_id); + struct rpc_pipe *pipe = nn->bl_device_pipe; + + spin_lock(&pipe->lock); + if (rpc_msg_is_inflight(&nn->bl_pipe_msg)) { + nn->bl_pipe_msg.copied = 0; + nn->bl_pipe_msg.errno = -EPIPE; + complete(&nn->bl_done); + } + spin_unlock(&pipe->lock); +} + static const struct rpc_pipe_ops bl_upcall_ops = { .upcall = rpc_pipe_generic_upcall, .downcall = bl_pipe_downcall, .destroy_msg = bl_pipe_destroy_msg, + .release_pipe = bl_release_pipe, }; static int nfs4blocklayout_register_sb(struct super_block *sb,