MM cleanups
Subsystems (4)
PATCH 1/2 MM cleanups
The attached patch does some cleaning up of the MM code preparatory to overhauling the high-order page handling:
(1) Trailing spaces have been cleaned up on lines in page_alloc.c and bootmem.c.
(2) bootmem.c now has a separate path to release pages to the main allocator that bypasses many of the checks performed on struct pages.
(3) __pagevec_free() has moved to swap.c with all the other pagevec functions.
(4) put_page() has moved to page_alloc.c with all the other related functions. This could be relegated to a separate file, but since there are many other conditionals in page_alloc.c, what's the point?
---
warthog>diffstat mmcleanup-2610rc2mm3.diff
bootmem.c | 35 ++++++++------- internal.h | 3 - page_alloc.c | 136 +++++++++++++++++++++++++++++++++++++---------------------- swap.c | 29 +++--------- 4 files changed, 116 insertions(+), 87 deletions(-)
mm/bootmem.c renamed from warthog/kernels/linux-2.6.10-rc2-mm3/mm/bootmem.c +19 -16
@@ -89,7 +89,7 @@ static void __init reserve_bootmem_core(* fully reserved. */ unsigned long sidx = (addr - bdata->node_boot_start)/PAGE_SIZE ; -unsigned long eidx = (addr + size - bdata->node_boot_start + +unsigned long eidx = (addr + size - bdata->node_boot_start +PAGE_SIZE -1 )/PAGE_SIZE ;unsigned long end = (addr + size +PAGE_SIZE -1 )/PAGE_SIZE ;
@@ -174,7 +174,7 @@ __alloc_bootmem_core(struct bootmem_data* We try to allocate bootmem pages above 'goal' * first, then we try to allocate lower pages. */ -if (goal && (goal >= bdata->node_boot_start) && +if (goal && (goal >= bdata->node_boot_start) && ((goal >>PAGE_SHIFT ) < bdata->node_low_pfn)) { preferred = goal - bdata->node_boot_start;
@@ -264,7 +264,7 @@ static unsigned long __init free_all_boobootmem_data_t *bdata = pgdat->bdata;unsigned long i, count, total =0 ;unsigned long idx; -unsigned long *map; +unsigned long *map;int gofast =0 ;BUG_ON (!bdata->node_bootmem_map);
@@ -274,55 +274,59 @@ static unsigned long __init free_all_boo page =virt_to_page (phys_to_virt (bdata->node_boot_start)); idx = bdata->node_low_pfn - (bdata->node_boot_start >>PAGE_SHIFT ); map = bdata->node_bootmem_map; +/* Check physaddr is O(LOG2(BITS_PER_LONG)) page aligned */ if (bdata->node_boot_start ==0 ||ffs (bdata->node_boot_start) -PAGE_SHIFT >ffs (BITS_PER_LONG )) gofast =1 ; +for (i =0 ; i < idx; ) {unsigned long v = ~map[i /BITS_PER_LONG ]; +if (gofast && v == ~0UL ) {int j, order; count +=BITS_PER_LONG ;__ClearPageReserved (page); order =ffs (BITS_PER_LONG ) -1 ; -set_page_refs (page, order);for (j =1 ; j <BITS_PER_LONG ; j++) {if (j +16 <BITS_PER_LONG )prefetchw (page + j +16 );__ClearPageReserved (page + j); } -__free_pages (page, order); +__free_pages_bootmem (page, order); i +=BITS_PER_LONG ; page +=BITS_PER_LONG ; + }else if (v) {unsigned long m;for (m =1 ; m && i < idx; m<<=1 , page++, i++) {if (v & m) { count++;__ClearPageReserved (page); -set_page_refs (page,0 ); -__free_page (page); +__free_pages_bootmem (page,0 ); } } + }else { - i+=BITS_PER_LONG ; + i +=BITS_PER_LONG ; page +=BITS_PER_LONG ; } } total += count;/* -* Now free the allocator bitmap itself, it's not -* needed anymore: +* Now free the allocator bitmap itself, it's not needed anymore: */ page =virt_to_page (bdata->node_bootmem_map); - count =0 ; -for (i =0 ; i < ((bdata->node_low_pfn-(bdata->node_boot_start >>PAGE_SHIFT ))/8 +PAGE_SIZE -1 )/PAGE_SIZE ; i++,page++) { - count++; + + count = bdata->node_low_pfn - (bdata->node_boot_start >>PAGE_SHIFT ); + count = ((count /8 ) +PAGE_SIZE -1 ) >>PAGE_SHIFT ; + +for (i = count; i >0 ; i--) {__ClearPageReserved (page); -set_page_count (page,1 ); -__free_page (page); +__free_pages_bootmem (page,0 ); + page++; } total += count; bdata->node_bootmem_map =NULL ;
@@ -402,4 +406,3 @@ void * __init __alloc_bootmem_node (pg_dreturn __alloc_bootmem (size, align, goal); } -
mm/internal.h renamed from warthog/kernels/linux-2.6.10-rc2-mm3/mm/internal.h +2 -1
@@ -10,4 +10,5 @@*/ /* page_alloc.c */ -extern void set_page_refs (struct page *page,int order); +extern void fastcall free_hot_cold_page(struct page *page, int cold); +extern fastcall void __init __free_pages_bootmem(struct page *page, unsigned int order);
mm/page_alloc.c renamed from warthog/kernels/linux-2.6.10-rc2-mm3/mm/page_alloc.c +86 -50
273 lines not on this page · raw message
mm/swap.c renamed from warthog/kernels/linux-2.6.10-rc2-mm3/mm/swap.c +9 -20
@@ -30,30 +30,11 @@#include <linux/cpu.h> #include <linux/notifier.h> #include <linux/init.h> +#include "internal.h" /* How many pages do we try to swap or page in/out together? */ int page_cluster; -#ifdef CONFIG_HUGETLB_PAGE - -void put_page (struct page *page) -{ -if (unlikely (PageCompound (page))) { - page = (struct page *)page->private; -if (put_page_testzero (page)) { -void (*dtor)(struct page *page); - - dtor = (void (*)(struct page *))page[1 ].mapping; - (*dtor)(page); - } -return ; - } -if (!PageReserved (page) &&put_page_testzero (page)) -__page_cache_release (page); -} -EXPORT_SYMBOL (put_page); -#endif -/* * Writeback is about to end against a page which has been marked for immediate * reclaim. If it still appears to be reclaimable, move it to the tail of the
@@ -242,6 +223,14 @@ void release_pages(struct page **pages,pagevec_free (&pages_to_free); } +void __pagevec_free (struct pagevec *pvec) +{ +int i =pagevec_count (pvec); + +while (--i >=0 ) +free_hot_cold_page (pvec->pages[i], pvec->cold); +} +/* * The pages which we're about to release may be in the deferred lru-addition * queues. That would prevent them from really being freed right now. That's
PATCH 2/2 High-order page management overhaul
The attached patch overhauls high-order page handling.
(1) A new bit flag PG_compound_slave has been added. This is used to mark the second+ subpages of a compound page, thus making get_page() and put_page() able to determine the need to perform weird stuff quickly.
This could be changed to do horribly things with the page count or to abuse the page->lru member instead of eating another page flag.
(2) Compound page metadata is now always set on high-order pages when allocating and always checked when freeing. This metadata is mostly as it was before:
- PG_compound is set on all subpages
- PG_compound_slave is set on all but the first subpage <--- [1]
- page[1].index holds the compound page order
- page[1...N-1].private points to page[0]. <--- [2]
- page[1].mapping may hold a destructor function for put_page()
This is now done in prep_new_page().
[1] New metadata addition
[2] Page private is no longer modified on page[0]
(3) __page_first() is now provided to find the first page of any page set (even single page sets).
(4) A new config option ENHANCED_COMPOUND_PAGES is now available. This is only set on !MMU or HUGETLB_PAGE. It causes __page_first() to dereference page->private if PG_compound_slave is set.
(5) __GFP_COMP is no longer required since compound metadata is always now set.
(6) compound_page_order() is now available. This will indicate the order of any page, high-order or not.
Since it is now trivial to work out the order of any page, free_pages() and co could all lose their order arguments.
(7) bad_page() now prints more information, including information about more pages in the case of a compound page.
(8) prep_compound_page() and destroy_compound_page() have been absorbed.
(9) A lot more unlikely() clauses have been inserted in the free page checking functions.
(10) The !MMU bits have all gone from page_alloc.c.
(11) There's now a page destructor prototype and a function to set the destructor on compound pages.
---
warthog>diffstat compound-2610rc2mm3-2.diff
include/linux/gfp.h | 3 include/linux/mm.h | 65 ++++++--- include/linux/page-flags.h | 6 init/Kconfig | 13 + mm/hugetlb.c | 6 mm/page_alloc.c | 325 +++++++++++++++++++++++++++------------------ 6 files changed, 269 insertions(+), 149 deletions(-)
include/linux/gfp.h +1 -2
@@ -36,7 +36,6 @@ struct vm_area_struct;#define __GFP_NOFAIL 0x800/* Retry for ever. Cannot fail */ #define __GFP_NORETRY 0x1000/* Do not retry. Might fail */ #define __GFP_NO_GROW 0x2000/* Slab internal usage */ -#define __GFP_COMP 0x4000/* Add compound page metadata */ #define __GFP_BITS_SHIFT 16/* Room for 16 __GFP_FOO bits */ #define __GFP_BITS_MASK ((1 << __GFP_BITS_SHIFT) - 1)
@@ -44,7 +43,7 @@ struct vm_area_struct;/* if you forget to add the bitmask here kernel will crash, period */ #define GFP_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_FS| \ __GFP_COLD|__GFP_NOWARN|__GFP_REPEAT| \ - __GFP_NOFAIL|__GFP_NORETRY|__GFP_NO_GROW|__GFP_COMP) + __GFP_NOFAIL|__GFP_NORETRY|__GFP_NO_GROW)#define GFP_ATOMIC (__GFP_HIGH)#define GFP_NOIO (__GFP_WAIT)
include/linux/mm.h +49 -16
100 lines not on this page · raw message
include/linux/page-flags.h +6 -0
@@ -78,6 +78,7 @@#define PG_sharedpolicy 19/* Page was allocated for a file mapping using a shared_policy */ +#define PG_compound_slave 20/* second+ page of a compound page */ /* * Global page accounting. One instance per CPU. Only unsigned longs are
@@ -294,6 +295,11 @@ extern unsigned long __read_page_state(u#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) +#define __ClearPageCompound (page) __clear_bit(PG_compound, &(page)->flags) + +#define PageCompoundSlave (page) test_bit(PG_compound_slave, &(page)->flags) +#define SetPageCompoundSlave (page) set_bit(PG_compound_slave, &(page)->flags) +#define ClearPageCompoundSlave (page) clear_bit(PG_compound_slave, &(page)->flags)#define PageSharedPolicy (page) test_bit(PG_sharedpolicy, &(page)->flags)#define SetPageSharedPolicy (page) set_bit(PG_sharedpolicy, &(page)->flags)
init/Kconfig +13 -0
@@ -380,6 +380,19 @@ config TINY_SHMEM default !SHMEM bool +config ENHANCED_COMPOUND_PAGES + bool + default HUGETLB_PAGE || !MMU + help + + Enhance management of high-order pages by pointing the 2nd+ pages at + the first. get_page() and put_page() then use the usage count on the + first page to manage all the pages in the block. + + This is used when it might be necessary to access the intermediate + pages of a block, such as ptrace() might under nommu of hugetlb + conditions. + menu "Loadable module support" config MODULES
mm/hugetlb.c +3 -3
@@ -52,7 +52,7 @@ static struct page *alloc_fresh_huge_pag {static int nid =0 ;struct page *page; - page =alloc_pages_node (nid,GFP_HIGHUSER |__GFP_COMP|__GFP_NOWARN, + page =alloc_pages_node (nid,GFP_HIGHUSER |__GFP_NOWARN,HUGETLB_PAGE_ORDER ); nid = (nid +1 ) % numnodes;if (page) {
@@ -67,7 +67,7 @@ void free_huge_page(struct page *page)BUG_ON (page_count (page));INIT_LIST_HEAD (&page->lru); - page[1 ].mapping =NULL ; +set_page_dtor (page,NULL );spin_lock (&hugetlb_lock);enqueue_huge_page (page);
@@ -87,7 +87,7 @@ struct page *alloc_huge_page(void) }spin_unlock (&hugetlb_lock);set_page_count (page,1 ); - page[1 ].mapping = (void *)free_huge_page; +set_page_dtor (page, free_huge_page);for (i =0 ; i < (HPAGE_SIZE /PAGE_SIZE ); ++i)clear_highpage (&page[i]);return page;
mm/page_alloc.c +197 -128
419 lines not on this page · raw message