diff options
Diffstat (limited to 'mm/swap.c')
-rw-r--r-- | mm/swap.c | 77 |
1 files changed, 52 insertions, 25 deletions
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/memcontrol.h> | 31 | #include <linux/memcontrol.h> |
32 | #include <linux/gfp.h> | 32 | #include <linux/gfp.h> |
33 | #include <linux/uio.h> | 33 | #include <linux/uio.h> |
34 | #include <linux/hugetlb.h> | ||
34 | 35 | ||
35 | #include "internal.h" | 36 | #include "internal.h" |
36 | 37 | ||
@@ -81,6 +82,19 @@ static void __put_compound_page(struct page *page) | |||
81 | 82 | ||
82 | static void put_compound_page(struct page *page) | 83 | static void put_compound_page(struct page *page) |
83 | { | 84 | { |
85 | /* | ||
86 | * hugetlbfs pages cannot be split from under us. If this is a | ||
87 | * hugetlbfs page, check refcount on head page and release the page if | ||
88 | * the refcount becomes zero. | ||
89 | */ | ||
90 | if (PageHuge(page)) { | ||
91 | page = compound_head(page); | ||
92 | if (put_page_testzero(page)) | ||
93 | __put_compound_page(page); | ||
94 | |||
95 | return; | ||
96 | } | ||
97 | |||
84 | if (unlikely(PageTail(page))) { | 98 | if (unlikely(PageTail(page))) { |
85 | /* __split_huge_page_refcount can run under us */ | 99 | /* __split_huge_page_refcount can run under us */ |
86 | struct page *page_head = compound_trans_head(page); | 100 | struct page *page_head = compound_trans_head(page); |
@@ -184,38 +198,51 @@ bool __get_page_tail(struct page *page) | |||
184 | * proper PT lock that already serializes against | 198 | * proper PT lock that already serializes against |
185 | * split_huge_page(). | 199 | * split_huge_page(). |
186 | */ | 200 | */ |
187 | unsigned long flags; | ||
188 | bool got = false; | 201 | bool got = false; |
189 | struct page *page_head = compound_trans_head(page); | 202 | struct page *page_head; |
190 | 203 | ||
191 | if (likely(page != page_head && get_page_unless_zero(page_head))) { | 204 | /* |
205 | * If this is a hugetlbfs page it cannot be split under us. Simply | ||
206 | * increment refcount for the head page. | ||
207 | */ | ||
208 | if (PageHuge(page)) { | ||
209 | page_head = compound_head(page); | ||
210 | atomic_inc(&page_head->_count); | ||
211 | got = true; | ||
212 | } else { | ||
213 | unsigned long flags; | ||
214 | |||
215 | page_head = compound_trans_head(page); | ||
216 | if (likely(page != page_head && | ||
217 | get_page_unless_zero(page_head))) { | ||
218 | |||
219 | /* Ref to put_compound_page() comment. */ | ||
220 | if (PageSlab(page_head)) { | ||
221 | if (likely(PageTail(page))) { | ||
222 | __get_page_tail_foll(page, false); | ||
223 | return true; | ||
224 | } else { | ||
225 | put_page(page_head); | ||
226 | return false; | ||
227 | } | ||
228 | } | ||
192 | 229 | ||
193 | /* Ref to put_compound_page() comment. */ | 230 | /* |
194 | if (PageSlab(page_head)) { | 231 | * page_head wasn't a dangling pointer but it |
232 | * may not be a head page anymore by the time | ||
233 | * we obtain the lock. That is ok as long as it | ||
234 | * can't be freed from under us. | ||
235 | */ | ||
236 | flags = compound_lock_irqsave(page_head); | ||
237 | /* here __split_huge_page_refcount won't run anymore */ | ||
195 | if (likely(PageTail(page))) { | 238 | if (likely(PageTail(page))) { |
196 | __get_page_tail_foll(page, false); | 239 | __get_page_tail_foll(page, false); |
197 | return true; | 240 | got = true; |
198 | } else { | ||
199 | put_page(page_head); | ||
200 | return false; | ||
201 | } | 241 | } |
242 | compound_unlock_irqrestore(page_head, flags); | ||
243 | if (unlikely(!got)) | ||
244 | put_page(page_head); | ||
202 | } | 245 | } |
203 | |||
204 | /* | ||
205 | * page_head wasn't a dangling pointer but it | ||
206 | * may not be a head page anymore by the time | ||
207 | * we obtain the lock. That is ok as long as it | ||
208 | * can't be freed from under us. | ||
209 | */ | ||
210 | flags = compound_lock_irqsave(page_head); | ||
211 | /* here __split_huge_page_refcount won't run anymore */ | ||
212 | if (likely(PageTail(page))) { | ||
213 | __get_page_tail_foll(page, false); | ||
214 | got = true; | ||
215 | } | ||
216 | compound_unlock_irqrestore(page_head, flags); | ||
217 | if (unlikely(!got)) | ||
218 | put_page(page_head); | ||
219 | } | 246 | } |
220 | return got; | 247 | return got; |
221 | } | 248 | } |