aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2017-01-11 13:20:04 -0500
committerDarrick J. Wong <darrick.wong@oracle.com>2017-01-11 13:20:04 -0500
commit0a417b8dc1f10b03e8f558b8a831f07ec4c23795 (patch)
tree871ad399028165211ec365d7bc19a35798a32995
parent84a4620cfe97c9d57e39b2369bfb77faff55063d (diff)
xfs: Timely free truncated dirty pages
Commit 99579ccec4e2 "xfs: skip dirty pages in ->releasepage()" started to skip dirty pages in xfs_vm_releasepage() which also has the effect that if a dirty page is truncated, it does not get freed by block_invalidatepage() and is lingering in LRU list waiting for reclaim. So a simple loop like: while true; do dd if=/dev/zero of=file bs=1M count=100 rm file done will keep using more and more memory until we hit low watermarks and start pagecache reclaim which will eventually reclaim also the truncate pages. Keeping these truncated (and thus never usable) pages in memory is just a waste of memory, is unnecessarily stressing page cache reclaim, and reportedly also leads to anonymous mmap(2) returning ENOMEM prematurely. So instead of just skipping dirty pages in xfs_vm_releasepage(), return to old behavior of skipping them only if they have delalloc or unwritten buffers and fix the spurious warnings by warning only if the page is clean. CC: stable@vger.kernel.org CC: Brian Foster <bfoster@redhat.com> CC: Vlastimil Babka <vbabka@suse.cz> Reported-by: Petr Tůma <petr.tuma@d3s.mff.cuni.cz> Fixes: 99579ccec4e271c3d4d4e7c946058766812afdab Signed-off-by: Jan Kara <jack@suse.cz> Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
-rw-r--r--fs/xfs/xfs_aops.c19
1 files changed, 11 insertions, 8 deletions
diff --git a/fs/xfs/xfs_aops.c b/fs/xfs/xfs_aops.c
index 0f56fcd3a5d5..631e7c0e0a29 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -1152,19 +1152,22 @@ xfs_vm_releasepage(
1152 * block_invalidatepage() can send pages that are still marked dirty 1152 * block_invalidatepage() can send pages that are still marked dirty
1153 * but otherwise have invalidated buffers. 1153 * but otherwise have invalidated buffers.
1154 * 1154 *
1155 * We've historically freed buffers on the latter. Instead, quietly 1155 * We want to release the latter to avoid unnecessary buildup of the
1156 * filter out all dirty pages to avoid spurious buffer state warnings. 1156 * LRU, skip the former and warn if we've left any lingering
1157 * This can likely be removed once shrink_active_list() is fixed. 1157 * delalloc/unwritten buffers on clean pages. Skip pages with delalloc
1158 * or unwritten buffers and warn if the page is not dirty. Otherwise
1159 * try to release the buffers.
1158 */ 1160 */
1159 if (PageDirty(page))
1160 return 0;
1161
1162 xfs_count_page_state(page, &delalloc, &unwritten); 1161 xfs_count_page_state(page, &delalloc, &unwritten);
1163 1162
1164 if (WARN_ON_ONCE(delalloc)) 1163 if (delalloc) {
1164 WARN_ON_ONCE(!PageDirty(page));
1165 return 0; 1165 return 0;
1166 if (WARN_ON_ONCE(unwritten)) 1166 }
1167 if (unwritten) {
1168 WARN_ON_ONCE(!PageDirty(page));
1167 return 0; 1169 return 0;
1170 }
1168 1171
1169 return try_to_free_buffers(page); 1172 return try_to_free_buffers(page);
1170} 1173}