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>
This commit is contained in:
parent
b32d285539
commit
2197e9b06c
@ -204,44 +204,39 @@ EXPORT_SYMBOL_GPL(nfs_file_mmap);
|
|||||||
static int
|
static int
|
||||||
nfs_file_fsync_commit(struct file *file, int datasync)
|
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);
|
struct inode *inode = file_inode(file);
|
||||||
int do_resend, status;
|
int ret;
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
dprintk("NFS: fsync file(%pD2) datasync %d\n", file, datasync);
|
dprintk("NFS: fsync file(%pD2) datasync %d\n", file, datasync);
|
||||||
|
|
||||||
nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
|
nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
|
||||||
do_resend = test_and_clear_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags);
|
ret = nfs_commit_inode(inode, FLUSH_SYNC);
|
||||||
status = nfs_commit_inode(inode, FLUSH_SYNC);
|
if (ret < 0)
|
||||||
if (status == 0)
|
return ret;
|
||||||
status = file_check_and_advance_wb_err(file);
|
return 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
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);
|
struct inode *inode = file_inode(file);
|
||||||
|
int ret;
|
||||||
|
|
||||||
trace_nfs_fsync_enter(inode);
|
trace_nfs_fsync_enter(inode);
|
||||||
|
|
||||||
do {
|
for (;;) {
|
||||||
ret = file_write_and_wait_range(file, start, end);
|
ret = file_write_and_wait_range(file, start, end);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
break;
|
break;
|
||||||
ret = nfs_file_fsync_commit(file, datasync);
|
ret = nfs_file_fsync_commit(file, datasync);
|
||||||
if (!ret)
|
if (ret != 0)
|
||||||
ret = pnfs_sync_inode(inode, !!datasync);
|
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
|
* If nfs_file_fsync_commit detected a server reboot, then
|
||||||
* resend all dirty pages that might have been covered by
|
* 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;
|
start = 0;
|
||||||
end = LLONG_MAX;
|
end = LLONG_MAX;
|
||||||
} while (ret == -EAGAIN);
|
}
|
||||||
|
|
||||||
trace_nfs_fsync_exit(inode, ret);
|
trace_nfs_fsync_exit(inode, ret);
|
||||||
return ret;
|
return ret;
|
||||||
|
Loading…
Reference in New Issue
Block a user