Skip to content

Commit 8d0d254

Browse files
jtlaytonchucklever
authored andcommitted
nfsd: fix nfsd_file_unhash_and_dispose
nfsd_file_unhash_and_dispose() is called for two reasons: We're either shutting down and purging the filecache, or we've gotten a notification about a file delete, so we want to go ahead and unhash it so that it'll get cleaned up when we close. We're either walking the hashtable or doing a lookup in it and we don't take a reference in either case. What we want to do in both cases is to try and unhash the object and put it on the dispose list if that was successful. If it's no longer hashed, then we don't want to touch it, with the assumption being that something else is already cleaning up the sentinel reference. Instead of trying to selectively decrement the refcount in this function, just unhash it, and if that was successful, move it to the dispose list. Then, the disposal routine will just clean that up as usual. Also, just make this a void function, drop the WARN_ON_ONCE, and the comments about deadlocking since the nature of the purported deadlock is no longer clear. Signed-off-by: Jeff Layton <jlayton@kernel.org> Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
1 parent 895ddf5 commit 8d0d254

File tree

1 file changed

+7
-29
lines changed

1 file changed

+7
-29
lines changed

fs/nfsd/filecache.c

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -405,22 +405,15 @@ nfsd_file_unhash(struct nfsd_file *nf)
405405
return false;
406406
}
407407

408-
/*
409-
* Return true if the file was unhashed.
410-
*/
411-
static bool
408+
static void
412409
nfsd_file_unhash_and_dispose(struct nfsd_file *nf, struct list_head *dispose)
413410
{
414411
trace_nfsd_file_unhash_and_dispose(nf);
415-
if (!nfsd_file_unhash(nf))
416-
return false;
417-
/* keep final reference for nfsd_file_lru_dispose */
418-
if (refcount_dec_not_one(&nf->nf_ref))
419-
return true;
420-
421-
nfsd_file_lru_remove(nf);
422-
list_add(&nf->nf_lru, dispose);
423-
return true;
412+
if (nfsd_file_unhash(nf)) {
413+
/* caller must call nfsd_file_dispose_list() later */
414+
nfsd_file_lru_remove(nf);
415+
list_add(&nf->nf_lru, dispose);
416+
}
424417
}
425418

426419
static void
@@ -562,8 +555,6 @@ nfsd_file_dispose_list_delayed(struct list_head *dispose)
562555
* @lock: LRU list lock (unused)
563556
* @arg: dispose list
564557
*
565-
* Note this can deadlock with nfsd_file_cache_purge.
566-
*
567558
* Return values:
568559
* %LRU_REMOVED: @item was removed from the LRU
569560
* %LRU_ROTATE: @item is to be moved to the LRU tail
@@ -748,8 +739,6 @@ nfsd_file_close_inode(struct inode *inode)
748739
*
749740
* Walk the LRU list and close any entries that have not been used since
750741
* the last scan.
751-
*
752-
* Note this can deadlock with nfsd_file_cache_purge.
753742
*/
754743
static void
755744
nfsd_file_delayed_close(struct work_struct *work)
@@ -891,16 +880,12 @@ nfsd_file_cache_init(void)
891880
goto out;
892881
}
893882

894-
/*
895-
* Note this can deadlock with nfsd_file_lru_cb.
896-
*/
897883
static void
898884
__nfsd_file_cache_purge(struct net *net)
899885
{
900886
struct rhashtable_iter iter;
901887
struct nfsd_file *nf;
902888
LIST_HEAD(dispose);
903-
bool del;
904889

905890
rhashtable_walk_enter(&nfsd_file_rhash_tbl, &iter);
906891
do {
@@ -910,14 +895,7 @@ __nfsd_file_cache_purge(struct net *net)
910895
while (!IS_ERR_OR_NULL(nf)) {
911896
if (net && nf->nf_net != net)
912897
continue;
913-
del = nfsd_file_unhash_and_dispose(nf, &dispose);
914-
915-
/*
916-
* Deadlock detected! Something marked this entry as
917-
* unhased, but hasn't removed it from the hash list.
918-
*/
919-
WARN_ON_ONCE(!del);
920-
898+
nfsd_file_unhash_and_dispose(nf, &dispose);
921899
nf = rhashtable_walk_next(&iter);
922900
}
923901

0 commit comments

Comments
 (0)