diff options
Diffstat (limited to 'fs/nfs/file.c')
-rw-r--r-- | fs/nfs/file.c | 51 |
1 files changed, 21 insertions, 30 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index f036153d9f50..2d141a74ae82 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -203,37 +203,11 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) | |||
203 | } | 203 | } |
204 | 204 | ||
205 | /* | 205 | /* |
206 | * Helper for nfs_file_flush() and nfs_file_fsync() | ||
207 | * | ||
208 | * Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to | ||
209 | * disk, but it retrieves and clears ctx->error after synching, despite | ||
210 | * the two being set at the same time in nfs_context_set_write_error(). | ||
211 | * This is because the former is used to notify the _next_ call to | ||
212 | * nfs_file_write() that a write error occured, and hence cause it to | ||
213 | * fall back to doing a synchronous write. | ||
214 | */ | ||
215 | static int nfs_do_fsync(struct nfs_open_context *ctx, struct inode *inode) | ||
216 | { | ||
217 | int have_error, status; | ||
218 | int ret = 0; | ||
219 | |||
220 | have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); | ||
221 | status = nfs_wb_all(inode); | ||
222 | have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); | ||
223 | if (have_error) | ||
224 | ret = xchg(&ctx->error, 0); | ||
225 | if (!ret) | ||
226 | ret = status; | ||
227 | return ret; | ||
228 | } | ||
229 | |||
230 | /* | ||
231 | * Flush all dirty pages, and check for write errors. | 206 | * Flush all dirty pages, and check for write errors. |
232 | */ | 207 | */ |
233 | static int | 208 | static int |
234 | nfs_file_flush(struct file *file, fl_owner_t id) | 209 | nfs_file_flush(struct file *file, fl_owner_t id) |
235 | { | 210 | { |
236 | struct nfs_open_context *ctx = nfs_file_open_context(file); | ||
237 | struct dentry *dentry = file->f_path.dentry; | 211 | struct dentry *dentry = file->f_path.dentry; |
238 | struct inode *inode = dentry->d_inode; | 212 | struct inode *inode = dentry->d_inode; |
239 | 213 | ||
@@ -246,7 +220,7 @@ nfs_file_flush(struct file *file, fl_owner_t id) | |||
246 | return 0; | 220 | return 0; |
247 | 221 | ||
248 | /* Flush writes to the server and return any errors */ | 222 | /* Flush writes to the server and return any errors */ |
249 | return nfs_do_fsync(ctx, inode); | 223 | return vfs_fsync(file, 0); |
250 | } | 224 | } |
251 | 225 | ||
252 | static ssize_t | 226 | static ssize_t |
@@ -321,6 +295,13 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) | |||
321 | * Flush any dirty pages for this process, and check for write errors. | 295 | * Flush any dirty pages for this process, and check for write errors. |
322 | * The return status from this call provides a reliable indication of | 296 | * The return status from this call provides a reliable indication of |
323 | * whether any write errors occurred for this process. | 297 | * whether any write errors occurred for this process. |
298 | * | ||
299 | * Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to | ||
300 | * disk, but it retrieves and clears ctx->error after synching, despite | ||
301 | * the two being set at the same time in nfs_context_set_write_error(). | ||
302 | * This is because the former is used to notify the _next_ call to | ||
303 | * nfs_file_write() that a write error occured, and hence cause it to | ||
304 | * fall back to doing a synchronous write. | ||
324 | */ | 305 | */ |
325 | static int | 306 | static int |
326 | nfs_file_fsync(struct file *file, int datasync) | 307 | nfs_file_fsync(struct file *file, int datasync) |
@@ -328,13 +309,23 @@ nfs_file_fsync(struct file *file, int datasync) | |||
328 | struct dentry *dentry = file->f_path.dentry; | 309 | struct dentry *dentry = file->f_path.dentry; |
329 | struct nfs_open_context *ctx = nfs_file_open_context(file); | 310 | struct nfs_open_context *ctx = nfs_file_open_context(file); |
330 | struct inode *inode = dentry->d_inode; | 311 | struct inode *inode = dentry->d_inode; |
312 | int have_error, status; | ||
313 | int ret = 0; | ||
314 | |||
331 | 315 | ||
332 | dprintk("NFS: fsync file(%s/%s) datasync %d\n", | 316 | dprintk("NFS: fsync file(%s/%s) datasync %d\n", |
333 | dentry->d_parent->d_name.name, dentry->d_name.name, | 317 | dentry->d_parent->d_name.name, dentry->d_name.name, |
334 | datasync); | 318 | datasync); |
335 | 319 | ||
336 | nfs_inc_stats(inode, NFSIOS_VFSFSYNC); | 320 | nfs_inc_stats(inode, NFSIOS_VFSFSYNC); |
337 | return nfs_do_fsync(ctx, inode); | 321 | have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); |
322 | status = nfs_commit_inode(inode, FLUSH_SYNC); | ||
323 | have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); | ||
324 | if (have_error) | ||
325 | ret = xchg(&ctx->error, 0); | ||
326 | if (!ret) | ||
327 | ret = status; | ||
328 | return ret; | ||
338 | } | 329 | } |
339 | 330 | ||
340 | /* | 331 | /* |
@@ -648,7 +639,7 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
648 | 639 | ||
649 | /* Return error values for O_DSYNC and IS_SYNC() */ | 640 | /* Return error values for O_DSYNC and IS_SYNC() */ |
650 | if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) { | 641 | if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) { |
651 | int err = nfs_do_fsync(nfs_file_open_context(iocb->ki_filp), inode); | 642 | int err = vfs_fsync(iocb->ki_filp, 0); |
652 | if (err < 0) | 643 | if (err < 0) |
653 | result = err; | 644 | result = err; |
654 | } | 645 | } |
@@ -684,7 +675,7 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, | |||
684 | written = ret; | 675 | written = ret; |
685 | 676 | ||
686 | if (ret >= 0 && nfs_need_sync_write(filp, inode)) { | 677 | if (ret >= 0 && nfs_need_sync_write(filp, inode)) { |
687 | int err = nfs_do_fsync(nfs_file_open_context(filp), inode); | 678 | int err = vfs_fsync(filp, 0); |
688 | if (err < 0) | 679 | if (err < 0) |
689 | ret = err; | 680 | ret = err; |
690 | } | 681 | } |