diff options
author | Andrea Arcangeli <aarcange@redhat.com> | 2011-01-13 15:46:33 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 17:32:39 -0800 |
commit | a95a82e96c48270980dd248ccd5546f1b49e6f8a (patch) | |
tree | 35f10c2a8d2cd0e1aa9d33f7a4f55332c0733ee6 /mm/swap.c | |
parent | 9180706344487700b40da9eca5dedd3d11cb33b4 (diff) | |
download | lwn-a95a82e96c48270980dd248ccd5546f1b49e6f8a.tar.gz lwn-a95a82e96c48270980dd248ccd5546f1b49e6f8a.zip |
thp: put_page: recheck PageHead after releasing the compound_lock
After releasing the compound_lock split_huge_page can still run and release the
page before put_page_testzero runs.
Signed-off-by: Andrea Arcangeli <aarcange@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/swap.c')
-rw-r--r-- | mm/swap.c | 8 |
1 files changed, 6 insertions, 2 deletions
diff --git a/mm/swap.c b/mm/swap.c index 33f5292fe132..e0eeef940886 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -131,8 +131,12 @@ static void put_compound_page(struct page *page) atomic_dec(&page->_count); VM_BUG_ON(atomic_read(&page_head->_count) <= 0); compound_unlock_irqrestore(page_head, flags); - if (put_page_testzero(page_head)) - __put_compound_page(page_head); + if (put_page_testzero(page_head)) { + if (PageHead(page_head)) + __put_compound_page(page_head); + else + __put_single_page(page_head); + } } else { /* page_head is a dangling pointer */ VM_BUG_ON(PageTail(page)); |