aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNick Piggin <npiggin@suse.de>2008-04-30 03:55:16 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-04-30 11:29:55 -0400
commit3a902c5f6851cd0b64c33efaa3bd57aa27a82efb (patch)
tree9803f7bdc847ed8cd5192816d9ca0ee9e310cd60
parent969a19f1c405a8e9d15ceb9e75e3f4a321aaf56f (diff)
mm: fix warning on memory offline
KAMEZAWA Hiroyuki found a warning message in the buffer dirtying code that is coming from page migration caller. WARNING: at fs/buffer.c:720 __set_page_dirty+0x330/0x360() Call Trace: [<a000000100015220>] show_stack+0x80/0xa0 [<a000000100015270>] dump_stack+0x30/0x60 [<a000000100089ed0>] warn_on_slowpath+0x90/0xe0 [<a0000001001f8b10>] __set_page_dirty+0x330/0x360 [<a0000001001ffb90>] __set_page_dirty_buffers+0xd0/0x280 [<a00000010012fec0>] set_page_dirty+0xc0/0x260 [<a000000100195670>] migrate_page_copy+0x5d0/0x5e0 [<a000000100197840>] buffer_migrate_page+0x2e0/0x3c0 [<a000000100195eb0>] migrate_pages+0x770/0xe00 What was happening is that migrate_page_copy wants to transfer the PG_dirty bit from old page to new page, so what it would do is set_page_dirty(newpage). However set_page_dirty() is used to set the entire page dirty, wheras in this case, only part of the page was dirty, and it also was not uptodate. Marking the whole page dirty with set_page_dirty would lead to corruption or unresolvable conditions -- a dirty && !uptodate page and dirty && !uptodate buffers. Possibly we could just ClearPageDirty(oldpage); SetPageDirty(newpage); however in the interests of keeping the change minimal... Signed-off-by: Nick Piggin <npiggin@suse.de> Tested-by: KAMEZAWA Hiroyuki <kamezawa.hiroyu@jp.fujitsu.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--mm/migrate.c9
1 files changed, 8 insertions, 1 deletions
diff --git a/mm/migrate.c b/mm/migrate.c
index 4e0eccca5e26..449d77d409f5 100644
--- a/mm/migrate.c
+++ b/mm/migrate.c
@@ -383,7 +383,14 @@ static void migrate_page_copy(struct page *newpage, struct page *page)
383 383
384 if (PageDirty(page)) { 384 if (PageDirty(page)) {
385 clear_page_dirty_for_io(page); 385 clear_page_dirty_for_io(page);
386 set_page_dirty(newpage); 386 /*
387 * Want to mark the page and the radix tree as dirty, and
388 * redo the accounting that clear_page_dirty_for_io undid,
389 * but we can't use set_page_dirty because that function
390 * is actually a signal that all of the page has become dirty.
391 * Wheras only part of our page may be dirty.
392 */
393 __set_page_dirty_nobuffers(newpage);
387 } 394 }
388 395
389#ifdef CONFIG_SWAP 396#ifdef CONFIG_SWAP