diff options
-rw-r--r-- | include/linux/hugetlb.h | 6 | ||||
-rw-r--r-- | mm/hugetlb.c | 17 | ||||
-rw-r--r-- | mm/swap.c | 143 |
3 files changed, 106 insertions, 60 deletions
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h index feaf0c7fb7d8..c8958f563116 100644 --- a/include/linux/hugetlb.h +++ b/include/linux/hugetlb.h | |||
@@ -31,6 +31,7 @@ struct hugepage_subpool *hugepage_new_subpool(long nr_blocks); | |||
31 | void hugepage_put_subpool(struct hugepage_subpool *spool); | 31 | void hugepage_put_subpool(struct hugepage_subpool *spool); |
32 | 32 | ||
33 | int PageHuge(struct page *page); | 33 | int PageHuge(struct page *page); |
34 | int PageHeadHuge(struct page *page_head); | ||
34 | 35 | ||
35 | void reset_vma_resv_huge_pages(struct vm_area_struct *vma); | 36 | void reset_vma_resv_huge_pages(struct vm_area_struct *vma); |
36 | int hugetlb_sysctl_handler(struct ctl_table *, int, void __user *, size_t *, loff_t *); | 37 | int hugetlb_sysctl_handler(struct ctl_table *, int, void __user *, size_t *, loff_t *); |
@@ -98,6 +99,11 @@ static inline int PageHuge(struct page *page) | |||
98 | return 0; | 99 | return 0; |
99 | } | 100 | } |
100 | 101 | ||
102 | static inline int PageHeadHuge(struct page *page_head) | ||
103 | { | ||
104 | return 0; | ||
105 | } | ||
106 | |||
101 | static inline void reset_vma_resv_huge_pages(struct vm_area_struct *vma) | 107 | static inline void reset_vma_resv_huge_pages(struct vm_area_struct *vma) |
102 | { | 108 | { |
103 | } | 109 | } |
diff --git a/mm/hugetlb.c b/mm/hugetlb.c index 7c5eb85ec645..40ad2c6e0ca9 100644 --- a/mm/hugetlb.c +++ b/mm/hugetlb.c | |||
@@ -690,6 +690,23 @@ int PageHuge(struct page *page) | |||
690 | } | 690 | } |
691 | EXPORT_SYMBOL_GPL(PageHuge); | 691 | EXPORT_SYMBOL_GPL(PageHuge); |
692 | 692 | ||
693 | /* | ||
694 | * PageHeadHuge() only returns true for hugetlbfs head page, but not for | ||
695 | * normal or transparent huge pages. | ||
696 | */ | ||
697 | int PageHeadHuge(struct page *page_head) | ||
698 | { | ||
699 | compound_page_dtor *dtor; | ||
700 | |||
701 | if (!PageHead(page_head)) | ||
702 | return 0; | ||
703 | |||
704 | dtor = get_compound_page_dtor(page_head); | ||
705 | |||
706 | return dtor == free_huge_page; | ||
707 | } | ||
708 | EXPORT_SYMBOL_GPL(PageHeadHuge); | ||
709 | |||
693 | pgoff_t __basepage_index(struct page *page) | 710 | pgoff_t __basepage_index(struct page *page) |
694 | { | 711 | { |
695 | struct page *page_head = compound_head(page); | 712 | struct page *page_head = compound_head(page); |
@@ -79,19 +79,6 @@ static void __put_compound_page(struct page *page) | |||
79 | 79 | ||
80 | static void put_compound_page(struct page *page) | 80 | static void put_compound_page(struct page *page) |
81 | { | 81 | { |
82 | /* | ||
83 | * hugetlbfs pages cannot be split from under us. If this is a | ||
84 | * hugetlbfs page, check refcount on head page and release the page if | ||
85 | * the refcount becomes zero. | ||
86 | */ | ||
87 | if (PageHuge(page)) { | ||
88 | page = compound_head(page); | ||
89 | if (put_page_testzero(page)) | ||
90 | __put_compound_page(page); | ||
91 | |||
92 | return; | ||
93 | } | ||
94 | |||
95 | if (unlikely(PageTail(page))) { | 82 | if (unlikely(PageTail(page))) { |
96 | /* __split_huge_page_refcount can run under us */ | 83 | /* __split_huge_page_refcount can run under us */ |
97 | struct page *page_head = compound_trans_head(page); | 84 | struct page *page_head = compound_trans_head(page); |
@@ -108,14 +95,31 @@ static void put_compound_page(struct page *page) | |||
108 | * still hot on arches that do not support | 95 | * still hot on arches that do not support |
109 | * this_cpu_cmpxchg_double(). | 96 | * this_cpu_cmpxchg_double(). |
110 | */ | 97 | */ |
111 | if (PageSlab(page_head)) { | 98 | if (PageSlab(page_head) || PageHeadHuge(page_head)) { |
112 | if (PageTail(page)) { | 99 | if (likely(PageTail(page))) { |
100 | /* | ||
101 | * __split_huge_page_refcount | ||
102 | * cannot race here. | ||
103 | */ | ||
104 | VM_BUG_ON(!PageHead(page_head)); | ||
105 | atomic_dec(&page->_mapcount); | ||
113 | if (put_page_testzero(page_head)) | 106 | if (put_page_testzero(page_head)) |
114 | VM_BUG_ON(1); | 107 | VM_BUG_ON(1); |
115 | 108 | if (put_page_testzero(page_head)) | |
116 | atomic_dec(&page->_mapcount); | 109 | __put_compound_page(page_head); |
117 | goto skip_lock_tail; | 110 | return; |
118 | } else | 111 | } else |
112 | /* | ||
113 | * __split_huge_page_refcount | ||
114 | * run before us, "page" was a | ||
115 | * THP tail. The split | ||
116 | * page_head has been freed | ||
117 | * and reallocated as slab or | ||
118 | * hugetlbfs page of smaller | ||
119 | * order (only possible if | ||
120 | * reallocated as slab on | ||
121 | * x86). | ||
122 | */ | ||
119 | goto skip_lock; | 123 | goto skip_lock; |
120 | } | 124 | } |
121 | /* | 125 | /* |
@@ -129,8 +133,27 @@ static void put_compound_page(struct page *page) | |||
129 | /* __split_huge_page_refcount run before us */ | 133 | /* __split_huge_page_refcount run before us */ |
130 | compound_unlock_irqrestore(page_head, flags); | 134 | compound_unlock_irqrestore(page_head, flags); |
131 | skip_lock: | 135 | skip_lock: |
132 | if (put_page_testzero(page_head)) | 136 | if (put_page_testzero(page_head)) { |
133 | __put_single_page(page_head); | 137 | /* |
138 | * The head page may have been | ||
139 | * freed and reallocated as a | ||
140 | * compound page of smaller | ||
141 | * order and then freed again. | ||
142 | * All we know is that it | ||
143 | * cannot have become: a THP | ||
144 | * page, a compound page of | ||
145 | * higher order, a tail page. | ||
146 | * That is because we still | ||
147 | * hold the refcount of the | ||
148 | * split THP tail and | ||
149 | * page_head was the THP head | ||
150 | * before the split. | ||
151 | */ | ||
152 | if (PageHead(page_head)) | ||
153 | __put_compound_page(page_head); | ||
154 | else | ||
155 | __put_single_page(page_head); | ||
156 | } | ||
134 | out_put_single: | 157 | out_put_single: |
135 | if (put_page_testzero(page)) | 158 | if (put_page_testzero(page)) |
136 | __put_single_page(page); | 159 | __put_single_page(page); |
@@ -152,7 +175,6 @@ out_put_single: | |||
152 | VM_BUG_ON(atomic_read(&page->_count) != 0); | 175 | VM_BUG_ON(atomic_read(&page->_count) != 0); |
153 | compound_unlock_irqrestore(page_head, flags); | 176 | compound_unlock_irqrestore(page_head, flags); |
154 | 177 | ||
155 | skip_lock_tail: | ||
156 | if (put_page_testzero(page_head)) { | 178 | if (put_page_testzero(page_head)) { |
157 | if (PageHead(page_head)) | 179 | if (PageHead(page_head)) |
158 | __put_compound_page(page_head); | 180 | __put_compound_page(page_head); |
@@ -195,51 +217,52 @@ bool __get_page_tail(struct page *page) | |||
195 | * proper PT lock that already serializes against | 217 | * proper PT lock that already serializes against |
196 | * split_huge_page(). | 218 | * split_huge_page(). |
197 | */ | 219 | */ |
220 | unsigned long flags; | ||
198 | bool got = false; | 221 | bool got = false; |
199 | struct page *page_head; | 222 | struct page *page_head = compound_trans_head(page); |
200 | |||
201 | /* | ||
202 | * If this is a hugetlbfs page it cannot be split under us. Simply | ||
203 | * increment refcount for the head page. | ||
204 | */ | ||
205 | if (PageHuge(page)) { | ||
206 | page_head = compound_head(page); | ||
207 | atomic_inc(&page_head->_count); | ||
208 | got = true; | ||
209 | } else { | ||
210 | unsigned long flags; | ||
211 | 223 | ||
212 | page_head = compound_trans_head(page); | 224 | if (likely(page != page_head && get_page_unless_zero(page_head))) { |
213 | if (likely(page != page_head && | 225 | /* Ref to put_compound_page() comment. */ |
214 | get_page_unless_zero(page_head))) { | 226 | if (PageSlab(page_head) || PageHeadHuge(page_head)) { |
215 | |||
216 | /* Ref to put_compound_page() comment. */ | ||
217 | if (PageSlab(page_head)) { | ||
218 | if (likely(PageTail(page))) { | ||
219 | __get_page_tail_foll(page, false); | ||
220 | return true; | ||
221 | } else { | ||
222 | put_page(page_head); | ||
223 | return false; | ||
224 | } | ||
225 | } | ||
226 | |||
227 | /* | ||
228 | * page_head wasn't a dangling pointer but it | ||
229 | * may not be a head page anymore by the time | ||
230 | * we obtain the lock. That is ok as long as it | ||
231 | * can't be freed from under us. | ||
232 | */ | ||
233 | flags = compound_lock_irqsave(page_head); | ||
234 | /* here __split_huge_page_refcount won't run anymore */ | ||
235 | if (likely(PageTail(page))) { | 227 | if (likely(PageTail(page))) { |
228 | /* | ||
229 | * This is a hugetlbfs page or a slab | ||
230 | * page. __split_huge_page_refcount | ||
231 | * cannot race here. | ||
232 | */ | ||
233 | VM_BUG_ON(!PageHead(page_head)); | ||
236 | __get_page_tail_foll(page, false); | 234 | __get_page_tail_foll(page, false); |
237 | got = true; | 235 | return true; |
238 | } | 236 | } else { |
239 | compound_unlock_irqrestore(page_head, flags); | 237 | /* |
240 | if (unlikely(!got)) | 238 | * __split_huge_page_refcount run |
239 | * before us, "page" was a THP | ||
240 | * tail. The split page_head has been | ||
241 | * freed and reallocated as slab or | ||
242 | * hugetlbfs page of smaller order | ||
243 | * (only possible if reallocated as | ||
244 | * slab on x86). | ||
245 | */ | ||
241 | put_page(page_head); | 246 | put_page(page_head); |
247 | return false; | ||
248 | } | ||
249 | } | ||
250 | |||
251 | /* | ||
252 | * page_head wasn't a dangling pointer but it | ||
253 | * may not be a head page anymore by the time | ||
254 | * we obtain the lock. That is ok as long as it | ||
255 | * can't be freed from under us. | ||
256 | */ | ||
257 | flags = compound_lock_irqsave(page_head); | ||
258 | /* here __split_huge_page_refcount won't run anymore */ | ||
259 | if (likely(PageTail(page))) { | ||
260 | __get_page_tail_foll(page, false); | ||
261 | got = true; | ||
242 | } | 262 | } |
263 | compound_unlock_irqrestore(page_head, flags); | ||
264 | if (unlikely(!got)) | ||
265 | put_page(page_head); | ||
243 | } | 266 | } |
244 | return got; | 267 | return got; |
245 | } | 268 | } |