diff options
Diffstat (limited to 'fs/nfs/file.c')
-rw-r--r-- | fs/nfs/file.c | 64 |
1 files changed, 44 insertions, 20 deletions
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 07f43791f696..5595b32c0915 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -177,6 +177,31 @@ static loff_t nfs_file_llseek(struct file *filp, loff_t offset, int origin) | |||
177 | } | 177 | } |
178 | 178 | ||
179 | /* | 179 | /* |
180 | * Helper for nfs_file_flush() and nfs_fsync() | ||
181 | * | ||
182 | * Notice that it clears the NFS_CONTEXT_ERROR_WRITE before synching to | ||
183 | * disk, but it retrieves and clears ctx->error after synching, despite | ||
184 | * the two being set at the same time in nfs_context_set_write_error(). | ||
185 | * This is because the former is used to notify the _next_ call to | ||
186 | * nfs_file_write() that a write error occured, and hence cause it to | ||
187 | * fall back to doing a synchronous write. | ||
188 | */ | ||
189 | static int nfs_do_fsync(struct nfs_open_context *ctx, struct inode *inode) | ||
190 | { | ||
191 | int have_error, status; | ||
192 | int ret = 0; | ||
193 | |||
194 | have_error = test_and_clear_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); | ||
195 | status = nfs_wb_all(inode); | ||
196 | have_error |= test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags); | ||
197 | if (have_error) | ||
198 | ret = xchg(&ctx->error, 0); | ||
199 | if (!ret) | ||
200 | ret = status; | ||
201 | return ret; | ||
202 | } | ||
203 | |||
204 | /* | ||
180 | * Flush all dirty pages, and check for write errors. | 205 | * Flush all dirty pages, and check for write errors. |
181 | * | 206 | * |
182 | */ | 207 | */ |
@@ -192,16 +217,11 @@ nfs_file_flush(struct file *file, fl_owner_t id) | |||
192 | if ((file->f_mode & FMODE_WRITE) == 0) | 217 | if ((file->f_mode & FMODE_WRITE) == 0) |
193 | return 0; | 218 | return 0; |
194 | nfs_inc_stats(inode, NFSIOS_VFSFLUSH); | 219 | nfs_inc_stats(inode, NFSIOS_VFSFLUSH); |
195 | lock_kernel(); | 220 | |
196 | /* Ensure that data+attribute caches are up to date after close() */ | 221 | /* Ensure that data+attribute caches are up to date after close() */ |
197 | status = nfs_wb_all(inode); | 222 | status = nfs_do_fsync(ctx, inode); |
198 | if (!status) { | 223 | if (!status) |
199 | status = ctx->error; | 224 | nfs_revalidate_inode(NFS_SERVER(inode), inode); |
200 | ctx->error = 0; | ||
201 | if (!status) | ||
202 | nfs_revalidate_inode(NFS_SERVER(inode), inode); | ||
203 | } | ||
204 | unlock_kernel(); | ||
205 | return status; | 225 | return status; |
206 | } | 226 | } |
207 | 227 | ||
@@ -278,19 +298,11 @@ nfs_fsync(struct file *file, struct dentry *dentry, int datasync) | |||
278 | { | 298 | { |
279 | struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; | 299 | struct nfs_open_context *ctx = (struct nfs_open_context *)file->private_data; |
280 | struct inode *inode = dentry->d_inode; | 300 | struct inode *inode = dentry->d_inode; |
281 | int status; | ||
282 | 301 | ||
283 | dfprintk(VFS, "nfs: fsync(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); | 302 | dfprintk(VFS, "nfs: fsync(%s/%ld)\n", inode->i_sb->s_id, inode->i_ino); |
284 | 303 | ||
285 | nfs_inc_stats(inode, NFSIOS_VFSFSYNC); | 304 | nfs_inc_stats(inode, NFSIOS_VFSFSYNC); |
286 | lock_kernel(); | 305 | return nfs_do_fsync(ctx, inode); |
287 | status = nfs_wb_all(inode); | ||
288 | if (!status) { | ||
289 | status = ctx->error; | ||
290 | ctx->error = 0; | ||
291 | } | ||
292 | unlock_kernel(); | ||
293 | return status; | ||
294 | } | 306 | } |
295 | 307 | ||
296 | /* | 308 | /* |
@@ -377,6 +389,18 @@ static struct vm_operations_struct nfs_file_vm_ops = { | |||
377 | .page_mkwrite = nfs_vm_page_mkwrite, | 389 | .page_mkwrite = nfs_vm_page_mkwrite, |
378 | }; | 390 | }; |
379 | 391 | ||
392 | static int nfs_need_sync_write(struct file *filp, struct inode *inode) | ||
393 | { | ||
394 | struct nfs_open_context *ctx; | ||
395 | |||
396 | if (IS_SYNC(inode) || (filp->f_flags & O_SYNC)) | ||
397 | return 1; | ||
398 | ctx = filp->private_data; | ||
399 | if (test_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags)) | ||
400 | return 1; | ||
401 | return 0; | ||
402 | } | ||
403 | |||
380 | static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, | 404 | static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, |
381 | unsigned long nr_segs, loff_t pos) | 405 | unsigned long nr_segs, loff_t pos) |
382 | { | 406 | { |
@@ -413,8 +437,8 @@ static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
413 | nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count); | 437 | nfs_add_stats(inode, NFSIOS_NORMALWRITTENBYTES, count); |
414 | result = generic_file_aio_write(iocb, iov, nr_segs, pos); | 438 | result = generic_file_aio_write(iocb, iov, nr_segs, pos); |
415 | /* Return error values for O_SYNC and IS_SYNC() */ | 439 | /* Return error values for O_SYNC and IS_SYNC() */ |
416 | if (result >= 0 && (IS_SYNC(inode) || (iocb->ki_filp->f_flags & O_SYNC))) { | 440 | if (result >= 0 && nfs_need_sync_write(iocb->ki_filp, inode)) { |
417 | int err = nfs_fsync(iocb->ki_filp, dentry, 1); | 441 | int err = nfs_do_fsync(iocb->ki_filp->private_data, inode); |
418 | if (err < 0) | 442 | if (err < 0) |
419 | result = err; | 443 | result = err; |
420 | } | 444 | } |