Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

thp: add compound_trans_head() helper

Cleanup some code with common compound_trans_head helper.

Signed-off-by: Andrea Arcangeli <aarcange@redhat.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Johannes Weiner <jweiner@redhat.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Avi Kivity <avi@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Andrea Arcangeli and committed by
Linus Torvalds
22e5c47e 29ad768c

+35 -36
+18
include/linux/huge_mm.h
··· 126 126 return HPAGE_PMD_NR; 127 127 return 1; 128 128 } 129 + static inline struct page *compound_trans_head(struct page *page) 130 + { 131 + if (PageTail(page)) { 132 + struct page *head; 133 + head = page->first_page; 134 + smp_rmb(); 135 + /* 136 + * head may be a dangling pointer. 137 + * __split_huge_page_refcount clears PageTail before 138 + * overwriting first_page, so if PageTail is still 139 + * there it means the head pointer isn't dangling. 140 + */ 141 + if (PageTail(page)) 142 + return head; 143 + } 144 + return page; 145 + } 129 146 #else /* CONFIG_TRANSPARENT_HUGEPAGE */ 130 147 #define HPAGE_PMD_SHIFT ({ BUG(); 0; }) 131 148 #define HPAGE_PMD_MASK ({ BUG(); 0; }) ··· 161 144 do { } while (0) 162 145 #define wait_split_huge_page(__anon_vma, __pmd) \ 163 146 do { } while (0) 147 + #define compound_trans_head(page) compound_head(page) 164 148 static inline int hugepage_madvise(struct vm_area_struct *vma, 165 149 unsigned long *vm_flags, int advice) 166 150 {
+3 -12
mm/ksm.c
··· 415 415 static struct page *page_trans_compound_anon(struct page *page) 416 416 { 417 417 if (PageTransCompound(page)) { 418 - struct page *head; 419 - head = compound_head(page); 418 + struct page *head = compound_trans_head(page); 420 419 /* 421 - * head may be a dangling pointer. 422 - * __split_huge_page_refcount clears PageTail 423 - * before overwriting first_page, so if 424 - * PageTail is still there it means the head 425 - * pointer isn't dangling. 420 + * head may actually be splitted and freed from under 421 + * us but it's ok here. 426 422 */ 427 - if (head != page) { 428 - smp_rmb(); 429 - if (!PageTransCompound(page)) 430 - return NULL; 431 - } 432 423 if (PageAnon(head)) 433 424 return head; 434 425 }
+14 -24
virt/kvm/kvm_main.c
··· 104 104 inline int kvm_is_mmio_pfn(pfn_t pfn) 105 105 { 106 106 if (pfn_valid(pfn)) { 107 - struct page *head; 107 + int reserved; 108 108 struct page *tail = pfn_to_page(pfn); 109 - head = compound_head(tail); 109 + struct page *head = compound_trans_head(tail); 110 + reserved = PageReserved(head); 110 111 if (head != tail) { 111 - smp_rmb(); 112 112 /* 113 - * head may be a dangling pointer. 114 - * __split_huge_page_refcount clears PageTail 115 - * before overwriting first_page, so if 116 - * PageTail is still there it means the head 117 - * pointer isn't dangling. 113 + * "head" is not a dangling pointer 114 + * (compound_trans_head takes care of that) 115 + * but the hugepage may have been splitted 116 + * from under us (and we may not hold a 117 + * reference count on the head page so it can 118 + * be reused before we run PageReferenced), so 119 + * we've to check PageTail before returning 120 + * what we just read. 118 121 */ 119 - if (PageTail(tail)) { 120 - /* 121 - * the "head" is not a dangling 122 - * pointer but the hugepage may have 123 - * been splitted from under us (and we 124 - * may not hold a reference count on 125 - * the head page so it can be reused 126 - * before we run PageReferenced), so 127 - * we've to recheck PageTail before 128 - * returning what we just read. 129 - */ 130 - int reserved = PageReserved(head); 131 - smp_rmb(); 132 - if (PageTail(tail)) 133 - return reserved; 134 - } 122 + smp_rmb(); 123 + if (PageTail(tail)) 124 + return reserved; 135 125 } 136 126 return PageReserved(tail); 137 127 }