forked from mirrors/linux
		
	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
					
				
					 1 changed files with 16 additions and 21 deletions
				
			
		|  | @ -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: | ||||
| 	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) | ||||
| 		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; | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Trond Myklebust
						Trond Myklebust