[PATCH RFC] pnfs/blocklayout: fix lost wakeup in bl_resolve_deviceid()

FAN YE <[email protected]>
Newsgroups org.kernel.feeds.b4-sent,org.kernel.vger.linux-kernel,org.kernel.vger.linux-nfs
Message-ID <[email protected]>
bl_resolve_deviceid() queues itself on nn->bl_wq and calls
rpc_queue_upcall(), but sets TASK_UNINTERRUPTIBLE only after that call
returns.  If blkmapd answers on another CPU in between, the wake_up()
from bl_pipe_downcall() finds the task runnable and the assignment that
follows overwrites it, so schedule() never returns.  The caller holds
nn->bl_mutex, so every later blocklayout device resolution blocks behind
it.

Set the state before queueing the upcall and restore TASK_RUNNING on the
error path.  Of the four rpc_queue_upcall() callers this is the only
open-coded waiter; __cld_pipe_upcall() uses wait_for_completion(), which
cannot lose a wakeup this way.

Fixes: fe0a9b740881 ("pnfsblock: add device operations")
Assisted-by: Claude:claude-opus-5
Signed-off-by: FAN YE <[email protected]>
---
Not seen on a real pNFS mount.  In a VM I reached bl_resolve_deviceid()
through a debugfs hook with a fake blkmapd and an mdelay() widening the
window: the caller sticks in D state at schedule(), and the next caller
then blocks on nn->bl_mutex.  Both go away with this patch.

Two questions:
- Would you rather have bl_wq converted to a completion, like
  __cld_pipe_upcall() in fs/nfsd/nfs4recover.c?
- rpc_queue_upcall() calls dput().  If the pipe were unlinked meanwhile,
  that could sleep with the task already in TASK_UNINTERRUPTIBLE.  Is that
  acceptable here?
---
 fs/nfs/blocklayout/rpc_pipefs.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/fs/nfs/blocklayout/rpc_pipefs.c b/fs/nfs/blocklayout/rpc_pipefs.c
index d526f5ba7887..15972ca0daf1 100644
--- a/fs/nfs/blocklayout/rpc_pipefs.c
+++ b/fs/nfs/blocklayout/rpc_pipefs.c
@@ -84,14 +84,16 @@ bl_resolve_deviceid(struct nfs_server *server, struct pnfs_block_volume *b,
 
 	dprintk("%s CALLING USERSPACE DAEMON\n", __func__);
 	add_wait_queue(&nn->bl_wq, &wq);
+	set_current_state(TASK_UNINTERRUPTIBLE);
 	rc = rpc_queue_upcall(nn->bl_device_pipe, msg);
 	if (rc < 0) {
+		__set_current_state(TASK_RUNNING);
 		remove_wait_queue(&nn->bl_wq, &wq);
 		goto out_free_data;
 	}
 
-	set_current_state(TASK_UNINTERRUPTIBLE);
 	schedule();
+	__set_current_state(TASK_RUNNING);
 	remove_wait_queue(&nn->bl_wq, &wq);
 
 	if (reply->status != BL_DEVICE_REQUEST_PROC) {

---
base-commit: 818bebeb63dd6bf5f4e07e145f6cdbace520a34c
change-id: 20260821-rpc-pipefs-blwake-b57669bfd26c

Best regards,
--  
FAN YE <[email protected]>
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.