[PATCH RFC] pnfs/blocklayout: fix lost wakeup in bl_resolve_deviceid()
FAN YE via B4 Relay <[email protected]>
| Newsgroups | org.kernel.vger.linux-nfs,org.kernel.feeds.b4-sent,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
From: FAN YE <[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]>