aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2017-01-11 13:20:04 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-01-19 14:18:00 -0500
commit6ba35da690f30af09706095b914d8031902fd3e5 (patch)
tree7836bbd1453038fa0252e352d33a91e9f29f2d01
parent86673e9331c929f43ff4c89bee056273ac2e3ed5 (diff)
xfs: Timely free truncated dirty pages
commit 0a417b8dc1f10b03e8f558b8a831f07ec4c23795 upstream. 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: 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> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-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 2693ba84ec25..06763f5cc701 100644
--- a/fs/xfs/xfs_aops.c
+++ b/fs/xfs/xfs_aops.c
@@ -1158,19 +1158,22 @@ xfs_vm_releasepage(
1158 * block_invalidatepage() can send pages that are still marked dirty 1158 * block_invalidatepage() can send pages that are still marked dirty
1159 * but otherwise have invalidated buffers. 1159 * but otherwise have invalidated buffers.
1160 * 1160 *
1161 * We've historically freed buffers on the latter. Instead, quietly 1161 * We want to release the latter to avoid unnecessary buildup of the
1162 * filter out all dirty pages to avoid spurious buffer state warnings. 1162 * LRU, skip the former and warn if we've left any lingering
1163 * This can likely be removed once shrink_active_list() is fixed. 1163 * delalloc/unwritten buffers on clean pages. Skip pages with delalloc
1164 * or unwritten buffers and warn if the page is not dirty. Otherwise
1165 * try to release the buffers.
1164 */ 1166 */
1165 if (PageDirty(page))
1166 return 0;
1167
1168 xfs_count_page_state(page, &delalloc, &unwritten); 1167 xfs_count_page_state(page, &delalloc, &unwritten);
1169 1168
1170 if (WARN_ON_ONCE(delalloc)) 1169 if (delalloc) {
1170 WARN_ON_ONCE(!PageDirty(page));
1171 return 0; 1171 return 0;
1172 if (WARN_ON_ONCE(unwritten)) 1172 }
1173 if (unwritten) {
1174 WARN_ON_ONCE(!PageDirty(page));
1173 return 0; 1175 return 0;
1176 }
1174 1177
1175 return try_to_free_buffers(page); 1178 return try_to_free_buffers(page);
1176} 1179}