aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfs/file.c')
-rw-r--r--fs/nfs/file.c64
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 */
189static 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
392static 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
380static ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, 404static 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 }