diff options
| author | Andrea Arcangeli <aarcange@redhat.com> | 2011-01-13 18:47:20 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 20:32:48 -0500 |
| commit | 22e5c47ee238abe636655c3862ed28d6eb084ad4 (patch) | |
| tree | 4a4e7d330cbef6c99a8914de482eb0e8daba2485 | |
| parent | 29ad768cfc08611a4c1070d0f13f82eeea2bac7b (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.h | 18 | ||||
| -rw-r--r-- | mm/ksm.c | 15 | ||||
| -rw-r--r-- | virt/kvm/kvm_main.c | 38 |
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 | } |
| 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 | #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) | ||
| 147 | static inline int hugepage_madvise(struct vm_area_struct *vma, | 165 | static 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 | { |
| @@ -415,20 +415,11 @@ out: | |||
| 415 | static struct page *page_trans_compound_anon(struct page *page) | 415 | static 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; | |||
| 104 | inline int kvm_is_mmio_pfn(pfn_t pfn) | 104 | inline 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 | } |
