OSDN Git Service

NFS: Fix up fsync() when the server rebooted
authorTrond Myklebust <trondmy@gmail.com>
Mon, 6 Jan 2020 20:25:03 +0000 (15:25 -0500)
committerAnna Schumaker <Anna.Schumaker@Netapp.com>
Wed, 15 Jan 2020 15:54:32 +0000 (10:54 -0500)
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>
fs/nfs/file.c

index ccd9bc0..f96367a 100644 (file)
@@ -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;