Skip to content

Commit fdd015d

Browse files
author
Trond Myklebust
committed
NFS/localio: nfs_uuid_put() fix races with nfs_open/close_local_fh()
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 <[email protected]> Tested-by: Mike Snitzer <[email protected]> Link: https://lore.kernel.org/all/[email protected]/ Fixes: 21fb440 ("nfs_localio: protect race between nfs_uuid_put() and nfs_close_local_fh()") Signed-off-by: Trond Myklebust <[email protected]>
1 parent e144d53 commit fdd015d

File tree

1 file changed

+15
-8
lines changed

1 file changed

+15
-8
lines changed

fs/nfs_common/nfslocalio.c

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ static bool nfs_uuid_put(nfs_uuid_t *nfs_uuid)
177177
/* nfs_close_local_fh() is doing the
178178
* close and we must wait. until it unlinks
179179
*/
180-
wait_var_event_spinlock(nfl,
180+
wait_var_event_spinlock(nfs_uuid,
181181
list_first_entry_or_null(
182182
&nfs_uuid->files,
183183
struct nfs_file_localio,
@@ -243,15 +243,20 @@ void nfs_localio_invalidate_clients(struct list_head *nn_local_clients,
243243
}
244244
EXPORT_SYMBOL_GPL(nfs_localio_invalidate_clients);
245245

246-
static void nfs_uuid_add_file(nfs_uuid_t *nfs_uuid, struct nfs_file_localio *nfl)
246+
static int nfs_uuid_add_file(nfs_uuid_t *nfs_uuid, struct nfs_file_localio *nfl)
247247
{
248+
int ret = 0;
249+
248250
/* Add nfl to nfs_uuid->files if it isn't already */
249251
spin_lock(&nfs_uuid->lock);
250-
if (list_empty(&nfl->list)) {
252+
if (rcu_access_pointer(nfs_uuid->net) == NULL) {
253+
ret = -ENXIO;
254+
} else if (list_empty(&nfl->list)) {
251255
rcu_assign_pointer(nfl->nfs_uuid, nfs_uuid);
252256
list_add_tail(&nfl->list, &nfs_uuid->files);
253257
}
254258
spin_unlock(&nfs_uuid->lock);
259+
return ret;
255260
}
256261

257262
/*
@@ -285,11 +290,13 @@ struct nfsd_file *nfs_open_local_fh(nfs_uuid_t *uuid,
285290
}
286291
rcu_read_unlock();
287292
/* We have an implied reference to net thanks to nfsd_net_try_get */
288-
localio = nfs_to->nfsd_open_local_fh(net, uuid->dom, rpc_clnt,
289-
cred, nfs_fh, pnf, fmode);
293+
localio = nfs_to->nfsd_open_local_fh(net, uuid->dom, rpc_clnt, cred,
294+
nfs_fh, pnf, fmode);
295+
if (!IS_ERR(localio) && nfs_uuid_add_file(uuid, nfl) < 0) {
296+
/* Delete the cached file when racing with nfs_uuid_put() */
297+
nfs_to_nfsd_file_put_local(pnf);
298+
}
290299
nfs_to_nfsd_net_put(net);
291-
if (!IS_ERR(localio))
292-
nfs_uuid_add_file(uuid, nfl);
293300

294301
return localio;
295302
}
@@ -338,7 +345,7 @@ void nfs_close_local_fh(struct nfs_file_localio *nfl)
338345
*/
339346
spin_lock(&nfs_uuid->lock);
340347
list_del_init(&nfl->list);
341-
wake_up_var_locked(&nfl->nfs_uuid, &nfs_uuid->lock);
348+
wake_up_var_locked(nfs_uuid, &nfs_uuid->lock);
342349
spin_unlock(&nfs_uuid->lock);
343350
}
344351
EXPORT_SYMBOL_GPL(nfs_close_local_fh);

0 commit comments

Comments
 (0)