Merge tag 'nfs-for-3.7-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
[sfrench/cifs-2.6.git] / fs / nfs / file.c
index f692be97676d264d8e9100df4306e9e9fb021a7f..582bb8866131d27a8d53d069c8bd7714caa7af4d 100644 (file)
@@ -259,7 +259,7 @@ nfs_file_fsync_commit(struct file *file, loff_t start, loff_t end, int datasync)
        struct dentry *dentry = file->f_path.dentry;
        struct nfs_open_context *ctx = nfs_file_open_context(file);
        struct inode *inode = dentry->d_inode;
-       int have_error, status;
+       int have_error, do_resend, status;
        int ret = 0;
 
        dprintk("NFS: fsync file(%s/%s) datasync %d\n",
@@ -267,15 +267,23 @@ nfs_file_fsync_commit(struct file *file, loff_t start, loff_t end, int datasync)
                        datasync);
 
        nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
+       do_resend = test_and_clear_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags);
        have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
        status = nfs_commit_inode(inode, FLUSH_SYNC);
-       if (status >= 0 && ret < 0)
-               status = ret;
        have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
-       if (have_error)
+       if (have_error) {
                ret = xchg(&ctx->error, 0);
-       if (!ret && status < 0)
+               if (ret)
+                       goto out;
+       }
+       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;
 }
 EXPORT_SYMBOL_GPL(nfs_file_fsync_commit);
@@ -286,13 +294,22 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
        int ret;
        struct inode *inode = file->f_path.dentry->d_inode;
 
-       ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
-       if (ret != 0)
-               goto out;
-       mutex_lock(&inode->i_mutex);
-       ret = nfs_file_fsync_commit(file, start, end, datasync);
-       mutex_unlock(&inode->i_mutex);
-out:
+       do {
+               ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
+               if (ret != 0)
+                       break;
+               mutex_lock(&inode->i_mutex);
+               ret = nfs_file_fsync_commit(file, start, end, datasync);
+               mutex_unlock(&inode->i_mutex);
+               /*
+                * If nfs_file_fsync_commit detected a server reboot, then
+                * resend all dirty pages that might have been covered by
+                * the NFS_CONTEXT_RESEND_WRITES flag
+                */
+               start = 0;
+               end = LLONG_MAX;
+       } while (ret == -EAGAIN);
+
        return ret;
 }