aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Chinner <david@fromorbit.com>2009-04-06 12:45:44 -0400
committerChristoph Hellwig <hch@brick.lst.de>2009-04-06 12:45:44 -0400
commit5825294edd3364cbba6514f70d88debec4f6cec7 (patch)
tree5462388cdb6b36b2f0f1cf75dc6ee60a7c643a23
parenta8d770d987ee20b59fba6c37d7f0f2a351913c4b (diff)
xfs: make inode flush at ENOSPC synchronous
When we are writing to a single file and hit ENOSPC, we trigger a background flush of the inode and try again. Because we hold page locks and the iolock, the flush won't proceed until after we release these locks. This occurs once we've given up and ENOSPC has been reported. Hence if this one is the only dirty inode in the system, we'll get an ENOSPC prematurely. To fix this, remove the async flush from the allocation routines and move it to the top of the write path where we can do a synchronous flush and retry the write again. Only retry once as a second ENOSPC indicates that we really are ENOSPC. This avoids a page cache deadlock when trying to do this flush synchronously in the allocation layer that was identified by Mikulas Patocka. Signed-off-by: Dave Chinner <david@fromorbit.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
-rw-r--r--fs/xfs/linux-2.6/xfs_lrw.c18
-rw-r--r--fs/xfs/linux-2.6/xfs_sync.c25
-rw-r--r--fs/xfs/linux-2.6/xfs_sync.h1
-rw-r--r--fs/xfs/xfs_iomap.c2
4 files changed, 18 insertions, 28 deletions
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c
index 7e90daa0d1d1..9142192ccbe6 100644
--- a/fs/xfs/linux-2.6/xfs_lrw.c
+++ b/fs/xfs/linux-2.6/xfs_lrw.c
@@ -751,10 +751,26 @@ start:
751 goto relock; 751 goto relock;
752 } 752 }
753 } else { 753 } else {
754 int enospc = 0;
755 ssize_t ret2 = 0;
756
757write_retry:
754 xfs_rw_enter_trace(XFS_WRITE_ENTER, xip, (void *)iovp, segs, 758 xfs_rw_enter_trace(XFS_WRITE_ENTER, xip, (void *)iovp, segs,
755 *offset, ioflags); 759 *offset, ioflags);
756 ret = generic_file_buffered_write(iocb, iovp, segs, 760 ret2 = generic_file_buffered_write(iocb, iovp, segs,
757 pos, offset, count, ret); 761 pos, offset, count, ret);
762 /*
763 * if we just got an ENOSPC, flush the inode now we
764 * aren't holding any page locks and retry *once*
765 */
766 if (ret2 == -ENOSPC && !enospc) {
767 error = xfs_flush_pages(xip, 0, -1, 0, FI_NONE);
768 if (error)
769 goto out_unlock_internal;
770 enospc = 1;
771 goto write_retry;
772 }
773 ret = ret2;
758 } 774 }
759 775
760 current->backing_dev_info = NULL; 776 current->backing_dev_info = NULL;
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c
index 88caafc8ef1b..73cf8dc19738 100644
--- a/fs/xfs/linux-2.6/xfs_sync.c
+++ b/fs/xfs/linux-2.6/xfs_sync.c
@@ -426,31 +426,6 @@ xfs_syncd_queue_work(
426 * heads, looking about for more room... 426 * heads, looking about for more room...
427 */ 427 */
428STATIC void 428STATIC void
429xfs_flush_inode_work(
430 struct xfs_mount *mp,
431 void *arg)
432{
433 struct inode *inode = arg;
434 filemap_flush(inode->i_mapping);
435 iput(inode);
436}
437
438void
439xfs_flush_inode(
440 xfs_inode_t *ip)
441{
442 struct inode *inode = VFS_I(ip);
443
444 igrab(inode);
445 xfs_syncd_queue_work(ip->i_mount, inode, xfs_flush_inode_work);
446 delay(msecs_to_jiffies(500));
447}
448
449/*
450 * This is the "bigger hammer" version of xfs_flush_inode_work...
451 * (IOW, "If at first you don't succeed, use a Bigger Hammer").
452 */
453STATIC void
454xfs_flush_inodes_work( 429xfs_flush_inodes_work(
455 struct xfs_mount *mp, 430 struct xfs_mount *mp,
456 void *arg) 431 void *arg)
diff --git a/fs/xfs/linux-2.6/xfs_sync.h b/fs/xfs/linux-2.6/xfs_sync.h
index ec95e264805b..6e83a35626ed 100644
--- a/fs/xfs/linux-2.6/xfs_sync.h
+++ b/fs/xfs/linux-2.6/xfs_sync.h
@@ -44,7 +44,6 @@ int xfs_sync_fsdata(struct xfs_mount *mp, int flags);
44int xfs_quiesce_data(struct xfs_mount *mp); 44int xfs_quiesce_data(struct xfs_mount *mp);
45void xfs_quiesce_attr(struct xfs_mount *mp); 45void xfs_quiesce_attr(struct xfs_mount *mp);
46 46
47void xfs_flush_inode(struct xfs_inode *ip);
48void xfs_flush_inodes(struct xfs_inode *ip); 47void xfs_flush_inodes(struct xfs_inode *ip);
49 48
50int xfs_reclaim_inode(struct xfs_inode *ip, int locked, int sync_mode); 49int xfs_reclaim_inode(struct xfs_inode *ip, int locked, int sync_mode);
diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c
index 8b97d82d7a88..7b8b17071030 100644
--- a/fs/xfs/xfs_iomap.c
+++ b/fs/xfs/xfs_iomap.c
@@ -347,7 +347,7 @@ xfs_flush_space(
347 case 0: 347 case 0:
348 if (ip->i_delayed_blks) { 348 if (ip->i_delayed_blks) {
349 xfs_iunlock(ip, XFS_ILOCK_EXCL); 349 xfs_iunlock(ip, XFS_ILOCK_EXCL);
350 xfs_flush_inode(ip); 350 delay(1);
351 xfs_ilock(ip, XFS_ILOCK_EXCL); 351 xfs_ilock(ip, XFS_ILOCK_EXCL);
352 *fsynced = 1; 352 *fsynced = 1;
353 } else { 353 } else {