diff options
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r-- | mm/page_alloc.c | 29 |
1 files changed, 20 insertions, 9 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index 542fc088ff50..fc241fe295ab 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -225,7 +225,7 @@ static void bad_page(struct page *page) | |||
225 | 225 | ||
226 | static void free_compound_page(struct page *page) | 226 | static void free_compound_page(struct page *page) |
227 | { | 227 | { |
228 | __free_pages_ok(page, (unsigned long)page[1].lru.prev); | 228 | __free_pages_ok(page, compound_order(page)); |
229 | } | 229 | } |
230 | 230 | ||
231 | static void prep_compound_page(struct page *page, unsigned long order) | 231 | static void prep_compound_page(struct page *page, unsigned long order) |
@@ -234,12 +234,14 @@ static void prep_compound_page(struct page *page, unsigned long order) | |||
234 | int nr_pages = 1 << order; | 234 | int nr_pages = 1 << order; |
235 | 235 | ||
236 | set_compound_page_dtor(page, free_compound_page); | 236 | set_compound_page_dtor(page, free_compound_page); |
237 | page[1].lru.prev = (void *)order; | 237 | set_compound_order(page, order); |
238 | for (i = 0; i < nr_pages; i++) { | 238 | __SetPageCompound(page); |
239 | for (i = 1; i < nr_pages; i++) { | ||
239 | struct page *p = page + i; | 240 | struct page *p = page + i; |
240 | 241 | ||
242 | __SetPageTail(p); | ||
241 | __SetPageCompound(p); | 243 | __SetPageCompound(p); |
242 | set_page_private(p, (unsigned long)page); | 244 | p->first_page = page; |
243 | } | 245 | } |
244 | } | 246 | } |
245 | 247 | ||
@@ -248,15 +250,19 @@ static void destroy_compound_page(struct page *page, unsigned long order) | |||
248 | int i; | 250 | int i; |
249 | int nr_pages = 1 << order; | 251 | int nr_pages = 1 << order; |
250 | 252 | ||
251 | if (unlikely((unsigned long)page[1].lru.prev != order)) | 253 | if (unlikely(compound_order(page) != order)) |
252 | bad_page(page); | 254 | bad_page(page); |
253 | 255 | ||
254 | for (i = 0; i < nr_pages; i++) { | 256 | if (unlikely(!PageCompound(page))) |
257 | bad_page(page); | ||
258 | __ClearPageCompound(page); | ||
259 | for (i = 1; i < nr_pages; i++) { | ||
255 | struct page *p = page + i; | 260 | struct page *p = page + i; |
256 | 261 | ||
257 | if (unlikely(!PageCompound(p) | | 262 | if (unlikely(!PageCompound(p) | !PageTail(p) | |
258 | (page_private(p) != (unsigned long)page))) | 263 | (p->first_page != page))) |
259 | bad_page(page); | 264 | bad_page(page); |
265 | __ClearPageTail(p); | ||
260 | __ClearPageCompound(p); | 266 | __ClearPageCompound(p); |
261 | } | 267 | } |
262 | } | 268 | } |
@@ -429,13 +435,18 @@ static inline int free_pages_check(struct page *page) | |||
429 | 1 << PG_private | | 435 | 1 << PG_private | |
430 | 1 << PG_locked | | 436 | 1 << PG_locked | |
431 | 1 << PG_active | | 437 | 1 << PG_active | |
432 | 1 << PG_reclaim | | ||
433 | 1 << PG_slab | | 438 | 1 << PG_slab | |
434 | 1 << PG_swapcache | | 439 | 1 << PG_swapcache | |
435 | 1 << PG_writeback | | 440 | 1 << PG_writeback | |
436 | 1 << PG_reserved | | 441 | 1 << PG_reserved | |
437 | 1 << PG_buddy )))) | 442 | 1 << PG_buddy )))) |
438 | bad_page(page); | 443 | bad_page(page); |
444 | /* | ||
445 | * PageReclaim == PageTail. It is only an error | ||
446 | * for PageReclaim to be set if PageCompound is clear. | ||
447 | */ | ||
448 | if (unlikely(!PageCompound(page) && PageReclaim(page))) | ||
449 | bad_page(page); | ||
439 | if (PageDirty(page)) | 450 | if (PageDirty(page)) |
440 | __ClearPageDirty(page); | 451 | __ClearPageDirty(page); |
441 | /* | 452 | /* |