Skip to content

Commit b066a4e

Browse files
Abhi DasAstralBob
authored andcommitted
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 <[email protected]> Signed-off-by: Bob Peterson <[email protected]>
1 parent a91323e commit b066a4e

File tree

3 files changed

+18
-1
lines changed

3 files changed

+18
-1
lines changed

fs/gfs2/aops.c

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,19 @@ static int gfs2_jdata_writepage(struct page *page, struct writeback_control *wbc
234234
static int gfs2_writepages(struct address_space *mapping,
235235
struct writeback_control *wbc)
236236
{
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;
238250
}
239251

240252
/**

fs/gfs2/incore.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,7 @@ enum {
606606
SDF_NOJOURNALID = 6,
607607
SDF_RORECOVERY = 7, /* read only recovery */
608608
SDF_SKIP_DLM_UNLOCK = 8,
609+
SDF_FORCE_AIL_FLUSH = 9,
609610
};
610611

611612
enum gfs2_freeze_state {

fs/gfs2/log.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -898,6 +898,10 @@ static inline int gfs2_jrnl_flush_reqd(struct gfs2_sbd *sdp)
898898
static inline int gfs2_ail_flush_reqd(struct gfs2_sbd *sdp)
899899
{
900900
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+
901905
return used_blocks + atomic_read(&sdp->sd_log_blks_needed) >=
902906
atomic_read(&sdp->sd_log_thresh2);
903907
}

0 commit comments

Comments
 (0)