nfsd: Ensure sampling of the commit verifier is atomic with the commit
authorTrond Myklebust <trondmy@gmail.com>
Mon, 6 Jan 2020 18:40:36 +0000 (13:40 -0500)
committerJ. Bruce Fields <bfields@redhat.com>
Wed, 22 Jan 2020 21:25:41 +0000 (16:25 -0500)
When we have a successful commit, ensure we sample the commit verifier
before releasing the lock.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
fs/nfsd/nfs3proc.c
fs/nfsd/nfs3xdr.c
fs/nfsd/nfs4proc.c
fs/nfsd/vfs.c
fs/nfsd/vfs.h
fs/nfsd/xdr3.h

index cea68d8..ffdc592 100644 (file)
@@ -683,7 +683,8 @@ nfsd3_proc_commit(struct svc_rqst *rqstp)
                RETURN_STATUS(nfserr_inval);
 
        fh_copy(&resp->fh, &argp->fh);
-       nfserr = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count);
+       nfserr = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count,
+                       resp->verf);
 
        RETURN_STATUS(nfserr);
 }
index c997b71..1ae4fc2 100644 (file)
@@ -1121,16 +1121,12 @@ int
 nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p)
 {
        struct nfsd3_commitres *resp = rqstp->rq_resp;
-       struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
-       __be32 verf[2];
 
        p = encode_wcc_data(rqstp, p, &resp->fh);
        /* Write verifier */
        if (resp->status == 0) {
-               /* unique identifier, y2038 overflow can be ignored */
-               nfsd_copy_boot_verifier(verf, nn);
-               *p++ = verf[0];
-               *p++ = verf[1];
+               *p++ = resp->verf[0];
+               *p++ = resp->verf[1];
        }
        return xdr_ressize_check(rqstp, p);
 }
index 634f32d..c3455e1 100644 (file)
@@ -590,9 +590,9 @@ nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
 {
        struct nfsd4_commit *commit = &u->commit;
 
-       gen_boot_verifier(&commit->co_verf, SVC_NET(rqstp));
        return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset,
-                            commit->co_count);
+                            commit->co_count,
+                            (__be32 *)commit->co_verf.data);
 }
 
 static __be32
index 126149b..dc07d97 100644 (file)
@@ -1105,7 +1105,7 @@ out:
  */
 __be32
 nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
-               loff_t offset, unsigned long count)
+               loff_t offset, unsigned long count, __be32 *verf)
 {
        struct nfsd_file        *nf;
        loff_t                  end = LLONG_MAX;
@@ -1130,6 +1130,8 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
                err2 = vfs_fsync_range(nf->nf_file, offset, end, 0);
                switch (err2) {
                case 0:
+                       nfsd_copy_boot_verifier(verf, net_generic(nf->nf_net,
+                                               nfsd_net_id));
                        break;
                case -EINVAL:
                        err = nfserr_notsupp;
@@ -1140,7 +1142,9 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
                                                 nfsd_net_id));
                }
                up_write(&nf->nf_rwsem);
-       }
+       } else
+               nfsd_copy_boot_verifier(verf, net_generic(nf->nf_net,
+                                       nfsd_net_id));
 
        nfsd_file_put(nf);
 out:
index a91cd79..d23d9da 100644 (file)
@@ -74,7 +74,7 @@ __be32                do_nfsd_create(struct svc_rqst *, struct svc_fh *,
                                struct svc_fh *res, int createmode,
                                u32 *verifier, bool *truncp, bool *created);
 __be32         nfsd_commit(struct svc_rqst *, struct svc_fh *,
-                               loff_t, unsigned long);
+                               loff_t, unsigned long, __be32 *verf);
 #endif /* CONFIG_NFSD_V3 */
 int            nfsd_open_break_lease(struct inode *, int);
 __be32         nfsd_open(struct svc_rqst *, struct svc_fh *, umode_t,
index 0fa1298..fe6fd45 100644 (file)
@@ -223,6 +223,7 @@ struct nfsd3_pathconfres {
 struct nfsd3_commitres {
        __be32                  status;
        struct svc_fh           fh;
+       __be32                  verf[2];
 };
 
 struct nfsd3_getaclres {