aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/file.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2012-09-11 16:01:22 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2012-09-28 16:03:05 -0400
commit05990d1bf2708b9e84d67074551f964d3738eedc (patch)
treeb4133627b503563eadea21aab695df78080402e1 /fs/nfs/file.c
parent795a88c968eef031f370973512b42124bacb2f17 (diff)
NFS: Fix fdatasync/fsync() when confronted with a server reboot
If the server reboots before it can commit the unstable writes to disk, then nfs_commit_release_pages() will detect this when it compares the verifier returned by COMMIT to the one returned by WRITE. When this happens, the client needs to resend those writes in order to guarantee that they make it to stable storage. This patch adds a signalling mechanism to notify fsync() that it needs to retry all writes before it can exit. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/file.c')
-rw-r--r--fs/nfs/file.c34
1 files changed, 22 insertions, 12 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 6a7fcab7ecb3..cc9b56691bef 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -259,7 +259,7 @@ nfs_file_fsync_commit(struct file *file, loff_t start, loff_t end, int datasync)
259 struct dentry *dentry = file->f_path.dentry; 259 struct dentry *dentry = file->f_path.dentry;
260 struct nfs_open_context *ctx = nfs_file_open_context(file); 260 struct nfs_open_context *ctx = nfs_file_open_context(file);
261 struct inode *inode = dentry->d_inode; 261 struct inode *inode = dentry->d_inode;
262 int have_error, status; 262 int have_error, do_resend, status;
263 int ret = 0; 263 int ret = 0;
264 264
265 dprintk("NFS: fsync file(%s/%s) datasync %d\n", 265 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)
267 datasync); 267 datasync);
268 268
269 nfs_inc_stats(inode, NFSIOS_VFSFSYNC); 269 nfs_inc_stats(inode, NFSIOS_VFSFSYNC);
270 do_resend = test_and_clear_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags);
270 have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); 271 have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
271 status = nfs_commit_inode(inode, FLUSH_SYNC); 272 status = nfs_commit_inode(inode, FLUSH_SYNC);
272 if (status >= 0 && ret < 0)
273 status = ret;
274 have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); 273 have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
275 if (have_error) 274 if (have_error) {
276 ret = xchg(&ctx->error, 0); 275 ret = xchg(&ctx->error, 0);
277 if (!ret && status < 0) 276 if (ret)
277 goto out;
278 }
279 if (status < 0) {
278 ret = status; 280 ret = status;
281 goto out;
282 }
283 do_resend |= test_bit(NFS_CONTEXT_RESEND_WRITES, &ctx->flags);
284 if (do_resend)
285 ret = -EAGAIN;
286out:
279 return ret; 287 return ret;
280} 288}
281EXPORT_SYMBOL_GPL(nfs_file_fsync_commit); 289EXPORT_SYMBOL_GPL(nfs_file_fsync_commit);
@@ -286,13 +294,15 @@ nfs_file_fsync(struct file *file, loff_t start, loff_t end, int datasync)
286 int ret; 294 int ret;
287 struct inode *inode = file->f_path.dentry->d_inode; 295 struct inode *inode = file->f_path.dentry->d_inode;
288 296
289 ret = filemap_write_and_wait_range(inode->i_mapping, start, end); 297 do {
290 if (ret != 0) 298 ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
291 goto out; 299 if (ret != 0)
292 mutex_lock(&inode->i_mutex); 300 break;
293 ret = nfs_file_fsync_commit(file, start, end, datasync); 301 mutex_lock(&inode->i_mutex);
294 mutex_unlock(&inode->i_mutex); 302 ret = nfs_file_fsync_commit(file, start, end, datasync);
295out: 303 mutex_unlock(&inode->i_mutex);
304 } while (ret == -EAGAIN);
305
296 return ret; 306 return ret;
297} 307}
298 308