diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-07-31 14:29:06 -0400 |
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2010-08-03 22:06:07 -0400 |
| commit | af7fa16506bf9b6323e862a61e14c20555152bb3 (patch) | |
| tree | a9d5e5713d1d4662c0fb2097f506e60036404a37 /fs/nfs/file.c | |
| parent | 77041ed9b49a9e10f374bfa6e482d30ee7a3d46e (diff) | |
NFS: Fix up the fsync code
Christoph points out that the VFS will always flush out data before calling
nfs_fsync(), so we can dispense with a full call to nfs_wb_all(), and
replace that with a simpler call to nfs_commit_inode().
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
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 36a5e74f51b4..f36581cd4767 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
| @@ -202,37 +202,11 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) | |||
| 202 | } | 202 | } |
| 203 | 203 | ||
| 204 | /* | 204 | /* |
| 205 | * Helper for nfs_file_flush() and nfs_file_fsync() | ||
| 206 | * | ||
| 207 | * Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to | ||
| 208 | * disk, but it retrieves and clears ctx->error after synching, despite | ||
| 209 | * the two being set at the same time in nfs_context_set_write_error(). | ||
| 210 | * This is because the former is used to notify the _next_ call to | ||
| 211 | * nfs_file_write() that a write error occured, and hence cause it to | ||
| 212 | * fall back to doing a synchronous write. | ||
| 213 | */ | ||
| 214 | static int nfs_do_fsync(struct nfs_open_context *ctx, struct inode *inode) | ||
| 215 | { | ||
| 216 | int have_error, status; | ||
| 217 | int ret = 0; | ||
| 218 | |||
| 219 | have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); | ||
| 220 | status = nfs_wb_all(inode); | ||
| 221 | have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); | ||
| 222 | if (have_error) | ||
| 223 | ret = xchg(&ctx->error, 0); | ||
| 224 | if (!ret) | ||
| 225 | ret = status; | ||
| 226 | return ret; | ||
| 227 | } | ||
| 228 | |||
| 229 | /* | ||
| 230 | * Flush all dirty pages, and check for write errors. | 205 | * Flush all dirty pages, and check for write errors. |
| 231 | */ | 206 | */ |
| 232 | static int | 207 | static int |
| 233 | nfs_file_flush(struct file *file, fl_owner_t id) | 208 | nfs_file_flush(struct file *file, fl_owner_t id) |
| 234 | { | 209 | { |
| 235 | struct nfs_open_context *ctx = nfs_file_open_context(file); | ||
| 236 | struct dentry *dentry = file->f_path.dentry; | 210 | struct dentry *dentry = file->f_path.dentry; |
| 237 | struct inode *inode = dentry->d_inode; | 211 | struct inode *inode = dentry->d_inode; |
| 238 | 212 | ||
| @@ -245,7 +219,7 @@ nfs_file_flush(struct file *file, fl_owner_t id) | |||
| 245 | return 0; | 219 | return 0; |
| 246 | 220 | ||
| 247 | /* Flush writes to the server and return any errors */ | 221 | /* Flush writes to the server and return any errors */ |
| 248 | return nfs_do_fsync(ctx, inode); | 222 | return vfs_fsync(file, 0); |
| 249 | } | 223 | } |
| 250 | 224 | ||
| 251 | static ssize_t | 225 | static ssize_t |
| @@ -320,6 +294,13 @@ nfs_file_mmap(struct file * file, struct vm_area_struct * vma) | |||
| 320 | * Flush any dirty pages for this process, and check for write errors. | 294 | * Flush any dirty pages for this process, and check for write errors. |
| 321 | * The return status from this call provides a reliable indication of | 295 | * The return status from this call provides a reliable indication of |
| 322 | * whether any write errors occurred for this process. | 296 | * whether any write errors occurred for this process. |
| 297 | * | ||
| 298 | * Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to | ||
| 299 | * disk, but it retrieves and clears ctx->error after synching, despite | ||
| 300 | * the two being set at the same time in nfs_context_set_write_error(). | ||
| 301 | * This is because the former is used to notify the _next_ call to | ||
| 302 | * nfs_file_write() that a write error occured, and hence cause it to | ||
| 303 | * fall back to doing a synchronous write. | ||
| 323 | */ | 304 | */ |
| 324 | static int | 305 | static int |
| 325 | nfs_file_fsync(struct file *file, int datasync) | 306 | nfs_file_fsync(struct file *file, int datasync) |
| @@ -327,13 +308,23 @@ nfs_file_fsync(struct file *file, int datasync) | |||
| 327 | struct dentry *dentry = file->f_path.dentry; | 308 | struct dentry *dentry = file->f_path.dentry; |
| 328 | struct nfs_open_context *ctx = nfs_file_open_context(file); | 309 | struct nfs_open_context *ctx = nfs_file_open_context(file); |
| 329 | struct inode *inode = dentry->d_inode; | 310 | struct inode *inode = dentry->d_inode; |
| 311 | int have_error, status; | ||
| 312 | int ret = 0; | ||
| 313 | |||
| 330 | 314 | ||
| 331 | dprintk("NFS: fsync file(%s/%s) datasync %d\n", | 315 | dprintk("NFS: fsync file(%s/%s) datasync %d\n", |
| 332 | dentry->d_parent->d_name.name, dentry->d_name.name, | 316 | dentry->d_parent->d_name.name, dentry->d_name.name, |
| 333 | datasync); | 317 | datasync); |
| 334 | 318 | ||
| 335 | nfs_inc_stats(inode, NFSIOS_VFSFSYNC); | 319 | nfs_inc_stats(inode, NFSIOS_VFSFSYNC); |
| 336 | return nfs_do_fsync(ctx, inode); | 320 | have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); |
| 321 | status = nfs_commit_inode(inode, FLUSH_SYNC); | ||
| 322 | have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); | ||
| 323 | if (have_error) | ||
| 324 | ret = xchg(&ctx->error, 0); | ||
| 325 | if (!ret) | ||
| 326 | ret = status; | ||
| 327 | return ret; | ||
| 337 | } | 328 | } |
| 338 | 329 | ||
| 339 | /* | 330 | /* |
| @@ -639,7 +630,7 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 639 | 630 | ||
| 640 | /* Return error values for O_DSYNC and IS_SYNC() */ | 631 | /* Return error values for O_DSYNC and IS_SYNC() */ |
| 641 | if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) { | 632 | if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) { |
| 642 | int err = nfs_do_fsync(nfs_file_open_context(iocb->ki_filp), inode); | 633 | int err = vfs_fsync(iocb->ki_filp, 0); |
| 643 | if (err < 0) | 634 | if (err < 0) |
| 644 | result = err; | 635 | result = err; |
| 645 | } | 636 | } |
| @@ -675,7 +666,7 @@ static ssize_t nfs_file_splice_write(struct pipe_inode_info *pipe, | |||
| 675 | written = ret; | 666 | written = ret; |
| 676 | 667 | ||
| 677 | if (ret >= 0 && nfs_need_sync_write(filp, inode)) { | 668 | if (ret >= 0 && nfs_need_sync_write(filp, inode)) { |
| 678 | int err = nfs_do_fsync(nfs_file_open_context(filp), inode); | 669 | int err = vfs_fsync(filp, 0); |
| 679 | if (err < 0) | 670 | if (err < 0) |
| 680 | ret = err; | 671 | ret = err; |
| 681 | } | 672 | } |
