aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2006-12-21 14:00:33 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-21 14:17:26 -0500
commit3e67c0987d7567ad666641164a153dca9a43b11d (patch)
treee8bd583fc8fe6e9e2e8533319a30577c0081f70e /mm
parent921320210bd2ec4f17053d283355b73048ac0e56 (diff)
[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: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/truncate.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/mm/truncate.c b/mm/truncate.c
index bf9e2965d666..89a5c359b6e8 100644
--- a/mm/truncate.c
+++ b/mm/truncate.c
@@ -60,11 +60,12 @@ void cancel_dirty_page(struct page *page, unsigned int account_size)
60 WARN_ON(++warncount < 5); 60 WARN_ON(++warncount < 5);
61 } 61 }
62 62
63 if (TestClearPageDirty(page) && account_size) 63 if (TestClearPageDirty(page) && account_size) {
64 dec_zone_page_state(page, NR_FILE_DIRTY);
64 task_io_account_cancelled_write(account_size); 65 task_io_account_cancelled_write(account_size);
66 }
65} 67}
66 68
67
68/* 69/*
69 * If truncate cannot remove the fs-private metadata from the page, the page 70 * If truncate cannot remove the fs-private metadata from the page, the page
70 * becomes anonymous. It will be left on the LRU and may even be mapped into 71 * 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 if (page->mapping != mapping) 82 if (page->mapping != mapping)
82 return; 83 return;
83 84
85 cancel_dirty_page(page, PAGE_CACHE_SIZE);
86
84 if (PagePrivate(page)) 87 if (PagePrivate(page))
85 do_invalidatepage(page, 0); 88 do_invalidatepage(page, 0);
86 89
87 cancel_dirty_page(page, PAGE_CACHE_SIZE);
88
89 ClearPageUptodate(page); 90 ClearPageUptodate(page);
90 ClearPageMappedToDisk(page); 91 ClearPageMappedToDisk(page);
91 remove_from_page_cache(page); 92 remove_from_page_cache(page);