From: David Rientjes <[email protected]>
Subject: mm, page_alloc: make first_page visible before PageTail
Commit bf6bddf1924e ("mm: introduce compaction and migration for ballooned
pages") introduces page_count(page) into memory compaction which
dereferences page->first_page if PageTail(page).
This results in a very rare NULL pointer dereference on the aforementioned
page_count(page). Indeed, anything that does compound_head(), including
page_count() is susceptible to racing with prep_compound_page() and seeing
a NULL or dangling page->first_page pointer.
This patch uses Andrea's implementation of compound_trans_head() that
deals with such a race and makes it the default compound_head()
implementation. This includes a read memory barrier that ensures that
if PageTail(head) is true that we return a head page that is neither
NULL nor dangling. The patch then adds a store memory barrier to
prep_compound_page() to ensure page->first_page is set.
Hugetlbfs is the exception, we don't enforce a store memory barrier
Signed-off-by: David Rientjes <[email protected]>
Reported-by: Holger Kiehl <[email protected]>
Cc: Holger Kiehl <[email protected]>
Cc: Christoph Lameter <[email protected]>
Cc: Rafael Aquini <[email protected]>
Cc: Vlastimil Babka <[email protected]>
Cc: Michal Hocko <[email protected]>
Cc: Mel Gorman <[email protected]>
Cc: Andrea Arcangeli <[email protected]>
Cc: Rik van Riel <[email protected]>
Cc: "Kirill A. Shutemov" <[email protected]>
Cc: <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
---
mm/page_alloc.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff -puN mm/page_alloc.c~mm-page_alloc-make-first_page-visible-before-pagetail
mm/page_alloc.c
--- a/mm/page_alloc.c~mm-page_alloc-make-first_page-visible-before-pagetail
+++ a/mm/page_alloc.c
@@ -369,9 +369,11 @@ void prep_compound_page(struct page *pag
__SetPageHead(page);
for (i = 1; i < nr_pages; i++) {
struct page *p = page + i;
- __SetPageTail(p);
set_page_count(p, 0);
p->first_page = page;
+ /* Make sure p->first_page is always valid for PageTail() */
+ smp_wmb();
+ __SetPageTail(p);
}
}
_
--
To unsubscribe from this list: send the line "unsubscribe stable" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html