Commit 19e0663f authored by Trond Myklebust's avatar Trond Myklebust Committed by J. Bruce Fields

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: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 524ff1af
...@@ -203,7 +203,7 @@ nfsd3_proc_write(struct svc_rqst *rqstp) ...@@ -203,7 +203,7 @@ nfsd3_proc_write(struct svc_rqst *rqstp)
RETURN_STATUS(nfserr_io); RETURN_STATUS(nfserr_io);
nfserr = nfsd_write(rqstp, &resp->fh, argp->offset, nfserr = nfsd_write(rqstp, &resp->fh, argp->offset,
rqstp->rq_vec, nvecs, &cnt, rqstp->rq_vec, nvecs, &cnt,
resp->committed); resp->committed, resp->verf);
resp->count = cnt; resp->count = cnt;
RETURN_STATUS(nfserr); RETURN_STATUS(nfserr);
} }
......
...@@ -747,17 +747,13 @@ int ...@@ -747,17 +747,13 @@ int
nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p) nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p)
{ {
struct nfsd3_writeres *resp = rqstp->rq_resp; struct nfsd3_writeres *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); p = encode_wcc_data(rqstp, p, &resp->fh);
if (resp->status == 0) { if (resp->status == 0) {
*p++ = htonl(resp->count); *p++ = htonl(resp->count);
*p++ = htonl(resp->committed); *p++ = htonl(resp->committed);
/* unique identifier, y2038 overflow can be ignored */ *p++ = resp->verf[0];
nfsd_copy_boot_verifier(verf, nn); *p++ = resp->verf[1];
*p++ = verf[0];
*p++ = verf[1];
} }
return xdr_ressize_check(rqstp, p); return xdr_ressize_check(rqstp, p);
} }
......
...@@ -1015,7 +1015,6 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -1015,7 +1015,6 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
} }
write->wr_how_written = write->wr_stable_how; write->wr_how_written = write->wr_stable_how;
gen_boot_verifier(&write->wr_verifier, SVC_NET(rqstp));
nvecs = svc_fill_write_vector(rqstp, write->wr_pagelist, nvecs = svc_fill_write_vector(rqstp, write->wr_pagelist,
&write->wr_head, write->wr_buflen); &write->wr_head, write->wr_buflen);
...@@ -1023,7 +1022,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, ...@@ -1023,7 +1022,8 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
status = nfsd_vfs_write(rqstp, &cstate->current_fh, nf, status = nfsd_vfs_write(rqstp, &cstate->current_fh, nf,
write->wr_offset, rqstp->rq_vec, nvecs, &cnt, write->wr_offset, rqstp->rq_vec, nvecs, &cnt,
write->wr_how_written); write->wr_how_written,
(__be32 *)write->wr_verifier.data);
nfsd_file_put(nf); nfsd_file_put(nf);
write->wr_bytes_written = cnt; write->wr_bytes_written = cnt;
......
...@@ -226,7 +226,7 @@ nfsd_proc_write(struct svc_rqst *rqstp) ...@@ -226,7 +226,7 @@ nfsd_proc_write(struct svc_rqst *rqstp)
return nfserr_io; return nfserr_io;
nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh), nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
argp->offset, rqstp->rq_vec, nvecs, argp->offset, rqstp->rq_vec, nvecs,
&cnt, NFS_DATA_SYNC); &cnt, NFS_DATA_SYNC, NULL);
return nfsd_return_attrs(nfserr, resp); return nfsd_return_attrs(nfserr, resp);
} }
......
...@@ -962,7 +962,8 @@ static int wait_for_concurrent_writes(struct file *file) ...@@ -962,7 +962,8 @@ static int wait_for_concurrent_writes(struct file *file)
__be32 __be32
nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,
loff_t offset, struct kvec *vec, int vlen, loff_t offset, struct kvec *vec, int vlen,
unsigned long *cnt, int stable) unsigned long *cnt, int stable,
__be32 *verf)
{ {
struct file *file = nf->nf_file; struct file *file = nf->nf_file;
struct svc_export *exp; struct svc_export *exp;
...@@ -1004,6 +1005,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf, ...@@ -1004,6 +1005,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,
up_write(&nf->nf_rwsem); up_write(&nf->nf_rwsem);
} else { } else {
down_read(&nf->nf_rwsem); down_read(&nf->nf_rwsem);
if (verf)
nfsd_copy_boot_verifier(verf,
net_generic(SVC_NET(rqstp),
nfsd_net_id));
host_err = vfs_iter_write(file, &iter, &pos, flags); host_err = vfs_iter_write(file, &iter, &pos, flags);
up_read(&nf->nf_rwsem); up_read(&nf->nf_rwsem);
} }
...@@ -1074,7 +1079,8 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -1074,7 +1079,8 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
*/ */
__be32 __be32
nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
struct kvec *vec, int vlen, unsigned long *cnt, int stable) struct kvec *vec, int vlen, unsigned long *cnt, int stable,
__be32 *verf)
{ {
struct nfsd_file *nf; struct nfsd_file *nf;
__be32 err; __be32 err;
...@@ -1086,7 +1092,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, ...@@ -1086,7 +1092,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
goto out; goto out;
err = nfsd_vfs_write(rqstp, fhp, nf, offset, vec, err = nfsd_vfs_write(rqstp, fhp, nf, offset, vec,
vlen, cnt, stable); vlen, cnt, stable, verf);
nfsd_file_put(nf); nfsd_file_put(nf);
out: out:
trace_nfsd_write_done(rqstp, fhp, offset, *cnt); trace_nfsd_write_done(rqstp, fhp, offset, *cnt);
......
...@@ -94,11 +94,12 @@ __be32 nfsd_read(struct svc_rqst *, struct svc_fh *, ...@@ -94,11 +94,12 @@ __be32 nfsd_read(struct svc_rqst *, struct svc_fh *,
loff_t, struct kvec *, int, unsigned long *, loff_t, struct kvec *, int, unsigned long *,
u32 *eof); u32 *eof);
__be32 nfsd_write(struct svc_rqst *, struct svc_fh *, loff_t, __be32 nfsd_write(struct svc_rqst *, struct svc_fh *, loff_t,
struct kvec *, int, unsigned long *, int); struct kvec *, int, unsigned long *,
int stable, __be32 *verf);
__be32 nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, __be32 nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp,
struct nfsd_file *nf, loff_t offset, struct nfsd_file *nf, loff_t offset,
struct kvec *vec, int vlen, unsigned long *cnt, struct kvec *vec, int vlen, unsigned long *cnt,
int stable); int stable, __be32 *verf);
__be32 nfsd_readlink(struct svc_rqst *, struct svc_fh *, __be32 nfsd_readlink(struct svc_rqst *, struct svc_fh *,
char *, int *); char *, int *);
__be32 nfsd_symlink(struct svc_rqst *, struct svc_fh *, __be32 nfsd_symlink(struct svc_rqst *, struct svc_fh *,
......
...@@ -159,6 +159,7 @@ struct nfsd3_writeres { ...@@ -159,6 +159,7 @@ struct nfsd3_writeres {
struct svc_fh fh; struct svc_fh fh;
unsigned long count; unsigned long count;
int committed; int committed;
__be32 verf[2];
}; };
struct nfsd3_renameres { struct nfsd3_renameres {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment