In mm/vmscan.c, the page reclaim may have the following sequence 2 running concurrently with sequence 1 on another CPU: 1 2 find_get_page(); write to page write_lock(tree_lock); SetPageDirty(); if (page_count != 2 put_page(); || PageDirty()) /* page dirty or busy */ else /* free it */ The comment indicates that PageDirty must be checked *after* page_count indicates there are no users of this page, which prevents the dirty bit from being lost in the case that that sequence 2 might see the state of PageDirty() *before* SetPageDirty() in 1, but page_count *after* put_page in 1. However, there is no read memory barrier there, and so nothing to stop a CPU from loading page_count before PageDirty (ie. ->flags). Theoretically, data corruption is possible. Signed-off-by: Nick Piggin Index: linux-2.6/mm/vmscan.c =================================================================== --- linux-2.6.orig/mm/vmscan.c +++ linux-2.6/mm/vmscan.c @@ -511,7 +511,12 @@ static int shrink_list(struct list_head * PageDirty _after_ making sure that the page is freeable and * not in use by anybody. (pagecache + us == 2) */ - if (page_count(page) != 2 || PageDirty(page)) { + if (page_count(page) != 2) { + write_unlock_irq(&mapping->tree_lock); + goto keep_locked; + } + smp_rmb(); + if (PageDirty(page)) { write_unlock_irq(&mapping->tree_lock); goto keep_locked; }