| From stable+bounces-272078-greg=kroah.com@vger.kernel.org Sun Jul 5 16:40:33 2026 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Sun, 5 Jul 2026 10:40:22 -0400 |
| Subject: nfsd: Don't reset the write verifier on a commit EAGAIN |
| To: stable@vger.kernel.org |
| Cc: Trond Myklebust <trond.myklebust@hammerspace.com>, Jeff Layton <jlayton@kernel.org>, Chuck Lever <chuck.lever@oracle.com>, Sasha Levin <sashal@kernel.org> |
| Message-ID: <20260705144023.1865360-1-sashal@kernel.org> |
| |
| From: Trond Myklebust <trond.myklebust@hammerspace.com> |
| |
| [ Upstream commit 1b2021bdeeca12364ad0fa7aac9ddba5cae964f3 ] |
| |
| If fsync() is returning EAGAIN, then we can assume that the filesystem |
| being exported is something like NFS with the 'softerr' mount option |
| enabled, and that it is just asking us to replay the fsync() operation |
| at a later date. |
| |
| If we see an ESTALE, then ditto: the file is gone, so there is no danger |
| of losing the error. |
| |
| For those cases, do not reset the write verifier. A write verifier |
| change has a global effect, causing retransmission by all clients of |
| all uncommitted unstable writes for all files, so it is worth |
| mitigating where possible. |
| |
| Link: https://lore.kernel.org/linux-nfs/20230911184357.11739-1-trond.myklebust@hammerspace.com/ |
| Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> |
| Reviewed-by: Jeff Layton <jlayton@kernel.org> |
| Signed-off-by: Chuck Lever <chuck.lever@oracle.com> |
| Stable-dep-of: 2090b05803fa ("nfsd: reset write verifier on deferred writeback errors") |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| fs/nfsd/vfs.c | 33 +++++++++++++++++++++++---------- |
| 1 file changed, 23 insertions(+), 10 deletions(-) |
| |
| --- a/fs/nfsd/vfs.c |
| +++ b/fs/nfsd/vfs.c |
| @@ -338,6 +338,24 @@ out: |
| return err; |
| } |
| |
| +static void |
| +commit_reset_write_verifier(struct nfsd_net *nn, struct svc_rqst *rqstp, |
| + int err) |
| +{ |
| + switch (err) { |
| + case -EAGAIN: |
| + case -ESTALE: |
| + /* |
| + * Neither of these are the result of a problem with |
| + * durable storage, so avoid a write verifier reset. |
| + */ |
| + break; |
| + default: |
| + nfsd_reset_write_verifier(nn); |
| + trace_nfsd_writeverf_reset(nn, rqstp, err); |
| + } |
| +} |
| + |
| /* |
| * Commit metadata changes to stable storage. |
| */ |
| @@ -659,8 +677,7 @@ __be32 nfsd4_clone_file_range(struct svc |
| &nfsd4_get_cstate(rqstp)->current_fh, |
| dst_pos, |
| count, status); |
| - nfsd_reset_write_verifier(nn); |
| - trace_nfsd_writeverf_reset(nn, rqstp, status); |
| + commit_reset_write_verifier(nn, rqstp, status); |
| ret = nfserrno(status); |
| } |
| } |
| @@ -1177,8 +1194,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, s |
| host_err = vfs_iter_write(file, &iter, &pos, flags); |
| file_end_write(file); |
| if (host_err < 0) { |
| - nfsd_reset_write_verifier(nn); |
| - trace_nfsd_writeverf_reset(nn, rqstp, host_err); |
| + commit_reset_write_verifier(nn, rqstp, host_err); |
| goto out_nfserr; |
| } |
| *cnt = host_err; |
| @@ -1193,10 +1209,8 @@ nfsd_vfs_write(struct svc_rqst *rqstp, s |
| |
| if (stable && use_wgather) { |
| host_err = wait_for_concurrent_writes(file); |
| - if (host_err < 0) { |
| - nfsd_reset_write_verifier(nn); |
| - trace_nfsd_writeverf_reset(nn, rqstp, host_err); |
| - } |
| + if (host_err < 0) |
| + commit_reset_write_verifier(nn, rqstp, host_err); |
| } |
| |
| out_nfserr: |
| @@ -1343,8 +1357,7 @@ nfsd_commit(struct svc_rqst *rqstp, stru |
| err = nfserr_notsupp; |
| break; |
| default: |
| - nfsd_reset_write_verifier(nn); |
| - trace_nfsd_writeverf_reset(nn, rqstp, err2); |
| + commit_reset_write_verifier(nn, rqstp, err2); |
| err = nfserrno(err2); |
| } |
| } else |