nfsd: Fix stable writes
Strictly speaking, a stable write error needs to reflect the write + the commit of that write (and only that write). To ensure that we don't pick up the write errors from other writebacks, add a rw_semaphore to provide exclusion. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
This commit is contained in:
parent
16f8f89410
commit
5011af4c69
@ -195,6 +195,7 @@ nfsd_file_alloc(struct inode *inode, unsigned int may, unsigned int hashval,
|
|||||||
__set_bit(NFSD_FILE_BREAK_READ, &nf->nf_flags);
|
__set_bit(NFSD_FILE_BREAK_READ, &nf->nf_flags);
|
||||||
}
|
}
|
||||||
nf->nf_mark = NULL;
|
nf->nf_mark = NULL;
|
||||||
|
init_rwsem(&nf->nf_rwsem);
|
||||||
trace_nfsd_file_alloc(nf);
|
trace_nfsd_file_alloc(nf);
|
||||||
}
|
}
|
||||||
return nf;
|
return nf;
|
||||||
|
@ -46,6 +46,7 @@ struct nfsd_file {
|
|||||||
atomic_t nf_ref;
|
atomic_t nf_ref;
|
||||||
unsigned char nf_may;
|
unsigned char nf_may;
|
||||||
struct nfsd_file_mark *nf_mark;
|
struct nfsd_file_mark *nf_mark;
|
||||||
|
struct rw_semaphore nf_rwsem;
|
||||||
};
|
};
|
||||||
|
|
||||||
int nfsd_file_cache_init(void);
|
int nfsd_file_cache_init(void);
|
||||||
|
@ -982,7 +982,18 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct nfsd_file *nf,
|
|||||||
flags |= RWF_SYNC;
|
flags |= RWF_SYNC;
|
||||||
|
|
||||||
iov_iter_kvec(&iter, WRITE, vec, vlen, *cnt);
|
iov_iter_kvec(&iter, WRITE, vec, vlen, *cnt);
|
||||||
host_err = vfs_iter_write(file, &iter, &pos, flags);
|
if (flags & RWF_SYNC) {
|
||||||
|
down_write(&nf->nf_rwsem);
|
||||||
|
host_err = vfs_iter_write(file, &iter, &pos, flags);
|
||||||
|
if (host_err < 0)
|
||||||
|
nfsd_reset_boot_verifier(net_generic(SVC_NET(rqstp),
|
||||||
|
nfsd_net_id));
|
||||||
|
up_write(&nf->nf_rwsem);
|
||||||
|
} else {
|
||||||
|
down_read(&nf->nf_rwsem);
|
||||||
|
host_err = vfs_iter_write(file, &iter, &pos, flags);
|
||||||
|
up_read(&nf->nf_rwsem);
|
||||||
|
}
|
||||||
if (host_err < 0)
|
if (host_err < 0)
|
||||||
goto out_nfserr;
|
goto out_nfserr;
|
||||||
*cnt = host_err;
|
*cnt = host_err;
|
||||||
@ -1097,8 +1108,10 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|||||||
if (err)
|
if (err)
|
||||||
goto out;
|
goto out;
|
||||||
if (EX_ISSYNC(fhp->fh_export)) {
|
if (EX_ISSYNC(fhp->fh_export)) {
|
||||||
int err2 = vfs_fsync_range(nf->nf_file, offset, end, 0);
|
int err2;
|
||||||
|
|
||||||
|
down_write(&nf->nf_rwsem);
|
||||||
|
err2 = vfs_fsync_range(nf->nf_file, offset, end, 0);
|
||||||
switch (err2) {
|
switch (err2) {
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
@ -1110,6 +1123,7 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
|||||||
nfsd_reset_boot_verifier(net_generic(nf->nf_net,
|
nfsd_reset_boot_verifier(net_generic(nf->nf_net,
|
||||||
nfsd_net_id));
|
nfsd_net_id));
|
||||||
}
|
}
|
||||||
|
up_write(&nf->nf_rwsem);
|
||||||
}
|
}
|
||||||
|
|
||||||
nfsd_file_put(nf);
|
nfsd_file_put(nf);
|
||||||
|
Loading…
Reference in New Issue
Block a user