[PATCH] Use separate page bit for tail We cannot use PG_reclaim for compound pages if we put them onto the LRU. Make them use a separate page flag. Add compound handling to pagevec_free. Signed-off-by: Christoph Lameter --- include/linux/mm.h | 1 - include/linux/page-flags.h | 43 ++++++++++++------------------------------- mm/internal.h | 2 +- mm/page_alloc.c | 20 ++++++++++++-------- 4 files changed, 25 insertions(+), 41 deletions(-) Index: linux-2.6.21-rc7-mm1/include/linux/page-flags.h =================================================================== --- linux-2.6.21-rc7-mm1.orig/include/linux/page-flags.h 2007-04-25 07:38:25.000000000 -0700 +++ linux-2.6.21-rc7-mm1/include/linux/page-flags.h 2007-04-25 08:11:47.000000000 -0700 @@ -83,7 +83,8 @@ #define PG_private 11 /* If pagecache, has fs-private data */ #define PG_writeback 12 /* Page is under writeback */ -#define PG_compound 14 /* Part of a compound page */ +#define PG_head 13 /* Page is head of a compound page */ +#define PG_tail 14 /* Page is tail of a compound page */ #define PG_swapcache 15 /* Swap page: swp_entry_t in private */ #define PG_mappedtodisk 16 /* Has blocks allocated on-disk */ @@ -95,6 +96,7 @@ #define PG_readahead 21 /* Reminder to do read-ahead */ + /* PG_owner_priv_1 users should have descriptive aliases */ #define PG_checked PG_owner_priv_1 /* Used by some filesystems */ @@ -218,37 +220,16 @@ static inline void SetPageUptodate(struc #define ClearPageLazyFree(page) clear_bit(PG_lazyfree, &(page)->flags) #define __ClearPageLazyFree(page) __clear_bit(PG_lazyfree, &(page)->flags) -#define PageCompound(page) test_bit(PG_compound, &(page)->flags) -#define __SetPageCompound(page) __set_bit(PG_compound, &(page)->flags) -#define __ClearPageCompound(page) __clear_bit(PG_compound, &(page)->flags) - -/* - * PG_reclaim is used in combination with PG_compound to mark the - * head and tail of a compound page - * - * PG_compound & PG_reclaim => Tail page - * PG_compound & ~PG_reclaim => Head page - */ - -#define PG_head_tail_mask ((1L << PG_compound) | (1L << PG_reclaim)) - -#define PageTail(page) ((page->flags & PG_head_tail_mask) \ - == PG_head_tail_mask) - -static inline void __SetPageTail(struct page *page) -{ - page->flags |= PG_head_tail_mask; -} - -static inline void __ClearPageTail(struct page *page) -{ - page->flags &= ~PG_head_tail_mask; -} +#define PageHead(page) test_bit(PG_head, &(page)->flags) +#define __SetPageHead(page) __set_bit(PG_head, &(page)->flags) +#define __ClearPageHead(page) __clear_bit(PG_head, &(page)->flags) + +#define PageTail(page) test_bit(PG_tail, &(page->flags)) +#define __SetPageTail(page) __set_bit(PG_tail, &(page)->flags) +#define __ClearPageTail(page) __clear_bit(PG_tail, &(page)->flags) -#define PageHead(page) ((page->flags & PG_head_tail_mask) \ - == (1L << PG_compound)) -#define __SetPageHead(page) __SetPageCompound(page) -#define __ClearPageHead(page) __ClearPageCompound(page) +#define PageCompound(page) ((page)->flags & \ + ((1L << PG_head) | (1L << PG_tail))) #ifdef CONFIG_SWAP #define PageSwapCache(page) test_bit(PG_swapcache, &(page)->flags) Index: linux-2.6.21-rc7-mm1/mm/page_alloc.c =================================================================== --- linux-2.6.21-rc7-mm1.orig/mm/page_alloc.c 2007-04-25 07:38:25.000000000 -0700 +++ linux-2.6.21-rc7-mm1/mm/page_alloc.c 2007-04-25 07:38:57.000000000 -0700 @@ -485,18 +485,13 @@ static inline int free_pages_check(struc 1 << PG_private | 1 << PG_locked | 1 << PG_active | + 1 << PG_reclaim | 1 << PG_slab | 1 << PG_swapcache | 1 << PG_writeback | 1 << PG_reserved | 1 << PG_buddy )))) bad_page(page); - /* - * PageReclaim == PageTail. It is only an error - * for PageReclaim to be set if PageCompound is clear. - */ - if (unlikely(!PageCompound(page) && PageReclaim(page))) - bad_page(page); if (PageDirty(page)) __ClearPageDirty(page); if (PageLazyFree(page)) @@ -1778,8 +1773,17 @@ void __pagevec_free(struct pagevec *pvec { int i = pagevec_count(pvec); - while (--i >= 0) - free_hot_cold_page(pvec->pages[i], pvec->cold); + while (--i >= 0) { + struct page *page = pvec->pages[i]; + + if (PageCompound(page)) { + compound_page_dtor *dtor; + + dtor = get_compound_page_dtor(page); + (*dtor)(page); + } else + free_hot_cold_page(page, pvec->cold); + } } fastcall void __free_pages(struct page *page, unsigned int order) Index: linux-2.6.21-rc7-mm1/include/linux/mm.h =================================================================== --- linux-2.6.21-rc7-mm1.orig/include/linux/mm.h 2007-04-25 07:38:25.000000000 -0700 +++ linux-2.6.21-rc7-mm1/include/linux/mm.h 2007-04-25 08:45:31.000000000 -0700 @@ -293,7 +293,6 @@ static inline int put_page_testzero(stru */ static inline int get_page_unless_zero(struct page *page) { - VM_BUG_ON(PageCompound(page)); return atomic_inc_not_zero(&page->_count); } Index: linux-2.6.21-rc7-mm1/mm/internal.h =================================================================== --- linux-2.6.21-rc7-mm1.orig/mm/internal.h 2007-04-25 07:38:25.000000000 -0700 +++ linux-2.6.21-rc7-mm1/mm/internal.h 2007-04-25 07:38:57.000000000 -0700 @@ -24,7 +24,7 @@ static inline void set_page_count(struct */ static inline void set_page_refcounted(struct page *page) { - VM_BUG_ON(PageCompound(page) && PageTail(page)); + VM_BUG_ON(PageTail(page)); VM_BUG_ON(atomic_read(&page->_count)); set_page_count(page, 1); }