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

nfsd: Reset the boot verifier on all write I/O errors

If multiple clients are writing to the same file, then due to the fact
we share a single file descriptor between all NFSv3 clients writing
to the file, we have a situation where clients can miss the fact that
their file data was not persisted. While this should be rare, it
could cause silent data loss in situations where multiple clients
are using NLM locking or O_DIRECT to write to the same file.
Unfortunately, the stateless nature of NFSv3 and the fact that we
can only identify clients by their IP address means that we cannot
trivially cache errors; we would not know when it is safe to
release them from the cache.

So the solution is to declare a reboot. We understand that this
should be a rare occurrence, since disks are usually stable. The
most frequent occurrence is likely to be ENOSPC, at which point
all writes to the given filesystem are likely to fail anyway.

So the expectation is that clients will be forced to retry their
writes until they hit the fatal error.
Signed-off-by: default avatarTrond Myklebust <trond.myklebust@hammerspace.com>
Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
parent 055b24a8
...@@ -958,8 +958,12 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, ...@@ -958,8 +958,12 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
nfsdstats.io_write += *cnt; nfsdstats.io_write += *cnt;
fsnotify_modify(file); fsnotify_modify(file);
if (stable && use_wgather) if (stable && use_wgather) {
host_err = wait_for_concurrent_writes(file); host_err = wait_for_concurrent_writes(file);
if (host_err < 0)
nfsd_reset_boot_verifier(net_generic(SVC_NET(rqstp),
nfsd_net_id));
}
out_nfserr: out_nfserr:
if (host_err >= 0) { if (host_err >= 0) {
...@@ -1063,10 +1067,17 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp, ...@@ -1063,10 +1067,17 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
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 = vfs_fsync_range(nf->nf_file, offset, end, 0);
if (err2 != -EINVAL) switch (err2) {
err = nfserrno(err2); case 0:
else break;
case -EINVAL:
err = nfserr_notsupp; err = nfserr_notsupp;
break;
default:
err = nfserrno(err2);
nfsd_reset_boot_verifier(net_generic(nf->nf_net,
nfsd_net_id));
}
} }
nfsd_file_put(nf); nfsd_file_put(nf);
......
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