Re: [PATCH 3/3] NFS/localio: nfs_uuid_put() fix the wake up after unlinking the file

NeilBrown
2025-07-16T01:31:30Z

On Wed, 16 Jul 2025, Trond Myklebust wrote:
> From: Trond Myklebust <trond.myklebust@hammerspace.com>
>
> After setting nfl->nfs_uuid to NULL, dereferences of nfl should be
> avoided, since there are no further guarantees that the memory is still
> allocated.

nfl is not being dereferenced here. The difference between using "nfl"
and "&nfl->nfs_uuid" as the event variable is simply some address
arithmetic. As long as both are the same it doesn't matter which is
used.

> Also change the wake_up_var_locked() to be a regular wake_up_var(),
> since nfs_close_local_fh() cannot retake the nfs_uuid->lock after
> dropping it.

The point of wake_up_var_locked() is to document why wake_up_var() is
safe. In general you need a barrier between an assignment and a
wake_up_var(). I would like to eventually remove all wake_up_var()
calls, replacing them with other calls which document why the wakeup is
safe (e.g. store_release_wake_up(), atomic_dec_and_wake_up()). In this
case it is safe because both the waker and the waiter hold the same
spinlock. I would like that documentation to remain.

Also the change from RCU_INIT_POINTER() to rcu_assign_pointer() is not
documented and not needed. The primary purpose of rcu_assign_pointer()
is to include a barer so that anything that the new value points to will
be visible to a concurrent reader that uses rcu_dereference_pointer().
As NULL doesn't point to anything, no possible barrier is needed and
RCU_INIT_POINTER() is the correct interface to use.

So I think this patch is unnecessary and while it doesn't change
behaviour in any important way, it does make the intention of the code a
little less clear.

Thanks,
NeilBrown

>
> 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 | 7 +++----
> 1 file changed, 3 insertions(+), 4 deletions(-)
>
> diff --git a/fs/nfs_common/nfslocalio.c b/fs/nfs_common/nfslocalio.c
> index d157fdc068d7..27ad5263e400 100644
> --- a/fs/nfs_common/nfslocalio.c
> +++ b/fs/nfs_common/nfslocalio.c
> @@ -199,8 +199,8 @@ static bool nfs_uuid_put(nfs_uuid_t *nfs_uuid)
> /* Now we can allow racing nfs_close_local_fh() to
> * skip the locking.
> */
> - RCU_INIT_POINTER(nfl->nfs_uuid, NULL);
> - wake_up_var_locked(&nfl->nfs_uuid, &nfs_uuid->lock);
> + rcu_assign_pointer(nfl->nfs_uuid, NULL);
> + wake_up_var(nfl);
> }
>
> /* Remove client from nn->local_clients */
> @@ -321,8 +321,7 @@ void nfs_close_local_fh(struct nfs_file_localio *nfl)
> */
> spin_unlock(&nfs_uuid->lock);
> rcu_read_unlock();
> - wait_var_event(&nfl->nfs_uuid,
> - rcu_access_pointer(nfl->nfs_uuid) == NULL);
> + wait_var_event(nfl, rcu_access_pointer(nfl->nfs_uuid) == NULL);
> return;
> }
> /* tell nfs_uuid_put() to wait for us */
> --
> 2.50.1
>
>