summaryrefslogtreecommitdiff
path: root/fs/gfs2/aops.c
diff options
context:
space:
mode:
authorAbhi Das <adas@redhat.com>2017-08-04 20:15:32 +0300
committerBob Peterson <rpeterso@redhat.com>2017-08-10 18:51:03 +0300
commitb066a4eebd4f5ea77f7e5c7d13104d38e1a1d4bf (patch)
treeb8f53940b11052f2cb444f21586063eed0c1f3e5 /fs/gfs2/aops.c
parenta91323e255fa8bc84b0acf63376b395c534a38fa (diff)
downloadlinux-b066a4eebd4f5ea77f7e5c7d13104d38e1a1d4bf.tar.xz
gfs2: forcibly flush ail to relieve memory pressure
On systems with low memory, it is possible for gfs2 to infinitely loop in balance_dirty_pages() under heavy IO (creating sparse files). balance_dirty_pages() attempts to write out the dirty pages via gfs2_writepages() but none are found because these dirty pages are being used by the journaling code in the ail. Normally, the journal has an upper threshold which when hit triggers an automatic flush of the ail. But this threshold can be higher than the number of allowable dirty pages and result in the ail never being flushed. This patch forces an ail flush when gfs2_writepages() fails to write anything. This is a good indication that the ail might be holding some dirty pages. Signed-off-by: Abhi Das <adas@redhat.com> Signed-off-by: Bob Peterson <rpeterso@redhat.com>
Diffstat (limited to 'fs/gfs2/aops.c')
-rw-r--r--fs/gfs2/aops.c14
1 files changed, 13 insertions, 1 deletions
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c
index ed7a2e252ad8..68ed06962537 100644
--- a/fs/gfs2/aops.c
+++ b/fs/gfs2/aops.c
@@ -234,7 +234,19 @@ out:
static int gfs2_writepages(struct address_space *mapping,
struct writeback_control *wbc)
{
- return mpage_writepages(mapping, wbc, gfs2_get_block_noalloc);
+ struct gfs2_sbd *sdp = gfs2_mapping2sbd(mapping);
+ int ret = mpage_writepages(mapping, wbc, gfs2_get_block_noalloc);
+
+ /*
+ * Even if we didn't write any pages here, we might still be holding
+ * dirty pages in the ail. We forcibly flush the ail because we don't
+ * want balance_dirty_pages() to loop indefinitely trying to write out
+ * pages held in the ail that it can't find.
+ */
+ if (ret == 0)
+ set_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags);
+
+ return ret;
}
/**