Skip to content

Commit bbf2f09

Browse files
trondmyJ. Bruce Fields
authored andcommitted
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: Trond Myklebust <[email protected]> Signed-off-by: J. Bruce Fields <[email protected]>
1 parent 055b24a commit bbf2f09

File tree

1 file changed

+15
-4
lines changed

1 file changed

+15
-4
lines changed

fs/nfsd/vfs.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -958,8 +958,12 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
958958
nfsdstats.io_write += *cnt;
959959
fsnotify_modify(file);
960960

961-
if (stable && use_wgather)
961+
if (stable && use_wgather) {
962962
host_err = wait_for_concurrent_writes(file);
963+
if (host_err < 0)
964+
nfsd_reset_boot_verifier(net_generic(SVC_NET(rqstp),
965+
nfsd_net_id));
966+
}
963967

964968
out_nfserr:
965969
if (host_err >= 0) {
@@ -1063,10 +1067,17 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
10631067
if (EX_ISSYNC(fhp->fh_export)) {
10641068
int err2 = vfs_fsync_range(nf->nf_file, offset, end, 0);
10651069

1066-
if (err2 != -EINVAL)
1067-
err = nfserrno(err2);
1068-
else
1070+
switch (err2) {
1071+
case 0:
1072+
break;
1073+
case -EINVAL:
10691074
err = nfserr_notsupp;
1075+
break;
1076+
default:
1077+
err = nfserrno(err2);
1078+
nfsd_reset_boot_verifier(net_generic(nf->nf_net,
1079+
nfsd_net_id));
1080+
}
10701081
}
10711082

10721083
nfsd_file_put(nf);

0 commit comments

Comments
 (0)