|
31 | 31 | #include <linux/memcontrol.h>
|
32 | 32 | #include <linux/gfp.h>
|
33 | 33 | #include <linux/uio.h>
|
| 34 | +#include <linux/hugetlb.h> |
34 | 35 |
|
35 | 36 | #include "internal.h"
|
36 | 37 |
|
@@ -81,6 +82,19 @@ static void __put_compound_page(struct page *page)
|
81 | 82 |
|
82 | 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 | 98 | if (unlikely(PageTail(page))) {
|
85 | 99 | /* __split_huge_page_refcount can run under us */
|
86 | 100 | struct page *page_head = compound_trans_head(page);
|
@@ -184,38 +198,51 @@ bool __get_page_tail(struct page *page)
|
184 | 198 | * proper PT lock that already serializes against
|
185 | 199 | * split_huge_page().
|
186 | 200 | */
|
187 |
| - unsigned long flags; |
188 | 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. */ |
194 |
| - if (PageSlab(page_head)) { |
| 230 | + /* |
| 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 | 238 | if (likely(PageTail(page))) {
|
196 | 239 | __get_page_tail_foll(page, false);
|
197 |
| - return true; |
198 |
| - } else { |
199 |
| - put_page(page_head); |
200 |
| - return false; |
| 240 | + got = true; |
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 | 247 | return got;
|
221 | 248 | }
|
|
0 commit comments