mirror of
git://git.yoctoproject.org/linux-yocto.git
synced 2025-10-22 23:13:01 +02:00
NFS/localio: nfs_uuid_put() fix races with nfs_open/close_local_fh()
[ Upstream commitfdd015de76
] In order for the wait in nfs_uuid_put() to be safe, it is necessary to ensure that nfs_uuid_add_file() doesn't add a new entry once the nfs_uuid->net has been NULLed out. Also fix up the wake_up_var_locked() / wait_var_event_spinlock() to both use the nfs_uuid address, since nfl, and &nfl->uuid could be used elsewhere. Acked-by: Mike Snitzer <snitzer@kernel.org> Tested-by: Mike Snitzer <snitzer@kernel.org> Link: https://lore.kernel.org/all/175262893035.2234665.1735173020338594784@noble.neil.brown.name/ Fixes:21fb440346
("nfs_localio: protect race between nfs_uuid_put() and nfs_close_local_fh()") Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
33c9293337
commit
7cac8a129f
|
@ -177,7 +177,7 @@ 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,
|
||||
wait_var_event_spinlock(nfs_uuid,
|
||||
list_first_entry_or_null(
|
||||
&nfs_uuid->files,
|
||||
struct nfs_file_localio,
|
||||
|
@ -243,15 +243,20 @@ void nfs_localio_invalidate_clients(struct list_head *nn_local_clients,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_localio_invalidate_clients);
|
||||
|
||||
static void nfs_uuid_add_file(nfs_uuid_t *nfs_uuid, struct nfs_file_localio *nfl)
|
||||
static int nfs_uuid_add_file(nfs_uuid_t *nfs_uuid, struct nfs_file_localio *nfl)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Add nfl to nfs_uuid->files if it isn't already */
|
||||
spin_lock(&nfs_uuid->lock);
|
||||
if (list_empty(&nfl->list)) {
|
||||
if (rcu_access_pointer(nfs_uuid->net) == NULL) {
|
||||
ret = -ENXIO;
|
||||
} else if (list_empty(&nfl->list)) {
|
||||
rcu_assign_pointer(nfl->nfs_uuid, nfs_uuid);
|
||||
list_add_tail(&nfl->list, &nfs_uuid->files);
|
||||
}
|
||||
spin_unlock(&nfs_uuid->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -285,11 +290,13 @@ struct nfsd_file *nfs_open_local_fh(nfs_uuid_t *uuid,
|
|||
}
|
||||
rcu_read_unlock();
|
||||
/* We have an implied reference to net thanks to nfsd_net_try_get */
|
||||
localio = nfs_to->nfsd_open_local_fh(net, uuid->dom, rpc_clnt,
|
||||
cred, nfs_fh, pnf, fmode);
|
||||
localio = nfs_to->nfsd_open_local_fh(net, uuid->dom, rpc_clnt, cred,
|
||||
nfs_fh, pnf, fmode);
|
||||
if (!IS_ERR(localio) && nfs_uuid_add_file(uuid, nfl) < 0) {
|
||||
/* Delete the cached file when racing with nfs_uuid_put() */
|
||||
nfs_to_nfsd_file_put_local(pnf);
|
||||
}
|
||||
nfs_to_nfsd_net_put(net);
|
||||
if (!IS_ERR(localio))
|
||||
nfs_uuid_add_file(uuid, nfl);
|
||||
|
||||
return localio;
|
||||
}
|
||||
|
@ -338,7 +345,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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user