From: Youquan Song Date: Wed, 30 Nov 2011 04:03:02 +0000 (+1100) Subject: thp: set compound tail page _count to zero X-Git-Tag: next-20111130~3^2~191 X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=663dc6c9666938b0bd9a8c786e98daceef96000b;p=karo-tx-linux.git thp: set compound tail page _count to zero 70b50f94f1644 ("mm: thp: tail page refcounting fix") keeps all page_tail->_count zero at all times. But the current kernel does not set page_tail->_count to zero if a 1GB page is utilized. So when an IOMMU 1GB page is used at KVM, it wil result in a kernel oops because a tail page's _count does not equal zero. kernel BUG at include/linux/mm.h:386! invalid opcode: 0000 [#1] SMP Call Trace: [] gup_pud_range+0xb8/0x19d [] get_user_pages_fast+0xcb/0x192 [] ? trace_hardirqs_off+0xd/0xf [] hva_to_pfn+0x119/0x2f2 [] gfn_to_pfn_memslot+0x2c/0x2e [] kvm_iommu_map_pages+0xfd/0x1c1 [] kvm_iommu_map_memslots+0x7c/0xbd [] ? kvm_iommu_map_pages+0x1c1/0x1c1 [] kvm_iommu_map_guest+0xaa/0xbf [] kvm_vm_ioctl_assigned_device+0x2ef/0xa47 [] ? kvm_vm_ioctl_assigned_device+0xac/0xa47 [] ? native_sched_clock+0x32/0x6b [] ? sched_clock_cpu+0x45/0xd4 [] ? trace_hardirqs_off+0xd/0xf [] ? local_clock+0x41/0x5a [] ? lock_release_holdtime+0x2c/0x129 [] ? cmpxchg_double_slab+0xd0/0x12b [] ? avc_has_perm_noaudit+0x388/0x399 [] ? native_sched_clock+0x32/0x6b [] ? sched_clock+0x9/0xd [] kvm_vm_ioctl+0x36c/0x3a2 [] ? native_sched_clock+0x32/0x6b [] ? sched_clock+0x9/0xd [] do_vfs_ioctl+0x49e/0x4e4 [] sys_ioctl+0x5a/0x7c [] system_call_fastpath+0x16/0x1b RIP [] gup_huge_pud+0xf2/0x159 Signed-off-by: Youquan Song Reviewed-by: Andrea Arcangeli Signed-off-by: Andrew Morton --- diff --git a/mm/hugetlb.c b/mm/hugetlb.c index bb28a5f9db8d..73f17c0293c0 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c @@ -576,6 +576,7 @@ static void prep_compound_gigantic_page(struct page *page, unsigned long order) __SetPageHead(page); for (i = 1; i < nr_pages; i++, p = mem_map_next(p, page, i)) { __SetPageTail(p); + set_page_count(p, 0); p->first_page = page; } } diff --git a/mm/page_alloc.c b/mm/page_alloc.c index e51802d7c8ff..500cde18f841 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c @@ -356,8 +356,8 @@ void prep_compound_page(struct page *page, unsigned long order) __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; } }