Skip to content

Commit

Permalink
nfsd: Ensure sampling of the write verifier is atomic with the write
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: J. Bruce Fields <[email protected]>
  • Loading branch information
trondmy authored and J. Bruce Fields committed Jan 22, 2020
1 parent 524ff1a commit 19e0663
Show file tree
Hide file tree
Showing 7 changed files with 19 additions and 15 deletions.
2 changes: 1 addition & 1 deletion fs/nfsd/nfs3proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ nfsd3_proc_write(struct svc_rqst *rqstp)
RETURN_STATUS(nfserr_io);
nfserr = nfsd_write(rqstp, &resp->fh, argp->offset,
rqstp->rq_vec, nvecs, &cnt,
resp->committed);
resp->committed, resp->verf);
resp->count = cnt;
RETURN_STATUS(nfserr);
}
Expand Down
8 changes: 2 additions & 6 deletions fs/nfsd/nfs3xdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -747,17 +747,13 @@ int
nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p)
{
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);
if (resp->status == 0) {
*p++ = htonl(resp->count);
*p++ = htonl(resp->committed);
/* 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);
}
Expand Down
4 changes: 2 additions & 2 deletions fs/nfsd/nfs4proc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1015,15 +1015,15 @@ nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
}

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,
&write->wr_head, write->wr_buflen);
WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec));

status = nfsd_vfs_write(rqstp, &cstate->current_fh, nf,
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);

write->wr_bytes_written = cnt;
Expand Down
2 changes: 1 addition & 1 deletion fs/nfsd/nfsproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ nfsd_proc_write(struct svc_rqst *rqstp)
return nfserr_io;
nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
argp->offset, rqstp->rq_vec, nvecs,
&cnt, NFS_DATA_SYNC);
&cnt, NFS_DATA_SYNC, NULL);
return nfsd_return_attrs(nfserr, resp);
}

Expand Down
12 changes: 9 additions & 3 deletions fs/nfsd/vfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -962,7 +962,8 @@ static int wait_for_concurrent_writes(struct file *file)
__be32
nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,
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 svc_export *exp;
Expand Down Expand Up @@ -1004,6 +1005,10 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,
up_write(&nf->nf_rwsem);
} else {
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);
up_read(&nf->nf_rwsem);
}
Expand Down Expand Up @@ -1074,7 +1079,8 @@ __be32 nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp,
*/
__be32
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;
__be32 err;
Expand All @@ -1086,7 +1092,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset,
goto out;

err = nfsd_vfs_write(rqstp, fhp, nf, offset, vec,
vlen, cnt, stable);
vlen, cnt, stable, verf);
nfsd_file_put(nf);
out:
trace_nfsd_write_done(rqstp, fhp, offset, *cnt);
Expand Down
5 changes: 3 additions & 2 deletions fs/nfsd/vfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,12 @@ __be32 nfsd_read(struct svc_rqst *, struct svc_fh *,
loff_t, struct kvec *, int, unsigned long *,
u32 *eof);
__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,
struct nfsd_file *nf, loff_t offset,
struct kvec *vec, int vlen, unsigned long *cnt,
int stable);
int stable, __be32 *verf);
__be32 nfsd_readlink(struct svc_rqst *, struct svc_fh *,
char *, int *);
__be32 nfsd_symlink(struct svc_rqst *, struct svc_fh *,
Expand Down
1 change: 1 addition & 0 deletions fs/nfsd/xdr3.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ struct nfsd3_writeres {
struct svc_fh fh;
unsigned long count;
int committed;
__be32 verf[2];
};

struct nfsd3_renameres {
Expand Down

0 comments on commit 19e0663

Please sign in to comment.