Skip to content

Commit

Permalink
gfs2: forcibly flush ail to relieve memory pressure
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Abhi Das authored and Bob Peterson committed Aug 10, 2017
1 parent a91323e commit b066a4e
Show file tree
Hide file tree
Showing 3 changed files with 18 additions and 1 deletion.
14 changes: 13 additions & 1 deletion fs/gfs2/aops.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,19 @@ static int gfs2_jdata_writepage(struct page *page, struct writeback_control *wbc
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;
}

/**
Expand Down
1 change: 1 addition & 0 deletions fs/gfs2/incore.h
Original file line number Diff line number Diff line change
Expand Up @@ -606,6 +606,7 @@ enum {
SDF_NOJOURNALID = 6,
SDF_RORECOVERY = 7, /* read only recovery */
SDF_SKIP_DLM_UNLOCK = 8,
SDF_FORCE_AIL_FLUSH = 9,
};

enum gfs2_freeze_state {
Expand Down
4 changes: 4 additions & 0 deletions fs/gfs2/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,10 @@ static inline int gfs2_jrnl_flush_reqd(struct gfs2_sbd *sdp)
static inline int gfs2_ail_flush_reqd(struct gfs2_sbd *sdp)
{
unsigned int used_blocks = sdp->sd_jdesc->jd_blocks - atomic_read(&sdp->sd_log_blks_free);

if (test_and_clear_bit(SDF_FORCE_AIL_FLUSH, &sdp->sd_flags))
return 1;

return used_blocks + atomic_read(&sdp->sd_log_blks_needed) >=
atomic_read(&sdp->sd_log_thresh2);
}
Expand Down

0 comments on commit b066a4e

Please sign in to comment.