NFSD: NFSv4 CLOSE should release an nfsd_file immediately
authorChuck Lever <chuck.lever@oracle.com>
Fri, 8 Jul 2022 18:27:02 +0000 (14:27 -0400)
committerChuck Lever <chuck.lever@oracle.com>
Sat, 30 Jul 2022 00:16:42 +0000 (20:16 -0400)
The last close of a file should enable other accessors to open and
use that file immediately. Leaving the file open in the filecache
prevents other users from accessing that file until the filecache
garbage-collects the file -- sometimes that takes several seconds.

Reported-by: Wang Yugui <wangyugui@e16-tech.com>
Link: https://bugzilla.linux-nfs.org/show_bug.cgi?387
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
fs/nfsd/filecache.c
fs/nfsd/filecache.h
fs/nfsd/nfs4state.c

index ac38b41..58721fc 100644 (file)
@@ -452,6 +452,24 @@ nfsd_file_put(struct nfsd_file *nf)
                nfsd_file_put_noref(nf);
 }
 
+/**
+ * nfsd_file_close - Close an nfsd_file
+ * @nf: nfsd_file to close
+ *
+ * If this is the final reference for @nf, free it immediately.
+ * This reflects an on-the-wire CLOSE or DELEGRETURN into the
+ * VFS and exported filesystem.
+ */
+void nfsd_file_close(struct nfsd_file *nf)
+{
+       nfsd_file_put(nf);
+       if (refcount_dec_if_one(&nf->nf_ref)) {
+               nfsd_file_unhash(nf);
+               nfsd_file_lru_remove(nf);
+               nfsd_file_free(nf);
+       }
+}
+
 struct nfsd_file *
 nfsd_file_get(struct nfsd_file *nf)
 {
index ee9ed99..28145f1 100644 (file)
@@ -52,6 +52,7 @@ void nfsd_file_cache_shutdown(void);
 int nfsd_file_cache_start_net(struct net *net);
 void nfsd_file_cache_shutdown_net(struct net *net);
 void nfsd_file_put(struct nfsd_file *nf);
+void nfsd_file_close(struct nfsd_file *nf);
 struct nfsd_file *nfsd_file_get(struct nfsd_file *nf);
 void nfsd_file_close_inode_sync(struct inode *inode);
 bool nfsd_file_is_cached(struct inode *inode);
index 3a05c09..9d1a3e1 100644 (file)
@@ -820,9 +820,9 @@ static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
                        swap(f2, fp->fi_fds[O_RDWR]);
                spin_unlock(&fp->fi_lock);
                if (f1)
-                       nfsd_file_put(f1);
+                       nfsd_file_close(f1);
                if (f2)
-                       nfsd_file_put(f2);
+                       nfsd_file_close(f2);
        }
 }