aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/file.c
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2007-07-25 14:09:54 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2007-10-09 17:15:23 -0400
commit7b159fc18d417980f57aef64cab3417ee6af70f8 (patch)
tree880f31179a9836ad9cd63b91dd6d77b61b01017c /fs/nfs/file.c
parent34901f70d119d88126e7390351b8c780646628e1 (diff)
NFS: Fall back to synchronous writes when a background write errors...
This helps prevent huge queues of background writes from building up whenever the server runs out of disk or quota space, or if someone changes the file access modes behind our backs. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
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 }