summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <trondmy@gmail.com>2020-01-06 15:25:03 -0500
committerAnna Schumaker <Anna.Schumaker@Netapp.com>2020-01-15 10:54:32 -0500
commit2197e9b06c228b65a2cef98ef34d6bf42fa1af3d (patch)
tree1d36b340780c97d478d987105a684d7c69e33c7e
parentb32d285539e061dc3961e86f825d4ded5ba6de14 (diff)
downloadlinux-2197e9b06c228b65a2cef98ef34d6bf42fa1af3d.tar.bz2
NFS: Fix up fsync() when the server rebooted
Don't clear the NFS_CONTEXT_RESEND_WRITES flag until after calling nfs_commit_inode(). Otherwise, if nfs_commit_inode() returns an error, we end up with dirty pages in the page cache, but no tag to tell us that those pages need resending. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> Signed-off-by: Anna Schumaker <Anna.Schumaker@Netapp.com>
-rw-r--r--fs/nfs/file.c37
1 files changed, 16 insertions, 21 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index ccd9bc098806..f96367a2463e 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -204,44 +204,39 @@ EXPORT_SYMBOL_GPL(nfs_file_mmap);
static int
nfs_file_fsync_commit(struct file *file, int datasync)
{
- struct nfs_open_context *ctx = nfs_file_open_context(file);
struct inode *inode = file_inode(file);
- int do_resend, status;
- int ret = 0;
+ int ret;
dprintk("NFS: fsync file(%pD2) datasync %d\n", file, datasync);
nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
- do_resend = test_and_clear_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags);
- status = nfs_commit_inode(inode, FLUSH_SYNC);
- if (status == 0)
- status = file_check_and_advance_wb_err(file);
- if (status < 0) {
- ret = status;
- goto out;
- }
- do_resend |= test_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags);
- if (do_resend)
- ret = -EAGAIN;
-out:
- return ret;
+ ret = nfs_commit_inode(inode, FLUSH_SYNC);
+ if (ret < 0)
+ return ret;
+ return file_check_and_advance_wb_err(file);
}
int
nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
{
- int ret;
+ struct nfs_open_context *ctx = nfs_file_open_context(file);
struct inode *inode = file_inode(file);
+ int ret;
trace_nfs_fsync_enter(inode);
- do {
+ for (;;) {
ret = file_write_and_wait_range(file, start, end);
if (ret != 0)
break;
ret = nfs_file_fsync_commit(file, datasync);
- if (!ret)
- ret = pnfs_sync_inode(inode, !!datasync);
+ if (ret != 0)
+ break;
+ ret = pnfs_sync_inode(inode, !!datasync);
+ if (ret != 0)
+ break;
+ if (!test_and_clear_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags))
+ break;
/*
* If nfs_file_fsync_commit detected a server reboot, then
* resend all dirty pages that might have been covered by
@@ -249,7 +244,7 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
*/
start = 0;
end = LLONG_MAX;
- } while (ret == -EAGAIN);
+ }
trace_nfs_fsync_exit(inode, ret);
return ret;