From 8ed71bd12b61b31da7c8af8b5a452bd38ceee461 Mon Sep 17 00:00:00 2001 From: Christoph Lameter Date: Wed, 25 Jul 2007 20:05:38 -0700 Subject: [PATCH] compound pages: Allow freeing of compound pages via pagevec Allow the freeing of compound pages via pagevec. In release_pages() we currently special case for compound pages in order to be sure to always decrement the page count of the head page and not the tail page. However that redirection to the head page is only necessary for tail pages. So we can actually use PageTail instead of PageCompound there by avoiding the redirection to the first page. Tail page handling is not changed. The head page of a compound pages now represents single page large page. We do the usual processing including checking if its on the LRU and removing it (not useful right now but later when compound pages are on the LRU this will work). Then we add the compound page to the pagevec. Only head pages will end up on the pagevec not tail pages. In __pagevec_free() we then check if we are freeing a head page and if so call the destructor for the compound page. Signed-off-by: Christoph Lameter --- fs/reiserfs/file.c | 2 +- mm/page_alloc.c | 13 +++++++++++-- mm/swap.c | 8 +++++++- 3 files changed, 19 insertions(+), 4 deletions(-) Index: linux-2.6/mm/page_alloc.c =================================================================== --- linux-2.6.orig/mm/page_alloc.c 2007-08-30 21:43:38.000000000 -0700 +++ linux-2.6/mm/page_alloc.c 2007-08-30 21:43:46.000000000 -0700 @@ -1441,8 +1441,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 (PageHead(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/mm/swap.c =================================================================== --- linux-2.6.orig/mm/swap.c 2007-08-30 20:20:13.000000000 -0700 +++ linux-2.6/mm/swap.c 2007-08-30 21:43:46.000000000 -0700 @@ -263,7 +263,13 @@ void release_pages(struct page **pages, for (i = 0; i < nr; i++) { struct page *page = pages[i]; - if (unlikely(PageCompound(page))) { + /* + * If we have a tail page on the LRU then we need to + * decrement the page count of the head page. There + * is no further need to do anything since tail pages + * cannot be on the LRU. + */ + if (unlikely(PageTail(page))) { if (zone) { spin_unlock_irq(&zone->lru_lock); zone = NULL; Index: linux-2.6/fs/reiserfs/file.c =================================================================== --- linux-2.6.orig/fs/reiserfs/file.c 2007-08-30 21:43:55.000000000 -0700 +++ linux-2.6/fs/reiserfs/file.c 2007-08-30 21:44:08.000000000 -0700 @@ -748,7 +748,7 @@ static int reiserfs_copy_from_user_to_fi page_fault = __copy_from_user(page_address(page) + offset, buf, count); // Copy the data. /* Flush processor's dcache for this page */ - flush_dcache_page(page); + flush_mapping_page(page); kunmap(page); buf += count; write_bytes -= count;