[PATCH 2/3] NFS/localio: nfs_uuid_put() fix the wait for file unlink events

Trond Myklebust
2025-07-15T22:52:54Z

From: Trond Myklebust <trond.myklebust@hammerspace.com>

No reference to nfl is held when waiting in nfs_uuid_put(), so not only
must the event condition check if the first entry in the list has
changed, it must also check if the nfl->nfs_uuid field is still NULL,
in case the old entry was replaced.

Also change the event variable to be nfs_uuid, for the same reason that
no reference is held to nfl.

Acked-by: Mike Snitzer <snitzer@kernel.org>
Tested-by: Mike Snitzer <snitzer@kernel.org>
Fixes: 21fb44034695 ("nfs_localio: protect race between nfs_uuid_put() and nfs_close_local_fh()")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
---
fs/nfs_common/nfslocalio.c | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)

diff --git a/fs/nfs_common/nfslocalio.c b/fs/nfs_common/nfslocalio.c
index 64949c46c174..d157fdc068d7 100644
--- a/fs/nfs_common/nfslocalio.c
+++ b/fs/nfs_common/nfslocalio.c
@@ -177,12 +177,13 @@ static bool nfs_uuid_put(nfs_uuid_t *nfs_uuid)
/* nfs_close_local_fh() is doing the
* close and we must wait. until it unlinks
*/
- wait_var_event_spinlock(nfl,
- list_first_entry_or_null(
- &nfs_uuid->files,
- struct nfs_file_localio,
- list) != nfl,
- &nfs_uuid->lock);
+ wait_var_event_spinlock(
+ nfs_uuid,
+ list_first_entry_or_null(
+ &nfs_uuid->files,
+ struct nfs_file_localio, list) != nfl ||
+ rcu_access_pointer(nfl->nfs_uuid),
+ &nfs_uuid->lock);
continue;
}

@@ -338,7 +339,7 @@ void nfs_close_local_fh(struct nfs_file_localio *nfl)
*/
spin_lock(&nfs_uuid->lock);
list_del_init(&nfl->list);
- wake_up_var_locked(&nfl->nfs_uuid, &nfs_uuid->lock);
+ wake_up_var_locked(nfs_uuid, &nfs_uuid->lock);
spin_unlock(&nfs_uuid->lock);
}
EXPORT_SYMBOL_GPL(nfs_close_local_fh);
--
2.50.1