Messages in this thread Patch in this message | | | From | "Kirill A. Shutemov" <> | Subject | [PATCH 1/2] mm: drop bogus VM_BUG_ON_PAGE assert in put_page() codepath | Date | Tue, 28 Apr 2015 19:24:57 +0300 |
| |
My patch 8d63d99a5dfb which was merged during 4.1 merge window caused regression:
page:ffffea0010a15040 count:0 mapcount:1 mapping: (null) index:0x0 flags: 0x8000000000008014(referenced|dirty|tail) page dumped because: VM_BUG_ON_PAGE(page_mapcount(page) != 0) ------------[ cut here ]------------ kernel BUG at mm/swap.c:134!
The problem can be reproduced by playing *two* audio files at the same time and then stopping one of players. I used two mplayers to trigger this.
The VM_BUG_ON_PAGE() which triggers the bug is bogus:
Sound subsystem uses compound pages for its buffers, but unlike most __GFP_COMP sound maps compound pages to userspace with PTEs.
In our case with two players map the buffer twice and therefore elevates page_mapcount() on tail pages by two. When one of players exits it unmaps the VMA and drops page_mapcount() to one and try to release reference on the page with put_page().
My commit changes which path it takes under put_compound_page(). It hits put_unrefcounted_compound_page() where VM_BUG_ON_PAGE() is. It sees page_mapcount() == 1. The function wrongly assumes that subpages of compound page cannot be be mapped by itself with PTEs..
The solution is simply drop the VM_BUG_ON_PAGE().
Note: there's no need to move the check under put_page_testzero(). Allocator will check the mapcount by itself before putting on free list.
Signed-off-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> Reported-by: Andrea Arcangeli <aarcange@redhat.com> Reviewed-by: Andrea Arcangeli <aarcange@redhat.com> Reported-by: Borislav Petkov <bp@alien8.de> Cc: Hugh Dickins <hughd@google.com> Cc: Andrew Morton <akpm@linux-foundation.org> --- mm/swap.c | 1 - 1 file changed, 1 deletion(-)
diff --git a/mm/swap.c b/mm/swap.c index a7251a8ed532..a3a0a2f1f7c3 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -131,7 +131,6 @@ void put_unrefcounted_compound_page(struct page *page_head, struct page *page) * here, see the comment above this function. */ VM_BUG_ON_PAGE(!PageHead(page_head), page_head); - VM_BUG_ON_PAGE(page_mapcount(page) != 0, page); if (put_page_testzero(page_head)) { /* * If this is the tail of a slab THP page, -- 2.1.4
| |