aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2011-12-06 16:21:15 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2011-12-09 11:52:46 -0500
commitedb9a31845c5ba0ff325daa58f17f881d60d1559 (patch)
tree0ffeb6668a822dd80aa96f2cfeb116bb4fba68e8 /fs/xfs
parenta980e5dccb3ff8cb8f77ff27264b13837958119d (diff)
xfs: force buffer writeback before blocking on the ilock in inode reclaim
commit 4dd2cb4a28b7ab1f37163a4eba280926a13a8749 upstream. If we are doing synchronous inode reclaim we block the VM from making progress in memory reclaim. So if we encouter a flush locked inode promote it in the delwri list and wake up xfsbufd to write it out now. Without this we can get hangs of up to 30 seconds during workloads hitting synchronous inode reclaim. The scheme is copied from what we do for dquot reclaims. Reported-by: Simon Kirby <sim@hostway.ca> Signed-off-by: Christoph Hellwig <hch@lst.de> Tested-by: Simon Kirby <sim@hostway.ca> Signed-off-by: Ben Myers <bpm@sgi.com> Acked-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/linux-2.6/xfs_sync.c11
-rw-r--r--fs/xfs/xfs_inode.c21
-rw-r--r--fs/xfs/xfs_inode.h1
3 files changed, 33 insertions, 0 deletions
diff --git a/fs/xfs/linux-2.6/xfs_sync.c b/fs/xfs/linux-2.6/xfs_sync.c
index 8ecad5ff9f9..b69688d0776 100644
--- a/fs/xfs/linux-2.6/xfs_sync.c
+++ b/fs/xfs/linux-2.6/xfs_sync.c
@@ -772,6 +772,17 @@ restart:
772 if (!xfs_iflock_nowait(ip)) { 772 if (!xfs_iflock_nowait(ip)) {
773 if (!(sync_mode & SYNC_WAIT)) 773 if (!(sync_mode & SYNC_WAIT))
774 goto out; 774 goto out;
775
776 /*
777 * If we only have a single dirty inode in a cluster there is
778 * a fair chance that the AIL push may have pushed it into
779 * the buffer, but xfsbufd won't touch it until 30 seconds
780 * from now, and thus we will lock up here.
781 *
782 * Promote the inode buffer to the front of the delwri list
783 * and wake up xfsbufd now.
784 */
785 xfs_promote_inode(ip);
775 xfs_iflock(ip); 786 xfs_iflock(ip);
776 } 787 }
777 788
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index a098a20ca63..c6888a420c5 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -3099,6 +3099,27 @@ corrupt_out:
3099 return XFS_ERROR(EFSCORRUPTED); 3099 return XFS_ERROR(EFSCORRUPTED);
3100} 3100}
3101 3101
3102void
3103xfs_promote_inode(
3104 struct xfs_inode *ip)
3105{
3106 struct xfs_buf *bp;
3107
3108 ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL|XFS_ILOCK_SHARED));
3109
3110 bp = xfs_incore(ip->i_mount->m_ddev_targp, ip->i_imap.im_blkno,
3111 ip->i_imap.im_len, XBF_TRYLOCK);
3112 if (!bp)
3113 return;
3114
3115 if (XFS_BUF_ISDELAYWRITE(bp)) {
3116 xfs_buf_delwri_promote(bp);
3117 wake_up_process(ip->i_mount->m_ddev_targp->bt_task);
3118 }
3119
3120 xfs_buf_relse(bp);
3121}
3122
3102/* 3123/*
3103 * Return a pointer to the extent record at file index idx. 3124 * Return a pointer to the extent record at file index idx.
3104 */ 3125 */
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
index 964cfea7768..28b3596453e 100644
--- a/fs/xfs/xfs_inode.h
+++ b/fs/xfs/xfs_inode.h
@@ -509,6 +509,7 @@ int xfs_iunlink(struct xfs_trans *, xfs_inode_t *);
509void xfs_iext_realloc(xfs_inode_t *, int, int); 509void xfs_iext_realloc(xfs_inode_t *, int, int);
510void xfs_iunpin_wait(xfs_inode_t *); 510void xfs_iunpin_wait(xfs_inode_t *);
511int xfs_iflush(xfs_inode_t *, uint); 511int xfs_iflush(xfs_inode_t *, uint);
512void xfs_promote_inode(struct xfs_inode *);
512void xfs_lock_inodes(xfs_inode_t **, int, uint); 513void xfs_lock_inodes(xfs_inode_t **, int, uint);
513void xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint); 514void xfs_lock_two_inodes(xfs_inode_t *, xfs_inode_t *, uint);
514 515