aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAbhi Das <adas@redhat.com>2017-08-04 13:15:32 -0400
committerBob Peterson <rpeterso@redhat.com>2017-08-10 11:51:03 -0400
commitb066a4eebd4f5ea77f7e5c7d13104d38e1a1d4bf (patch)
treeb8f53940b11052f2cb444f21586063eed0c1f3e5
parenta91323e255fa8bc84b0acf63376b395c534a38fa (diff)
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>
-rw-r--r--fs/gfs2/aops.c14
-rw-r--r--fs/gfs2/incore.h1
-rw-r--r--fs/gfs2/log.c4
3 files changed, 18 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:
234static int gfs2_writepages(struct address_space *mapping, 234static int gfs2_writepages(struct address_space *mapping,
235 struct writeback_control *wbc) 235 struct writeback_control *wbc)
236{ 236{
237 return mpage_writepages(mapping, wbc, gfs2_get_block_noalloc); 237 struct gfs2_sbd *sdp = gfs2_mapping2sbd(mapping);
238 int ret = mpage_writepages(mapping, wbc, gfs2_get_block_noalloc);
239
240 /*
241 * Even if we didn't write any pages here, we might still be holding
242 * dirty pages in the ail. We forcibly flush the ail because we don't
243 * want balance_dirty_pages() to loop indefinitely trying to write out
244 * pages held in the ail that it can't find.
245 */
246 if (ret == 0)
247 set_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags);
248
249 return ret;
238} 250}
239 251
240/** 252/**
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 73fce76e67ee..a7b0331c549d 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -606,6 +606,7 @@ enum {
606 SDF_NOJOURNALID = 6, 606 SDF_NOJOURNALID = 6,
607 SDF_RORECOVERY = 7, /* read only recovery */ 607 SDF_RORECOVERY = 7, /* read only recovery */
608 SDF_SKIP_DLM_UNLOCK = 8, 608 SDF_SKIP_DLM_UNLOCK = 8,
609 SDF_FORCE_AIL_FLUSH = 9,
609}; 610};
610 611
611enum gfs2_freeze_state { 612enum gfs2_freeze_state {
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index 9a624f694400..31585c2d22fe 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -898,6 +898,10 @@ static inline int gfs2_jrnl_flush_reqd(struct gfs2_sbd *sdp)
898static inline int gfs2_ail_flush_reqd(struct gfs2_sbd *sdp) 898static inline int gfs2_ail_flush_reqd(struct gfs2_sbd *sdp)
899{ 899{
900 unsigned int used_blocks = sdp->sd_jdesc->jd_blocks - atomic_read(&sdp->sd_log_blks_free); 900 unsigned int used_blocks = sdp->sd_jdesc->jd_blocks - atomic_read(&sdp->sd_log_blks_free);
901
902 if (test_and_clear_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags))
903 return 1;
904
901 return used_blocks + atomic_read(&sdp->sd_log_blks_needed) >= 905 return used_blocks + atomic_read(&sdp->sd_log_blks_needed) >=
902 atomic_read(&sdp->sd_log_thresh2); 906 atomic_read(&sdp->sd_log_thresh2);
903} 907}