Compound page overhaul
Subsystems (4)
PATCH 1/1 Compound page overhaul
The attached patch overhauls compound 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:
- PG_compound is set on all subpages
- PG_compound_slave is set on all but the first subpage
- page[1].index holds the compound page order
- page[1...N-1].private points to page[0]
- page[1].mapping may hold a destructor function for put_page()
This is now done in prep_new_page().
(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) Trailing spaces have been cleaned up on lines in page_alloc.c.
(8) bootmem.c now has a separate path to release pages to the main allocator that bypasses many of the checks performed on struct pages.
bootmem.c's page releaser could be improved by giving the boot allocator's bitmap sufficient bits to make sure bit 0 is 32-page or 64-page aligned (depending on bits/long), even if the page to which it corresponds doesn't actually exist.
(9) bad_page() now prints more information, including information about more pages in the case of a compound page.
(10) prep_compound_page() and destroy_compound_page() have been absorbed.
(11) A lot more unlikely() clauses have been inserted in the free page checking functions.
(12) The !MMU bits have all gone from page_alloc.c.
(13) __pagevec_free() has moved to swap.c with all the other pagevec functions.
(14) 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 compound-2610rc2mm3.diff
include/linux/gfp.h | 3 include/linux/mm.h | 58 ++++-- include/linux/page-flags.h | 6 init/Kconfig | 13 + mm/bootmem.c | 28 +-- mm/hugetlb.c | 2 mm/internal.h | 3 mm/page_alloc.c | 399 +++++++++++++++++++++++++++------------------ mm/swap.c | 29 +-- 9 files changed, 335 insertions(+), 206 deletions(-)
include/linux/gfp.h renamed from warthog/kernels/linux-2.6.10-rc2-mm3/include/linux/gfp.h +1 -2
@@ -36,7 +36,6 @@#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 @@/* 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 renamed from warthog/kernels/linux-2.6.10-rc2-mm3/include/linux/mm.h +42 -16
93 lines not on this page · raw message
include/linux/page-flags.h renamed from warthog/kernels/linux-2.6.10-rc2-mm3/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 @@#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 renamed from warthog/kernels/linux-2.6.10-rc2-mm3/init/Kconfig +13 -0
@@ -380,6 +380,19 @@ 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/bootmem.c renamed from warthog/kernels/linux-2.6.10-rc2-mm3/mm/bootmem.c +16 -12
@@ -274,55 +274,59 @@ 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 ;
mm/hugetlb.c renamed from warthog/kernels/linux-2.6.10-rc2-mm3/mm/hugetlb.c +1 -1
@@ -52,7 +52,7 @@ {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) {
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 +245 -154
592 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 @@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
Quoted 1 line · David Howells
The attached patch overhauls compound page handling.
There's not really much to object to in concept.
Quoted 5 lines · David Howells
(1) A new bit flag
PG_compound_slavehas been added. This is used to mark the second+ subpages of a compound page, thus makingget_page()andput_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 thepage->lrumember instead of eating another page flag.
There are a lot of ways to do these things. Most of it is bitpacking and dodging assumptions in other code about various fields always being something or other they expect (e.g. bh's vs. page->private).
Quoted 8 lines · David Howells
(2) Compound page metadata is now always set on high-order pages when allocating and always checked when freeing:
-PG_compoundis set on all subpages
-PG_compound_slaveis set on all but the first subpage
- page[1].index holds the compound page order
- page[1...N-1].private points to page[0]
- page[1].mapping may hold a destructor function forput_page()
This is now done inprep_new_page().
A generally innocuous rearrangement. Some explanation of the advantage of these new bitpacking and field arrangements over the current arrangement may be good to have.
Quoted 2 lines · David Howells
(3)
__page_first()is now provided to find the first page of any page set (even single page sets).
I have to question the underscores. Also, there's a commonly-used term in the superpage literature, ``head of the superpage'', that may be more easily recognizable for readers familiar with that but not Linux specifics, but that's just nomenclature and not particularly pressing or any kind of requirement, just a non-Linux precedent.
Quoted 5 lines · David Howells
(4) A new config option
ENHANCED_COMPOUND_PAGESis now available. This is only set on !MMU orHUGETLB_PAGE. It causes__page_first()to dereferencepage->privateifPG_compound_slaveis set.
(5)__GFP_COMPis no longer required since compound metadata is always now set.
__GFP_COMP was introduced because several unusual drivers allocate higher-order pages and then move on to free fragments of them. There's a small danger some others may allocate higher-order pages and then treat each piece as a separate entity (particularly in the freeing pass).
Sweeping affected drivers to use a fragmenting primitive may help here.
Quoted 4 lines · David Howells
(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.
Possible, but it's likely a micro-optimization to cache the order in registers across function calls. The allocator is something of a ``hot path'' and small alterations can have noticeable effects.
Quoted 1 line · David Howells
(7) Trailing spaces have been cleaned up on lines in
page_alloc.c.
I like this quite a bit. =)
Quoted 6 lines · David Howells
(8)
bootmem.cnow has a separate path to release pages to the main allocator that bypasses many of the checks performed on struct pages. bootmem.c's page releaser could be improved by giving the boot allocator's bitmap sufficient bits to make sure bit 0 is 32-page or 64-page aligned (depending on bits/long), even if the page to which it corresponds doesn't actually exist.
Clearly it could merely scan the bitmap for the largest properly-sized, properly-aligned leading run of free bits beyond even that, though I wouldn't expect you to pursue that as it's far beyond the scope of the patch. I was hit up to deal with bootmem.c issues, and will be looking into that and more after the current set of bootmem changes has settled down and ia64 bootstrap has been stable for a while.
Quoted 3 lines · David Howells
(9)
bad_page()now prints more information, including information about more pages in the case of a compound page.
(10)prep_compound_page()anddestroy_compound_page()have been absorbed.
Not much to say about these.
Quoted 2 lines · David Howells
(11) A lot more
unlikely()clauses have been inserted in the free page checking functions.
Some people aren't wild about the branch prediction hints, though error checking is the poster child for ``predict not taken''.
Quoted 6 lines · David Howells
(12) The !MMU bits have all gone from
page_alloc.c.
(13)__pagevec_free()has moved toswap.cwith all the other pagevec functions.
(14)put_page()has moved topage_alloc.cwith all the other related functions. This could be relegated to a separate file, but since there are many other conditionals inpage_alloc.c, what's the point?
Not much to say here, either.
So, going over the code:
(1) the set_page_count() parenthesization is probably qualifies as a fix for a latent bug.
(2) The physaddr alignment comment in bootmem.c is mangled. It's not O(LOG2(BITS_PER_LONG)) -aligned, it's exactly LOG2(BITS_PER_LONG) aligned. But we don't have a LOG2(...) macro, we have fls()/ffs().
(3) page_count() probably deserves the %0*lx treatment in __bad_page(). Conserving screenspace when possible helps some, though that's offset a bit against predictable field alignment. Maybe putting variable-length fields at the end of the line would help. Also, the pfn would be great to have there, too, while you're at it.
(4) I wonder if anyone's run with CONFIG_DEBUG_PAGEALLOC recently. bootmem.c seems a bit early for kernel_map_pages() et al. It could be okay depending.
(5) This patch does a fair number of different things and it takes a bit of effort to wade through some of the longer rearrangements as they overflow 80x24. It would be helpful for reviewers if you could break this down into a somewhat more easily-digestible series of smaller patches.
Anyway, a more intense review from me will have to wait until my current hugetlb bughunt is wrapped up.
-- wli
Quoted 5 lines · William Lee Irwin III
Quoted 2 lines
(1) A new bit flag
PG_compound_slavehas been added. This is used to mark
...There are a lot of ways to do these things. Most of it is bitpacking and dodging assumptions in other code about various fields always being something or other they expect (e.g. bh's vs.
page->private).
I want to avoid putting magic numbers in page->private. What goes in there could be anything, as it's up to the filesystem.
Do you have any preferences? I'd prefer to use page->mapping, I think, except that's used for the destructor.
I should probably make a set-destructor function for hugetlbfs to call.
Quoted 3 lines
A generally innocuous rearrangement. Some explanation of the advantage of these new bitpacking and field arrangements over the current arrangement may be good to have.
The only differences are:
(1) PG_compound_slave now exists.
(2) I'm permitting the owner of the page to do do what it will with
page->private on the first page.
Quoted 4 lines
Quoted 2 lines
(3)
__page_first()is now provided to find the first page of any page set (even single page sets).I have to question the underscores.
The underscores can be dropped if they're not wanted.
Quoted 5 lines
Also, there's a commonly-used term in the superpage literature, ``head of the superpage'', that may be more easily recognizable for readers familiar with that but not Linux specifics, but that's just nomenclature and not particularly pressing or any kind of requirement, just a non-Linux precedent.
I couldn't think of a good name for it, so I settled on it being the first page.
How about page_head()?
Quoted 4 lines
__GFP_COMPwas introduced because several unusual drivers allocate higher-order pages and then move on to free fragments of them. There's a small danger some others may allocate higher-order pages and then treat each piece as a separate entity (particularly in the freeing pass).
I wasn't aware of that. Looking at the mm code, doing a fragmentary release would cause bad_page() to be invoked. Presumably these drivers modify the various struct pages involved directly to keep the allocator happy.
It would be better, I think, to provide a page splitter function. Thus allowing pages to be cut in half, and then have the two halves made into the equivalent allocated pages.
Quoted 1 line
Sweeping affected drivers to use a fragmenting primitive may help here.
Do you know which drivers?
Quoted 5 lines
Quoted 1 line
(6)
compound_page_order()is now available. This will indicate the order...
Possible, but it's likely a micro-optimization to cache the order in registers across function calls. The allocator is something of a ``hot path'' and small alterations can have noticeable effects.
Yes... but the order gets examined anyway in the free page checker, and the second plus page structs get modified too, so I don't think it'll make much of a difference. Plus the filesystem or driver that owned the page won't need to keep track of the size, nor will it need to calculate it.
Quoted 3 lines
Quoted 1 line
(7) Trailing spaces have been cleaned up on lines in
page_alloc.c.I like this quite a bit. =)
(defun trim () "Delete trailing whitespace in buffer" (interactive) (save-excursion (goto-char (point-min)) (replace-regexp "[ \t\r]+$" "") (goto-char (point-max)) (skip-chars-backward "\n") (if (not (eobp)) (delete-region (1+ (point)) (point-max)))))
Quoted 9 lines
Quoted 2 lines
(8)
bootmem.cnow has a separate path to release pages to the main allocator...
Clearly it could merely scan the bitmap for the largest properly-sized, properly-aligned leading run of free bits beyond even that, though I wouldn't expect you to pursue that as it's far beyond the scope of the patch. I was hit up to deal withbootmem.cissues, and will be looking into that and more after the current set of bootmem changes has settled down and ia64 bootstrap has been stable for a while.
I may look at doing this after this patch (or similar) goes in. If so, I'll send you the patch.
Quoted 3 lines
(2) The physaddr alignment comment in
bootmem.cis mangled. It's not O(LOG2(BITS_PER_LONG)) -aligned, it's exactlyLOG2(BITS_PER_LONG)aligned. But we don't have a LOG2(...) macro, we have fls()/ffs().
I suspect that's meant to be mathematical notation, not strictly compilable code, though I think there may be a missing "if" in it.
Quoted 4 lines
(3)
page_count()probably deserves the %0*lx treatment in__bad_page(). Conserving screenspace when possible helps some, though that's offset a bit against predictable field alignment. Maybe putting variable-length fields at the end of the line would help.
I don't think that matters too much. This message should never be seen, after all...
That said, I think I should probably provide a 64-bit version too... some of the fields will have 16-char widths there.
Quoted 1 line
Also, the pfn would be great to have there, too, while you're at it.
Okay.
Quoted 3 lines
(4) I wonder if anyone's run with
CONFIG_DEBUG_PAGEALLOCrecently.bootmem.cseems a bit early forkernel_map_pages()et al. It could be okay depending.
I can try it. BTW, should the free page checking be contingent on this option? Or maybe it should have its own option.
Quoted 5 lines
(5) This patch does a fair number of different things and it takes a bit of effort to wade through some of the longer rearrangements as they overflow 80x24. It would be helpful for reviewers if you could break this down into a somewhat more easily-digestible series of smaller patches.
It's a little tricky to break it up logically since it's mostly incredibly interrelated.
I could separate out some of the cleanups: rearrangement between files, trailing space splatting.
David
Quoted 3 lines · William Lee Irwin III
Quoted 3 lines
There are a lot of ways to do these things. Most of it is bitpacking and dodging assumptions in other code about various fields always being something or other they expect (e.g. bh's vs.
page->private).
Quoted 5 lines · David Howells
I want to avoid putting magic numbers in
page->private. What goes in there could be anything, as it's up to the filesystem.
Do you have any preferences? I'd prefer to usepage->mapping, I think, except that's used for the destructor.
I should probably make a set-destructor function for hugetlbfs to call.
That would help. I didn't look closely at the interaction with hugetlbfs owing to limited attention.
Quoted 3 lines · William Lee Irwin III
Quoted 3 lines
A generally innocuous rearrangement. Some explanation of the advantage of these new bitpacking and field arrangements over the current arrangement may be good to have.
Quoted 4 lines · David Howells
The only differences are:
(1)PG_compound_slavenow exists.
(2) I'm permitting the owner of the page to do do what it will withpage->private on the first page.
Freeing up page->private is helpful, true.
Quoted 5 lines · William Lee Irwin III
Quoted 5 lines
Also, there's a commonly-used term in the superpage literature, ``head of the superpage'', that may be more easily recognizable for readers familiar with that but not Linux specifics, but that's just nomenclature and not particularly pressing or any kind of requirement, just a non-Linux precedent.
Quoted 3 lines · David Howells
I couldn't think of a good name for it, so I settled on it being the first page.
How aboutpage_head()?
I held up the precedent because I sensed an afterthought. It would handle the underscores, too. =)
Quoted 5 lines · William Lee Irwin III
Quoted 5 lines
__GFP_COMPwas introduced because several unusual drivers allocate higher-order pages and then move on to free fragments of them. There's a small danger some others may allocate higher-order pages and then treat each piece as a separate entity (particularly in the freeing pass). Sweeping affected drivers to use a fragmenting primitive may help here.
Quoted 7 lines · David Howells
I wasn't aware of that. Looking at the mm code, doing a fragmentary release would cause
bad_page()to be invoked. Presumably these drivers modify the various struct pages involved directly to keep the allocator happy. It would be better, I think, to provide a page splitter function. Thus allowing pages to be cut in half, and then have the two halves made into the equivalent allocated pages.
Do you know which drivers?
I seem to remember something like acornfb, but I don't not the others.
Quoted 3 lines · William Lee Irwin III
Quoted 3 lines
Possible, but it's likely a micro-optimization to cache the order in registers across function calls. The allocator is something of a ``hot path'' and small alterations can have noticeable effects.
Quoted 4 lines · David Howells
Yes... but the order gets examined anyway in the free page checker, and the second plus page structs get modified too, so I don't think it'll make much of a difference. Plus the filesystem or driver that owned the page won't need to keep track of the size, nor will it need to calculate it.
Bringing in something like that as proof it removes instructions etc. should do the trick.
Quoted 1 line · William Lee Irwin III
Quoted 1 line
I like this quite a bit. =)
Quoted 10 lines · David Howells
(defun trim () "Delete trailing whitespace in buffer" (interactive) (save-excursion (goto-char (point-min)) (replace-regexp "[ \t\r]+$" "") (goto-char (point-max)) (skip-chars-backward "\n") (if (not (eobp)) (delete-region (1+ (point)) (point-max)))))
I'm not much of an EMACS fan. I can do similar things with other tools.
Quoted 6 lines · William Lee Irwin III
Quoted 6 lines
Clearly it could merely scan the bitmap for the largest properly-sized, properly-aligned leading run of free bits beyond even that, though I wouldn't expect you to pursue that as it's far beyond the scope of the patch. I was hit up to deal with
bootmem.cissues, and will be looking into that and more after the current set of bootmem changes has settled down and ia64 bootstrap has been stable for a while.
Quoted 2 lines · David Howells
I may look at doing this after this patch (or similar) goes in. If so, I'll send you the patch.
By all means.
Quoted 3 lines · William Lee Irwin III
Quoted 3 lines
(2) The physaddr alignment comment in
bootmem.cis mangled. It's not O(LOG2(BITS_PER_LONG)) -aligned, it's exactlyLOG2(BITS_PER_LONG)aligned. But we don't have a LOG2(...) macro, we have fls()/ffs().
Quoted 2 lines · David Howells
I suspect that's meant to be mathematical notation, not strictly compilable code, though I think there may be a missing "if" in it.
The specific choice of mathematical notation actually makes the whole thing meaningless. It really is meant to denote a specific value.
http://planetmath.org/encyclopedia/LandauNotation.html
http://mathworld.wolfram.com/LandauSymbols.html
http://www.nist.gov/dads/HTML/bigOnotation.html
http://en.wikipedia.org/wiki/Big_O_notation
http://encyclopedia.thefreedictionary.com/Landau%20symbol
Quoted 4 lines · William Lee Irwin III
Quoted 4 lines
(3)
page_count()probably deserves the %0*lx treatment in__bad_page(). Conserving screenspace when possible helps some, though that's offset a bit against predictable field alignment. Maybe putting variable-length fields at the end of the line would help.
Quoted 4 lines · David Howells
I don't think that matters too much. This message should never be seen, after all...
That said, I think I should probably provide a 64-bit version too... some of the fields will have 16-char widths there.
It does matter when people are trying to debug; I recently sent in an adjustment to widen the fields so useful bugreports wouldn't be mangled.
Quoted 3 lines · William Lee Irwin III
Quoted 3 lines
(4) I wonder if anyone's run with
CONFIG_DEBUG_PAGEALLOCrecently.bootmem.cseems a bit early forkernel_map_pages()et al. It could be okay depending.
Quoted 2 lines · David Howells
I can try it. BTW, should the free page checking be contingent on this option? Or maybe it should have its own option.
I'd be pretty hesitant to make the more basic integrity checks optional. Errors in this area are among the most common of all bugs in the kernel.
Quoted 5 lines · William Lee Irwin III
Quoted 5 lines
(5) This patch does a fair number of different things and it takes a bit of effort to wade through some of the longer rearrangements as they overflow 80x24. It would be helpful for reviewers if you could break this down into a somewhat more easily-digestible series of smaller patches.
Quoted 4 lines · David Howells
It's a little tricky to break it up logically since it's mostly incredibly interrelated.
I could separate out some of the cleanups: rearrangement between files, trailing space splatting.
Anything to lighten up the load on reviewers would help, really. At least for me, who has several urgent bughunts going on simultaneously.
-- wli
Quoted 10 lines · David Howells
The attached patch overhauls compound page handling.
(1) A new bit flag
PG_compound_slavehas been added. This is used to mark the second+ subpages of a compound page, thus makingget_page()andput_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->lrumember instead of eating another page flag.
Quoted 8 lines
(2) Compound page metadata is now always set on high-order pages when allocating and always checked when freeing:
-
PG_compoundis set on all subpages
-PG_compound_slaveis set on all but the first subpage
- page[1].index holds the compound page order
- page[1...N-1].private points to page[0]
- page[1].mapping may hold a destructor function forput_page()
ugh, sorry, I'd forgotten that !MMU needs to use the fields inside pages[1]. It seems that the !MMU requirement is in that case quite dissimilar from what compound pages are supposed to do. Perhaps we should just forget the whole thing and stick with the current design approach?
Andrew Morton <[email protected]>:
Quoted 4 lines
ugh, sorry, I'd forgotten that !MMU needs to use the fields inside pages[1]. It seems that the !MMU requirement is in that case quite dissimilar from what compound pages are supposed to do. Perhaps we should just forget the whole thing and stick with the current design approach?
Nonono... you misunderstand. Compound-pages support uses fields from page[1] to store extra data. It's nothing at all to do with MMU vs !MMU.
David
Quoted 10 lines · David Howells
Andrew Morton <[email protected]>:
Quoted 4 lines
ugh, sorry, I'd forgotten that !MMU needs to use the fields inside pages[1]. It seems that the !MMU requirement is in that case quite dissimilar from what compound pages are supposed to do. Perhaps we should just forget the whole thing and stick with the current design approach?
Nonono... you misunderstand. Compound-pages support uses fields from page[1] to store extra data.
I know. I wrote it.
Quoted 2 lines
It's nothing at all to do with MMU vs !MMU.
In that case I just dunno what's going on now.
I thought we were discussing the removal of this, from __free_pages_ok():
#ifndef CONFIG_MMU if (order > 0) for (i = 1 ; i < (1 << order) ; ++i) __put_page(page + i);
#endif
by using compound page's refcounting logic instead. But !MMU really wants to treat that higher-order page as an array of zero-order pages, and that requires the usual usage of the fields of page[1], page[2], etc.
So what I'm saying is "compound pages are designed for treating a higher-order page as a higher-order page. !MMU wants to treat a higher order page as an array of zero-order pages. Hence give up and stick with the current code".
What are you saying?
Quoted 3 lines
Quoted 3 lines
ugh, sorry, I'd forgotten that !MMU needs to use the fields inside pages[1].
Perhaps I misunderstood what you meant here. I _assumed_ you meant that it used the bits of pages[1] for compound page metadata - which it now does only because it's now using compound pages (if only with my patch applied).
Quoted 3 lines
But !MMU really wants to treat that higher-order page as an array of zero-order pages, and that requires the usual usage of the fields of page[1], page[2], etc.
That's not really so. For the most part, !MMU linux treats pages identically to MMU linux, whether those pages are big or small.
It's only for interprocess userspace access that there's an issue, and the issue there is, I think, that access_process_vm() wants to pin the page in place to stop it going away whilst it is being fiddled with.
Normally, the page is pinned in place by its refcount and/or flags. However, for compound pages, the refcount in question is really on the first page of the batch, and so refcount accesses should be directed there, and not to a secondary page.
Quoted 1 line
What are you saying?
!MMU linux doesn't actually need to use anything in page[1...N] of a compound page. The drivers don't. mmap doesn't.
The only thing I know of that comes close to breaking this rule is access_process_vm(), and that only slightly dents it, and then hammers the dent out afterwards.
Of course, there may an exception that breaks the rules, but I'm not aware of one.
David
Quoted 1 line · David Howells
Quoted 1 line
It's nothing at all to do with MMU vs !MMU.
Quoted 6 lines · Andrew Morton
In that case I just dunno what's going on now.
I thought we were discussing the removal of this, from__free_pages_ok():#ifndef CONFIG_MMU if (order > 0) for (i = 1 ; i < (1 << order) ; ++i) __put_page(page + i);
Quoted 9 lines
#endif
by using compound page's refcounting logic instead. But !MMU really wants to treat that higher-order page as an array of zero-order pages, and that requires the usual usage of the fields of page[1], page[2], etc. So what I'm saying is "compound pages are designed for treating a higher-order page as a higher-order page. !MMU wants to treat a higher order page as an array of zero-order pages. Hence give up and stick with the current code".
What are you saying?
The way I interpreted this is something like:
The usual way this goes (as I've seen it elsewhere) is that some fields are "base page properties", so each struct page in the subarray of mem_map the higher-order page represents can have some different, meaningful value for the field, and so on. Others are "superpage properties", which refer to the head of the higher-order page.
The MMU-less code appears to assume the refcounts of the tail pages will remain balanced, and elevates them to avoid the obvious disaster. But this looks rather broken barring some rather unlikely invariants. I presume the patch is backing that out so refcounting works properly, or in the nomenclature above (for which there is a precedent) makes the refcount a superpage property uniformly across MMU and MMU-less cases.
It's unclear (to me) how the current MMU-less code works properly, at the very least. It would appear to leak memory since there is no obvious guarantee the reference to the head page will be dropped when needed, though things may have intended to free the various tail pages.
i.e. AFAICT things really need to acquire and release references on the whole higher-order page as a unit for refcounting to actually work, regardless of MMU or no.
It may also be helpful for Greg Ungerer to help review these patches, as he appears to represent some of the other MMU-less concerns, and may have more concrete notions of how things behave in the MMU-less case than I myself do (hardware tends to resolve these issues, but that's not always feasible; perhaps an MMU-less port of a "normal" architecture would be enlightening to those otherwise unable to directly observe MMU-less behavior). In particular, correcting what misinterpretations in the above there may be.
-- wli
Quoted 4 lines · William Lee Irwin III
Quoted 2 lines
I had to fix it to make it work, but what's currently lurking in Andrew's tree seems more or less correct, just not necessarily safe.
Pardon my saying so, but "correct, but unsafe" sounds a bit oxymoronic. =)
True.
Quoted 2 lines
Unless FRV is surprisingly more widely distributed than it appears, it's unclear it will do much to help the
CONFIG_MMU=ntesting level.
Also true. It certainly won't hurt to get other archs (both MMU and !MMU testing this patch).
David
Quoted 3 lines · William Lee Irwin III
The MMU-less code appears to assume the refcounts of the tail pages will remain balanced, and elevates them to avoid the obvious disaster. But this looks rather broken barring some rather unlikely invariants.
I had to fix it to make it work, but what's currently lurking in Andrew's tree seems more or less correct, just not necessarily safe.
Quoted 3 lines
I presume the patch is backing that out so refcounting works properly, or in the nomenclature above (for which there is a precedent) makes the refcount a superpage property uniformly across MMU and MMU-less cases.
My patch drops the old !MMU page refcount wangling stuff in favour of using compound pages, which seem to work just as well.
Quoted 2 lines
It's unclear (to me) how the current MMU-less code works properly, at the very least.
For the most part it's down to two !MMU bits in page_alloc.c - one sets all the refcounts on the pages of a high-order allocation, and the other decrements them all again during the first part of freeing.
This works okay with access_process_vm() as is because that pins the mm_struct semaphore too; but it's also possible that something else does or will pin a secondary page and then drop the semaphore.
Quoted 3 lines
It would appear to leak memory since there is no obvious guarantee the reference to the head page will be dropped when needed, though things may have intended to free the various tail pages.
Actually, it's more a problem of the "superpage" being freed when the subpages have elevated counts.
Quoted 3 lines
i.e. AFAICT things really need to acquire and release references on the whole higher-order page as a unit for refcounting to actually work, regardless of MMU or no.
I agree.
Quoted 8 lines
It may also be helpful for Greg Ungerer to help review these patches, as he appears to represent some of the other MMU-less concerns, and may have more concrete notions of how things behave in the MMU-less case than I myself do (hardware tends to resolve these issues, but that's not always feasible; perhaps an MMU-less port of a "normal" architecture would be enlightening to those otherwise unable to directly observe MMU-less behavior). In particular, correcting what misinterpretations in the above there may be.
The FRV arch does both MMU and !MMU versions. It's settable by a config option, and I check both.
David
Quoted 3 lines
So why did you create a "Compound page overhaul" in the first place? Was it not to address some insufficiency for !MMU?
Not entirely. Part of it was to improve for !MMU use, and part of it was it looked like I could improve it in general both by making it more readable and by things such as making page->private available on the head page.
Linus suggested adding a CONFIG_COMPOUND_PAGE or something similar. By making half of the compound page stuff mandatory I could also get rid of some #ifdefs[*] for what appears to be a small overhead when allocating high-order pages when HUGETLBFS is not defined by making use of the fact that we'd be tickling the cache over the secondary page structures anyway.
[*] People seem to want to give me the impression that #ifdefs are evil and
should all be buried at least 10 feet down:-)
This in turn provides a way to simplify a number of other things, such as the "free_pages" functions.
There should be no overhead on single page handling when ENHANCED_COMPOUND_PAGES is not set. If it is set, then the overhead is pretty much the same as for hugetlbfs being compiled in now.
Quoted 1 line
The current compound page logic should handle that quite happily, no?
The current compound page implementation takes page->private away. What I've done gives it back, currently at the cost of one page flag bit, but there are ways around even that.
David
Quoted 3 lines · William Lee Irwin III
Quoted 3 lines
The MMU-less code appears to assume the refcounts of the tail pages will remain balanced, and elevates them to avoid the obvious disaster. But this looks rather broken barring some rather unlikely invariants.
Quoted 2 lines · David Howells
I had to fix it to make it work, but what's currently lurking in Andrew's tree seems more or less correct, just not necessarily safe.
Pardon my saying so, but "correct, but unsafe" sounds a bit oxymoronic. =)
Quoted 2 lines · William Lee Irwin III
Quoted 2 lines
It's unclear (to me) how the current MMU-less code works properly, at the very least.
Quoted 3 lines · David Howells
For the most part it's down to two !MMU bits in
page_alloc.c- one sets all the refcounts on the pages of a high-order allocation, and the other decrements them all again during the first part of freeing.
Yes, the issue centered around this not being sound.
Quoted 3 lines · William Lee Irwin III
Quoted 3 lines
It would appear to leak memory since there is no obvious guarantee the reference to the head page will be dropped when needed, though things may have intended to free the various tail pages.
Quoted 2 lines · David Howells
Actually, it's more a problem of the "superpage" being freed when the subpages have elevated counts.
I realized this shortly after hitting 'y'.
Quoted 8 lines · William Lee Irwin III
Quoted 8 lines
It may also be helpful for Greg Ungerer to help review these patches, as he appears to represent some of the other MMU-less concerns, and may have more concrete notions of how things behave in the MMU-less case than I myself do (hardware tends to resolve these issues, but that's not always feasible; perhaps an MMU-less port of a "normal" architecture would be enlightening to those otherwise unable to directly observe MMU-less behavior). In particular, correcting what misinterpretations in the above there may be.
Quoted 2 lines · David Howells
The FRV arch does both MMU and !MMU versions. It's settable by a config option, and I check both.
Unless FRV is surprisingly more widely distributed than it appears, it's unclear it will do much to help the CONFIG_MMU=n testing level.
Thanks.
-- wli
Quoted 8 lines · David Howells
Quoted 4 lines
Quoted 4 lines
ugh, sorry, I'd forgotten that !MMU needs to use the fields inside pages[1].
Perhaps I misunderstood what you meant here. I _assumed_ you meant that it used the bits of pages[1] for compound page metadata - which it now does only because it's now using compound pages (if only with my patch applied).
I thought that's what you meant ;)
So why did you create a "Compound page overhaul" in the first place? Was it not to address some insufficiency for !MMU?
Quoted 7 lines
Quoted 3 lines
But !MMU really wants to treat that higher-order page as an array of zero-order pages, and that requires the usual usage of the fields of page[1], page[2], etc.
That's not really so. For the most part, !MMU linux treats pages identically to MMU linux, whether those pages are big or small.
Quoted 8 lines
It's only for interprocess userspace access that there's an issue, and the issue there is, I think, that
access_process_vm()wants to pin the page in place to stop it going away whilst it is being fiddled with.Normally, the page is pinned in place by its refcount and/or flags. However, for compound pages, the refcount in question is really on the first page of the batch, and so refcount accesses should be directed there, and not to a secondary page.
The current compound page logic should handle that quite happily, no?
Quoted 32 lines · William Lee Irwin III
Quoted 1 line · David Howells
Quoted 1 line
It's nothing at all to do with MMU vs !MMU.
Quoted 6 lines · Andrew Morton
In that case I just dunno what's going on now.
I thought we were discussing the removal of this, from__free_pages_ok():#ifndef CONFIG_MMU if (order > 0) for (i = 1 ; i < (1 << order) ; ++i) __put_page(page + i);Quoted 9 lines
#endif
by using compound page's refcounting logic instead. But !MMU really wants to treat that higher-order page as an array of zero-order pages, and that requires the usual usage of the fields of page[1], page[2], etc. So what I'm saying is "compound pages are designed for treating a higher-order page as a higher-order page. !MMU wants to treat a higher order page as an array of zero-order pages. Hence give up and stick with the current code".
What are you saying?The way I interpreted this is something like:
The usual way this goes (as I've seen it elsewhere) is that some fields are "base page properties", so each struct page in the subarray of
mem_mapthe higher-order page represents can have some different, meaningful value for the field, and so on. Others are "superpage properties", which refer to the head of the higher-order page.
Quoted 6 lines
The MMU-less code appears to assume the refcounts of the tail pages will remain balanced, and elevates them to avoid the obvious disaster. But this looks rather broken barring some rather unlikely invariants. I presume the patch is backing that out so refcounting works properly, or in the nomenclature above (for which there is a precedent) makes the refcount a superpage property uniformly across MMU and MMU-less cases.
The MMUless code probably does not need to be done differently, as it is now. Backing out the refcounting changes for non-MMU is good, once the procfs problem is fixed. (At least as far as I can tell this is the case, and some limited testing seems to back that up).
Quoted 4 lines
It's unclear (to me) how the current MMU-less code works properly, at the very least. It would appear to leak memory since there is no obvious guarantee the reference to the head page will be dropped when needed, though things may have intended to free the various tail pages.
I am not aware of any memory leaks in practice, and I haven't heard from others of any specific problem.
Quoted 4 lines
i.e. AFAICT things really need to acquire and release references on the whole higher-order page as a unit for refcounting to actually work, regardless of MMU or no.
Quoted 8 lines
It may also be helpful for Greg Ungerer to help review these patches, as he appears to represent some of the other MMU-less concerns, and may have more concrete notions of how things behave in the MMU-less case than I myself do (hardware tends to resolve these issues, but that's not always feasible; perhaps an MMU-less port of a "normal" architecture would be enlightening to those otherwise unable to directly observe MMU-less behavior). In particular, correcting what misinterpretations in the above there may be.
The refcounting has been annoying me for a while, it just feels wrong. It has been done that way for a very long time (since 2.4.0 IIRC). I am sure there was more to it back in the 2.4 but I don't think we need to do it like this any more.
I don't have any problem with what David has done so far though I need to test it more extensively first.
Regards
Greg
------------------------------------------------------------------------
Greg Ungerer -- Chief Software Dude EMAIL: [email protected] SnapGear -- a CyberGuard Company PHONE: +61 7 3435 2888 825 Stanley St, FAX: +61 7 3891 3630 Woolloongabba, QLD, 4102, Australia WEB: http://www.SnapGear.com
Greg Ungerer <[email protected]>:
Quoted 4 lines
The refcounting has been annoying me for a while, it just feels wrong. It has been done that way for a very long time (since 2.4.0 IIRC). I am sure there was more to it back in the 2.4 but I don't think we need to do it like this any more.
It was like that in 2.4 also - where I first developed this arch and these mm changes. The refcount-on-free bug is there also. I don't know why no one else has hit it.
Quoted 2 lines
I don't have any problem with what David has done so far though I need to test it more extensively first.
That'd be great! :-)
I need to look at dumping my 2.4 arch & changes into the 2.4-uc kernels too.
David
Hi David,
Quoted 13 lines · David Howells
Greg Ungerer <[email protected]>:
Quoted 4 lines
The refcounting has been annoying me for a while, it just feels wrong. It has been done that way for a very long time (since 2.4.0 IIRC). I am sure there was more to it back in the 2.4 but I don't think we need to do it like this any more.
It was like that in 2.4 also - where I first developed this arch and these mm changes. The refcount-on-free bug is there also. I don't know why no one else has hit it.
Quoted 7 lines
Quoted 2 lines
I don't have any problem with what David has done so far though I need to test it more extensively first.
That'd be great! :-)
I need to look at dumping my 2.4 arch & changes into the 2.4-uc kernels too.
That would be good :-)
Regards
Greg
------------------------------------------------------------------------
Greg Ungerer -- Chief Software Dude EMAIL: [email protected] SnapGear -- a CyberGuard Company PHONE: +61 7 3435 2888 825 Stanley St, FAX: +61 7 3891 3630 Woolloongabba, QLD, 4102, Australia WEB: http://www.SnapGear.com