@@ -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
412409nfsd_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
426419static 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 */
754743static void
755744nfsd_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- */
897883static 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
@@ -1064,9 +1042,10 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
10641042 .need = may_flags & NFSD_FILE_MAY_MASK ,
10651043 .net = SVC_NET (rqstp ),
10661044 };
1067- struct nfsd_file * nf , * new ;
1068- bool retry = true ;
1045+ bool open_retry = true ;
1046+ struct nfsd_file * nf ;
10691047 __be32 status ;
1048+ int ret ;
10701049
10711050 status = fh_verify (rqstp , fhp , S_IFREG ,
10721051 may_flags |NFSD_MAY_OWNER_OVERRIDE );
@@ -1076,47 +1055,45 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
10761055 key .cred = get_current_cred ();
10771056
10781057retry :
1079- /* Avoid allocation if the item is already in cache */
1080- nf = rhashtable_lookup_fast (& nfsd_file_rhash_tbl , & key ,
1081- nfsd_file_rhash_params );
1058+ rcu_read_lock ();
1059+ nf = rhashtable_lookup (& nfsd_file_rhash_tbl , & key ,
1060+ nfsd_file_rhash_params );
10821061 if (nf )
10831062 nf = nfsd_file_get (nf );
1063+ rcu_read_unlock ();
10841064 if (nf )
10851065 goto wait_for_construction ;
10861066
1087- new = nfsd_file_alloc (& key , may_flags );
1088- if (!new ) {
1067+ nf = nfsd_file_alloc (& key , may_flags );
1068+ if (!nf ) {
10891069 status = nfserr_jukebox ;
10901070 goto out_status ;
10911071 }
10921072
1093- nf = rhashtable_lookup_get_insert_key (& nfsd_file_rhash_tbl ,
1094- & key , & new -> nf_rhash ,
1095- nfsd_file_rhash_params );
1096- if (!nf ) {
1097- nf = new ;
1098- goto open_file ;
1099- }
1100- if (IS_ERR (nf ))
1101- goto insert_err ;
1102- nf = nfsd_file_get (nf );
1103- if (nf == NULL ) {
1104- nf = new ;
1073+ ret = rhashtable_lookup_insert_key (& nfsd_file_rhash_tbl ,
1074+ & key , & nf -> nf_rhash ,
1075+ nfsd_file_rhash_params );
1076+ if (likely (ret == 0 ))
11051077 goto open_file ;
1106- }
1107- nfsd_file_slab_free (& new -> nf_rcu );
1078+
1079+ nfsd_file_slab_free (& nf -> nf_rcu );
1080+ if (ret == - EEXIST )
1081+ goto retry ;
1082+ trace_nfsd_file_insert_err (rqstp , key .inode , may_flags , ret );
1083+ status = nfserr_jukebox ;
1084+ goto out_status ;
11081085
11091086wait_for_construction :
11101087 wait_on_bit (& nf -> nf_flags , NFSD_FILE_PENDING , TASK_UNINTERRUPTIBLE );
11111088
11121089 /* Did construction of this file fail? */
11131090 if (!test_bit (NFSD_FILE_HASHED , & nf -> nf_flags )) {
11141091 trace_nfsd_file_cons_err (rqstp , key .inode , may_flags , nf );
1115- if (!retry ) {
1092+ if (!open_retry ) {
11161093 status = nfserr_jukebox ;
11171094 goto out ;
11181095 }
1119- retry = false;
1096+ open_retry = false;
11201097 nfsd_file_put_noref (nf );
11211098 goto retry ;
11221099 }
@@ -1164,13 +1141,6 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
11641141 smp_mb__after_atomic ();
11651142 wake_up_bit (& nf -> nf_flags , NFSD_FILE_PENDING );
11661143 goto out ;
1167-
1168- insert_err :
1169- nfsd_file_slab_free (& new -> nf_rcu );
1170- trace_nfsd_file_insert_err (rqstp , key .inode , may_flags , PTR_ERR (nf ));
1171- nf = NULL ;
1172- status = nfserr_jukebox ;
1173- goto out_status ;
11741144}
11751145
11761146/**
0 commit comments