Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

nfsd: Ensure sampling of the write verifier is atomic with the write

When doing an unstable write, we need to ensure that we sample the
write verifier before releasing the lock, and allowing a commit to
the same file to proceed.

Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>

authored by

Trond Myklebust and committed by
J. Bruce Fields
19e0663f 524ff1af

+19 -15
+1 -1
fs/nfsd/nfs3proc.c
··· 203 203 RETURN_STATUS(nfserr_io); 204 204 nfserr = nfsd_write(rqstp, &resp->fh, argp->offset, 205 205 rqstp->rq_vec, nvecs, &cnt, 206 - resp->committed); 206 + resp->committed, resp->verf); 207 207 resp->count = cnt; 208 208 RETURN_STATUS(nfserr); 209 209 }
+2 -6
fs/nfsd/nfs3xdr.c
··· 747 747 nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p) 748 748 { 749 749 struct nfsd3_writeres *resp = rqstp->rq_resp; 750 - struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); 751 - __be32 verf[2]; 752 750 753 751 p = encode_wcc_data(rqstp, p, &resp->fh); 754 752 if (resp->status == 0) { 755 753 *p++ = htonl(resp->count); 756 754 *p++ = htonl(resp->committed); 757 - /* unique identifier, y2038 overflow can be ignored */ 758 - nfsd_copy_boot_verifier(verf, nn); 759 - *p++ = verf[0]; 760 - *p++ = verf[1]; 755 + *p++ = resp->verf[0]; 756 + *p++ = resp->verf[1]; 761 757 } 762 758 return xdr_ressize_check(rqstp, p); 763 759 }
+2 -2
fs/nfsd/nfs4proc.c
··· 1015 1015 } 1016 1016 1017 1017 write->wr_how_written = write->wr_stable_how; 1018 - gen_boot_verifier(&write->wr_verifier, SVC_NET(rqstp)); 1019 1018 1020 1019 nvecs = svc_fill_write_vector(rqstp, write->wr_pagelist, 1021 1020 &write->wr_head, write->wr_buflen); ··· 1022 1023 1023 1024 status = nfsd_vfs_write(rqstp, &cstate->current_fh, nf, 1024 1025 write->wr_offset, rqstp->rq_vec, nvecs, &cnt, 1025 - write->wr_how_written); 1026 + write->wr_how_written, 1027 + (__be32 *)write->wr_verifier.data); 1026 1028 nfsd_file_put(nf); 1027 1029 1028 1030 write->wr_bytes_written = cnt;
+1 -1
fs/nfsd/nfsproc.c
··· 226 226 return nfserr_io; 227 227 nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), 228 228 argp->offset, rqstp->rq_vec, nvecs, 229 - &cnt, NFS_DATA_SYNC); 229 + &cnt, NFS_DATA_SYNC, NULL); 230 230 return nfsd_return_attrs(nfserr, resp); 231 231 } 232 232
+9 -3
fs/nfsd/vfs.c
··· 962 962 __be32 963 963 nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, 964 964 loff_t offset, struct kvec *vec, int vlen, 965 - unsigned long *cnt, int stable) 965 + unsigned long *cnt, int stable, 966 + __be32 *verf) 966 967 { 967 968 struct file *file = nf->nf_file; 968 969 struct svc_export *exp; ··· 1005 1004 up_write(&nf->nf_rwsem); 1006 1005 } else { 1007 1006 down_read(&nf->nf_rwsem); 1007 + if (verf) 1008 + nfsd_copy_boot_verifier(verf, 1009 + net_generic(SVC_NET(rqstp), 1010 + nfsd_net_id)); 1008 1011 host_err = vfs_iter_write(file, &iter, &pos, flags); 1009 1012 up_read(&nf->nf_rwsem); 1010 1013 } ··· 1079 1074 */ 1080 1075 __be32 1081 1076 nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, 1082 - struct kvec *vec, int vlen, unsigned long *cnt, int stable) 1077 + struct kvec *vec, int vlen, unsigned long *cnt, int stable, 1078 + __be32 *verf) 1083 1079 { 1084 1080 struct nfsd_file *nf; 1085 1081 __be32 err; ··· 1092 1086 goto out; 1093 1087 1094 1088 err = nfsd_vfs_write(rqstp, fhp, nf, offset, vec, 1095 - vlen, cnt, stable); 1089 + vlen, cnt, stable, verf); 1096 1090 nfsd_file_put(nf); 1097 1091 out: 1098 1092 trace_nfsd_write_done(rqstp, fhp, offset, *cnt);
+3 -2
fs/nfsd/vfs.h
··· 94 94 loff_t, struct kvec *, int, unsigned long *, 95 95 u32 *eof); 96 96 __be32 nfsd_write(struct svc_rqst *, struct svc_fh *, loff_t, 97 - struct kvec *, int, unsigned long *, int); 97 + struct kvec *, int, unsigned long *, 98 + int stable, __be32 *verf); 98 99 __be32 nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, 99 100 struct nfsd_file *nf, loff_t offset, 100 101 struct kvec *vec, int vlen, unsigned long *cnt, 101 - int stable); 102 + int stable, __be32 *verf); 102 103 __be32 nfsd_readlink(struct svc_rqst *, struct svc_fh *, 103 104 char *, int *); 104 105 __be32 nfsd_symlink(struct svc_rqst *, struct svc_fh *,
+1
fs/nfsd/xdr3.h
··· 159 159 struct svc_fh fh; 160 160 unsigned long count; 161 161 int committed; 162 + __be32 verf[2]; 162 163 }; 163 164 164 165 struct nfsd3_renameres {