Re: [PATCH v5 11/13] NFSD: Refactor find_file()
From: NeilBrown <hidden>
Date: 2022-10-25 00:47:45
On Tue, 25 Oct 2022, Chuck Lever wrote:
quoted hunk ↗ jump to hunk
find_file() is now the only caller of find_file_locked(), so just fold these two together. Name nfs4_file-related helpers consistently. There are already nfs4_file_yada functions, so let's go with the same convention used by put_nfs4_file(): find_nfs4_file(). Signed-off-by: Chuck Lever <chuck.lever@oracle.com> --- fs/nfsd/nfs4state.c | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-)diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 529995a9e916..abed795bb4ec 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c@@ -4666,31 +4666,23 @@ move_to_close_lru(struct nfs4_ol_stateid *s, struct net *net) nfs4_put_stid(&last->st_stid); } -/* search file_hashtbl[] for file */ -static struct nfs4_file * -find_file_locked(const struct svc_fh *fh, unsigned int hashval) +static noinline_for_stack struct nfs4_file * +find_nfs4_file(const struct svc_fh *fhp) { - struct nfs4_file *fp; + unsigned int hashval = file_hashval(fhp); + struct nfs4_file *fi = NULL; - hlist_for_each_entry_rcu(fp, &file_hashtbl[hashval], fi_hash, - lockdep_is_held(&state_lock)) { - if (fh_match(&fp->fi_fhandle, &fh->fh_handle)) { - if (refcount_inc_not_zero(&fp->fi_ref)) - return fp; + rcu_read_lock(); + hlist_for_each_entry_rcu(fi, &file_hashtbl[hashval], fi_hash, + lockdep_is_held(&state_lock)) { + if (fh_match(&fi->fi_fhandle, &fhp->fh_handle)) { + if (!refcount_inc_not_zero(&fi->fi_ref)) + fi = NULL;
This looks .... imperfect to me. If the refcount_inc_not_zero fails, it means we haven't found what we are looking for, so why break out of the loop? I guess we can *know* that if some other thread has deleted the entry and some third thread has added a new entry then the new entry will be early in the list so it doesn't hurt to stop now. But it seems unnecessary. I would write this. if (fh_match(&fi->fi_fhandle, &fhp->fh_handle) && refcount_inc_not_zero(&fi->fi_ref)) break;
+ break; } }
..
rcu_read_unlock();
..
+ return fi;
This assumes that when the loop completes normally, the loop variable is NULL. That is the case for this particular for_each loop, but isn't for some others. There was a recent spate of patches for for_each loops that made the wrong assumption so I feel a bit wary. At most I might suggest a comment ... but that probably wouldn't help at all.. So it is probably fine as it is. So I'd like to see the loop simplified to remove the assignment (fi = NULL), but either way Reviewed-by: NeilBrown <redacted> Thanks, NeilBrown