aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/vfs.c
diff options
context:
space:
mode:
authorTrond Myklebust <trondmy@gmail.com>2019-09-02 13:02:58 -0400
committerJ. Bruce Fields <bfields@redhat.com>2019-09-10 09:23:41 -0400
commitbbf2f098838aa86cee240a7a11486e0601d56a3f (patch)
treec099d49e802180aa5616cb5a217ec4085f01aefa /fs/nfsd/vfs.c
parent055b24a8f23090043b2ce0c30f03e12c5f2c9e72 (diff)
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 <trond.myklebust@hammerspace.com> Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'fs/nfsd/vfs.c')
-rw-r--r--fs/nfsd/vfs.c19
1 files changed, 15 insertions, 4 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 84e87772c2b8..0867d5319fdb 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -958,8 +958,12 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
958 nfsdstats.io_write += *cnt; 958 nfsdstats.io_write += *cnt;
959 fsnotify_modify(file); 959 fsnotify_modify(file);
960 960
961 if (stable && use_wgather) 961 if (stable && use_wgather) {
962 host_err = wait_for_concurrent_writes(file); 962 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 }
963 967
964out_nfserr: 968out_nfserr:
965 if (host_err >= 0) { 969 if (host_err >= 0) {
@@ -1063,10 +1067,17 @@ nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
1063 if (EX_ISSYNC(fhp->fh_export)) { 1067 if (EX_ISSYNC(fhp->fh_export)) {
1064 int err2 = vfs_fsync_range(nf->nf_file, offset, end, 0); 1068 int err2 = vfs_fsync_range(nf->nf_file, offset, end, 0);
1065 1069
1066 if (err2 != -EINVAL) 1070 switch (err2) {
1067 err = nfserrno(err2); 1071 case 0:
1068 else 1072 break;
1073 case -EINVAL:
1069 err = nfserr_notsupp; 1074 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 }
1070 } 1081 }
1071 1082
1072 nfsd_file_put(nf); 1083 nfsd_file_put(nf);