aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrea Arcangeli <aarcange@redhat.com>2011-01-13 18:47:20 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-01-13 20:32:48 -0500
commit22e5c47ee238abe636655c3862ed28d6eb084ad4 (patch)
tree4a4e7d330cbef6c99a8914de482eb0e8daba2485
parent29ad768cfc08611a4c1070d0f13f82eeea2bac7b (diff)
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>
-rw-r--r--include/linux/huge_mm.h18
-rw-r--r--mm/ksm.c15
-rw-r--r--virt/kvm/kvm_main.c38
3 files changed, 35 insertions, 36 deletions
diff --git a/include/linux/huge_mm.h b/include/linux/huge_mm.h
index bddfba1d7b85..8e6c8c42bc3c 100644
--- a/include/linux/huge_mm.h
+++ b/include/linux/huge_mm.h
@@ -126,6 +126,23 @@ static inline int hpage_nr_pages(struct page *page)
126 return HPAGE_PMD_NR; 126 return HPAGE_PMD_NR;
127 return 1; 127 return 1;
128} 128}
129static 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#else /* CONFIG_TRANSPARENT_HUGEPAGE */ 146#else /* CONFIG_TRANSPARENT_HUGEPAGE */
130#define HPAGE_PMD_SHIFT ({ BUG(); 0; }) 147#define HPAGE_PMD_SHIFT ({ BUG(); 0; })
131#define HPAGE_PMD_MASK ({ BUG(); 0; }) 148#define HPAGE_PMD_MASK ({ BUG(); 0; })
@@ -144,6 +161,7 @@ static inline int split_huge_page(struct page *page)
144 do { } while (0) 161 do { } while (0)
145#define wait_split_huge_page(__anon_vma, __pmd) \ 162#define wait_split_huge_page(__anon_vma, __pmd) \
146 do { } while (0) 163 do { } while (0)
164#define compound_trans_head(page) compound_head(page)
147static inline int hugepage_madvise(struct vm_area_struct *vma, 165static inline int hugepage_madvise(struct vm_area_struct *vma,
148 unsigned long *vm_flags, int advice) 166 unsigned long *vm_flags, int advice)
149{ 167{
diff --git a/mm/ksm.c b/mm/ksm.c
index 4d5a681923bb..33781de0b6bf 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -415,20 +415,11 @@ out:
415static struct page *page_trans_compound_anon(struct page *page) 415static struct page *page_trans_compound_anon(struct page *page)
416{ 416{
417 if (PageTransCompound(page)) { 417 if (PageTransCompound(page)) {
418 struct page *head; 418 struct page *head = compound_trans_head(page);
419 head = compound_head(page);
420 /* 419 /*
421 * head may be a dangling pointer. 420 * head may actually be splitted and freed from under
422 * __split_huge_page_refcount clears PageTail 421 * us but it's ok here.
423 * before overwriting first_page, so if
424 * PageTail is still there it means the head
425 * pointer isn't dangling.
426 */ 422 */
427 if (head != page) {
428 smp_rmb();
429 if (!PageTransCompound(page))
430 return NULL;
431 }
432 if (PageAnon(head)) 423 if (PageAnon(head))
433 return head; 424 return head;
434 } 425 }
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 4286d4766510..f29abeb6a912 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -104,34 +104,24 @@ static pfn_t fault_pfn;
104inline int kvm_is_mmio_pfn(pfn_t pfn) 104inline int kvm_is_mmio_pfn(pfn_t pfn)
105{ 105{
106 if (pfn_valid(pfn)) { 106 if (pfn_valid(pfn)) {
107 struct page *head; 107 int reserved;
108 struct page *tail = pfn_to_page(pfn); 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 if (head != tail) { 111 if (head != tail) {
111 smp_rmb();
112 /* 112 /*
113 * head may be a dangling pointer. 113 * "head" is not a dangling pointer
114 * __split_huge_page_refcount clears PageTail 114 * (compound_trans_head takes care of that)
115 * before overwriting first_page, so if 115 * but the hugepage may have been splitted
116 * PageTail is still there it means the head 116 * from under us (and we may not hold a
117 * pointer isn't dangling. 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)) { 122 smp_rmb();
120 /* 123 if (PageTail(tail))
121 * the "head" is not a dangling 124 return reserved;
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 }
135 } 125 }
136 return PageReserved(tail); 126 return PageReserved(tail);
137 } 127 }