page-types: kernel pageflags mode
Subsystems (5)
PATCH 1/1 page-types: kernel pageflags mode
An earlier commit taught page-types the -d|--describe argument, which allows the user to describe page flags passed on the command line:
# ./Documentation/vm/page-types -d 0x4000 0x0000000000004000 ______________b___________________ swapbacked
In -d mode, page-types expects the page flag bits in the order generated by the kernel function get_uflags().
However, those bits are rearranged compared to what is actually stored in struct page->flags. A kernel developer dumping a page's flags using printk, e.g., may get misleading results in -d mode.
Teach page-types the -k mode, which parses and describes the bits in the internal kernel order:
# ./Documentation/vm/page-types -k 0x4000 0x0000000000004000 ______________H_________ compound_head
Note that the recommended way to build page-types is from the top-level kernel source directory. This ensures that it will get the same CONFIG_* defines used to build the kernel source.
# make Documentation/vm/
The implication is that attempting to use page-types -k on a kernel with different CONFIG_* settings may lead to surprising and misleading results. To retain sanity, always use the page-types built out of the kernel tree you are actually testing.
---
Applies on top of mmotm.
Documentation/vm/Makefile | 2 + Documentation/vm/page-types.c | 117 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 113 insertions(+), 6 deletions(-)
Documentation/vm/Makefile +2 -0
@@ -1,6 +1,8 @@ # kbuild trick to avoid linker error. Can be omitted if a module is built. obj- := dummy.o +HOSTCFLAGS_page-types.o += $(LINUXINCLUDE) + # List of programs to build hostprogs-y := slabinfo page-types
Documentation/vm/page-types.c +111 -6
183 lines not on this page · raw message
Quoted 48 lines · On Fri, 04 Dec 2009 14:29:48 -0700 Alex Chiang wrote:
An earlier commit taught page-types the -d|--describe argument, which allows the user to describe page flags passed on the command line:
#
./Documentation/vm/page-types-d0x40000x0000000000004000______________b___________________swapbackedIn -d mode, page-types expects the page flag bits in the order generated by the kernel function
get_uflags().However, those bits are rearranged compared to what is actually stored in struct
page->flags. A kernel developer dumping a page's flags using printk, e.g., may get misleading results in -d mode.Teach page-types the -k mode, which parses and describes the bits in the internal kernel order:
#
./Documentation/vm/page-types-k0x40000x0000000000004000______________H_________compound_headNote that the recommended way to build page-types is from the top-level kernel source directory. This ensures that it will get the same CONFIG_* defines used to build the kernel source.
# make Documentation/vm/The implication is that attempting to use page-types -k on a kernel with different CONFIG_* settings may lead to surprising and misleading results. To retain sanity, always use the page-types built out of the kernel tree you are actually testing.
Cc Haicheng Li <[email protected]>Cc Andi Kleen <[email protected]>Cc Randy Dunlap <[email protected]>Signed-off-by Alex Chiang <[email protected]>---
Applies on top of mmotm.
Documentation/vm/Makefile | 2 + Documentation/vm/page-types.c | 117 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 113 insertions(+), 6 deletions(-)Documentation/vm/Makefile +0
-0
Documentation/vm/Makefile line 7
Quoted 7 lines
Documentation/vm/Makefile +2
-0@@ -1,6 +1,8 @@ # kbuild trick to avoid linker error. Can be omitted if a module is built. obj- := dummy.o +HOSTCFLAGS_page-types.o += $(LINUXINCLUDE) + # List of programs to build hostprogs-y := slabinfo page-types
I can ack the Makefile part. Thanks for the patch.
Not that I expect this patch to change for this, but I think that we need to move tools (like this one) from Documentation/ to tools/ and possibly move examples from Documentation/ to samples/ or tools/.
---
~Randy
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
RFC 1/1 print symbolic page flag names in bad_page()
In reply to Alex ChiangHi Alex,
On Sat, Dec 05, 2009 at 05:29:48AM +0800, Alex Chiang wrote:
[...]
Quoted 5 lines
Teach page-types the -k mode, which parses and describes the bits in the internal kernel order:
#
./Documentation/vm/page-types-k0x40000x0000000000004000______________H_________compound_head
[...]
Quoted 4 lines
The implication is that attempting to use page-types -k on a kernel with different CONFIG_* settings may lead to surprising and misleading results. To retain sanity, always use the page-types built out of the kernel tree you are actually testing.
This is useful feature, however not as convenient if the kernel can print its page flag names directly :)
(especially when the dmesg comes from some end user)
So how about this patch?
---
mm: introduce dump_page()
- introduce dump_page() to print the page info for debugging some error condition.
- print an extra field: the symbolic names of page->flags
- convert three mm users: bad_page(), print_bad_pte() and memory offline failure.
--- mm/internal.h | 2 + mm/memory.c | 8 +--- mm/memory_hotplug.c | 6 +-- mm/page_alloc.c | 75 +++++++++++++++++++++++++++++++++++++++--- 4 files changed, 78 insertions(+), 13 deletions(-)
mm/page_alloc.c +71 -4
@@ -48,6 +48,7 @@#include <linux/page_cgroup.h> #include <linux/debugobjects.h> #include <linux/kmemleak.h> +#include <linux/kernel-page-flags.h> #include <trace/events/kmem.h> #include <asm/tlbflush.h>
@@ -262,10 +263,7 @@ static void bad_page(struct page *page)printk (KERN_ALERT "BUG: Bad page state in process %s pfn:%05lx\n" , current->comm,page_to_pfn (page)); -printk (KERN_ALERT -"page:%p flags:%p count:%d mapcount:%d mapping:%p index:%lx\n" , - page, (void *)page->flags,page_count (page), -page_mapcount (page), page->mapping, page->index); +dump_page (page);dump_stack (); out:
@@ -5106,3 +5104,72 @@ bool is_free_buddy_page(struct page *pagreturn order <MAX_ORDER ; }#endif + +static char *page_flag_names[] = { + [KPF_LOCKED ] ="L:locked" , + [KPF_ERROR ] ="E:error" , + [KPF_REFERENCED ] ="R:referenced" , + [KPF_UPTODATE ] ="U:uptodate" , + [KPF_DIRTY ] ="D:dirty" , + [KPF_LRU ] ="l:lru" , + [KPF_ACTIVE ] ="A:active" , + [KPF_SLAB ] ="S:slab" , + [KPF_WRITEBACK ] ="W:writeback" , + [KPF_RECLAIM ] ="I:reclaim" , + [KPF_BUDDY ] ="B:buddy" , + + [KPF_MMAP ] ="M:mmap" , + [KPF_ANON ] ="a:anonymous" , + [KPF_SWAPCACHE ] ="s:swapcache" , + [KPF_SWAPBACKED ] ="b:swapbacked" , + [KPF_COMPOUND_HEAD ] ="H:compound_head" , + [KPF_COMPOUND_TAIL ] ="T:compound_tail" , + [KPF_HUGE ] ="G:huge" , + [KPF_UNEVICTABLE ] ="u:unevictable" , + [KPF_HWPOISON ] ="X:hwpoison" , + [KPF_NOPAGE ] ="n:nopage" , + [KPF_KSM ] ="V:shared" , + + [KPF_RESERVED ] ="r:reserved" , + [KPF_MLOCKED ] ="m:mlocked" , + [KPF_MAPPEDTODISK ] ="d:mappedtodisk" , + [KPF_PRIVATE ] ="P:private" , + [KPF_PRIVATE_2 ] ="p:private_2" , + [KPF_OWNER_PRIVATE ] ="O:owner_private" , + [KPF_ARCH ] ="h:arch" , + [KPF_UNCACHED ] ="c:uncached" , +}; + +static char *page_flags_longname (struct page *page,char *buf,int buflen) +{ +int i, n; +u64 flags; + + flags =stable_page_flags (page); + +for (i =0 , n =0 ; i <ARRAY_SIZE (page_flag_names); i++) { +if (!page_flag_names[i]) +continue ; +if ((flags >> i) &1 ) + n +=snprintf (buf + n, buflen - n,"%s," , + page_flag_names[i] +2 ); + } +if (n) + n--; + buf[n] ='\0' ; + +return buf; +} + +void dump_page (struct page *page) +{ +char buf[1024 ]; + +printk (KERN_ALERT +"page:%p flags:%p(%s) count:%d mapcount:%d mapping:%p index:%lx\n" , + page, (void *)page->flags, +page_flags_longname (page, buf,sizeof (buf)), +page_count (page),page_mapcount (page), + page->mapping, page->index); +} +EXPORT_SYMBOL (dump_page);
mm/memory.c +2 -6
@@ -430,12 +430,8 @@ static void print_bad_pte(struct vm_area"BUG: Bad page map in process %s pte:%08llx pmd:%08llx\n" , current->comm, (long long)pte_val(pte), (long long)pmd_val(*pmd)); -if (page) { -printk (KERN_ALERT -"page:%p flags:%p count:%d mapcount:%d mapping:%p index:%lx\n" , - page, (void *)page->flags,page_count (page), -page_mapcount (page), page->mapping, page->index); - } +if (page) +dump_page (page);printk (KERN_ALERT "addr:%p vm_flags:%08lx anon_vma:%p mapping:%p index:%lx\n" , (void *)addr, vma->vm_flags, vma->anon_vma, mapping, index);
mm/internal.h +2 -0
@@ -264,6 +264,8 @@ int __get_user_pages(struct task_struct#define ZONE_RECLAIM_SUCCESS 1#endif +void dump_page (struct page *page); +extern int hwpoison_filter (struct page *p);extern u32 hwpoison_filter_dev_major;
mm/memory_hotplug.c +3 -3
@@ -678,9 +678,9 @@ do_migrate_range(unsigned long start_pfnif (page_count (page)) not_managed++;#ifdef CONFIG_DEBUG_VM -printk (KERN_INFO "removing from LRU failed" -" %lx/%d/%lx\n" , - pfn,page_count (page), page->flags); +printk (KERN_INFO "removing pfn %lx from LRU failed\n" , + pfn); +dump_page (page);#endif } }
Re: [RFC] print symbolic page flag names in bad_page()
Quoted 1 line
So how about this patch?
I like it. Decoding the flags by hand is always a very unpleasant experience.
Bonus: dump_page can be called from kgdb too.
-Andi
Re: [RFC] print symbolic page flag names in bad_page()
* Andi Kleen <[email protected]>:
Quoted 4 lines
Quoted 1 line
So how about this patch?
I like it. Decoding the flags by hand is always a very unpleasant experience.
Bonus:dump_pagecan be called from kgdb too.
This is fine by me too.
Thanks,
/ac
Re: [RFC] print symbolic page flag names in bad_page()
In reply to Andi KleenQuoted 4 lines · Andi Kleen
Quoted 1 line
So how about this patch?
I like it. Decoding the flags by hand is always a very unpleasant experience.
Bonus:dump_pagecan be called from kgdb too.
Thank you. And I'd like to elaborate a bit more on the rational.
Making the page-types tool depend on .config is fragile and dangerous. It would seem to work but silently return wrong results for a newbie user or a careless hacker.
And it's troublesome even for home made kernels by a kernel developer.
For example, typically I run many kernel trees with different versions and kconfigs (both of which change frequently) concurrently. This means I would have to judge to run "this" page-types or "that" page-types, and to check if this page-types is uptodate, and if the .config is in sync with the running kernel image..
An in-kernel dump_page() makes life easier.
Thanks,
Fengguang
Re: [RFC] print symbolic page flag names in bad_page()
In reply to Andi KleenQuoted 4 lines · Andi Kleen
Quoted 1 line
So how about this patch?
I like it. Decoding the flags by hand is always a very unpleasant experience. Bonus:
dump_pagecan be called from kgdb too.
Guys, please do more review:
mm/page_alloc.c bool is_free_buddy_page(struct page *pag · line 5166
Quoted 3 lines
mm/page_alloc.c +3
-0+void dump_page (struct page *page) +{ +char buf[1024 ];
NAK. This code causes a brutal, +1K kernel stack footprint spike that can crash a system _precisely_ when we are trying to dump a (presumably rare) condition.
Quoted 1 line
+EXPORT_SYMBOL(dump_page);
( Small detail: such exports are EXPORT_SYMBOL_GPL - we dont want random
external modules start using it. )
Thanks,
Ingo
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [RFC] print symbolic page flag names in bad_page()
In reply to Wu FengguangQuoted 15 lines · Wu Fengguang
Hi Alex,
On Sat, Dec 05, 2009 at 05:29:48AM +0800, Alex Chiang wrote:
[...]Quoted 5 lines
Teach page-types the -k mode, which parses and describes the bits in the internal kernel order:
#
./Documentation/vm/page-types-k0x40000x0000000000004000______________H_________compound_head[...]
Quoted 4 lines
The implication is that attempting to use page-types -k on a kernel with different CONFIG_* settings may lead to surprising and misleading results. To retain sanity, always use the page-types built out of the kernel tree you are actually testing.
Quoted 5 lines
This is useful feature, however not as convenient if the kernel can print its page flag names directly :)
(especially when the dmesg comes from some end user)So how about this patch?
There is a neat way of declaring strings that are used for the symbolic printing of flags in a bitfield. It's orientated around ftrace so not immediately usable for printk. Maybe the approaches can be merged but minimally, it'd be nice to match the declaration style. An example is show_gfp_flags in include/event/trace/kmem.h
Quoted 75 lines
---
mm: introduce
dump_page()- introduce
dump_page()to print the page info for debugging some error condition.
- print an extra field: the symbolic names ofpage->flags
- convert three mm users:bad_page(),print_bad_pte()and memory offline failure.Signed-off-by Wu Fengguang <[email protected]>--- mm/internal.h | 2 + mm/memory.c | 8 +--- mm/memory_hotplug.c | 6 +-- mm/page_alloc.c | 75 +++++++++++++++++++++++++++++++++++++++--- 4 files changed, 78 insertions(+), 13 deletions(-)mm/page_alloc.c +35
-4@@ -48,6 +48,7 @@#include <linux/page_cgroup.h> #include <linux/debugobjects.h> #include <linux/kmemleak.h> +#include <linux/kernel-page-flags.h> #include <trace/events/kmem.h> #include <asm/tlbflush.h> @@ -262,10 +263,7 @@ static void bad_page(struct page *page)printk (KERN_ALERT "BUG: Bad page state in process %s pfn:%05lx\n" , current->comm,page_to_pfn (page)); -printk (KERN_ALERT -"page:%p flags:%p count:%d mapcount:%d mapping:%p index:%lx\n" , - page, (void *)page->flags,page_count (page), -page_mapcount (page), page->mapping, page->index); +dump_page (page);dump_stack (); out:@@ -5106,3 +5104,72 @@ bool is_free_buddy_page(struct page *pagreturn order <MAX_ORDER ; }#endif + +static char *page_flag_names[] = { + [KPF_LOCKED ] ="L:locked" , + [KPF_ERROR ] ="E:error" , + [KPF_REFERENCED ] ="R:referenced" , + [KPF_UPTODATE ] ="U:uptodate" , + [KPF_DIRTY ] ="D:dirty" , + [KPF_LRU ] ="l:lru" , + [KPF_ACTIVE ] ="A:active" , + [KPF_SLAB ] ="S:slab" , + [KPF_WRITEBACK ] ="W:writeback" , + [KPF_RECLAIM ] ="I:reclaim" , + [KPF_BUDDY ] ="B:buddy" , + + [KPF_MMAP ] ="M:mmap" , + [KPF_ANON ] ="a:anonymous" , + [KPF_SWAPCACHE ] ="s:swapcache" , + [KPF_SWAPBACKED ] ="b:swapbacked" , + [KPF_COMPOUND_HEAD ] ="H:compound_head" , + [KPF_COMPOUND_TAIL ] ="T:compound_tail" , + [KPF_HUGE ] ="G:huge" , + [KPF_UNEVICTABLE ] ="u:unevictable" , + [KPF_HWPOISON ] ="X:hwpoison" , + [KPF_NOPAGE ] ="n:nopage" , + [KPF_KSM ] ="V:shared" , + + [KPF_RESERVED ] ="r:reserved" , + [KPF_MLOCKED ] ="m:mlocked" , + [KPF_MAPPEDTODISK ] ="d:mappedtodisk" , + [KPF_PRIVATE ] ="P:private" , + [KPF_PRIVATE_2 ] ="p:private_2" , + [KPF_OWNER_PRIVATE ] ="O:owner_private" , + [KPF_ARCH ] ="h:arch" ,
mm/page_alloc.c bool is_free_buddy_page(struct page *pag · line 5149
Quoted 10 lines
mm/page_alloc.c +10
-0+ [KPF_UNCACHED] = "c:uncached", +}; + +static char *page_flags_longname (struct page *page,char *buf,int buflen) +{ +int i, n; +u64 flags; + + flags =stable_page_flags (page); +
I don't see where this is defined. I assume there is a patch dependency I'm not seeing.
mm/page_alloc.c bool is_free_buddy_page(struct page *pag · line 5152
Quoted 3 lines
mm/page_alloc.c +3
-0+for (i =0 , n =0 ; i <ARRAY_SIZE (page_flag_names); i++) { +if (!page_flag_names[i]) +continue ;
How it is possible to get flags that are not recognised? Surely that that spark some sort of warning.
mm/page_alloc.c bool is_free_buddy_page(struct page *pag · line 5155
Quoted 3 lines
mm/page_alloc.c +3
-0+if ((flags >> i) &1 ) + n +=snprintf (buf + n, buflen - n,"%s," , + page_flag_names[i] +2 );
Should that be | instead of , ?
Why page_flag_names[i] + 2?
mm/page_alloc.c bool is_free_buddy_page(struct page *pag · line 5162
Quoted 7 lines
mm/page_alloc.c +7
-0+ } +if (n) + n--; + buf[n] ='\0' ; + +return buf; +}
As the symbolic long name is always going to printk(), why buffer it? It's slower to call printk() multiple times but it's hardly a performance-critical path and it avoids the declaration of buf.
mm/page_alloc.c bool is_free_buddy_page(struct page *pag · line 5167
Quoted 5 lines
mm/page_alloc.c +5
-0+ +void dump_page (struct page *page) +{ +char buf[1024 ]; +
Ingo flagged this already.
mm/page_alloc.c bool is_free_buddy_page(struct page *pag · line 5171
Quoted 4 lines
mm/page_alloc.c +4
-0+ printk(KERN_ALERT + "page:%p flags:%p(%s) count:%d mapcount:%d mapping:%p index:%lx\n", + page, (void *)page->flags, + page_flags_longname(page, buf, sizeof(buf)),
This can push things like count, mapcount and the like beyond the edge of 80 columns. While it rarely matters, it can get truncated on serial consoles depending on how they are being recorded. Can the string go to a line of it's own?
mm/page_alloc.c bool is_free_buddy_page(struct page *pag · line 5175
Quoted 4 lines
mm/page_alloc.c +4
-0+page_count (page),page_mapcount (page), + page->mapping, page->index); +} +EXPORT_SYMBOL (dump_page);
Ingo pointed out that this is exported GPL but I'm confused as to why it's exported at all. What module needs it?
Quoted 31 lines
mm/memory.c +2
-6@@ -430,12 +430,8 @@ static void print_bad_pte(struct vm_area"BUG: Bad page map in process %s pte:%08llx pmd:%08llx\n" , current->comm, (long long)pte_val(pte), (long long)pmd_val(*pmd)); -if (page) { -printk (KERN_ALERT -"page:%p flags:%p count:%d mapcount:%d mapping:%p index:%lx\n" , - page, (void *)page->flags,page_count (page), -page_mapcount (page), page->mapping, page->index); - } +if (page) +dump_page (page);printk (KERN_ALERT "addr:%p vm_flags:%08lx anon_vma:%p mapping:%p index:%lx\n" , (void *)addr, vma->vm_flags, vma->anon_vma, mapping, index);mm/internal.h +2
-0@@ -264,6 +264,8 @@ int __get_user_pages(struct task_struct#define ZONE_RECLAIM_SUCCESS 1#endif +void dump_page (struct page *page); +extern int hwpoison_filter (struct page *p);extern u32 hwpoison_filter_dev_major;
mm/memory_hotplug.c do_migrate_range(unsigned long start_pfn · line 683
Quoted 9 lines
mm/memory_hotplug.c +3
-3@@ -678,9 +678,9 @@ do_migrate_range(unsigned long start_pfnif (page_count (page)) not_managed++;#ifdef CONFIG_DEBUG_VM -printk (KERN_INFO "removing from LRU failed" -" %lx/%d/%lx\n" , - pfn,page_count (page), page->flags); +printk (KERN_INFO "removing pfn %lx from LRU failed\n" , + pfn); +dump_page (page);
The message is printed at KERN_INFO and the dump at KERN_ALERT. Is this intentional?
Quoted 4 lines
mm/memory_hotplug.c +0
-0#endif } }
Signature · 3 lines
Mel Gorman Part-time Phd Student Linux Technology Center University of Limerick IBM Dublin Software Lab
Re: [RFC] print symbolic page flag names in bad_page()
Hi Mel,
Sorry for the delay!
Quoted 20 lines · Mel Gorman
Quoted 19 lines · Wu Fengguang
Hi Alex,
On Sat, Dec 05, 2009 at 05:29:48AM +0800, Alex Chiang wrote:
[...]Quoted 5 lines
Teach page-types the -k mode, which parses and describes the bits in the internal kernel order:
#
./Documentation/vm/page-types-k0x40000x0000000000004000______________H_________compound_head[...]
Quoted 4 lines
The implication is that attempting to use page-types -k on a kernel with different CONFIG_* settings may lead to surprising and misleading results. To retain sanity, always use the page-types built out of the kernel tree you are actually testing.
This is useful feature, however not as convenient if the kernel can print its page flag names directly :)
(especially when the dmesg comes from some end user)
Quoted 7 lines
Quoted 1 line
So how about this patch?
There is a neat way of declaring strings that are used for the symbolic printing of flags in a bitfield. It's orientated around ftrace so not immediately usable for printk. Maybe the approaches can be merged but minimally, it'd be nice to match the declaration style. An example is
show_gfp_flagsininclude/event/trace/kmem.h
Good tip, thanks!
Converting to the (mask, name) array almost doubles the space, however that makes it usable to ftrace users, so I converted the plain string array page_flag_names[] to "struct trace_print_flags *".
Quoted 80 lines
Quoted 80 lines
---
mm: introduce
dump_page()- introduce
dump_page()to print the page info for debugging some error condition.
- print an extra field: the symbolic names ofpage->flags
- convert three mm users:bad_page(),print_bad_pte()and memory offline failure.Signed-off-by Wu Fengguang <[email protected]>--- mm/internal.h | 2 + mm/memory.c | 8 +--- mm/memory_hotplug.c | 6 +-- mm/page_alloc.c | 75 +++++++++++++++++++++++++++++++++++++++--- 4 files changed, 78 insertions(+), 13 deletions(-)mm/page_alloc.c +40
-4@@ -48,6 +48,7 @@#include <linux/page_cgroup.h> #include <linux/debugobjects.h> #include <linux/kmemleak.h> +#include <linux/kernel-page-flags.h> #include <trace/events/kmem.h> #include <asm/tlbflush.h> @@ -262,10 +263,7 @@ static void bad_page(struct page *page)printk (KERN_ALERT "BUG: Bad page state in process %s pfn:%05lx\n" , current->comm,page_to_pfn (page)); -printk (KERN_ALERT -"page:%p flags:%p count:%d mapcount:%d mapping:%p index:%lx\n" , - page, (void *)page->flags,page_count (page), -page_mapcount (page), page->mapping, page->index); +dump_page (page);dump_stack (); out:@@ -5106,3 +5104,72 @@ bool is_free_buddy_page(struct page *pagreturn order <MAX_ORDER ; }#endif + +static char *page_flag_names[] = { + [KPF_LOCKED ] ="L:locked" , + [KPF_ERROR ] ="E:error" , + [KPF_REFERENCED ] ="R:referenced" , + [KPF_UPTODATE ] ="U:uptodate" , + [KPF_DIRTY ] ="D:dirty" , + [KPF_LRU ] ="l:lru" , + [KPF_ACTIVE ] ="A:active" , + [KPF_SLAB ] ="S:slab" , + [KPF_WRITEBACK ] ="W:writeback" , + [KPF_RECLAIM ] ="I:reclaim" , + [KPF_BUDDY ] ="B:buddy" , + + [KPF_MMAP ] ="M:mmap" , + [KPF_ANON ] ="a:anonymous" , + [KPF_SWAPCACHE ] ="s:swapcache" , + [KPF_SWAPBACKED ] ="b:swapbacked" , + [KPF_COMPOUND_HEAD ] ="H:compound_head" , + [KPF_COMPOUND_TAIL ] ="T:compound_tail" , + [KPF_HUGE ] ="G:huge" , + [KPF_UNEVICTABLE ] ="u:unevictable" , + [KPF_HWPOISON ] ="X:hwpoison" , + [KPF_NOPAGE ] ="n:nopage" , + [KPF_KSM ] ="V:shared" , + + [KPF_RESERVED ] ="r:reserved" , + [KPF_MLOCKED ] ="m:mlocked" , + [KPF_MAPPEDTODISK ] ="d:mappedtodisk" , + [KPF_PRIVATE ] ="P:private" , + [KPF_PRIVATE_2 ] ="p:private_2" , + [KPF_OWNER_PRIVATE ] ="O:owner_private" , + [KPF_ARCH ] ="h:arch" , + [KPF_UNCACHED ] ="c:uncached" , +}; + +static char *page_flags_longname (struct page *page,char *buf,int buflen) +{
Quoted 8 lines
mm/page_alloc.c bool is_free_buddy_page(struct page *pag · line 5149
Quoted 5 lines
mm/page_alloc.c +5
-0+int i, n; +u64 flags; + + flags =stable_page_flags (page); +I don't see where this is defined. I assume there is a patch dependency I'm not seeing.
It's posted several days ago:
http://lkml.org/lkml/2009/12/1/470
It's effectively the internal page flags plus some useful fake ones, eg. PageAnon(), PageKsm(), PageHuge().
It's not a big deal - developers can more or less deduce that for themselves. And there are two problems:
- stable_page_flags() currently depends on CONFIG_PROC_PAGE_MONITOR
- stable_page_flags() uses u64 flags, which is incompatible with struct trace_print_flags.
So I'll use plain page flags instead.
Quoted 6 lines
mm/page_alloc.c bool is_free_buddy_page(struct page *pag · line 5152
Quoted 3 lines
mm/page_alloc.c +3
-0+for (i =0 , n =0 ; i <ARRAY_SIZE (page_flag_names); i++) { +if (!page_flag_names[i]) +continue ;How it is possible to get flags that are not recognised? Surely that that spark some sort of warning.
OK. I'll print the remained raw bits just like ftrace_print_flags_seq(). (In fact I copied the main logic from ftrace_print_flags_seq() :)
Quoted 5 lines
mm/page_alloc.c bool is_free_buddy_page(struct page *pag · line 5155
Quoted 3 lines
mm/page_alloc.c +3
-0+if ((flags >> i) &1 ) + n +=snprintf (buf + n, buflen - n,"%s," , + page_flag_names[i] +2 );Why page_flag_names[i] + 2?
Sorry, the code (and string array) is copied from the user space tool Documentation/vm/page-types.c ... now completed rewritten based on the ftrace function.
Quoted 1 line
Should that be | instead of , ?
page-types chose "," because the pipe symbol "|" is not that user friendly. "|" is more developer friendly though, so will use it.
Quoted 12 lines
mm/page_alloc.c bool is_free_buddy_page(struct page *pag · line 5162
Quoted 7 lines
mm/page_alloc.c +7
-0+ } +if (n) + n--; + buf[n] ='\0' ; + +return buf; +}As the symbolic long name is always going to
printk(), why buffer it? It's slower to callprintk()multiple times but it's hardly a performance-critical path and it avoids the declaration of buf.
Quoted 7 lines
mm/page_alloc.c bool is_free_buddy_page(struct page *pag · line 5167
Quoted 5 lines
mm/page_alloc.c +5
-0+ +void dump_page (struct page *page) +{ +char buf[1024 ]; +Ingo flagged this already.
Removed now.
Quoted 9 lines
mm/page_alloc.c bool is_free_buddy_page(struct page *pag · line 5171
Quoted 4 lines
mm/page_alloc.c +4
-0+ printk(KERN_ALERT + "page:%p flags:%p(%s) count:%d mapcount:%d mapping:%p index:%lx\n", + page, (void *)page->flags, + page_flags_longname(page, buf, sizeof(buf)),This can push things like count, mapcount and the like beyond the edge of 80 columns. While it rarely matters, it can get truncated on serial consoles depending on how they are being recorded. Can the string go to a line of it's own?
OK, I make a standalone line for flags (showing both hex and string).
Quoted 7 lines
mm/page_alloc.c bool is_free_buddy_page(struct page *pag · line 5175
Quoted 4 lines
mm/page_alloc.c +4
-0+page_count (page),page_mapcount (page), + page->mapping, page->index); +} +EXPORT_SYMBOL (dump_page);Ingo pointed out that this is exported GPL but I'm confused as to why it's exported at all. What module needs it?
I'm testing dump_page() in a kernel module ;) Will remove the export for now.
Quoted 27 lines
Quoted 27 lines
mm/memory.c +2
-6@@ -430,12 +430,8 @@ static void print_bad_pte(struct vm_area"BUG: Bad page map in process %s pte:%08llx pmd:%08llx\n" , current->comm, (long long)pte_val(pte), (long long)pmd_val(*pmd)); -if (page) { -printk (KERN_ALERT -"page:%p flags:%p count:%d mapcount:%d mapping:%p index:%lx\n" , - page, (void *)page->flags,page_count (page), -page_mapcount (page), page->mapping, page->index); - } +if (page) +dump_page (page);printk (KERN_ALERT "addr:%p vm_flags:%08lx anon_vma:%p mapping:%p index:%lx\n" , (void *)addr, vma->vm_flags, vma->anon_vma, mapping, index);mm/internal.h +2
-0@@ -264,6 +264,8 @@ int __get_user_pages(struct task_struct#define ZONE_RECLAIM_SUCCESS 1#endif +void dump_page (struct page *page); +extern int hwpoison_filter (struct page *p);
Quoted 16 lines
mm/memory_hotplug.c do_migrate_range(unsigned long start_pfn · line 683
Quoted 13 lines
mm/internal.h +0
-0extern u32 hwpoison_filter_dev_major;mm/memory_hotplug.c +3
-3@@ -678,9 +678,9 @@ do_migrate_range(unsigned long start_pfnif (page_count (page)) not_managed++;#ifdef CONFIG_DEBUG_VM -printk (KERN_INFO "removing from LRU failed" -" %lx/%d/%lx\n" , - pfn,page_count (page), page->flags); +printk (KERN_INFO "removing pfn %lx from LRU failed\n" , + pfn); +dump_page (page);The message is printed at
KERN_INFOand the dump atKERN_ALERT. Is this intentional?
Good catch, it looks more consistent to convert the original KERN_INFO to KERN_ALERT.
Updated patch follows, thanks for the helpful review!
Thanks,
Fengguang
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>