Merge tag 'mm-stable-2023-11-01-14-33' of git://git.kernel.org/pub/scm/linux/kernel...
[sfrench/cifs-2.6.git] / fs / nfsd / filecache.c
index 9c62b4502539a5864da67066d4ed659c8098e804..ef063f93fde9d831e825634f6a4b80976d671747 100644 (file)
@@ -992,22 +992,21 @@ nfsd_file_do_acquire(struct svc_rqst *rqstp, struct svc_fh *fhp,
        unsigned char need = may_flags & NFSD_FILE_MAY_MASK;
        struct net *net = SVC_NET(rqstp);
        struct nfsd_file *new, *nf;
-       const struct cred *cred;
+       bool stale_retry = true;
        bool open_retry = true;
        struct inode *inode;
        __be32 status;
        int ret;
 
+retry:
        status = fh_verify(rqstp, fhp, S_IFREG,
                                may_flags|NFSD_MAY_OWNER_OVERRIDE);
        if (status != nfs_ok)
                return status;
        inode = d_inode(fhp->fh_dentry);
-       cred = get_current_cred();
 
-retry:
        rcu_read_lock();
-       nf = nfsd_file_lookup_locked(net, cred, inode, need, want_gc);
+       nf = nfsd_file_lookup_locked(net, current_cred(), inode, need, want_gc);
        rcu_read_unlock();
 
        if (nf) {
@@ -1029,7 +1028,7 @@ retry:
 
        rcu_read_lock();
        spin_lock(&inode->i_lock);
-       nf = nfsd_file_lookup_locked(net, cred, inode, need, want_gc);
+       nf = nfsd_file_lookup_locked(net, current_cred(), inode, need, want_gc);
        if (unlikely(nf)) {
                spin_unlock(&inode->i_lock);
                rcu_read_unlock();
@@ -1061,6 +1060,7 @@ wait_for_construction:
                        goto construction_err;
                }
                open_retry = false;
+               fh_put(fhp);
                goto retry;
        }
        this_cpu_inc(nfsd_file_cache_hits);
@@ -1077,7 +1077,6 @@ out:
                nfsd_file_check_write_error(nf);
                *pnf = nf;
        }
-       put_cred(cred);
        trace_nfsd_file_acquire(rqstp, inode, may_flags, nf, status);
        return status;
 
@@ -1091,8 +1090,20 @@ open_file:
                        status = nfs_ok;
                        trace_nfsd_file_opened(nf, status);
                } else {
-                       status = nfsd_open_verified(rqstp, fhp, may_flags,
-                                                   &nf->nf_file);
+                       ret = nfsd_open_verified(rqstp, fhp, may_flags,
+                                                &nf->nf_file);
+                       if (ret == -EOPENSTALE && stale_retry) {
+                               stale_retry = false;
+                               nfsd_file_unhash(nf);
+                               clear_and_wake_up_bit(NFSD_FILE_PENDING,
+                                                     &nf->nf_flags);
+                               if (refcount_dec_and_test(&nf->nf_ref))
+                                       nfsd_file_free(nf);
+                               nf = NULL;
+                               fh_put(fhp);
+                               goto retry;
+                       }
+                       status = nfserrno(ret);
                        trace_nfsd_file_open(nf, status);
                }
        } else