Commit 3e67c098 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] truncate: clear page dirtiness before running try_to_free_buffers()

truncate presently invalidates the dirty page's buffer_heads then shoots down
the page.  But try_to_free_buffers() will now bale out because the page is
dirty.

Net effect: the LRU gets filled with dirty pages which have invalidated
buffer_heads attached.  They have no ->mapping and hence cannot be cleaned.
The machine leaks memory at an enormous rate.

Fix this by cleaning the page before running try_to_free_buffers(), so
try_to_free_buffers() can do its work.

Also, remember to do dirty-page-acoounting in cancel_dirty_page() so the
machine won't wedge up trying to write non-existent dirty pages.

Probably still wrong, but now less so.
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 92132021
...@@ -60,11 +60,12 @@ void cancel_dirty_page(struct page *page, unsigned int account_size) ...@@ -60,11 +60,12 @@ void cancel_dirty_page(struct page *page, unsigned int account_size)
WARN_ON(++warncount < 5); WARN_ON(++warncount < 5);
} }
if (TestClearPageDirty(page) && account_size) if (TestClearPageDirty(page) && account_size) {
dec_zone_page_state(page, NR_FILE_DIRTY);
task_io_account_cancelled_write(account_size); task_io_account_cancelled_write(account_size);
}
} }
/* /*
* If truncate cannot remove the fs-private metadata from the page, the page * If truncate cannot remove the fs-private metadata from the page, the page
* becomes anonymous. It will be left on the LRU and may even be mapped into * becomes anonymous. It will be left on the LRU and may even be mapped into
...@@ -81,11 +82,11 @@ truncate_complete_page(struct address_space *mapping, struct page *page) ...@@ -81,11 +82,11 @@ truncate_complete_page(struct address_space *mapping, struct page *page)
if (page->mapping != mapping) if (page->mapping != mapping)
return; return;
cancel_dirty_page(page, PAGE_CACHE_SIZE);
if (PagePrivate(page)) if (PagePrivate(page))
do_invalidatepage(page, 0); do_invalidatepage(page, 0);
cancel_dirty_page(page, PAGE_CACHE_SIZE);
ClearPageUptodate(page); ClearPageUptodate(page);
ClearPageMappedToDisk(page); ClearPageMappedToDisk(page);
remove_from_page_cache(page); remove_from_page_cache(page);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment