提交 0a417b8d 编写于 作者: J Jan Kara 提交者: Darrick J. Wong

xfs: Timely free truncated dirty pages

Commit 99579cce "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: NPetr Tůma <petr.tuma@d3s.mff.cuni.cz>
Fixes: 99579cceSigned-off-by: NJan Kara <jack@suse.cz>
Reviewed-by: NBrian Foster <bfoster@redhat.com>
Signed-off-by: NDarrick J. Wong <darrick.wong@oracle.com>
上级 84a4620c
...@@ -1152,19 +1152,22 @@ xfs_vm_releasepage( ...@@ -1152,19 +1152,22 @@ xfs_vm_releasepage(
* block_invalidatepage() can send pages that are still marked dirty * block_invalidatepage() can send pages that are still marked dirty
* but otherwise have invalidated buffers. * but otherwise have invalidated buffers.
* *
* We've historically freed buffers on the latter. Instead, quietly * We want to release the latter to avoid unnecessary buildup of the
* filter out all dirty pages to avoid spurious buffer state warnings. * LRU, skip the former and warn if we've left any lingering
* This can likely be removed once shrink_active_list() is fixed. * delalloc/unwritten buffers on clean pages. Skip pages with delalloc
* or unwritten buffers and warn if the page is not dirty. Otherwise
* try to release the buffers.
*/ */
if (PageDirty(page))
return 0;
xfs_count_page_state(page, &delalloc, &unwritten); xfs_count_page_state(page, &delalloc, &unwritten);
if (WARN_ON_ONCE(delalloc)) if (delalloc) {
WARN_ON_ONCE(!PageDirty(page));
return 0; return 0;
if (WARN_ON_ONCE(unwritten)) }
if (unwritten) {
WARN_ON_ONCE(!PageDirty(page));
return 0; return 0;
}
return try_to_free_buffers(page); return try_to_free_buffers(page);
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册